No OneTemporary

File Metadata

Created
Sat, May 4, 7:08 AM
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/3rdparty/ext_lcms2/CMakeLists.txt b/3rdparty/ext_lcms2/CMakeLists.txt
index 79e77aae03..0ca88019f3 100644
--- a/3rdparty/ext_lcms2/CMakeLists.txt
+++ b/3rdparty/ext_lcms2/CMakeLists.txt
@@ -1,27 +1,27 @@
SET(PREFIX_ext_lcms2 "${EXTPREFIX}" )
if (MINGW)
ExternalProject_Add( ext_lcms2
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
- URL http://files.kde.org/krita/build/dependencies/lcms2-2.9.tar.gz
- URL_MD5 8de1b7724f578d2995c8fdfa35c3ad0e
+ URL http://files.kde.org/krita/build/dependencies/lcms2-2.10.tar.gz
+ URL_MD5 c5f915d681325e0767e40187799f23b1
- PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/lcms2-9.diff
+ PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/lcms2-10.diff
INSTALL_DIR ${PREFIX_ext_lcms2}
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${PREFIX_ext_lcms2} -DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE} ${GLOBAL_PROFILE} -DBUILD_TESTS=FALSE -DBUILD_UTILS=FALSE -DBUILD_STATIC=FALSE
UPDATE_COMMAND ""
DEPENDS ext_patch
)
else ()
ExternalProject_Add( ext_lcms2
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
- URL http://files.kde.org/krita/build/dependencies/lcms2-2.9.tar.gz
- URL_MD5 8de1b7724f578d2995c8fdfa35c3ad0e
+ URL http://files.kde.org/krita/build/dependencies/lcms2-2.10.tar.gz
+ URL_MD5 c5f915d681325e0767e40187799f23b1
- PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/lcms2-9.diff
+ PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/lcms2-10.diff
INSTALL_DIR ${PREFIX_ext_lcms2}
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${PREFIX_ext_lcms2} -DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE} ${GLOBAL_PROFILE} -DBUILD_TESTS=FALSE -DBUILD_UTILS=FALSE -DBUILD_STATIC=FALSE
UPDATE_COMMAND ""
)
endif ()
diff --git a/3rdparty/ext_lcms2/lcms2-9.diff b/3rdparty/ext_lcms2/lcms2-10.diff
similarity index 84%
rename from 3rdparty/ext_lcms2/lcms2-9.diff
rename to 3rdparty/ext_lcms2/lcms2-10.diff
index 841615dd40..698c3764d4 100644
--- a/3rdparty/ext_lcms2/lcms2-9.diff
+++ b/3rdparty/ext_lcms2/lcms2-10.diff
@@ -1,250 +1,258 @@
-commit e346c86dea71e995623f3a1702ff4ade847c16c7
+commit 5f0c7d33243388e0fc840c5e2aba49e1c6147a21
Author: Boudewijn Rempt <boud@valdyas.org>
-Date: Thu Jan 4 11:49:42 2018 +0100
+Date: Tue Jun 2 12:49:24 2020 +0200
- Add cmake build system to lcms 2.9
+ Add cmake build system
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
-index 0000000..735dd7a
+index 0000000..213c808
--- /dev/null
+++ b/CMakeLists.txt
-@@ -0,0 +1,22 @@
+@@ -0,0 +1,25 @@
+project(lcms2)
+
+option(BUILD_TESTS "build the test executable" OFF)
+option(BUILD_STATIC "build the static library" OFF)
+option(BUILD_UTILS "build the utilities executables" OFF)
++option(BUILD_PLUGINS "build the plugins" ON)
+
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+
+cmake_minimum_required(VERSION 2.6)
+
+include_directories(
+${CMAKE_BINARY_DIR}/include
+${CMAKE_SOURCE_DIR}/include
+)
+
+add_subdirectory(src)
++
+if(BUILD_TESTS)
+ add_subdirectory(testbed)
+endif(BUILD_TESTS)
++
+if(BUILD_UTILS)
+ add_subdirectory(utils)
+endif(BUILD_UTILS)
diff --git a/include/lcms2.h b/include/lcms2.h
-index 9e7ee4c..4ee1b7b 100644
+index 99e0308..3056533 100644
--- a/include/lcms2.h
+++ b/include/lcms2.h
-@@ -215,15 +215,14 @@ typedef int cmsBool;
+@@ -225,15 +225,14 @@ typedef int cmsBool;
#endif // CMS_USE_BIG_ENDIAN
-
// Calling convention -- this is hardly platform and compiler dependent
#ifdef CMS_IS_WINDOWS_
-# if defined(CMS_DLL) || defined(CMS_DLL_BUILD)
+# if !defined(CMS_STATIC)
# ifdef __BORLANDC__
# define CMSEXPORT __stdcall _export
# define CMSAPI
# else
-# define CMSEXPORT __stdcall
+# define CMSEXPORT
# ifdef CMS_DLL_BUILD
# define CMSAPI __declspec(dllexport)
# else
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
-index 0000000..ac575c7
+index 0000000..a8a0640
--- /dev/null
+++ b/src/CMakeLists.txt
-@@ -0,0 +1,64 @@
+@@ -0,0 +1,82 @@
+# some configure checks:
+if(WIN32)
+ if(MSVC)
+ set(UINT8_T "unsigned char")
+ set(UINT16_T "unsigned short")
+ set(UINT32_T "unsigned long")
+ set(INT8_T "char")
+ set(INT16_T "short")
+ set(INT32_T "long")
+ else(MSVC)
+ set(UINT8_T "uint8_t")
+ set(UINT16_T "uint16_t")
+ set(UINT32_T "uint32_t")
+ set(INT8_T "int8_t")
+ set(INT16_T "int16_t")
+ set(INT32_T "int32_t")
+ endif(MSVC)
+endif(WIN32)
+
+set(lcms_SRCS
+ cmscnvrt.c
+ cmserr.c
+ cmsgamma.c
+ cmsgmt.c
+ cmsintrp.c
+ cmsio0.c
+ cmsio1.c
+ cmslut.c
+ cmsplugin.c
+ cmssm.c
+ cmsmd5.c
+ cmsmtrx.c
+ cmspack.c
+ cmspcs.c
+ cmswtpnt.c
+ cmsxform.c
+ cmssamp.c
+ cmsnamed.c
+ cmscam02.c
+ cmsvirt.c
+ cmstypes.c
+ cmscgats.c
+ cmsps2.c
+ cmsopt.c
+ cmshalf.c
+ cmsalpha.c
+)
+
-+include_directories(${CMAKE_BINARY_DIR})
++if (BUILD_PLUGINS)
++ set(lcms_SRCS ${lcms_SRCS}
++ ../plugins/fast_float/src/fast_16_tethra.c
++ ../plugins/fast_float/src/fast_8_curves.c
++ ../plugins/fast_float/src/fast_8_matsh.c
++ ../plugins/fast_float/src/fast_8_matsh_sse.c
++ ../plugins/fast_float/src/fast_8_tethra.c
++ ../plugins/fast_float/src/fast_float_15bits.c
++ ../plugins/fast_float/src/fast_float_15mats.c
++ ../plugins/fast_float/src/fast_float_cmyk.c
++ ../plugins/fast_float/src/fast_float_curves.c
++ ../plugins/fast_float/src/fast_float_matsh.c
++ ../plugins/fast_float/src/fast_float_separate.c
++ ../plugins/fast_float/src/fast_float_sup.c
++ ../plugins/fast_float/src/fast_float_tethra.c
++ )
++endif()
++
++include_directories(${CMAKE_BINARY_DIR} ../plugins/fast_float/include)
+
+add_library(lcms SHARED ${lcms_SRCS})
+set_target_properties(lcms PROPERTIES OUTPUT_NAME "lcms2"
+ DEFINE_SYMBOL CMS_DLL_BUILD)
+
+if(BUILD_TESTS OR BUILD_UTILS OR BUILD_STATIC)
+ add_library(lcms_static ${lcms_SRCS})
+ set_target_properties(lcms_static PROPERTIES COMPILE_FLAGS -DCMS_STATIC)
+ set(LCMS_STATIC lcms_static)
+endif(BUILD_TESTS OR BUILD_UTILS OR BUILD_STATIC)
+
+install(TARGETS lcms ${LCMS_STATIC} RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib)
+install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../include/lcms2.h ${CMAKE_CURRENT_SOURCE_DIR}/../include/lcms2_plugin.h DESTINATION include)
diff --git a/testbed/CMakeLists.txt b/testbed/CMakeLists.txt
new file mode 100644
index 0000000..ca9008b
--- /dev/null
+++ b/testbed/CMakeLists.txt
@@ -0,0 +1,5 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include ${CMAKE_CURRENT_SOURCE_DIR}/../src)
+
+add_executable(testcms testcms2.c testplugin.c zoo_icc.c)
+target_link_libraries(testcms lcms_static)
+set_target_properties(testcms PROPERTIES COMPILE_FLAGS -DCMS_STATIC)
-diff --git a/testbed/testcms2.c b/testbed/testcms2.c
-index 5bd5447..ff650f2 100644
---- a/testbed/testcms2.c
-+++ b/testbed/testcms2.c
-@@ -28,7 +28,7 @@
- #include "testcms2.h"
-
- // On Visual Studio, use debug CRT
--#ifdef _MSC_VER
-+#ifdef _WIN32
- # include "crtdbg.h"
- # include <io.h>
- #endif
diff --git a/testbed/zoo_icc.c b/testbed/zoo_icc.c
-index f68861c..fdd0b7c 100755
+index a220db7..b5e253a 100755
--- a/testbed/zoo_icc.c
+++ b/testbed/zoo_icc.c
@@ -27,6 +27,11 @@
#include "testcms2.h"
+#ifdef _WIN32
+# include "crtdbg.h"
+# include <io.h>
+#endif
+
// ZOO checks ------------------------------------------------------------------------------------------------------------
diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
new file mode 100644
index 0000000..c3be5bf
--- /dev/null
+++ b/utils/CMakeLists.txt
@@ -0,0 +1,78 @@
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/../include
+ ${CMAKE_CURRENT_SOURCE_DIR}/../src
+ ${CMAKE_CURRENT_SOURCE_DIR}/../utils/common
+)
+
+find_package(JPEG)
+find_package(TIFF)
+
+set(UTILS_EXECUTABLES )
+set(UTILS_MANPAGES )
+
+###############################################################################
+if(JPEG_FOUND)
+ include_directories(${JPEG_INCLUDE_DIR})
+ set(JPGICC_SRCS
+ jpgicc/jpgicc.c
+ jpgicc/iccjpeg.c
+ common/xgetopt.c
+ common/vprf.c
+ )
+ add_executable(jpgicc ${JPGICC_SRCS})
+ target_link_libraries(jpgicc lcms ${JPEG_LIBRARIES})
+ list(APPEND UTILS_EXECUTABLES jpgicc)
+ list(APPEND UTILS_MANPAGES jpgicc/jpgicc.1)
+endif(JPEG_FOUND)
+
+###############################################################################
+set(LINKICC_SRCS
+ linkicc/linkicc.c
+ common/xgetopt.c
+ common/vprf.c
+)
+add_executable(linkicc ${LINKICC_SRCS})
+target_link_libraries(linkicc lcms)
+list(APPEND UTILS_EXECUTABLES linkicc)
+list(APPEND UTILS_MANPAGES linkicc/linkicc.1)
+
+###############################################################################
+set(PSICC_SRCS
+ psicc/psicc.c
+ common/xgetopt.c
+ common/vprf.c
+)
+add_executable(psicc ${PSICC_SRCS})
+target_link_libraries(psicc lcms)
+list(APPEND UTILS_EXECUTABLES psicc)
+list(APPEND UTILS_MANPAGES psicc/psicc.1)
+
+###############################################################################
+if(TIFF_FOUND)
+ include_directories(${TIFF_INCLUDE_DIR})
+ set(JPGICC_SRCS
+ tificc/tificc.c
+ common/xgetopt.c
+ common/vprf.c
+ )
+ add_executable(tificc ${JPGICC_SRCS})
+ target_link_libraries(tificc lcms ${TIFF_LIBRARIES})
+ list(APPEND UTILS_EXECUTABLES tificc)
+ list(APPEND UTILS_MANPAGES tificc/tificc.1)
+endif(TIFF_FOUND)
+
+###############################################################################
+set(TRANSICC_SRCS
+ transicc/transicc.c
+ common/xgetopt.c
+ common/vprf.c
+)
+add_executable(transicc ${TRANSICC_SRCS})
+target_link_libraries(transicc lcms)
+list(APPEND UTILS_EXECUTABLES transicc)
+list(APPEND UTILS_MANPAGES transicc/transicc.1)
+
+install(TARGETS ${UTILS_EXECUTABLES} RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib)
+install(FILES ${UTILS_MANPAGES} DESTINATION share/man/man1)
diff --git a/krita/data/actions/CMakeLists.txt b/krita/data/actions/CMakeLists.txt
index 18914973b4..85b086d3f0 100644
--- a/krita/data/actions/CMakeLists.txt
+++ b/krita/data/actions/CMakeLists.txt
@@ -1,6 +1,5 @@
install( FILES
InteractionTool.action
PathTool.action
- ConnectionTool.action
MoveTool.action
DESTINATION ${DATA_INSTALL_DIR}/krita/actions)
diff --git a/krita/data/actions/ConnectionTool.action b/krita/data/actions/ConnectionTool.action
deleted file mode 100644
index 22e2b77af1..0000000000
--- a/krita/data/actions/ConnectionTool.action
+++ /dev/null
@@ -1,160 +0,0 @@
-<!-- Disabled, since Connection Tool is disabled in Krita
-
-<?xml version="1.0" encoding="UTF-8"?>
-<ActionCollection version="2" name="Tools">
- <Actions category="connection-tool">
- <text>Connection Tool</text>
- <Action name="toggle-edit-mode">
- <iconText>Edit connection points</iconText>
- <shortcut></shortcut>
- <toolTip>Edit connection points</toolTip>
- <icon>path-break-segment</icon>
- <whatsThis></whatsThis>
- <statusTip></statusTip>
- <isCheckable>true</isCheckable>
- <text>Edit connection points</text>
- </Action>
- <Action name="align-relative">
- <iconText>%</iconText>
- <shortcut></shortcut>
- <toolTip>%</toolTip>
- <icon>path-break-segment</icon>
- <whatsThis></whatsThis>
- <statusTip></statusTip>
- <isCheckable>true</isCheckable>
- <text>%</text>
- </Action>
- <Action name="align-left">
- <iconText>Align to left edge</iconText>
- <shortcut></shortcut>
- <toolTip>Align to left edge</toolTip>
- <icon>align-horizontal-left</icon>
- <whatsThis></whatsThis>
- <statusTip></statusTip>
- <isCheckable>true</isCheckable>
- <text>Align to left edge</text>
- </Action>
- <Action name="align-centerh">
- <iconText>Align to horizontal center</iconText>
- <shortcut></shortcut>
- <toolTip>Align to horizontal center</toolTip>
- <icon>align-horizontal-center</icon>
- <whatsThis></whatsThis>
- <statusTip></statusTip>
- <isCheckable>true</isCheckable>
- <text>Align to horizontal center</text>
- </Action>
- <Action name="align-right">
- <iconText>Align to right edge</iconText>
- <shortcut></shortcut>
- <toolTip>Align to right edge</toolTip>
- <icon>align-horizontal-right</icon>
- <whatsThis></whatsThis>
- <statusTip></statusTip>
- <isCheckable>true</isCheckable>
- <text>Align to right edge</text>
- </Action>
- <Action name="align-top">
- <iconText>Align to top edge</iconText>
- <shortcut></shortcut>
- <toolTip>Align to top edge</toolTip>
- <icon>align-vertical-top</icon>
- <whatsThis></whatsThis>
- <statusTip></statusTip>
- <isCheckable>true</isCheckable>
- <text>Align to top edge</text>
- </Action>
- <Action name="align-centerv">
- <iconText>Align to vertical center</iconText>
- <shortcut></shortcut>
- <toolTip>Align to vertical center</toolTip>
- <icon>align-vertical-center</icon>
- <whatsThis></whatsThis>
- <statusTip></statusTip>
- <isCheckable>true</isCheckable>
- <text>Align to vertical center</text>
- </Action>
- <Action name="align-bottom">
- <iconText>Align to bottom edge</iconText>
- <shortcut></shortcut>
- <toolTip>Align to bottom edge</toolTip>
- <icon>align-vertical-bottom</icon>
- <whatsThis></whatsThis>
- <statusTip></statusTip>
- <isCheckable>true</isCheckable>
- <text>Align to bottom edge</text>
- </Action>
- <Action name="escape-all">
- <iconText>Escape in all directions</iconText>
- <shortcut></shortcut>
- <toolTip>Escape in all directions</toolTip>
- <icon>escape-direction-all</icon>
- <whatsThis></whatsThis>
- <statusTip></statusTip>
- <isCheckable>true</isCheckable>
- <text>Escape in all directions</text>
- </Action>
- <Action name="escape-horizontal">
- <iconText>Escape in horizontal directions</iconText>
- <shortcut></shortcut>
- <toolTip>Escape in horizontal directions</toolTip>
- <icon>escape-direction-horizontal</icon>
- <whatsThis></whatsThis>
- <statusTip></statusTip>
- <isCheckable>true</isCheckable>
- <text>Escape in horizontal directions</text>
- </Action>
- <Action name="escape-vertical">
- <iconText>Escape in vertical directions</iconText>
- <shortcut></shortcut>
- <toolTip>Escape in vertical directions</toolTip>
- <icon>escape-direction-vertical</icon>
- <whatsThis></whatsThis>
- <statusTip></statusTip>
- <isCheckable>true</isCheckable>
- <text>Escape in vertical directions</text>
- </Action>
- <Action name="escape-left">
- <iconText>Escape in left direction</iconText>
- <shortcut></shortcut>
- <toolTip>Escape in left direction</toolTip>
- <icon>escape-direction-left</icon>
- <whatsThis></whatsThis>
- <statusTip></statusTip>
- <isCheckable>true</isCheckable>
- <text>Escape in left direction</text>
- </Action>
- <Action name="escape-right">
- <iconText>Escape in right direction</iconText>
- <shortcut></shortcut>
- <toolTip>Escape in right direction</toolTip>
- <icon>escape-direction-right</icon>
- <whatsThis></whatsThis>
- <statusTip></statusTip>
- <isCheckable>true</isCheckable>
- <text>Escape in right direction</text>
- </Action>
- <Action name="escape-up">
- <iconText>Escape in up direction</iconText>
- <shortcut></shortcut>
- <toolTip>Escape in up direction</toolTip>
- <icon>escape-direction-up</icon>
- <whatsThis></whatsThis>
- <statusTip></statusTip>
- <isCheckable>true</isCheckable>
- <text>Escape in up direction</text>
- </Action>
- <Action name="escape-down">
- <iconText>Escape in down direction</iconText>
- <shortcut></shortcut>
- <toolTip>Escape in down direction</toolTip>
- <icon>escape-direction-down</icon>
- <whatsThis></whatsThis>
- <statusTip></statusTip>
- <isCheckable>true</isCheckable>
- <text>Escape in down direction</text>
- </Action>
- </Actions>
-</ActionCollection>
-
-commented out! -->
diff --git a/krita/data/cursors/cursors.qrc b/krita/data/cursors/cursors.qrc
index 46529e3237..1c51ade673 100644
--- a/krita/data/cursors/cursors.qrc
+++ b/krita/data/cursors/cursors.qrc
@@ -1,27 +1,28 @@
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource>
<file>color-picker_image_background.xpm</file>
<file>color-picker_image_foreground.xpm</file>
<file>color-picker_layer_background.xpm</file>
<file>color-picker_layer_foreground.xpm</file>
<file>cursor-cross.xpm</file>
<file>cursor-pixel-white.xpm</file>
<file>cursor-pixel-black.xpm</file>
<file>cursor-round.xpm</file>
<file>cursor-triangle_lefthanded.xpm</file>
<file>cursor-triangle_righthanded.xpm</file>
<file>exposure-cursor-gesture.xpm</file>
<file>gamma-cursor-gesture.xpm</file>
<file>precise-pick-layer-icon.xpm</file>
<file>rotate_discrete.xpm</file>
<file>rotate_smooth.xpm</file>
<file>move-tool.png</file>
<file>move-selection.png</file>
<file>shear_x.xpm</file>
<file>shear_y.xpm</file>
<file>zoom_discrete.xpm</file>
<file>zoom_smooth.xpm</file>
<file>tool_freehand_cursor.png</file>
+ <file>tool_color_picker_cursor.png</file>
</qresource>
</RCC>
diff --git a/krita/data/cursors/tool_color_picker_cursor.png b/krita/data/cursors/tool_color_picker_cursor.png
new file mode 100644
index 0000000000..6bed15cc3c
Binary files /dev/null and b/krita/data/cursors/tool_color_picker_cursor.png differ
diff --git a/krita/data/kritarc b/krita/data/kritarc
index 797f3bb7f8..22984f5d85 100644
--- a/krita/data/kritarc
+++ b/krita/data/kritarc
@@ -1,378 +1,378 @@
[advancedColorSelector]
allowHorizontalLayout=true
colorSelectorConfiguration=3|0|5|0
commonColorsAlignment=false
commonColorsAutoUpdate=false
commonColorsCount=12
commonColorsHeight=16
commonColorsNumCols=1
commonColorsNumRows=1
commonColorsScrolling=true
commonColorsShow=true
commonColorsWidth=16
customColorSpaceDepthID=U8
customColorSpaceModel=RGBA
customColorSpaceProfile=sRGB built-in
lastUsedColorsAlignment=true
lastUsedColorsCount=20
lastUsedColorsHeight=16
lastUsedColorsNumCols=1
lastUsedColorsNumRows=1
lastUsedColorsScrolling=true
lastUsedColorsShow=true
lastUsedColorsWidth=16
minimalShadeSelectorAsGradient=true
minimalShadeSelectorLineConfig=0|0.2|0|0|0|0|0;1|0|1|1|0|0|0;2|0|-1|1|0|0|0;
minimalShadeSelectorLineHeight=10
minimalShadeSelectorPatchCount=10
popupOnMouseClick=true
popupOnMouseOver=false
shadeSelectorHideable=false
shadeSelectorType=Minimal
shadeSelectorUpdateOnBackground=true
shadeSelectorUpdateOnForeground=true
shadeSelectorUpdateOnLeftClick=false
shadeSelectorUpdateOnRightClick=false
useCustomColorSpace=false
zoomSize=280
[DockWidget sharedtooldocker]
TabbedMode=false
[KisToolTransform]
filterId=Bicubic
[MainWindow]
State=AAAA/wAAAAD9AAAABAAAAAAAAABJAAADzfwCAAAAA/sAAAAOAFQAbwBvAGwAQgBvAHgBAAAAPwAAA80AAAAxAP////sAAAAkAEYAbABvAHcAUwBoAGEAcABlAEIAbwB4AEQAbwBjAGsAZQByAAAAA2oAAADHAAAAAAAAAAD7AAAAKABGAGwAbwB3AFMAdABlAG4AYwBpAGwAQgBvAHgARABvAGMAawBlAHIAAAADfQAAAMcAAAAAAAAAAAAAAAEAAAEGAAADzfwCAAAAQPsAAAAaAEsAaQBzAEIAaQByAGQAZQB5AGUAQgBvAHgAAAAAAP////8AAAAAAAAAAPsAAAAgAEsAaQBzAFAAYQBsAGUAdAB0AGUARABvAGMAawBlAHIAAAAAAP////8AAAAAAAAAAPsAAAAaAEsAbwBDAG8AbABvAHIARABvAGMAawBlAHIAAAAAAP////8AAAAAAAAAAPsAAAAwAEsAaQBzAFQAcgBpAGEAbgBnAGwAZQBDAG8AbABvAHIAUwBlAGwAZQBjAHQAbwByAAAAAAD/////AAAAAAAAAAD7AAAAIgBTAGgAYQBkAG8AdwAgAFAAcgBvAHAAZQByAHQAaQBlAHMAAAAAAP////8AAAAAAAAAAPsAAAAgAFMAaABhAHAAZQAgAFAAcgBvAHAAZQByAHQAaQBlAHMAAAAAAP////8AAAAAAAAAAPsAAAAaAFMAaABhAHAAZQBTAGUAbABlAGMAdABvAHIAAAAASAAAAEQAAAAAAAAAAPsAAAAkAFMAaQBtAHAAbABlACAAVABlAHgAdAAgAEUAZABpAHQAbwByAAAAAAD/////AAAAAAAAAAD8AAAAPwAAAOIAAACEAQAAHfoAAAAAAQAAAAf7AAAAHgBDAG8AbABvAHIAUwBlAGwAZQBjAHQAbwByAE4AZwEAAAAA/////wAAADoA////+wAAACAAcwBoAGEAcgBlAGQAdABvAG8AbABkAG8AYwBrAGUAcgEAAAAA/////wAAAFMA////+wAAABwATwB2AGUAcgB2AGkAZQB3AEQAbwBjAGsAZQByAQAAAAD/////AAAA2gD////7AAAAKgBTAHAAZQBjAGkAZgBpAGMAQwBvAGwAbwByAFMAZQBsAGUAYwB0AG8AcgAAAAAA/////wAAAL4A////+wAAABYAQwBvAGwAbwByAFMAbABpAGQAZQByAAAAAAD/////AAAAkQD////7AAAAFgBJAG0AYQBnAGUARABvAGMAawBlAHIAAAAAAP////8AAAAAAAAAAPsAAAAqAFMAaABhAHAAZQBDAG8AbABsAGUAYwB0AGkAbwBuAEQAbwBjAGsAZQByAAAABkgAAAEoAAAAAAAAAAD7AAAARgBLAHIAaQB0AGEAUwBoAGEAcABlAC8ASwBpAHMAVABvAG8AbABEAHkAbgBhAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQBAAAAUgAAABIAAAAAAAAAAPsAAAAsAEsAcgBpAHQAYQBTAGgAYQBwAGUALwBLAGkAcwBUAG8AbwBsAEwAaQBuAGUBAAAAPAAAAGkAAAAAAAAAAPsAAAAyAEsAcgBpAHQAYQBTAGgAYQBwAGUALwBLAGkAcwBUAG8AbwBsAEUAbABsAGkAcABzAGUBAAAAkQAAABIAAAAAAAAAAPsAAAAcAEsAaQBzAFQAbwBvAGwAUABvAGwAeQBnAG8AbgEAAACmAAAAEgAAAAAAAAAA+wAAAB4ASwBpAHMAVABvAG8AbABQAG8AbAB5AGwAaQBuAGUBAAAAuwAAABIAAAAAAAAAAPsAAAAWAEsAaQBzAFQAbwBvAGwAUwB0AGEAcgEAAADQAAAAEwAAAAAAAAAA+wAAACoAUwBuAGEAcABHAHUAaQBkAGUAQwBvAG4AZgBpAGcAVwBpAGQAZwBlAHQAAAAA7wAAAHEAAAAAAAAAAPsAAAAyAEsAaQBzAFQAbwBvAGwAQwByAG8AcAAgAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQBAAAA+wAAABIAAAAAAAAAAPsAAABQAEsAcgBpAHQAYQBUAHIAYQBuAHMAZgBvAHIAbQAvAEsAaQBzAFQAbwBvAGwATQBvAHYAZQAgAE8AcAB0AGkAbwBuACAAVwBpAGQAZwBlAHQBAAABEAAAABIAAAAAAAAAAPsAAAA8AEsAaQBzAFQAbwBvAGwAVAByAGEAbgBzAGYAbwByAG0AIABvAHAAdABpAG8AbgAgAHcAaQBkAGcAZQB0AQAAADwAAAAvAAAAAAAAAAD7AAAATgBLAHIAaQB0AGEAUwBoAGEAcABlAC8ASwBpAHMAVABvAG8AbABNAGUAYQBzAHUAcgBlACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAEAAAA8AAAAQgAAAAAAAAAA+wAAAFwASwByAGkAdABhAFMAZQBsAGUAYwB0AGUAZAAvAEsAaQBzAFQAbwBvAGwAQwBvAGwAbwByAFAAaQBjAGsAZQByACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAEAAAA8AAAA/wAAAAAAAAAA+wAAAEYASwBpAHMAUgB1AGwAZQByAEEAcwBzAGkAcwB0AGEAbgB0AFQAbwBvAGwAIABPAHAAdABpAG8AbgAgAFcAaQBkAGcAZQB0AQAAADwAAAASAAAAAAAAAAD7AAAASABLAGkAcwBUAG8AbwBsAFAAZQByAHMAcABlAGMAdABpAHYAZQBHAHIAaQBkACAATwBwAHQAaQBvAG4AIABXAGkAZABnAGUAdAEAAAGjAAAAEgAAAAAAAAAA+wAAADIASwBpAHMAVABvAG8AbABHAHIAaQBkACAATwBwAHQAaQBvAG4AIABXAGkAZABnAGUAdAEAAAG4AAAAEwAAAAAAAAAA+wAAAEwASwBpAHMAVABvAG8AbABTAGUAbABlAGMAdABSAGUAYwB0AGEAbgBnAHUAbABhAHIAIABvAHAAdABpAG8AbgAgAHcAaQBkAGcAZQB0AQAAAc4AAAASAAAAAAAAAAD7AAAASgBLAGkAcwBUAG8AbwBsAFMAZQBsAGUAYwB0AEUAbABsAGkAcAB0AGkAYwBhAGwAIABvAHAAdABpAG8AbgAgAHcAaQBkAGcAZQB0AQAAAeMAAAASAAAAAAAAAAD7AAAASABLAGkAcwBUAG8AbwBsAFMAZQBsAGUAYwB0AFAAbwBsAHkAZwBvAG4AYQBsACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAEAAAH4AAAAEgAAAAAAAAAA+wAAAEQASwBpAHMAVABvAG8AbABTAGUAbABlAGMAdABPAHUAdABsAGkAbgBlACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAEAAAINAAAAEgAAAAAAAAAA+wAAAEoASwBpAHMAVABvAG8AbABTAGUAbABlAGMAdABDAG8AbgB0AGkAZwB1AG8AdQBzACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAEAAAIiAAAAEgAAAAAAAAAA+wAAAEQASwBpAHMAVABvAG8AbABTAGUAbABlAGMAdABTAGkAbQBpAGwAYQByACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAEAAAI3AAAAEgAAAAAAAAAA/AAAAbYAAABaAAAAAAD////6AAAAAAEAAAAC+wAAAC4ASwBvAFMAaABhAHAAZQBDAG8AbABsAGUAYwB0AGkAbwBuAEQAbwBjAGsAZQByAQAAAAD/////AAAAAAAAAAD7AAAAJABTAG0AYQBsAGwAQwBvAGwAbwByAFMAZQBsAGUAYwB0AG8AcgAAAANuAAABBAAAADoA/////AAAASgAAAEwAAAA1QEAAB36AAAAAAEAAAAD+wAAABYASwBpAHMATABhAHkAZQByAEIAbwB4AQAAAAD/////AAABAgD////7AAAAGgBDAGgAYQBuAG4AZQBsAEQAbwBjAGsAZQByAQAAAAD/////AAAAVQD////7AAAALgBLAGkAcwBQAGEAaQBuAHQAZQByAGwAeQBNAGkAeABlAHIARABvAGMAawBlAHIAAAAAAP////8AAAAAAAAAAPwAAAJfAAABrQAAAJcBAAAd+gAAAAABAAAAAvsAAAAYAFAAcgBlAHMAZQB0AEQAbwBjAGsAZQByAQAAAAD/////AAAAZgD////7AAAAGgBQAHIAZQBzAGUAdABIAGkAcwB0AG8AcgB5AQAACPoAAAEGAAAAVQD////7AAAASABLAHIAaQB0AGEAUwBoAGEAcABlAC8ASwBpAHMAVABvAG8AbABCAHIAdQBzAGgAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAEAAAPcAAAAaAAAAAAAAAAA+wAAACIAUwB0AHIAbwBrAGUAIABQAHIAbwBwAGUAcgB0AGkAZQBzAAAAAAD/////AAAAAAAAAAD7AAAAFgBTAHQAeQBsAGUARABvAGMAawBlAHIAAAAAAP////8AAAAAAAAAAPsAAAAgAEsAaQBzAEgAaQBzAHQAbwBnAHIAYQBtAEQAbwBjAGsAAAAAAP////8AAAAAAAAAAPsAAAASAFMAYwByAGkAcAB0AGkAbgBnAAAAAAD/////AAAAAAAAAAD7AAAAMABEAGUAZgBhAHUAbAB0AFQAbwBvAGwAQQByAHIAYQBuAGcAZQBXAGkAZABnAGUAdAAAAAK8AAAAUgAAAAAAAAAA+wAAACIARABlAGYAYQB1AGwAdABUAG8AbwBsAFcAaQBkAGcAZQB0AAAAAxEAAABbAAAAAAAAAAD7AAAAJABLAGkAcwBIAGkAcwB0AG8AZwByAGEAbQBEAG8AYwBrAGUAcgAAAAJCAAAAewAAAAAAAAAA+wAAABgARABpAGcAaQB0AGEAbABNAGkAeABlAHIAAAAAAP////8AAACTAP////sAAAAOAEgAaQBzAHQAbwByAHkAAAADkAAAALQAAACuAP////sAAABOAEsAcgBpAHQAYQBGAGkAbABsAC8ASwBpAHMAVABvAG8AbABHAHIAYQBkAGkAZQBuAHQAIABvAHAAdABpAG8AbgAgAHcAaQBkAGcAZQB0AAAABCgAAAAcAAAAAAAAAAD7AAAARgBLAHIAaQB0AGEARgBpAGwAbAAvAEsAaQBzAFQAbwBvAGwARgBpAGwAbAAgAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQAAAADUAAAABwAAAAAAAAAAPsAAAA2AEsAcgBpAHQAYQBTAGgAYQBwAGUALwBLAGkAcwBUAG8AbwBsAFIAZQBjAHQAYQBuAGcAbABlAAAAAwUAAABnAAAAAAAAAAD7AAAAIgBDAG8AbQBwAG8AcwBpAHQAaQBvAG4ARABvAGMAawBlAHIAAAAAAP////8AAACMAP////sAAAAqAEEAcgB0AGkAcwB0AGkAYwBDAG8AbABvAHIAUwBlAGwAZQBjAHQAbwByAAAAAAD/////AAAAdwD////7AAAAGgBQAGEAdAB0AGUAcgBuAEQAbwBjAGsAZQByAAAAAtkAAAFJAAAAswD////7AAAAGgBUAGEAcwBrAHMAZQB0AEQAbwBjAGsAZQByAAAAAAD/////AAAAjAD////7AAAAKABTAG4AYQBwAEcAdQBpAGQAZQAgAFAAcgBvAHAAZQByAHQAaQBlAHMAAAAAAP////8AAAAAAAAAAPsAAAA4AFQAZQB4AHQARABvAGMAdQBtAGUAbgB0AEkAbgBzAHAAZQBjAHQAaQBvAG4ARABvAGMAawBlAHICAAAEmgAAAhUAAAEqAAAArvsAAAASAEwAdQB0AEQAbwBjAGsAZQByAAAAAAD/////AAABXQD////7AAAAGgBQAGEAbABlAHQAdABlAEQAbwBjAGsAZQByAAAAAAD/////AAAAQgD////7AAAAFABHAHIAaQBkAEQAbwBjAGsAZQByAAAAAAD/////AAABLQD////7AAAAHgBIAGkAcwB0AG8AZwByAGEAbQBEAG8AYwBrAGUAcgAAAAAA/////wAAAEcA////+wAAACoAQQBuAGkAbQBhAHQAaQBvAG4AQwB1AHIAdgBlAHMARABvAGMAawBlAHIAAAAAAP////8AAACMAP////sAAAAyAFMAdgBnAFMAeQBtAGIAbwBsAEMAbwBsAGwAZQBjAHQAaQBvAG4ARABvAGMAawBlAHIAAAAAAP////8AAACMAP////sAAAAWAFQAbwB1AGMAaABEAG8AYwBrAGUAcgAAAAJMAAABMQAAABMA////+wAAABoAQQByAHIAYQBuAGcAZQBEAG8AYwBrAGUAcgAAAAAA/////wAAAHoA////+wAAADoAYwBvAG0AaQBjAHMAXwBwAHIAbwBqAGUAYwB0AF8AbQBhAG4AYQBnAGUAcgBfAGQAbwBjAGsAZQByAAAAAAD/////AAAAuQD////7AAAAKgBxAHUAaQBjAGsAXwBzAGUAdAB0AGkAbgBnAHMAXwBkAG8AYwBrAGUAcgAAAAAA/////wAAAIwA////+wAAABYAUABhAGcAZQByAEQAbwBjAGsAZQByAAAAAAD/////AAAALQD////7AAAAJgBsAGEAcwB0AGQAbwBjAHUAbQBlAG4AdABzAGQAbwBjAGsAZQByAAAAAAD/////AAAAiQD///8AAAACAAAKAAAAALz8AQAAAAH7AAAAGgBUAG8AbwBsAEIAYQByAEQAbwBjAGsAZQByAAAAAAD/////AAAAAAAAAAAAAAADAAAAAAAAAAD8AQAAAAT7AAAAHABGAGwAaQBwAGIAbwBvAGsARABvAGMAawBlAHIAAAAAAP////8AAAAAAAAAAPsAAAAeAEEAbgBpAG0AYQB0AGkAbwBuAEQAbwBjAGsAZQByAAAAAAD/////AAABBQD////7AAAAIABPAG4AaQBvAG4AUwBrAGkAbgBzAEQAbwBjAGsAZQByAAAAAAD/////AAABNgD////7AAAAHABUAGkAbQBlAGwAaQBuAGUARABvAGMAawBlAHIAAAAAAP////8AAABVAP///wAABU0AAAPNAAAABAAAAAQAAAAIAAAACPwAAAABAAAAAgAAAAIAAAAWAG0AYQBpAG4AVABvAG8AbABCAGEAcgEAAAAA/////wAAAAAAAAAAAAAAHgBCAHIAdQBzAGgAZQBzAEEAbgBkAFMAdAB1AGYAZgEAAAC5/////wAAAAAAAAAA
[advancedColorSelector]
gamma=2.2000000000000002
hidePopupOnClickCheck=false
hsxSettingType=0
lumaB=0.0722
lumaG=0.71519999999999995
lumaR=0.21260000000000001
onDockerResize=0
shadeMyPaintType=HSV
zoomSelectorOptions=0
[calligra]
ColorSpaceExtensionsPlugins=\\0
ColorSpaceExtensionsPluginsDisabled=
ColorSpacePlugins=\\0
ColorSpacePluginsDisabled=
DockerPlugins=\\0
DockerPluginsDisabled=textdocumentinspection
FlakePlugins=,
ShapePlugins=,
-ToolsBlacklist=CreatePathTool,KoPencilTool,ConnectionTool,KarbonFilterEffectsTool,KritaShape/KisToolText,ArtisticTextTool,TextTool
+ToolsBlacklist=CreatePathTool,KoPencilTool,KarbonFilterEffectsTool,KritaShape/KisToolText
ToolPlugins=,,
ToolPluginsDisabled=
[colorhotkeys]
steps_blueyellow=10
steps_hue=36
steps_lightness=10
steps_redgreen=10
steps_saturation=10
[crashprevention]
CreatingCanvas=false
[hsxColorSlider]
hsiH=false
hsiI=false
hsiS=false
hslH=true
hslL=true
hslS=true
hsvH=false
hsvS=false
hsvV=false
hsyH=false
hsyS=false
hsyY=false
[krita]
State=AAAA/wAAAAD9AAAABAAAAAAAAABEAAAE6PwCAAAAA/sAAAAOAFQAbwBvAGwAQgBvAHgBAAAARAAABOgAAAAdAQAAA/sAAAAkAEYAbABvAHcAUwBoAGEAcABlAEIAbwB4AEQAbwBjAGsAZQByAAAAA2oAAADHAAAAAAAAAAD7AAAAKABGAGwAbwB3AFMAdABlAG4AYwBpAGwAQgBvAHgARABvAGMAawBlAHIAAAADfQAAAMcAAAAAAAAAAAAAAAEAAAEZAAAE6PwCAAAAO/sAAAAaAEsAaQBzAEIAaQByAGQAZQB5AGUAQgBvAHgAAAAAAP////8AAAAAAAAAAPsAAAAgAEsAaQBzAFAAYQBsAGUAdAB0AGUARABvAGMAawBlAHIAAAAAAP////8AAAAAAAAAAPsAAAAaAEsAbwBDAG8AbABvAHIARABvAGMAawBlAHIAAAAAAP////8AAAAAAAAAAPsAAAAwAEsAaQBzAFQAcgBpAGEAbgBnAGwAZQBDAG8AbABvAHIAUwBlAGwAZQBjAHQAbwByAAAAAAD/////AAAAAAAAAAD7AAAAIgBTAGgAYQBkAG8AdwAgAFAAcgBvAHAAZQByAHQAaQBlAHMAAAAAAP////8AAAAAAAAAAPsAAAAgAFMAaABhAHAAZQAgAFAAcgBvAHAAZQByAHQAaQBlAHMAAAAAAP////8AAAAAAAAAAPsAAAAaAFMAaABhAHAAZQBTAGUAbABlAGMAdABvAHIAAAAASAAAAEQAAAAAAAAAAPsAAAAkAFMAaQBtAHAAbABlACAAVABlAHgAdAAgAEUAZABpAHQAbwByAAAAAAD/////AAAAAAAAAAD8AAAARAAAAKUAAAAAAP////r/////AQAAAAL7AAAAFgBDAG8AbABvAHIAUwBsAGkAZABlAHIAAAAAAP////8AAACuAQAAA/sAAAAaAFAAYQBsAGUAdAB0AGUARABvAGMAawBlAHIAAAAAAP////8AAADtAQAAA/wAAABEAAABMgAAAIgBAAAb+gAAAAIBAAAABvsAAAAcAE8AdgBlAHIAdgBpAGUAdwBEAG8AYwBrAGUAcgEAAAAA/////wAAAKMBAAAD+wAAACAAcwBoAGEAcgBlAGQAdABvAG8AbABkAG8AYwBrAGUAcgEAAAAA/////wAAAJgBAAAD+wAAAB4AQwBvAGwAbwByAFMAZQBsAGUAYwB0AG8AcgBOAGcBAAAAAP////8AAAD7AQAAA/sAAAAqAFMAcABlAGMAaQBmAGkAYwBDAG8AbABvAHIAUwBlAGwAZQBjAHQAbwByAAAAAAD/////AAAA5gEAAAP7AAAAFgBJAG0AYQBnAGUARABvAGMAawBlAHIAAAAAAP////8AAADbAQAAA/sAAAAqAFMAaABhAHAAZQBDAG8AbABsAGUAYwB0AGkAbwBuAEQAbwBjAGsAZQByAAAABkgAAAEoAAAAAAAAAAD7AAAARgBLAHIAaQB0AGEAUwBoAGEAcABlAC8ASwBpAHMAVABvAG8AbABEAHkAbgBhAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQBAAAAUgAAABIAAAAAAAAAAPsAAAAsAEsAcgBpAHQAYQBTAGgAYQBwAGUALwBLAGkAcwBUAG8AbwBsAEwAaQBuAGUBAAAAPAAAAGkAAAAAAAAAAPsAAAAyAEsAcgBpAHQAYQBTAGgAYQBwAGUALwBLAGkAcwBUAG8AbwBsAEUAbABsAGkAcABzAGUBAAAAkQAAABIAAAAAAAAAAPsAAAAcAEsAaQBzAFQAbwBvAGwAUABvAGwAeQBnAG8AbgEAAACmAAAAEgAAAAAAAAAA+wAAAB4ASwBpAHMAVABvAG8AbABQAG8AbAB5AGwAaQBuAGUBAAAAuwAAABIAAAAAAAAAAPsAAAAWAEsAaQBzAFQAbwBvAGwAUwB0AGEAcgEAAADQAAAAEwAAAAAAAAAA+wAAACoAUwBuAGEAcABHAHUAaQBkAGUAQwBvAG4AZgBpAGcAVwBpAGQAZwBlAHQAAAAA7wAAAHEAAAAAAAAAAPsAAAAyAEsAaQBzAFQAbwBvAGwAQwByAG8AcAAgAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQBAAAA+wAAABIAAAAAAAAAAPsAAABQAEsAcgBpAHQAYQBUAHIAYQBuAHMAZgBvAHIAbQAvAEsAaQBzAFQAbwBvAGwATQBvAHYAZQAgAE8AcAB0AGkAbwBuACAAVwBpAGQAZwBlAHQBAAABEAAAABIAAAAAAAAAAPsAAAA8AEsAaQBzAFQAbwBvAGwAVAByAGEAbgBzAGYAbwByAG0AIABvAHAAdABpAG8AbgAgAHcAaQBkAGcAZQB0AQAAADwAAAAvAAAAAAAAAAD7AAAATgBLAHIAaQB0AGEAUwBoAGEAcABlAC8ASwBpAHMAVABvAG8AbABNAGUAYQBzAHUAcgBlACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAEAAAA8AAAAQgAAAAAAAAAA+wAAAFwASwByAGkAdABhAFMAZQBsAGUAYwB0AGUAZAAvAEsAaQBzAFQAbwBvAGwAQwBvAGwAbwByAFAAaQBjAGsAZQByACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAEAAAA8AAAA/wAAAAAAAAAA+wAAAEYASwBpAHMAUgB1AGwAZQByAEEAcwBzAGkAcwB0AGEAbgB0AFQAbwBvAGwAIABPAHAAdABpAG8AbgAgAFcAaQBkAGcAZQB0AQAAADwAAAASAAAAAAAAAAD7AAAASABLAGkAcwBUAG8AbwBsAFAAZQByAHMAcABlAGMAdABpAHYAZQBHAHIAaQBkACAATwBwAHQAaQBvAG4AIABXAGkAZABnAGUAdAEAAAGjAAAAEgAAAAAAAAAA+wAAADIASwBpAHMAVABvAG8AbABHAHIAaQBkACAATwBwAHQAaQBvAG4AIABXAGkAZABnAGUAdAEAAAG4AAAAEwAAAAAAAAAA+wAAAEwASwBpAHMAVABvAG8AbABTAGUAbABlAGMAdABSAGUAYwB0AGEAbgBnAHUAbABhAHIAIABvAHAAdABpAG8AbgAgAHcAaQBkAGcAZQB0AQAAAc4AAAASAAAAAAAAAAD7AAAASgBLAGkAcwBUAG8AbwBsAFMAZQBsAGUAYwB0AEUAbABsAGkAcAB0AGkAYwBhAGwAIABvAHAAdABpAG8AbgAgAHcAaQBkAGcAZQB0AQAAAeMAAAASAAAAAAAAAAD7AAAASABLAGkAcwBUAG8AbwBsAFMAZQBsAGUAYwB0AFAAbwBsAHkAZwBvAG4AYQBsACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAEAAAH4AAAAEgAAAAAAAAAA+wAAAEQASwBpAHMAVABvAG8AbABTAGUAbABlAGMAdABPAHUAdABsAGkAbgBlACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAEAAAINAAAAEgAAAAAAAAAA+wAAAEoASwBpAHMAVABvAG8AbABTAGUAbABlAGMAdABDAG8AbgB0AGkAZwB1AG8AdQBzACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAEAAAIiAAAAEgAAAAAAAAAA+wAAAEQASwBpAHMAVABvAG8AbABTAGUAbABlAGMAdABTAGkAbQBpAGwAYQByACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAEAAAI3AAAAEgAAAAAAAAAA/AAAAbYAAABaAAAAAAD////6AAAAAAEAAAAC+wAAAC4ASwBvAFMAaABhAHAAZQBDAG8AbABsAGUAYwB0AGkAbwBuAEQAbwBjAGsAZQByAQAAAAD/////AAAAAAAAAAD7AAAAJABTAG0AYQBsAGwAQwBvAGwAbwByAFMAZQBsAGUAYwB0AG8AcgAAAANuAAABBAAAANkBAAAD/AAAAXcAAAGjAAAA3gEAABv6AAAAAAEAAAAF+wAAABYASwBpAHMATABhAHkAZQByAEIAbwB4AQAAAAD/////AAABBgEAAAP7AAAAIgBDAG8AbQBwAG8AcwBpAHQAaQBvAG4ARABvAGMAawBlAHIAAAAAAP////8AAAC0AQAAA/sAAAAOAEgAaQBzAHQAbwByAHkAAAAAAP////8AAACxAQAAA/sAAAAaAEMAaABhAG4AbgBlAGwARABvAGMAawBlAHIBAAAAAP////8AAACjAQAAA/sAAAAuAEsAaQBzAFAAYQBpAG4AdABlAHIAbAB5AE0AaQB4AGUAcgBEAG8AYwBrAGUAcgAAAAAA/////wAAAAAAAAAA+wAAABgAUAByAGUAcwBlAHQARABvAGMAawBlAHIBAAADGwAAAhEAAACCAQAAA/sAAABIAEsAcgBpAHQAYQBTAGgAYQBwAGUALwBLAGkAcwBUAG8AbwBsAEIAcgB1AHMAaABvAHAAdABpAG8AbgAgAHcAaQBkAGcAZQB0AQAAA9wAAABoAAAAAAAAAAD7AAAAIgBTAHQAcgBvAGsAZQAgAFAAcgBvAHAAZQByAHQAaQBlAHMAAAAAAP////8AAAAAAAAAAPsAAAAWAFMAdAB5AGwAZQBEAG8AYwBrAGUAcgAAAAAA/////wAAAAAAAAAA+wAAACAASwBpAHMASABpAHMAdABvAGcAcgBhAG0ARABvAGMAawAAAAAA/////wAAAAAAAAAA+wAAABIAUwBjAHIAaQBwAHQAaQBuAGcAAAAAAP////8AAAAAAAAAAPsAAAAwAEQAZQBmAGEAdQBsAHQAVABvAG8AbABBAHIAcgBhAG4AZwBlAFcAaQBkAGcAZQB0AAAAArwAAABSAAAAAAAAAAD7AAAAIgBEAGUAZgBhAHUAbAB0AFQAbwBvAGwAVwBpAGQAZwBlAHQAAAADEQAAAFsAAAAAAAAAAPsAAAAkAEsAaQBzAEgAaQBzAHQAbwBnAHIAYQBtAEQAbwBjAGsAZQByAAAAAkIAAAB7AAAAAAAAAAD7AAAAGABEAGkAZwBpAHQAYQBsAE0AaQB4AGUAcgAAAAAA/////wAAAKEBAAAD+wAAAE4ASwByAGkAdABhAEYAaQBsAGwALwBLAGkAcwBUAG8AbwBsAEcAcgBhAGQAaQBlAG4AdAAgAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQAAAAEKAAAABwAAAAAAAAAAPsAAABGAEsAcgBpAHQAYQBGAGkAbABsAC8ASwBpAHMAVABvAG8AbABGAGkAbABsACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAAAAANQAAAAHAAAAAAAAAAA+wAAADYASwByAGkAdABhAFMAaABhAHAAZQAvAEsAaQBzAFQAbwBvAGwAUgBlAGMAdABhAG4AZwBsAGUAAAADBQAAAGcAAAAAAAAAAPsAAAAqAEEAcgB0AGkAcwB0AGkAYwBDAG8AbABvAHIAUwBlAGwAZQBjAHQAbwByAAAAAAD/////AAAAgAEAAAP7AAAAGgBQAGEAdAB0AGUAcgBuAEQAbwBjAGsAZQByAAAAAtkAAAFJAAAAvAEAAAP7AAAAGgBUAGEAcwBrAHMAZQB0AEQAbwBjAGsAZQByAAAAAAD/////AAAAmAEAAAP7AAAAKABTAG4AYQBwAEcAdQBpAGQAZQAgAFAAcgBvAHAAZQByAHQAaQBlAHMAAAAAAP////8AAAAAAAAAAPsAAAA4AFQAZQB4AHQARABvAGMAdQBtAGUAbgB0AEkAbgBzAHAAZQBjAHQAaQBvAG4ARABvAGMAawBlAHICAAAEmgAAAhUAAAEqAAAArvsAAAASAEwAdQB0AEQAbwBjAGsAZQByAAAAA3wAAAEuAAABsQEAAAP7AAAAFABHAHIAaQBkAEQAbwBjAGsAZQByAAAAAAD/////AAABNgEAAAP7AAAAHgBIAGkAcwB0AG8AZwByAGEAbQBEAG8AYwBrAGUAcgAAAAAA/////wAAAFABAAAD+wAAABoAUAByAGUAcwBlAHQASABpAHMAdABvAHIAeQAAAAAA/////wAAAHABAAAD+wAAADIAUwB2AGcAUwB5AG0AYgBvAGwAQwBvAGwAbABlAGMAdABpAG8AbgBEAG8AYwBrAGUAcgAAAAAA/////wAAAAAAAAAA+wAAABYAVABvAHUAYwBoAEQAbwBjAGsAZQByAAAAAAD/////AAAAHAEAAAP7AAAAGgBBAHIAcgBhAG4AZwBlAEQAbwBjAGsAZQByAAAAAAD/////AAAAkAEAAAP7AAAAKgBBAG4AaQBtAGEAdABpAG8AbgBDAHUAcgB2AGUAcwBEAG8AYwBrAGUAcgAAAAAA/////wAAAJgBAAADAAAAAgAAB4AAAAC8/AEAAAAB+wAAABoAVABvAG8AbABCAGEAcgBEAG8AYwBrAGUAcgAAAAAA/////wAAAAAAAAAAAAAAAwAAAAAAAAAA/AEAAAAE+wAAABwARgBsAGkAcABiAG8AbwBrAEQAbwBjAGsAZQByAAAAAAD/////AAAAAAAAAAD7AAAAIABPAG4AaQBvAG4AUwBrAGkAbgBzAEQAbwBjAGsAZQByAAAAAAD/////AAABSAEAAAP7AAAAHgBBAG4AaQBtAGEAdABpAG8AbgBEAG8AYwBrAGUAcgAAAAAA/////wAAASUBAAAD+wAAABwAVABpAG0AZQBsAGkAbgBlAEQAbwBjAGsAZQByAAAAAAD/////AAAAlgEAAAMAAAihAAAE6AAAAAQAAAAEAAAACAAAAAj8AAAAAQAAAAIAAAACAAAAFgBtAGEAaQBuAFQAbwBvAGwAQgBhAHIBAAAAAP////8AAAAAAAAAAAAAAB4AQgByAHUAcwBoAGUAcwBBAG4AZABTAHQAdQBmAGYBAAAA1P////8AAAAAAAAAAA==
ToolBarsMovable=Enabled
[krita][DockWidget AnimationCurvesDocker]
Collapsed=false
DockArea=2
Locked=false
height=421
width=448
xPosition=0
yPosition=0
[krita][DockWidget AnimationDocker]
Collapsed=false
DockArea=8
Locked=false
height=160
width=280
xPosition=0
yPosition=0
[krita][DockWidget ArtisticColorSelector]
Collapsed=false
DockArea=2
Locked=false
height=294
width=337
xPosition=0
yPosition=0
[krita][DockWidget ChannelDocker]
Collapsed=false
DockArea=2
Locked=false
height=30
width=100
xPosition=0
yPosition=0
[krita][DockWidget ColorSelectorNg]
Collapsed=false
DockArea=2
Locked=false
height=176
width=281
xPosition=0
yPosition=20
[krita][DockWidget ColorSlider]
Collapsed=false
DockArea=2
Locked=false
height=460
width=640
xPosition=0
yPosition=20
[krita][DockWidget CompositionDocker]
Collapsed=false
DockArea=2
Locked=false
height=300
width=400
xPosition=0
yPosition=0
[krita][DockWidget DigitalMixer]
Collapsed=false
DockArea=2
Locked=false
height=30
width=100
xPosition=0
yPosition=0
[krita][DockWidget GridDocker]
Collapsed=false
DockArea=2
Locked=false
height=342
width=441
xPosition=0
yPosition=0
[krita][DockWidget HistogramDocker]
Collapsed=false
DockArea=2
Locked=false
height=91
width=281
xPosition=0
yPosition=20
[krita][DockWidget History]
Collapsed=false
DockArea=2
Locked=false
height=460
width=640
xPosition=0
yPosition=20
[krita][DockWidget ImageDocker]
Collapsed=false
DockArea=2
Locked=false
height=300
width=399
xPosition=0
yPosition=0
[krita][DockWidget KisLayerBox]
DockArea=2
Locked=false
height=358
width=281
xPosition=0
yPosition=20
[krita][DockWidget LutDocker]
Collapsed=false
DockArea=2
Locked=false
height=286
width=357
xPosition=0
yPosition=0
[krita][DockWidget OnionSkinsDocker]
Collapsed=false
DockArea=8
Locked=false
height=210
width=356
xPosition=0
yPosition=0
[krita][DockWidget OverviewDocker]
Collapsed=false
DockArea=2
Locked=false
height=30
width=100
xPosition=0
yPosition=0
[krita][DockWidget PaletteDocker]
Collapsed=false
DockArea=2
Locked=false
height=219
width=256
xPosition=0
yPosition=0
[krita][DockWidget PatternDocker]
Collapsed=false
DockArea=2
Locked=false
height=30
width=100
xPosition=0
yPosition=0
[krita][DockWidget PresetDocker]
Collapsed=false
DockArea=2
Locked=false
height=460
width=640
xPosition=0
yPosition=20
[krita][DockWidget PresetHistory]
Collapsed=false
DockArea=2
Locked=false
height=30
width=100
xPosition=0
yPosition=0
[krita][DockWidget Shape Properties]
DockArea=2
Locked=false
height=480
width=640
xPosition=0
yPosition=0
[krita][DockWidget ShapeCollectionDocker]
Collapsed=false
DockArea=2
Locked=false
height=0
width=0
xPosition=0
yPosition=20
[krita][DockWidget SmallColorSelector]
DockArea=2
Locked=false
height=460
width=640
xPosition=0
yPosition=20
[krita][DockWidget SpecificColorSelector]
DockArea=2
Locked=false
height=460
width=640
xPosition=0
yPosition=20
[krita][DockWidget TasksetDocker]
Collapsed=false
DockArea=2
Locked=false
height=300
width=400
xPosition=0
yPosition=0
[krita][DockWidget TimelineDocker]
Collapsed=false
DockArea=8
Locked=false
height=30
width=100
xPosition=0
yPosition=0
[krita][DockWidget ToolBox]
DockArea=1
Locked=false
height=610
width=63
xPosition=0
yPosition=20
[krita][DockWidget sharedtooldocker]
Collapsed=false
DockArea=2
Locked=false
height=460
width=640
xPosition=0
yPosition=20
[krita][Toolbar mainToolBar]
ToolButtonStyle=IconOnly
[TemplateChooserDialog]
ShowCustomDocumentWidgetByDefault=true
LastReturnType=Custom Document
[theme]
Theme=Krita dark
[python]
enable_colorspace=true
enable_comics_project_management_tools=true
enable_documenttools=true
enable_exportlayers=true
enable_filtermanager=true
enable_lastdocumentsdocker=true
enable_quick_settings_docker=true
enable_scripter=true
enable_tenbrushes=true
enable_tenscripts=true
enable_plugin_importer=true
[SPenSettings]
actionButtonClick=spen_show_popup_palette
actionButtonDoubleClick=erase_action
actionGestureCircleCCW=shift_brush_color_counter_clockwise
actionGestureCircleCW=shift_brush_color_clockwise
actionGestureSwipeDown=make_brush_color_darker
actionGestureSwipeRight=KritaSelected/KisToolColorPicker
actionGestureSwipeLeft=KritaShape/KisToolBrush
actionGestureSwipeUp=make_brush_color_lighter
diff --git a/krita/data/shaders/overlay_inverted.frag b/krita/data/shaders/overlay_inverted.frag
new file mode 100644
index 0000000000..762c8b234c
--- /dev/null
+++ b/krita/data/shaders/overlay_inverted.frag
@@ -0,0 +1,10 @@
+uniform vec4 fragColor;
+uniform sampler2D texture0;
+
+in vec4 v_textureCoordinate;
+out vec4 resultFragmentColor;
+
+void main(void)
+{
+ resultFragmentColor = fragColor * vec4(vec3(1.0 - texture(texture0, v_textureCoordinate.xy)), 1.0);
+}
diff --git a/krita/data/shaders/shaders.qrc b/krita/data/shaders/shaders.qrc
index c3b076ac46..646a8a1c41 100644
--- a/krita/data/shaders/shaders.qrc
+++ b/krita/data/shaders/shaders.qrc
@@ -1,17 +1,18 @@
<RCC>
<qresource prefix="/">
<file>bilinear_gradient.frag</file>
<file>conical_gradient.frag</file>
<file>conical_symetric_gradient.frag</file>
<file>highq_downscale.frag</file>
<file>linear_gradient.frag</file>
<file>matrix_transform.vert</file>
<file>radial_gradient.frag</file>
<file>simple_texture.frag</file>
<file>square_gradient.frag</file>
<file>matrix_transform_legacy.vert</file>
<file>simple_texture_legacy.frag</file>
<file>solid_color.frag</file>
<file>solid_color_legacy.frag</file>
+ <file>overlay_inverted.frag</file>
</qresource>
</RCC>
diff --git a/krita/data/shortcuts/paint_tool_sai_compatible.shortcuts b/krita/data/shortcuts/paint_tool_sai_compatible.shortcuts
index 08eb92b5a2..eda241f5c3 100644
--- a/krita/data/shortcuts/paint_tool_sai_compatible.shortcuts
+++ b/krita/data/shortcuts/paint_tool_sai_compatible.shortcuts
@@ -1,428 +1,418 @@
[Shortcuts]
activateNextLayer=PgUp
activatePreviousLayer=PgDown
add_blank_frame=none
add_duplicate_frame=none
add_new_adjustment_layer=none
add_new_clone_layer=none
add_new_file_layer=none
add_new_fill_layer=none
add_new_filter_mask=none
add_new_group_layer=none
add_new_paint_layer=none
add_new_selection_mask=none
add_new_shape_layer=none
add_new_transform_mask=none
add_new_transparency_mask=none
-artistictext_anchor_end=none
-artistictext_anchor_middle=none
-artistictext_anchor_start=none
-artistictext_convert_to_path=none
-artistictext_detach_from_path=none
-artistictext_font_bold=none
-artistictext_font_italic=none
-artistictext_subscript=none
-artistictext_superscript=none
-ArtisticTextTool=none
borderselection=none
BrushesAndStuff=none
brushslider2=none
brushslider3=none
canvassize=Ctrl+Alt+C
change_text_direction=Ctrl+Shift+D
clear=D
clones_array=none
colorrange=none
composite_actions=none
configure_bibliography=none
configure_section=none
convert_selection_to_shape=none
convert_shapes_to_vector_selection=none
convert_to_filter_mask=none
convert_to_paint_layer=none
convert-to-path=none
convert_to_selection_mask=none
convert_to_transparency_mask=none
convert_to_vector_selection=none
copy_merged=Ctrl+Shift+C
copy_selection_to_new_layer=Ctrl+Alt+J
copy_sharp=none
create_bundle=none
create_copy=none
CreateShapesTool=none
create_template=none
cut_selection_to_new_layer=Ctrl+Shift+J
cut_sharp=none
decrease_brush_size=[
decrease_opacity=I
delete_keyframe=none
deselect=Ctrl+Shift+A
dual=none
duplicatelayer=Ctrl+J
edit_copy=Ctrl+C
edit_cut=Ctrl+X
edit_deselect_all=Ctrl+Shift+A
EditLayerMetaData=none
edit_paste=Ctrl+V
edit_paste_text=none
edit_redo=Ctrl+Y
edit_select_all=Ctrl+A
edit_undo=Ctrl+Z
erase_action=E
featherselection=Shift+F6
file_close_all=Ctrl+Shift+W
file_close=none
file_documentinfo=none
file_export_animation=none
file_export_file=none
file_export_pdf=none
file_import_file=none
file_new=Ctrl+N
file_open=Ctrl+O
file_open_recent=F4
file_print=Ctrl+P
file_print_preview=none
file_quit=Ctrl+Q
file_save_as=Ctrl+Shift+S
file_save=Ctrl+S
fill_selection_background_color=Backspace
fill_selection_background_color_opacity=Ctrl+Backspace
fill_selection_foreground_color_opacity=Ctrl+Shift+Backspace
fill_selection_foreground_color=Shift+Backspace
fill_selection_pattern=none
fill_selection_pattern_opacity=none
filter_apply_again=Ctrl+F
first_frame=none
flatten_image=Ctrl+Shift+E
flatten_layer=none
fontsizedown=Ctrl+<
fontsizeup=Ctrl+>
format_alignblock=Ctrl+Alt+R
format_aligncenter=Ctrl+Alt+C
format_alignleft=none
format_alignright=Ctrl+Alt+R
format_backgroundcolor=none
format_bold=Ctrl+B
format_bulletlist=none
format_decreaseindent=none
format_endnotes=none
format_font=Ctrl+Alt+F
format_fontfamily=none
format_fontsize=none
format_footnotes=none
format_increaseindent=none
format_italic=Ctrl+I
format_numberlist=none
format_paragraph=Ctrl+Alt+P
format_strike=none
format_stylist=Ctrl+Alt+S
format_sub=Ctrl+Shift+B
format_super=Ctrl+Shift+P
format_tableofcontents=none
format_textcolor=none
format_underline=Ctrl+U
fullscreen=Ctrl+Shift+F
gmic=none
gradients=none
growselection=none
grow_to_fit_height=none
grow_to_fit_width=none
help_about_app=none
help_about_kde=none
help_contents=F1
help_report_bug=none
histogram=none
hmirror_action=none
image_color=none
imagecolorspaceconversion=none
image_properties=none
imagesize=Ctrl+Alt+I
imagesplit=none
import_layer_as_filter_mask=none
import_layer_as_paint_layer=none
import_layer_as_selection_mask=none
import_layer_as_transparency_mask=none
import_layer_from_file=none
import_resources=none
increase_brush_size=]
increase_opacity=O
insert_annotation=Ctrl+Shift+C
insert_autoendnote=none
insert_autofootnote=none
insert_bibliography=none
insert_bookmark=none
insert_citation=none
insert_configure_tableofcontents=none
insert_custom_bibliography=none
insert_index=Ctrl+T
insert_labeledendnote=none
insert_labeledfootnote=none
insert_link=none
insert_section=none
insert_specialchar=Alt+Shift+C
insert_tableofcontents=none
InteractionTool=none
invert=Ctrl+Shift+I
invoke_bookmark_handler=none
isolate_active_layer=none
KarbonCalligraphyTool=none
KarbonGradientTool=none
KarbonPatternTool=none
KisRulerAssistantTool=none
KisToolCrop=C
KisToolPath=P
KisToolPencil=none
KisToolPerspectiveGrid=none
KisToolPolygon=none
KisToolPolyline=none
KisToolSelectContiguous=W
KisToolSelectElliptical=J
KisToolSelectOutline=none
KisToolSelectPath=none
KisToolSelectPolygonal=none
KisToolSelectRectangular=M
KisToolSelectSimilar=none
KisToolTransform=Ctrl+T
KritaFill/KisToolFill=G
KritaFill/KisToolGradient=none
krita_filter_autocontrast=none
krita_filter_blur=none
krita_filter_bottom edge detections=none
krita_filter_brightnesscontrast=none
krita_filter_burn=none
krita_filter_colorbalance=Ctrl+B
krita_filter_colortoalpha=none
krita_filter_colortransfer=none
krita_filter_desaturate=Ctrl+Shift+U
krita_filter_dodge=none
krita_filter_emboss all directions=none
krita_filter_emboss horizontal and vertical=none
krita_filter_emboss horizontal only=none
krita_filter_emboss laplascian=none
krita_filter_emboss=none
krita_filter_emboss vertical only=none
krita_filter_gaussian blur=none
krita_filter_gaussiannoisereducer=none
krita_filter_hsvadjustment=Ctrl+U
krita_filter_indexcolors=none
krita_filter_invert=Ctrl+I
krita_filter_left edge detections=none
krita_filter_lens blur=none
krita_filter_levels=Ctrl+L
krita_filter_maximize=none
krita_filter_mean removal=none
krita_filter_minimize=none
krita_filter_motion blur=none
krita_filter_noise=none
krita_filter_oilpaint=none
krita_filter_perchannel=Ctrl+M
krita_filter_phongbumpmap=none
krita_filter_pixelize=none
krita_filter_posterize=none
krita_filter_raindrops=none
krita_filter_randompick=none
krita_filter_right edge detections=none
krita_filter_roundcorners=none
krita_filter_sharpen=none
krita_filter_smalltiles=none
krita_filter_sobel=none
krita_filter_top edge detections=none
krita_filter_unsharp=none
krita_filter_waveletnoisereducer=none
krita_filter_wave=none
KritaSelected/KisToolColorPicker=none
KritaShape/KisToolBrush=B
KritaShape/KisToolDyna=none
KritaShape/KisToolEllipse=none
KritaShape/KisToolLine=none
KritaShape/KisToolMeasure=none
KritaShape/KisToolMultiBrush=Q
KritaShape/KisToolRectangle=none
KritaShape/KisToolText=none
KritaTransform/KisToolMove=T
last_frame=none
layercolorspaceconversion=none
LayerGroupSwitcher/next=none
LayerGroupSwitcher/previous=none
layer_properties=none
layersize=none
layersplit=none
layer_style=none
lazy_frame=none
level_of_detail_mode=Shift+L
Macro_Open_Edit=none
Macro_Open_Play=none
mainToolBar=none
make_brush_color_darker=K
make_brush_color_lighter=L
manage_bookmarks=none
manage_bundles=none
merge_layer=Ctrl+E
mirror_actions=none
mirror_canvas=Shift+H
mirrorImageHorizontal=none
mirrorImageVertical=none
mirrorNodeX=none
mirrorNodeY=none
move_layer_down=Ctrl+PgDown
move_layer_up=Ctrl+PgDown
next_favorite_preset=,
next_frame=none
next_keyframe=none
nonbreaking_hyphen=Ctrl+Shift+-
nonbreaking_space=Ctrl+Space
object_align_horizontal_center=none
object_align_horizontal_left=none
object_align_horizontal_right=none
object_align_vertical_bottom=none
object_align_vertical_center=none
object_align_vertical_top=none
object_group=none
object_order_back=Ctrl+Shift+[
object_order_front=Ctrl+Shift+]
object_order_lower=Ctrl+[
object_order_raise=Ctrl+]
object_ungroup=none
offsetimage=none
offsetlayer=none
open_resources_directory=none
options_configure_keybinding=none
options_configure=none
options_configure_toolbars=none
paintops=none
paste_at=none
paste_new=Ctrl+Shift+N
path-break-point=none
path-break-segment=none
pathpoint-corner=none
pathpoint-curve=none
pathpoint-insert=Ins
pathpoint-join=J
pathpoint-line=none
pathpoint-merge=none
pathpoint-remove=Backspace
pathpoint-smooth=none
pathpoint-symmetric=none
pathsegment-curve=Shift+C
pathsegment-line=F
PathTool=none
patterns=none
preserve_alpha=none
previous_favorite_preset=.
previous_frame=none
previous_keyframe=none
previous_preset=/
rasterize_layer=none
Recording_Start_Recording_Macro=none
Recording_Stop_Recording_Macro=none
ReferencesTool=none
reload_preset_action=none
remove_layer=none
rename_composition=none
RenameCurrentLayer=F2
repaint=none
reselect=Ctrl+Shift+D
reset_fg_bg=D
resizeimagetolayer=none
resizeimagetoselection=none
ReviewTool=none
rotate_canvas_left=Ctrl+[
rotate_canvas_right=Ctrl+]
rotateImage180=none
rotateImageCCW90=none
rotateImageCW90=none
rotateimage=none
rotateLayer180=none
rotateLayerCCW90=none
rotateLayerCW90=none
rotatelayer=none
save_groups_as_images=none
save_incremental_backup=F4
save_incremental_version=Ctrl+Alt+S
save_node_as_image=none
select_all=Ctrl+A
Select Behind Blending Mode=Alt+Shift+Q
Select Clear Blending Mode=Alt+Shift+R
Select Color Blending Mode=Alt+Shift+C
Select Color Burn Blending Mode=Alt+Shift+B
Select Color Dodge Blending Mode=Alt+Shift+D
Select Darken Blending Mode=Alt+Shift+K
Select Difference Blending Mode=Alt+Shift+E
Select Dissolve Blending Mode=Alt+Shift+I
Select Exclusion Blending Mode=Alt+Shift+X
Select Hard Light Blending Mode=Alt+Shift+H
Select Hard Mix Blending Mode=Alt+Shift+L
Select Hue Blending Mode=Alt+Shift+U
selectionscale=none
Select Lighten Blending Mode=Alt+Shift+G
Select Linear Burn Blending Mode=Alt+Shift+A
Select Linear Dodge Blending Mode=Alt+Shift+W
Select Linear Light Blending Mode=Alt+Shift+J
Select Luminosity Blending Mode=Alt+Shift+Y
Select Multiply Blending Mode=Alt+Shift+M
Select Normal Blending Mode=Alt+Shift+N
select_opaque=none
selectopaque=none
Select Overlay Blending Mode=Alt+Shift+O
Select Pin Light Blending Mode=Alt+Shift+Z
Select Saturation Blending Mode=Alt+Shift+T
Select Screen Blending Mode=Alt+Shift+S
Select Soft Light Blending Mode=Alt+Shift+F
Select Vivid Light Blending Mode=Alt+Shift+V
separate=none
set_no_brush_smoothing=none
set_simple_brush_smoothing=none
set_stabilizer_brush_smoothing=none
settings_active_author=none
set_weighted_brush_smoothing=none
shearimage=none
shearlayer=none
show_brush_presets=none
show_color_history=H
show_color_selector=Shift+I
show_common_colors=U
show-global-selection-mask=none
pin_to_timeline=none
show_minimal_shade_selector=Shift+N
show_mypaint_shade_selector=Shift+M
showStatusBar=none
shrinkselection=none
shrink_to_fit=none
smoothselection=none
soft_hyphen=none
split_alpha_into_mask=none
split_alpha_save_merged=none
split_alpha_write=none
split_sections=none
stroke_shapes=none
tablet_debugger=Ctrl+Shift+T
TextTool=none
toggle_assistant=Ctrl+Shift+L
toggle_display_selection=Ctrl+H
toggle_fg_bg=X
toggle_playback=none
toggle-selection-overlay-mode=none
trim_to_image=none
undo_polygon_selection=Shift+Z
VectorTool=none
view_clear_perspective_grid=none
view_grid=Ctrl+Shift+'
view_newwindow=none
view_ruler=none
view_show_canvas_only=none
view_show_guides=none
view_snap_to_grid=Ctrl+Shift+;
view_toggle_assistant_previews=none
view_toggledockers=Tab
view_toggledockertitlebars=none
view_toggle_painting_assistants=none
view_toggle_perspective_grid=none
view_zoom_in=none
view_zoom_out=none
vmirror_action=none
windows_cascade=none
windows_next=Ctrl+Tab
windows_previous=Ctrl+Shift+Tab
windows_tile=none
workspaces=none
zoom_to_100pct=Home
diff --git a/krita/data/shortcuts/photoshop_compatible.shortcuts b/krita/data/shortcuts/photoshop_compatible.shortcuts
index b0e4a57c71..ce38fddc62 100644
--- a/krita/data/shortcuts/photoshop_compatible.shortcuts
+++ b/krita/data/shortcuts/photoshop_compatible.shortcuts
@@ -1,428 +1,418 @@
black[Shortcuts]
activateNextLayer=Alt+]
activatePreviousLayer=Alt+[
add_blank_frame=none
add_duplicate_frame=none
add_new_adjustment_layer=none
add_new_clone_layer=none
add_new_file_layer=none
add_new_fill_layer=none
add_new_filter_mask=none
add_new_group_layer=Ctrl+G
add_new_paint_layer=Ctrl+Shift+N
add_new_selection_mask=none
add_new_shape_layer=none
add_new_transform_mask=none
add_new_transparency_mask=none
-artistictext_anchor_end=none
-artistictext_anchor_middle=none
-artistictext_anchor_start=none
-artistictext_convert_to_path=none
-artistictext_detach_from_path=none
-artistictext_font_bold=none
-artistictext_font_italic=none
-artistictext_subscript=none
-artistictext_superscript=none
-ArtisticTextTool=none
borderselection=none
BrushesAndStuff=none
brushslider2=none
brushslider3=none
canvassize=Ctrl+Alt+C
change_text_direction=Ctrl+Shift+D
clear=Del
clones_array=none
colorrange=none
composite_actions=none
configure_bibliography=none
configure_section=none
convert_selection_to_shape=none
convert_shapes_to_vector_selection=none
convert_to_filter_mask=none
convert_to_paint_layer=none
convert-to-path=P
convert_to_selection_mask=none
convert_to_transparency_mask=none
convert_to_vector_selection=none
copy_merged=Ctrl+Shift+C
copy_selection_to_new_layer=Ctrl+Alt+J
copy_sharp=none
create_bundle=none
create_copy=none
CreateShapesTool=none
create_template=none
cut_selection_to_new_layer=Ctrl+Shift+J
cut_sharp=none
decrease_brush_size=[
decrease_opacity=;\s
delete_keyframe=none
deselect=Ctrl+D
dual=none
duplicatelayer=Ctrl+J
edit_copy=Ctrl+C
edit_cut=Ctrl+X
edit_deselect_all=Ctrl+Shift+A
EditLayerMetaData=none
edit_paste=Ctrl+V
edit_paste_text=none
edit_redo=Ctrl+Shift+Z
edit_select_all=Ctrl+A
edit_undo=Ctrl+Z
erase_action=E
featherselection=Shift+F6
file_close_all=Ctrl+Shift+W
file_close=Ctrl+W
file_documentinfo=Ctrl+Alt+Shift+I
file_export_animation=none
file_export_file=none
file_export_pdf=none
file_import_file=none
file_new=Ctrl+N
file_open=Ctrl+O
file_open_recent=F4
file_print=Ctrl+P
file_print_preview=none
file_quit=Ctrl+Q
file_save_as=Ctrl+Shift+S
file_save=Ctrl+S
fill_selection_background_color=Backspace
fill_selection_background_color_opacity=Ctrl+Backspace
fill_selection_foreground_color_opacity=Ctrl+Shift+Backspace
fill_selection_foreground_color=Shift+Backspace
fill_selection_pattern=none
fill_selection_pattern_opacity=none
filter_apply_again=Ctrl+F
first_frame=none
flatten_image=Ctrl+Shift+E
flatten_layer=none
fontsizedown=Ctrl+<
fontsizeup=Ctrl+>
format_alignblock=Ctrl+Alt+R
format_aligncenter=Ctrl+Alt+C
format_alignleft=none
format_alignright=Ctrl+Alt+R
format_backgroundcolor=none
format_bold=Ctrl+B
format_bulletlist=none
format_decreaseindent=none
format_endnotes=none
format_font=Ctrl+Alt+F
format_fontfamily=none
format_fontsize=none
format_footnotes=none
format_increaseindent=none
format_italic=Ctrl+I
format_numberlist=none
format_paragraph=Ctrl+Alt+P
format_strike=none
format_stylist=Ctrl+Alt+S
format_sub=Ctrl+Shift+B
format_super=Ctrl+Shift+P
format_tableofcontents=none
format_textcolor=none
format_underline=Ctrl+U
fullscreen=Ctrl+Shift+F
gmic=none
gradients=none
growselection=none
grow_to_fit_height=none
grow_to_fit_width=none
help_about_app=none
help_about_kde=none
help_contents=F1
help_report_bug=none
histogram=none
hmirror_action=none
image_color=none
imagecolorspaceconversion=none
image_properties=none
imagesize=Ctrl+Alt+I
imagesplit=none
import_layer_as_filter_mask=none
import_layer_as_paint_layer=none
import_layer_as_selection_mask=none
import_layer_as_transparency_mask=none
import_layer_from_file=none
import_resources=none
increase_brush_size=]
increase_opacity=O
insert_annotation=Ctrl+Shift+C
insert_autoendnote=none
insert_autofootnote=none
insert_bibliography=none
insert_bookmark=none
insert_citation=none
insert_configure_tableofcontents=none
insert_custom_bibliography=none
insert_index=Ctrl+T
insert_labeledendnote=none
insert_labeledfootnote=none
insert_link=none
insert_section=none
insert_specialchar=Alt+Shift+C
insert_tableofcontents=none
InteractionTool=none
invert=Ctrl+Shift+I
invoke_bookmark_handler=none
isolate_active_layer=none
KarbonCalligraphyTool=none
KarbonGradientTool=none
KarbonPatternTool=none
KisRulerAssistantTool=none
KisToolCrop=C
KisToolPath=none
KisToolPencil=none
KisToolPerspectiveGrid=none
KisToolPolygon=none
KisToolPolyline=none
KisToolSelectContiguous=none
KisToolSelectElliptical=Shift+M
KisToolSelectOutline=none
KisToolSelectPath=none
KisToolSelectPolygonal=none
KisToolSelectRectangular=M
KisToolSelectSimilar=none
KisToolTransform=Ctrl+T
KritaFill/KisToolFill=Shift+G
KritaFill/KisToolGradient=G
krita_filter_autocontrast=none
krita_filter_blur=none
krita_filter_bottom edge detections=none
krita_filter_brightnesscontrast=none
krita_filter_burn=none
krita_filter_colorbalance=Ctrl+B
krita_filter_colortoalpha=none
krita_filter_colortransfer=none
krita_filter_desaturate=Ctrl+Shift+U
krita_filter_dodge=none
krita_filter_emboss all directions=none
krita_filter_emboss horizontal and vertical=none
krita_filter_emboss horizontal only=none
krita_filter_emboss laplascian=none
krita_filter_emboss=none
krita_filter_emboss vertical only=none
krita_filter_gaussian blur=none
krita_filter_gaussiannoisereducer=none
krita_filter_hsvadjustment=Ctrl+U
krita_filter_indexcolors=none
krita_filter_invert=Ctrl+I
krita_filter_left edge detections=none
krita_filter_lens blur=none
krita_filter_levels=Ctrl+L
krita_filter_maximize=none
krita_filter_mean removal=none
krita_filter_minimize=none
krita_filter_motion blur=none
krita_filter_noise=none
krita_filter_oilpaint=none
krita_filter_perchannel=Ctrl+M
krita_filter_phongbumpmap=none
krita_filter_pixelize=none
krita_filter_posterize=none
krita_filter_raindrops=none
krita_filter_randompick=none
krita_filter_right edge detections=none
krita_filter_roundcorners=none
krita_filter_sharpen=none
krita_filter_smalltiles=none
krita_filter_sobel=none
krita_filter_top edge detections=none
krita_filter_unsharp=none
krita_filter_waveletnoisereducer=none
krita_filter_wave=none
KritaSelected/KisToolColorPicker=I
KritaShape/KisToolBrush=B
KritaShape/KisToolDyna=none
KritaShape/KisToolEllipse=none
KritaShape/KisToolLine=none
KritaShape/KisToolMeasure=none
KritaShape/KisToolMultiBrush=Q
KritaShape/KisToolRectangle=none
KritaShape/KisToolText=T
KritaTransform/KisToolMove=V
last_frame=none
layercolorspaceconversion=none
LayerGroupSwitcher/next=none
LayerGroupSwitcher/previous=none
layer_properties=none
layersize=none
layersplit=none
layer_style=none
lazy_frame=none
level_of_detail_mode=Shift+L
Macro_Open_Edit=none
Macro_Open_Play=none
mainToolBar=none
make_brush_color_darker=K
make_brush_color_lighter=L
manage_bookmarks=none
manage_bundles=none
merge_layer=Ctrl+E
mirror_actions=none
mirror_canvas=;\s
mirrorImageHorizontal=none
mirrorImageVertical=none
mirrorNodeX=none
mirrorNodeY=none
move_layer_down=Ctrl+[
move_layer_up=Ctrl+]
next_favorite_preset=,
next_frame=none
next_keyframe=none
nonbreaking_hyphen=Ctrl+Shift+-
nonbreaking_space=Ctrl+Space
object_align_horizontal_center=none
object_align_horizontal_left=none
object_align_horizontal_right=none
object_align_vertical_bottom=none
object_align_vertical_center=none
object_align_vertical_top=none
object_group=none
object_order_back=Ctrl+Shift+[
object_order_front=Ctrl+Shift+]
object_order_lower=none
object_order_raise=none
object_ungroup=none
offsetimage=none
offsetlayer=none
open_resources_directory=none
options_configure_keybinding=none
options_configure=none
options_configure_toolbars=none
paintops=none
paste_at=none
paste_new=none
path-break-point=none
path-break-segment=none
pathpoint-corner=none
pathpoint-curve=none
pathpoint-insert=Ins
pathpoint-join=J
pathpoint-line=none
pathpoint-merge=none
pathpoint-remove=Backspace
pathpoint-smooth=none
pathpoint-symmetric=none
pathsegment-curve=Shift+C
pathsegment-line=F
PathTool=none
patterns=none
preserve_alpha=none
previous_favorite_preset=.
previous_frame=none
previous_keyframe=none
previous_preset=/
rasterize_layer=none
Recording_Start_Recording_Macro=none
Recording_Stop_Recording_Macro=none
ReferencesTool=none
reload_preset_action=none
remove_layer=none
rename_composition=none
RenameCurrentLayer=F2
repaint=none
reselect=Ctrl+Shift+D
reset_fg_bg=D
resizeimagetolayer=none
resizeimagetoselection=none
ReviewTool=none
rotate_canvas_left=none
rotate_canvas_right=none
rotateImage180=none
rotateImageCCW90=none
rotateImageCW90=none
rotateimage=none
rotateLayer180=none
rotateLayerCCW90=none
rotateLayerCW90=none
rotatelayer=none
save_groups_as_images=none
save_incremental_backup=F4
save_incremental_version=Ctrl+Alt+S
save_node_as_image=none
select_all=Ctrl+A
Select Behind Blending Mode=Alt+Shift+Q
Select Clear Blending Mode=Alt+Shift+R
Select Color Blending Mode=Alt+Shift+C
Select Color Burn Blending Mode=Alt+Shift+B
Select Color Dodge Blending Mode=Alt+Shift+D
Select Darken Blending Mode=Alt+Shift+K
Select Difference Blending Mode=Alt+Shift+E
Select Dissolve Blending Mode=Alt+Shift+I
Select Exclusion Blending Mode=Alt+Shift+X
Select Hard Light Blending Mode=Alt+Shift+H
Select Hard Mix Blending Mode=Alt+Shift+L
Select Hue Blending Mode=Alt+Shift+U
selectionscale=none
Select Lighten Blending Mode=Alt+Shift+G
Select Linear Burn Blending Mode=Alt+Shift+A
Select Linear Dodge Blending Mode=Alt+Shift+W
Select Linear Light Blending Mode=Alt+Shift+J
Select Luminosity Blending Mode=Alt+Shift+Y
Select Multiply Blending Mode=Alt+Shift+M
Select Normal Blending Mode=Alt+Shift+N
select_opaque=none
selectopaque=none
Select Overlay Blending Mode=Alt+Shift+O
Select Pin Light Blending Mode=Alt+Shift+Z
Select Saturation Blending Mode=Alt+Shift+T
Select Screen Blending Mode=Alt+Shift+S
Select Soft Light Blending Mode=Alt+Shift+F
Select Vivid Light Blending Mode=Alt+Shift+V
separate=none
set_no_brush_smoothing=none
set_simple_brush_smoothing=none
set_stabilizer_brush_smoothing=none
settings_active_author=none
set_weighted_brush_smoothing=none
shearimage=none
shearlayer=none
show_brush_presets=F6
show_color_history=H
show_color_selector=Shift+I
show_common_colors=U
show-global-selection-mask=none
pin_to_timeline=none
show_minimal_shade_selector=Shift+N
show_mypaint_shade_selector=;\s
showStatusBar=none
shrinkselection=none
shrink_to_fit=none
smoothselection=none
soft_hyphen=none
split_alpha_into_mask=none
split_alpha_save_merged=none
split_alpha_write=none
split_sections=none
stroke_shapes=none
tablet_debugger=Ctrl+Shift+T
TextTool=none
toggle_assistant=Ctrl+Shift+L
toggle_display_selection=Ctrl+H
toggle_fg_bg=X
toggle_playback=none
toggle-selection-overlay-mode=none
trim_to_image=none
undo_polygon_selection=Shift+Z
VectorTool=none
view_clear_perspective_grid=none
view_grid=Ctrl+Shift+'
view_newwindow=none
view_ruler=none
view_show_canvas_only=Tab
view_show_guides=none
view_snap_to_grid=Ctrl+Shift+;
view_toggle_assistant_previews=none
view_toggledockers=none
view_toggledockertitlebars=none
view_toggle_painting_assistants=none
view_toggle_perspective_grid=none
view_zoom_in=Ctrl++
view_zoom_out=Ctrl+-
vmirror_action=none
windows_cascade=none
windows_next=none
windows_previous=none
windows_tile=none
workspaces=none
zoom_to_100pct=Ctrl+0
diff --git a/krita/data/shortcuts/tablet_pro.shortcuts b/krita/data/shortcuts/tablet_pro.shortcuts
index 6fbd1a5449..413d9c862f 100644
--- a/krita/data/shortcuts/tablet_pro.shortcuts
+++ b/krita/data/shortcuts/tablet_pro.shortcuts
@@ -1,466 +1,456 @@
[Shortcuts]
activateNextLayer=PgUp
activatePreviousLayer=PgDown
add_blank_frame=none
add_duplicate_frame=none
add_new_adjustment_layer=none
add_new_clone_layer=none
add_new_file_layer=none
add_new_fill_layer=none
add_new_filter_mask=none
add_new_group_layer=none
add_new_paint_layer=Ins
add_new_selection_mask=none
add_new_shape_layer=none
add_new_transform_mask=none
add_new_transparency_mask=none
-artistictext_anchor_end=none
-artistictext_anchor_middle=none
-artistictext_anchor_start=none
-artistictext_convert_to_path=none
-artistictext_detach_from_path=none
-artistictext_font_bold=none
-artistictext_font_italic=none
-artistictext_subscript=none
-artistictext_superscript=none
-ArtisticTextTool=none
borderselection=none
BrushesAndStuff=none
brushslider1=none
brushslider2=none
brushslider3=none
canvassize=Ctrl+Alt+C
change_text_direction=Ctrl+Shift+D
clear=Del
clones_array=none
colorrange=none
composite_actions=none
configure_bibliography=none
configure_section=none
convert_selection_to_shape=none
convert_shapes_to_vector_selection=none
convert_to_filter_mask=none
convert_to_paint_layer=none
convert-to-path=P
convert_to_selection_mask=none
convert_to_transparency_mask=none
convert_to_vector_selection=none
copy_layer_clipboard=none
copy_merged=Ctrl+Shift+C
copy_selection_to_new_layer=Ctrl+Alt+J
copy_sharp=none
create_bundle=none
create_copy=none
create_quick_clipping_group=Ctrl+Shift+G
create_quick_group=Ctrl+G
CreateShapesTool=none
create_template=none
cut_layer_clipboard=none
cut_selection_to_new_layer=Ctrl+Shift+J
cut_sharp=none
decrease_brush_size=[
decrease_opacity=none
delete_keyframe=none
deselect=Ctrl+Shift+A
drop_frames=none
dual=none
duplicatelayer=Ctrl+J
edit_copy=Ctrl+C
edit_cut=Ctrl+X
edit_deselect_all=Ctrl+Shift+A
EditLayerMetaData=none
edit_paste=Ctrl+V
edit_paste_text=none
edit_redo=Ctrl+Shift+Z
edit_select_all=Ctrl+A
edit_undo=Ctrl+Z
erase_action=E
featherselection=Shift+F6
file_close_all=Ctrl+Shift+W
file_close=Ctrl+W
file_documentinfo=none
file_export_animation=none
file_export_file=none
file_export_pdf=none
file_import_animation=none
file_import_file=none
file_new=Ctrl+N
file_open=Ctrl+O
file_open_recent=none
file_quit=Ctrl+Q
file_save_as=Ctrl+Shift+S
file_save=Ctrl+S
fill_selection_background_color=Backspace
fill_selection_background_color_opacity=Ctrl+Backspace
fill_selection_foreground_color_opacity=Ctrl+Shift+Backspace
fill_selection_foreground_color=Shift+Backspace
fill_selection_pattern=none
fill_selection_pattern_opacity=none
filter_apply_again=Ctrl+F
first_frame=none
flatten_image=Ctrl+Shift+E
flatten_layer=none
fontsizedown=Ctrl+<
fontsizeup=Ctrl+>
format_alignblock=Ctrl+Alt+R
format_aligncenter=Ctrl+Alt+C
format_alignleft=none
format_alignright=Ctrl+Alt+R
format_backgroundcolor=none
format_bold=Ctrl+B
format_bulletlist=none
format_decreaseindent=none
format_endnotes=none
format_font=Ctrl+Alt+F
format_fontfamily=none
format_fontsize=none
format_footnotes=none
format_increaseindent=none
format_italic=Ctrl+I
format_numberlist=none
format_paragraph=Ctrl+Alt+P
format_strike=none
format_stylist=Ctrl+Alt+S
format_sub=Ctrl+Shift+B
format_super=Ctrl+Shift+P
format_tableofcontents=none
format_textcolor=none
format_underline=Ctrl+U
gmic=none
gradients=none
growselection=none
grow_to_fit_height=none
grow_to_fit_width=none
help_about_app=none
help_about_kde=none
help_contents=F1
help_report_bug=none
histogram=none
hmirror_action=none
image_color=none
imagecolorspaceconversion=none
image_properties=none
imagesize=Ctrl+Alt+I
imagesplit=none
import_layer_as_filter_mask=none
import_layer_as_paint_layer=none
import_layer_as_selection_mask=none
import_layer_as_transparency_mask=none
import_layer_from_file=none
increase_brush_size=]
increase_opacity=O
insert_annotation=Ctrl+Shift+C
insert_autoendnote=none
insert_autofootnote=none
insert_bibliography=none
insert_bookmark=none
insert_citation=none
insert_configure_tableofcontents=none
insert_custom_bibliography=none
insert_index=Ctrl+T
insert_labeledendnote=none
insert_labeledfootnote=none
insert_link=none
insert_section=none
insert_specialchar=Alt+Shift+C
insert_tableofcontents=none
InteractionTool=none
invert=Ctrl+Shift+I
invoke_bookmark_handler=none
isolate_active_layer=none
KarbonCalligraphyTool=none
KarbonGradientTool=none
KarbonPatternTool=none
KisRulerAssistantTool=none
KisToolCrop=C
KisToolPath=none
KisToolPencil=none
KisToolPolygon=none
KisToolPolyline=none
KisToolSelectContiguous=none
KisToolSelectElliptical=Shift+M
KisToolSelectOutline=L
KisToolSelectPath=none
KisToolSelectPolygonal=none
KisToolSelectRectangular=M
KisToolSelectSimilar=none
KisToolTransform=Ctrl+T
KritaFill/KisToolFill=Shift+G
KritaFill/KisToolGradient=G
krita_filter_autocontrast=none
krita_filter_blur=none
krita_filter_bottom edge detections=none
krita_filter_brightnesscontrast=none
krita_filter_burn=none
krita_filter_colorbalance=Ctrl+B
krita_filter_colortoalpha=none
krita_filter_colortransfer=none
krita_filter_desaturate=Ctrl+Shift+U
krita_filter_dodge=none
krita_filter_emboss all directions=none
krita_filter_emboss horizontal and vertical=none
krita_filter_emboss horizontal only=none
krita_filter_emboss laplascian=none
krita_filter_emboss=none
krita_filter_emboss vertical only=none
krita_filter_gaussian blur=none
krita_filter_gaussiannoisereducer=none
krita_filter_hsvadjustment=Ctrl+U
krita_filter_indexcolors=none
krita_filter_invert=Ctrl+I
krita_filter_left edge detections=none
krita_filter_lens blur=none
krita_filter_levels=Ctrl+L
krita_filter_maximize=none
krita_filter_mean removal=none
krita_filter_minimize=none
krita_filter_motion blur=none
krita_filter_noise=none
krita_filter_oilpaint=none
krita_filter_perchannel=Ctrl+M
krita_filter_phongbumpmap=none
krita_filter_pixelize=none
krita_filter_posterize=none
krita_filter_raindrops=none
krita_filter_randompick=none
krita_filter_right edge detections=none
krita_filter_roundcorners=none
krita_filter_sharpen=none
krita_filter_smalltiles=none
krita_filter_sobel=none
krita_filter_top edge detections=none
krita_filter_unsharp=none
krita_filter_waveletnoisereducer=none
krita_filter_wave=none
KritaSelected/KisToolColorPicker=I
KritaShape/KisToolBrush=B
KritaShape/KisToolDyna=none
KritaShape/KisToolEllipse=none
KritaShape/KisToolLine=none
KritaShape/KisToolMeasure=none
KritaShape/KisToolMultiBrush=Q
KritaShape/KisToolRectangle=none
KritaShape/KisToolText=T
KritaTransform/KisToolMove=V
last_frame=none
layercolorspaceconversion=none
LayerGroupSwitcher/next=none
LayerGroupSwitcher/previous=none
layer_properties=none
layersize=none
layersplit=none
layer_style=none
lazy_frame=none
level_of_detail_mode=Shift+L
Macro_Open_Edit=none
Macro_Open_Play=none
mainToolBar=none
make_brush_color_bluer=none
make_brush_color_darker=K
make_brush_color_desaturated=none
make_brush_color_greener=none
make_brush_color_lighter=none
make_brush_color_redder=none
make_brush_color_saturated=none
make_brush_color_yellower=none
manage_bookmarks=none
manage_bundles=none
merge_layer=Ctrl+E
mirror_actions=none
mirror_canvas=M
mirrorImageHorizontal=none
mirrorImageVertical=none
mirrorNodeX=none
mirrorNodeY=none
move_layer_down=none
move_layer_up=none
movetool-move-down=Down
movetool-move-down-more=Shift+Down
movetool-move-left=Left
movetool-move-left-more=Shift+Left
movetool-move-right-more=Shift+Right
movetool-move-right=Right
movetool-move-up-more=Shift+Up
movetool-move-up=Up
next_favorite_preset=,
next_frame=none
next_keyframe=none
nonbreaking_hyphen=Ctrl+Shift+-
nonbreaking_space=Ctrl+Space
object_align_horizontal_center=none
object_align_horizontal_left=none
object_align_horizontal_right=none
object_align_vertical_bottom=none
object_align_vertical_center=none
object_align_vertical_top=none
object_group=none
object_order_back=Ctrl+Shift+[
object_order_front=Ctrl+Shift+]
object_order_lower=none
object_order_raise=none
object_ungroup=none
offsetimage=none
offsetlayer=none
open_resources_directory=none
options_configure=none
options_configure_toolbars=none
paintops=none
paste_at=none
paste_layer_from_clipboard=none
paste_new=Ctrl+Shift+N
path-break-point=none
path-break-segment=none
pathpoint-corner=none
pathpoint-curve=none
pathpoint-insert=none
pathpoint-join=J
pathpoint-line=none
pathpoint-merge=none
pathpoint-remove=Backspace
pathpoint-smooth=none
pathpoint-symmetric=none
pathsegment-curve=Shift+C
pathsegment-line=F
PathTool=none
patterns=none
preserve_alpha=none
previous_favorite_preset=.
previous_frame=none
previous_keyframe=none
previous_preset=/
quick_ungroup=Ctrl+Alt+G
rasterize_layer=none
Recording_Start_Recording_Macro=none
Recording_Stop_Recording_Macro=none
ReferencesTool=none
reload_preset_action=none
remove_layer=Shift+Del
rename_composition=none
RenameCurrentLayer=F2
repaint=none
reselect=Ctrl+Shift+D
reset_canvas_rotation=none
reset_fg_bg=D
resizeimagetolayer=none
resizeimagetoselection=none
ReviewTool=none
rotate_canvas_left=Ctrl+[
rotate_canvas_right=Ctrl+]
rotateImage180=none
rotateImageCCW90=none
rotateImageCW90=none
rotateimage=none
rotateLayer180=none
rotateLayerCCW90=none
rotateLayerCW90=none
rotatelayer=none
rulers_track_mouse=none
save_groups_as_images=none
save_incremental_backup=F4
save_incremental_version=Ctrl+Alt+S
save_node_as_image=none
select_all=Ctrl+A
select_all_layers=none
Select Behind Blending Mode=Alt+Shift+Q
Select Clear Blending Mode=Alt+Shift+R
Select Color Blending Mode=Alt+Shift+C
Select Color Burn Blending Mode=Alt+Shift+B
Select Color Dodge Blending Mode=Alt+Shift+D
Select Darken Blending Mode=Alt+Shift+K
Select Difference Blending Mode=Alt+Shift+E
Select Dissolve Blending Mode=Alt+Shift+I
Select Exclusion Blending Mode=Alt+Shift+X
Select Hard Light Blending Mode=Alt+Shift+H
Select Hard Mix Blending Mode=Alt+Shift+L
Select Hue Blending Mode=Alt+Shift+U
select_invisible_layers=none
selectionscale=none
Select Lighten Blending Mode=Alt+Shift+G
Select Linear Burn Blending Mode=Alt+Shift+A
Select Linear Dodge Blending Mode=Alt+Shift+W
Select Linear Light Blending Mode=Alt+Shift+J
select_locked_layers=none
Select Luminosity Blending Mode=Alt+Shift+Y
Select Multiply Blending Mode=Alt+Shift+M
Select Normal Blending Mode=Alt+Shift+N
select_opaque=none
selectopaque=none
Select Overlay Blending Mode=Alt+Shift+O
Select Pin Light Blending Mode=Alt+Shift+Z
Select Saturation Blending Mode=Alt+Shift+T
Select Screen Blending Mode=Alt+Shift+S
Select Soft Light Blending Mode=Alt+Shift+F
select_unlocked_layers=none
select_visible_layers=none
Select Vivid Light Blending Mode=Alt+Shift+V
separate=none
set_no_brush_smoothing=none
set_simple_brush_smoothing=none
set_stabilizer_brush_smoothing=none
settings_active_author=none
set_weighted_brush_smoothing=none
shearimage=none
shearlayer=none
shift_brush_color_clockwise=none
shift_brush_color_counter_clockwise=none
show_brush_editor=F5
show_brush_presets=F6
show_color_history=H
show_color_selector=Shift+I
show_common_colors=U
show-global-selection-mask=none
pin_to_timeline=none
show_minimal_shade_selector=Shift+N
show_mypaint_shade_selector=none
show_snap_options_popup=Shift+S
showStatusBar=none
show_tool_options=\\
shrinkselection=none
shrink_to_fit=none
smoothselection=none
soft_hyphen=none
split_alpha_into_mask=none
split_alpha_save_merged=none
split_alpha_write=none
split_sections=none
stroke_shapes=none
switch_application_language=none
tablet_debugger=Ctrl+Shift+T
TextTool=none
toggle_assistant=Ctrl+Shift+L
toggle_display_selection=Ctrl+H
toggle_fg_bg=X
toggle_onion_skin=none
toggle_playback=none
toggle-selection-overlay-mode=none
trim_to_image=none
undo_polygon_selection=Shift+Z
VectorTool=none
view_grid=Ctrl+Shift+'
view_lock_guides=none
view_newwindow=none
view_ruler=none
view_show_canvas_only=Tab
view_show_guides=none
view_snap_bounding_box=none
view_snap_extension=none
view_snap_image_bounds=none
view_snap_image_center=none
view_snap_intersection=none
view_snap_node=none
view_snap_orthogonal=none
view_snap_to_grid=Ctrl+Shift+;
view_snap_to_guides=none
view_toggle_assistant_previews=none
view_toggledockers=none
view_toggledockertitlebars=none
view_toggle_painting_assistants=none
view_zoom_in=Ctrl++
view_zoom_out=Ctrl+-
vmirror_action=none
windows_cascade=none
windows_next=Ctrl+Tab
windows_previous=none
windows_tile=none
workspaces=none
zoom_to_100pct=Ctrl+0
diff --git a/krita/krita.qrc b/krita/krita.qrc
index 4e55340c89..34975a8d2d 100644
--- a/krita/krita.qrc
+++ b/krita/krita.qrc
@@ -1,75 +1,75 @@
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource prefix="/kconfig">
<file alias="kritarc">data/kritarc</file>
</qresource>
<qresource prefix="/kxmlgui5">
- <file alias="krita4.xmlgui">krita4.xmlgui</file>
+ <file alias="krita5.xmlgui">krita5.xmlgui</file>
</qresource>
<qresource>
<file>pics/broken-preset.png</file>
<file>pics/dark_layer-locked.png</file>
<file>pics/dark_layer-unlocked.png</file>
<file>pics/dark_novisible.svg</file>
<file>pics/dark_passthrough-disabled.png</file>
<file>pics/dark_passthrough-enabled.png</file>
<file>pics/dark_selection-mode_ants.png</file>
<file>pics/dark_selection-mode_invisible.png</file>
<file>pics/dark_selection-mode_mask.png</file>
<file>pics/dark_transparency-disabled.png</file>
<file>pics/dark_transparency-enabled.png</file>
<file>pics/dark_trim-to-image.png</file>
<file>pics/dark_visible.svg</file>
<file>pics/delete.png</file>
<file>pics/dirty-preset.svg</file>
<file>pics/height.png</file>
<file>pics/height_icon.png</file>
<file>pics/hi16-add_dialog.png</file>
<file>pics/hi16-palette_library.png</file>
<file>pics/icon-kritasketch-256.png</file>
<file>pics/layer-style-disabled.png</file>
<file>pics/layer-style-enabled.png</file>
<file>pics/light_layer-locked.png</file>
<file>pics/light_layer-unlocked.png</file>
<file>pics/light_novisible.svg</file>
<file>pics/light_passthrough-disabled.png</file>
<file>pics/light_passthrough-enabled.png</file>
<file>pics/light_selection-mode_ants.png</file>
<file>pics/light_selection-mode_invisible.png</file>
<file>pics/light_selection-mode_mask.png</file>
<file>pics/light_transparency-disabled.png</file>
<file>pics/light_transparency-enabled.png</file>
<file>pics/light_trim-to-image.png</file>
<file>pics/light_visible.svg</file>
<file>pics/linked.png</file>
<file>pics/local_selection_active.png</file>
<file>pics/local_selection_inactive.png</file>
<file>pics/mirrorAxis-HorizontalMove.png</file>
<file>pics/mirrorAxis-VerticalMove.png</file>
<file>pics/novisible.svg</file>
<file>pics/offset_horizontal.png</file>
<file>pics/offset_vertical.png</file>
<file>pics/ratio_icon.png</file>
<file>pics/select_pixel.png</file>
<file>pics/select_shape.png</file>
<file>pics/selection_add.png</file>
<file>pics/selection_symmetric_difference.png</file>
<file>pics/selection_intersect.png</file>
<file>pics/selection_replace.png</file>
<file>pics/selection_subtract.png</file>
<file>pics/shade.png</file>
<file>pics/shear_horizontal.png</file>
<file>pics/shear_vertical.png</file>
<file>pics/sidebaricon.png</file>
<file>pics/tablet.png</file>
<file>pics/tool_screenshot.png</file>
<file>pics/transparency-locked.png</file>
<file>pics/transparency-unlocked.png</file>
<file>pics/unlinked.png</file>
<file>pics/visible.svg</file>
<file>pics/width.png</file>
<file>pics/width_icon.png</file>
<file>pics/workspace-chooser.png</file>
</qresource>
</RCC>
diff --git a/krita/krita4.xmlgui b/krita/krita5.xmlgui
similarity index 99%
rename from krita/krita4.xmlgui
rename to krita/krita5.xmlgui
index 41673bc53b..e325777399 100644
--- a/krita/krita4.xmlgui
+++ b/krita/krita5.xmlgui
@@ -1,412 +1,413 @@
<?xml version="1.1"?>
<kpartgui xmlns="http://www.kde.org/standards/kxmlgui/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
name="Krita"
version="436"
xsi:schemaLocation="http://www.kde.org/standards/kxmlgui/1.0 http://www.kde.org/standards/kxmlgui/1.0/kxmlgui.xsd">
<MenuBar>
<Menu name="file">
<text>&amp;File</text>
<Action name="file_new"/>
<Action name="file_open"/>
<Action name="file_open_recent"/>
<Separator/>
<Action name="file_save"/>
<Action name="file_save_as"/>
<Action name="file_reload_file"/>
<Separator/>
<Action name="file_sessions"/>
<Separator/>
<Action name="file_import_file"/>
<Action name="file_export_file"/>
<Separator/>
<Action name="file_export_pdf"/>
<Separator/>
<Action name="file_import_animation"/>
<Action name="render_animation"/>
<Separator/>
<Action name="save_incremental_version"/>
<Action name="save_incremental_backup"/>
<Separator/>
<Action name="create_template"/>
<Action name="create_copy"/>
<!--Separator/>
<Action name="file_print"/>
<Action name="file_print_preview"/-->
<Separator/>
<Action name="file_documentinfo"/>
<Separator/>
<Action name="file_close"/>
<Action name="file_close_all"/>
<Action name="file_quit"/>
</Menu>
<Menu name="edit">
<text>&amp;Edit</text>
<Action name="edit_undo"/>
<Action name="edit_redo"/>
<Separator/>
<Action name="edit_cut"/>
<Action name="edit_copy"/>
<Action name="cut_sharp"/>
<Action name="copy_sharp"/>
<Action name="copy_merged"/>
<Action name="edit_paste"/>
<Action name="paste_at"/>
<Action name="paste_new"/>
<Action name="paste_as_reference"/>
<Action name="clear"/>
<Action name="fill_selection_foreground_color"/>
<Action name="fill_selection_background_color"/>
<Action name="fill_selection_pattern"/>
<Menu name="fill_special">
<text>Fill Special</text>
<Action name="fill_selection_foreground_color_opacity"/>
<Action name="fill_selection_background_color_opacity"/>
<Action name="fill_selection_pattern_opacity"/>
</Menu>
<Action name="stroke_shapes"/>
<Action name="stroke_selection"/>
<Action name="delete"/>
<Separator/>
<Action name="revert"/>
</Menu>
<Menu name="view">
<text>&amp;View</text>
<Action name="view_show_canvas_only"/>
<Action name="fullscreen"/>
<Action name="view_detached_canvas"/>
<Action name="wrap_around_mode"/>
<Action name="level_of_detail_mode"/>
<Action name="softProof"/>
<Action name="gamutCheck"/>
<Separator/>
<Menu name="Canvas">
<text>&amp;Canvas</text>
<Action name="mirror_canvas"/>
<Separator/>
<Action name="zoom_to_100pct" />
<Action name="rotate_canvas_right" />
<Action name="rotate_canvas_left" />
<Action name="reset_canvas_rotation" />
<!-- TODO: Something is not right with the way zoom actions are hooked up. These are in the KoZoomController.
It seems they are not being properly placed in the view manager since the MDI changes were implemented
-->
<Action name="view_zoom_in"/>
<Action name="view_zoom_out"/>
</Menu>
<!-- TODO: None of these actions are showing. There names must have been changed to something with the MDI changes?...
<Action name="actual_pixels"/>
<Action name="actual_size"/>
<Action name="fit_to_canvas"/>
-->
<Separator/>
<Action name="view_ruler"/>
<Action name="rulers_track_mouse"/>
<Action name="view_show_guides"/>
<Action name="view_lock_guides"/>
<Action name="showStatusBar" />
<Separator/>
<Action name="view_grid"/>
<Action name="view_pixel_grid"/>
<Separator/>
<Menu name="SnapTo">
<text>&amp;Snap To</text>
<Action name="view_snap_to_guides"/>
<Action name="view_snap_to_grid"/>
<Action name="view_snap_to_pixel"/>
<Action name="view_snap_orthogonal" />
<Action name="view_snap_node" />
<Action name="view_snap_extension" />
<Action name="view_snap_intersection" />
<Action name="view_snap_bounding_box" />
<Action name="view_snap_image_bounds" />
<Action name="view_snap_image_center" />
</Menu>
<Separator/>
<Action name="view_toggle_painting_assistants"/>
<Action name="view_toggle_assistant_previews"/>
<Action name="view_toggle_reference_images"/>
<Separator/>
<Action name="view_palette_action_menu"/>
<Separator/>
<Action name="refresh_canvas"/>
</Menu>
<Menu name="Image">
<text>&amp;Image</text>
<Action name="image_properties"/>
<Action name="image_color"/>
<Action name="imagecolorspaceconversion"/>
<Action name="duplicate_image"/>
<Separator/>
<Action name="trim_to_image"/>
<Action name="resizeimagetolayer"/>
<Action name="resizeimagetoselection"/>
<Separator/>
<Menu name="Rotate">
<text>&amp;Rotate</text>
<Action name="rotateimage"/>
<Separator/>
<Action name="rotateImageCW90"/>
<Action name="rotateImageCCW90"/>
<Action name="rotateImage180"/>
</Menu>
<Action name="shearimage"/>
<Separator/>
<Action name="mirrorImageHorizontal"/>
<Action name="mirrorImageVertical"/>
<Separator/>
<Action name="imagesize"/>
<Action name="offsetimage"/>
<Action name="imageresolution"/>
<Action name="canvassize"/>
<Separator/>
<Action name="imagesplit"/>
<Action name="waveletdecompose"/>
<Action name="separate"/>
</Menu>
<Menu name="Layer">
<text>&amp;Layer</text>
<Action name="cut_layer_clipboard"/>
<Action name="copy_layer_clipboard"/>
<Action name="paste_layer_from_clipboard"/>
<Separator/>
<Menu name="LayerNew">
- <text>New</text>
+ <text context="New layer">&amp;New</text>
<Action name="add_new_paint_layer"/>
<Action name="add_new_clone_layer"/>
<Action name="new_from_visible"/>
<Action name="duplicatelayer"/>
<Separator/>
<Action name="cut_selection_to_new_layer"/>
<Action name="copy_selection_to_new_layer"/>
</Menu>
<Menu name="LayerImportExport">
<text>&amp;Import/Export</text>
<Action name="save_node_as_image"/>
<Action name="save_vector_node_to_svg"/>
<Action name="save_groups_as_images"/>
<Separator/>
<Action name="import_layer_from_file"/>
<Menu name="LayerImportAs">
<text>Import</text>
<Action name="import_layer_as_paint_layer"/>
<Action name="import_layer_as_transparency_mask"/>
<Action name="import_layer_as_filter_mask"/>
<Action name="import_layer_as_selection_mask"/>
</Menu>
</Menu>
<Menu name="LayerConvert">
<text>&amp;Convert</text>
<Action name="convert_to_paint_layer"/>
<Action name="convert_to_transparency_mask"/>
<Action name="convert_to_filter_mask"/>
<Action name="convert_to_selection_mask"/>
<Action name="convert_to_file_layer"/>
<Action name="convert_group_to_animated"/>
<Action name="layercolorspaceconversion"/>
</Menu>
<Separator/>
<Menu name="LayerSelect">
<text>&amp;Select</text>
<Action name="select_all_layers"/>
<Action name="select_visible_layers"/>
<Action name="select_invisible_layers"/>
<Action name="select_locked_layers"/>
<Action name="select_unlocked_layers"/>
</Menu>
<Menu name="LayerGroup">
<text>&amp;Group</text>
<Action name="create_quick_group"/>
<Action name="create_quick_clipping_group"/>
<Action name="quick_ungroup"/>
</Menu>
<Menu name="LayerTransform">
<text>&amp;Transform</text>
<Action name="mirrorNodeX"/>
<Action name="mirrorNodeY"/>
<Action name="layersize"/>
<Menu name="Rotate">
<text>&amp;Rotate</text>
<Action name="rotatelayer"/>
<Separator/>
<Action name="rotateLayerCW90"/>
<Action name="rotateLayerCCW90"/>
<Action name="rotateLayer180"/>
</Menu>
<Action name="shearlayer"/>
<Action name="offsetlayer"/>
</Menu>
<Menu name="LayerTransformAll">
<text>Transform &amp;All Layers</text>
<Action name="mirrorAllNodesX"/>
<Action name="mirrorAllNodesY"/>
<Action name="scaleAllLayers"/>
<Menu name="Rotate">
<text>&amp;Rotate</text>
<Action name="rotateAllLayers"/>
<Separator/>
<Action name="rotateAllLayersCW90"/>
<Action name="rotateAllLayersCCW90"/>
<Action name="rotateAllLayers180"/>
</Menu>
<Action name="shearAllLayers"/>
</Menu>
<Menu name="LayerSplitAlpha">
<text>S&amp;plit</text>
<Menu name="LayerSplitAlpha">
<text>S&amp;plit Alpha</text>
<Action name="split_alpha_into_mask"/>
<Action name="split_alpha_write"/>
<Action name="split_alpha_save_merged"/>
</Menu>
<Action name="layersplit"/>
<Action name="clones_array"/>
</Menu>
<Separator/>
<Action name="EditLayerMetaData"/>
<Action name="histogram"/>
<Separator/>
<Action name="merge_layer"/>
<Action name="flatten_layer"/>
<Action name="rasterize_layer"/>
<Action name="merge_all_shape_layers"/>
<Action name="flatten_image"/>
<Action name="merge_selected_layers"/>
<Separator/>
<Action name="layer_style"/>
</Menu>
<Menu name="Select">
<text>&amp;Select</text>
<Action name="select_all"/>
<Action name="deselect"/>
<Action name="reselect"/>
<Action name="invert_selection"/>
<Separator/>
<Action name="edit_selection"/>
<Action name="convert_to_vector_selection"/>
<Action name="convert_to_raster_selection"/>
<Action name="convert_shapes_to_vector_selection"/>
<Action name="convert_selection_to_shape"/>
<Separator/>
<Action name="feather"/>
<Action name="similar"/>
<Separator/>
<Action name="toggle_display_selection"/>
<Action name="show-global-selection-mask"/>
<Action name="selectionscale"/>
<Separator/>
<Action name="colorrange"/>
<Menu name="selectopaquemenu">
<text>Select &amp;Opaque</text>
<Action name="selectopaque"/>
<Separator/>
<Action name="selectopaque_add"/>
<Action name="selectopaque_subtract"/>
<Action name="selectopaque_intersect"/>
</Menu>
<Separator/>
<Action name="featherselection"/>
<Action name="growselection"/>
<Action name="shrinkselection"/>
<Action name="borderselection"/>
<Action name="smoothselection"/>
</Menu>
<Menu name="Filter">
<text>Filte&amp;r</text>
<Action name="filter_apply_again"/>
<Action name="filter_gallery"/>
<Separator/>
<Action name="adjust_filters"/>
<Action name="artistic_filters"/>
<Action name="blur_filters"/>
<Action name="color_filters"/>
<Action name="decor_filters"/>
<Action name="edge_filters"/>
<Action name="emboss_filters"/>
<Action name="enhance_filters"/>
<Action name="map_filters"/>
<Action name="nonphotorealistic_filters"/>
<Action name="other_filters"/>
<Separator/>
<Action name="QMic"/>
<Action name="QMicAgain"/>
</Menu>
<Menu name="tools">
<text>&amp;Tools</text>
<Menu name="scripts"><text>Scripts</text></Menu>
</Menu>
<Menu name="settings">
<text>Setti&amp;ngs</text>
<Action name="options_configure"/>
<Action name="manage_bundles"/>
<Action name="dbexplorer"/>
<Separator/>
<Action name="options_configure_toolbars"/>
<Merge name="StandardToolBarMenuHandler" />
<Separator/>
<Action name="view_toggledockers"/>
<Action name="settings_dockers_menu"/>
<Separator/>
<Action name="theme_menu"/>
+ <Action name="style_menu"/>
<Separator/>
<!-- `Configure Shortcuts` was moved into main configuration menu -->
<!-- <Action name="options_configure_keybinding"/> -->
<Separator/>
<Action name="switch_application_language"/>
<Action name="settings_active_author"/>
<Separator/>
<Action name="reset_configurations"/>
<Separator/>
</Menu>
<Action name="window"/>
<Separator/>
<Menu name="help">
<text>&amp;Help</text>
<Action name="help_contents"/>
<Action name="help_whats_this"/>
<Separator/>
<MergeLocal/>
<Action name="help_show_tip"/>
<Separator/>
<Action name="help_report_bug"/>
<Action name="buginfo"/>
<Action name="sysinfo"/>
<Separator/>
<Action name="help_about_app"/>
<Action name="help_about_kde"/>
</Menu>
</MenuBar>
<ToolBar name="mainToolBar" fullWidth="false" noMerge="1">
<Text>File</Text>
<Action name="file_new"/>
<Action name="file_open"/>
<Action name="file_save"/>
<Separator/>
<Action name="edit_undo"/>
<Action name="edit_redo"/>
</ToolBar>
<ToolBar name="BrushesAndStuff" position="top">
<Text>Brushes and Stuff</Text>
<Action name="gradients"/>
<Action name="patterns"/>
<Separator/>
<Action name="dual"/>
<Separator/>
<Action name="paintops"/>
<Action name="paintop_options"/>
<Action name="composite_actions"/>
<Action name="brushslider1"/>
<Action name="brushslider2"/>
<Separator/>
<Action name="mirror_actions"/>
<Action name="expanding_spacer_1"/>
<Action name="select_layout"/>
<Action name="workspaces"/>
</ToolBar>
</kpartgui>
diff --git a/krita/kritamenu.action b/krita/kritamenu.action
index 9985e3ab16..af463440b6 100644
--- a/krita/kritamenu.action
+++ b/krita/kritamenu.action
@@ -1,1851 +1,1823 @@
<?xml version="1.0" encoding="UTF-8"?>
<ActionCollection version="2" name="Menu">
<Actions category="File">
<text>File</text>
<Action name="file_new">
<icon>document-new</icon>
- <text>&amp;New</text>
+ <text context="New document">&amp;New...</text>
<whatsThis></whatsThis>
<toolTip>Create new document</toolTip>
<iconText>New</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+N</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="file_open">
<icon>document-open</icon>
<text>&amp;Open...</text>
<whatsThis></whatsThis>
<toolTip>Open an existing document</toolTip>
<iconText>Open</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+O</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="file_open_recent">
<icon>document-open-recent</icon>
<text>Open &amp;Recent</text>
<whatsThis></whatsThis>
<toolTip>Open a document which was recently opened</toolTip>
<iconText>Open Recent</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="file_save">
<icon>document-save</icon>
<text>&amp;Save</text>
<whatsThis></whatsThis>
<toolTip>Save</toolTip>
<iconText>Save</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+S</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="file_save_as">
<icon>document-save-as</icon>
<text>Save &amp;As...</text>
<whatsThis></whatsThis>
<toolTip>Save document under a new name</toolTip>
<iconText>Save As</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+Shift+S</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
-<!-- commented out in the code right now
- <Action name="file_reload_file">
- <icon></icon>
- <text>Reload</text>
- <whatsThis></whatsThis>
- <toolTip>Reload</toolTip>
- <iconText>Reload</iconText>
- <activationFlags>1</activationFlags>
- <activationConditions>0</activationConditions>
- <shortcut></shortcut>
- <isCheckable>false</isCheckable>
- <statusTip></statusTip>
- </Action>
--->
<Action name="file_sessions">
<icon></icon>
<text>Sessions...</text>
<whatsThis></whatsThis>
<toolTip>Open session manager</toolTip>
<iconText>Sessions</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="file_import_file">
<icon>document-import</icon>
<text>Open ex&amp;isting Document as Untitled Document...</text>
<whatsThis></whatsThis>
<toolTip>Open existing Document as Untitled Document</toolTip>
<iconText>Open existing Document as Untitled Document</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="file_export_file">
<icon>document-export</icon>
<text>E&amp;xport...</text>
<whatsThis></whatsThis>
<toolTip>Export</toolTip>
<iconText>Export</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="file_import_animation">
<icon></icon>
<text>Import animation frames...</text>
<whatsThis></whatsThis>
<toolTip>Import animation frames</toolTip>
<iconText>Import animation frames</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="render_animation">
<icon></icon>
<text>&amp;Render Animation...</text>
<whatsThis></whatsThis>
<toolTip>Render Animation to GIF, Image Sequence or Video</toolTip>
<iconText>Render Animation</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="render_animation_again">
<icon></icon>
<text>&amp;Render Animation Again</text>
<whatsThis></whatsThis>
<toolTip>Render Animation Again</toolTip>
<iconText>Render Animation</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="save_incremental_version">
<icon></icon>
<text>Save Incremental &amp;Version</text>
<whatsThis></whatsThis>
<toolTip>Save Incremental Version</toolTip>
<iconText>Save Incremental Version</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+Alt+S</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="save_incremental_backup">
<icon></icon>
<text>Save Incremental &amp;Backup</text>
<whatsThis></whatsThis>
<toolTip>Save Incremental Backup</toolTip>
<iconText>Save Incremental Backup</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>F4</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="create_template">
<icon></icon>
<text>&amp;Create Template From Image...</text>
<whatsThis></whatsThis>
<toolTip>Create Template From Image</toolTip>
<iconText>Create Template From Image</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="create_copy">
<icon></icon>
<text>Create Copy &amp;From Current Image</text>
<whatsThis></whatsThis>
<toolTip>Create Copy From Current Image</toolTip>
<iconText>Create Copy From Current Image</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
- <Action name="file_print">
- <icon>document-print</icon>
- <text>&amp;Print...</text>
- <whatsThis></whatsThis>
- <toolTip>Print document</toolTip>
- <iconText>Print</iconText>
- <activationFlags>1</activationFlags>
- <activationConditions>0</activationConditions>
- <shortcut>Ctrl+P</shortcut>
- <isCheckable>false</isCheckable>
- <statusTip></statusTip>
- </Action>
- <Action name="file_print_preview">
- <icon>document-print-preview</icon>
- <text>Print Previe&amp;w</text>
- <whatsThis></whatsThis>
- <toolTip>Show a print preview of document</toolTip>
- <iconText>Print Preview</iconText>
- <activationFlags>1</activationFlags>
- <activationConditions>0</activationConditions>
- <shortcut></shortcut>
- <isCheckable>false</isCheckable>
- <statusTip></statusTip>
- </Action>
<Action name="file_documentinfo">
<icon>configure</icon>
<text>&amp;Document Information</text>
<whatsThis></whatsThis>
<toolTip>Document Information</toolTip>
<iconText>Document Information</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="file_close_all">
<icon></icon>
<text>&amp;Close All</text>
<whatsThis></whatsThis>
<toolTip>Close All</toolTip>
<iconText>Close All</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+Shift+W</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="file_close">
<icon></icon>
<text>C&amp;lose</text>
<whatsThis></whatsThis>
<toolTip>Close</toolTip>
<iconText>Close</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+W</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="file_quit">
<icon></icon>
<text>&amp;Quit</text>
<whatsThis></whatsThis>
<toolTip>Quit application</toolTip>
<iconText>Quit</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+Q</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
</Actions>
<Actions category="Edit">
<text>Edit</text>
<Action name="edit_undo">
<icon>edit-undo</icon>
<text>Undo</text>
<whatsThis></whatsThis>
<toolTip>Undo last action</toolTip>
<iconText>Undo</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+Z</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="edit_redo">
<icon>edit-redo</icon>
<text>Redo</text>
<whatsThis></whatsThis>
<toolTip>Redo last undone action</toolTip>
<iconText>Redo</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+Shift+Z</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="edit_cut">
<icon>edit-cut</icon>
<text>Cu&amp;t</text>
<whatsThis></whatsThis>
<toolTip>Cut selection to clipboard</toolTip>
<iconText>Cut</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+X</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="edit_copy">
<icon>edit-copy</icon>
<text>&amp;Copy</text>
<whatsThis></whatsThis>
<toolTip>Copy selection to clipboard</toolTip>
<iconText>Copy</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+C</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="copy_sharp">
<icon></icon>
<text>C&amp;opy (sharp)</text>
<whatsThis></whatsThis>
<toolTip>Copy (sharp)</toolTip>
<iconText>Copy (sharp)</iconText>
<activationFlags>100000000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="cut_sharp">
<icon></icon>
<text>Cut (&amp;sharp)</text>
<whatsThis></whatsThis>
<toolTip>Cut (sharp)</toolTip>
<iconText>Cut (sharp)</iconText>
<activationFlags>100000000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="copy_merged">
<icon></icon>
<text>Copy &amp;merged</text>
<whatsThis></whatsThis>
<toolTip>Copy merged</toolTip>
<iconText>Copy merged</iconText>
<activationFlags>100000000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+Shift+C</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="edit_paste">
<icon>edit-paste</icon>
<text>&amp;Paste</text>
<whatsThis></whatsThis>
<toolTip>Paste clipboard content</toolTip>
<iconText>Paste</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+V</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="paste_at">
<icon></icon>
<text>Paste at Cursor</text>
<whatsThis></whatsThis>
<toolTip>Paste at cursor</toolTip>
<iconText>Paste at cursor</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+Alt+V</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="paste_new">
<icon></icon>
<text>Paste into &amp;New Image</text>
<whatsThis></whatsThis>
<toolTip>Paste into New Image</toolTip>
<iconText>Paste into New Image</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+Shift+N</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="paste_as_reference">
<icon></icon>
<text>Paste as R&amp;eference Image</text>
<whatsThis></whatsThis>
<toolTip>Paste as Reference Image</toolTip>
<iconText>Paste as Reference Image</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+Shift+R</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="clear">
<icon>edit-clear</icon>
<text>C&amp;lear</text>
<whatsThis></whatsThis>
<toolTip>Clear</toolTip>
<iconText>Clear</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Del</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="fill_selection_foreground_color">
<icon></icon>
<text>&amp;Fill with Foreground Color</text>
<whatsThis></whatsThis>
<toolTip>Fill with Foreground Color</toolTip>
<iconText>Fill with Foreground Color</iconText>
<activationFlags>10000</activationFlags>
<activationConditions>1</activationConditions>
<shortcut>Shift+Backspace</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="fill_selection_background_color">
<icon></icon>
<text>Fill &amp;with Background Color</text>
<whatsThis></whatsThis>
<toolTip>Fill with Background Color</toolTip>
<iconText>Fill with Background Color</iconText>
<activationFlags>10000</activationFlags>
<activationConditions>1</activationConditions>
<shortcut>Backspace</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="fill_selection_pattern">
<icon></icon>
<text>F&amp;ill with Pattern</text>
<whatsThis></whatsThis>
<toolTip>Fill with Pattern</toolTip>
<iconText>Fill with Pattern</iconText>
<activationFlags>10000</activationFlags>
<activationConditions>1</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Actions category="EditFill">
<text>Fill Special</text>
<Action name="fill_selection_foreground_color_opacity">
<icon></icon>
<text>Fill with Foreground Color (Opacity)</text>
<whatsThis></whatsThis>
<toolTip>Fill with Foreground Color (Opacity)</toolTip>
<iconText>Fill with Foreground Color (Opacity)</iconText>
<activationFlags>10000</activationFlags>
<activationConditions>1</activationConditions>
<shortcut>Ctrl+Shift+Backspace</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="fill_selection_background_color_opacity">
<icon></icon>
<text>Fill with Background Color (Opacity)</text>
<whatsThis></whatsThis>
<toolTip>Fill with Background Color (Opacity)</toolTip>
<iconText>Fill with Background Color (Opacity)</iconText>
<activationFlags>10000</activationFlags>
<activationConditions>1</activationConditions>
<shortcut>Ctrl+Backspace</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="fill_selection_pattern_opacity">
<icon></icon>
<text>Fill with Pattern (Opacity)</text>
<whatsThis></whatsThis>
<toolTip>Fill with Pattern (Opacity)</toolTip>
<iconText>Fill with Pattern (Opacity)</iconText>
<activationFlags>10000</activationFlags>
<activationConditions>1</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
</Actions>
<Action name="stroke_shapes">
<icon></icon>
<text>Stro&amp;ke selected shapes</text>
<whatsThis></whatsThis>
<toolTip>Stroke selected shapes</toolTip>
<iconText>Stroke selected shapes</iconText>
<activationFlags>1000000000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="stroke_selection">
<icon></icon>
<text>Stroke Selec&amp;tion...</text>
<whatsThis></whatsThis>
<toolTip>Stroke selection</toolTip>
<iconText>Stroke selection</iconText>
<activationFlags>10000000000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="delete_keyframe">
<icon></icon>
<text>Delete keyframe</text>
<whatsThis></whatsThis>
<toolTip>Delete keyframe</toolTip>
<iconText>Delete keyframe</iconText>
<activationFlags>100000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
</Actions>
<Actions category="Window">
<text>Window</text>
<Action name="view_newwindow">
<icon>window-new</icon>
<text>&amp;New Window</text>
<whatsThis></whatsThis>
<toolTip>New Window</toolTip>
<iconText>New Window</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="windows_next">
<icon></icon>
<text>N&amp;ext</text>
<whatsThis></whatsThis>
<toolTip>Next</toolTip>
<iconText>Next</iconText>
<activationFlags>10</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="windows_previous">
<icon></icon>
<text>Previous</text>
<whatsThis></whatsThis>
<toolTip>Previous</toolTip>
<iconText>Previous</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
</Actions>
<Actions category="View">
<text>View</text>
<Action name="view_show_canvas_only">
<icon>document-new</icon>
<text>&amp;Show Canvas Only</text>
<whatsThis></whatsThis>
<toolTip>Show just the canvas or the whole window</toolTip>
<iconText>Show Canvas Only</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Tab</shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="fullscreen">
<icon>view-fullscreen</icon>
<text>F&amp;ull Screen Mode</text>
<whatsThis></whatsThis>
<toolTip>Display the window in full screen</toolTip>
<iconText>Full Screen Mode</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+Shift+F</shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_detached_canvas">
<icon></icon>
<text>Detach canvas</text>
<whatsThis></whatsThis>
<toolTip>Show the canvas on a separate window</toolTip>
<iconText>Detach canvas</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="wrap_around_mode">
<icon></icon>
<text>&amp;Wrap Around Mode</text>
<whatsThis></whatsThis>
<toolTip>Wrap Around Mode</toolTip>
<iconText>Wrap Around Mode</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="level_of_detail_mode">
<icon></icon>
<text>&amp;Instant Preview Mode</text>
<whatsThis></whatsThis>
<toolTip>Instant Preview Mode</toolTip>
<iconText>Instant Preview Mode</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Shift+L</shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="softProof">
<icon></icon>
<text>Soft Proofing</text>
<whatsThis></whatsThis>
<toolTip>Turns on Soft Proofing</toolTip>
<iconText>Turns on Soft Proofing</iconText>
<shortcut>Ctrl+Y</shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="gamutCheck">
<icon></icon>
<text>Out of Gamut Warnings</text>
<whatsThis></whatsThis>
<toolTip>Turns on warnings for colors out of proofed gamut, needs soft proofing to be turned on.</toolTip>
<iconText>Turns on warnings for colors out of proofed gamut, needs soft proofing to be turned on.</iconText>
<shortcut>Ctrl+Shift+Y</shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="mirror_canvas">
<icon>mirror-view</icon>
<text>Mirror View</text>
<whatsThis></whatsThis>
<toolTip>Mirror View</toolTip>
<iconText>Mirror View</iconText>
<shortcut>M</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="zoom_to_100pct">
<icon>zoom-original</icon>
<text>&amp;Reset zoom</text>
<whatsThis></whatsThis>
<toolTip>Reset zoom</toolTip>
<iconText>Reset zoom</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+0</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_zoom_in">
<icon>zoom-in</icon>
<text>Zoom &amp;In</text>
<whatsThis></whatsThis>
<toolTip>Zoom In</toolTip>
<iconText></iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl++</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_zoom_out">
<icon>zoom-out</icon>
<text>Zoom &amp;Out</text>
<whatsThis></whatsThis>
<toolTip>Zoom Out</toolTip>
<iconText></iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+-</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="rotate_canvas_right">
<icon>rotate-canvas-right</icon>
<text>Rotate &amp;Canvas Right</text>
<whatsThis></whatsThis>
<toolTip>Rotate Canvas Right</toolTip>
<iconText>Rotate Canvas Right</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+]</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="rotate_canvas_left">
<icon>rotate-canvas-left</icon>
<text>Rotate Canvas &amp;Left</text>
<whatsThis></whatsThis>
<toolTip>Rotate Canvas Left</toolTip>
<iconText>Rotate Canvas Left</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+[</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="reset_canvas_rotation">
<icon>rotation-reset</icon>
<text>Reset Canvas Rotation</text>
<whatsThis></whatsThis>
<toolTip>Reset Canvas Rotation</toolTip>
<iconText>Reset Canvas Rotation</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_ruler">
<icon></icon>
<text>Show &amp;Rulers</text>
<whatsThis>The rulers show the horizontal and vertical positions of the mouse on the image and can be used to position your mouse at the right place on the canvas. &lt;p>Uncheck this to hide the rulers.&lt;/p></whatsThis>
<toolTip>Show Rulers</toolTip>
<iconText>Show Rulers</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="rulers_track_mouse">
<icon></icon>
<text>Rulers Track Pointer</text>
<whatsThis>The rulers will track current mouse position and show it on screen. It can cause suptle performance slowdown</whatsThis>
<toolTip>Rulers Track Pointer</toolTip>
<iconText>Rulers Track Pointer</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_show_guides">
<icon></icon>
<text>Show Guides</text>
<whatsThis></whatsThis>
<toolTip>Show or hide guides</toolTip>
<iconText>Show Guides</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_lock_guides">
<icon></icon>
<text>Lock Guides</text>
<whatsThis></whatsThis>
<toolTip>Lock or unlock guides</toolTip>
<iconText>Lock Guides</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_snap_to_guides">
<icon></icon>
<text>Snap to Guides</text>
<whatsThis></whatsThis>
<toolTip>Snap cursor to guides position</toolTip>
<iconText>Snap to Guides</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="showStatusBar">
<icon></icon>
<text>Show Status &amp;Bar</text>
<whatsThis></whatsThis>
<toolTip>Show or hide the status bar</toolTip>
<iconText>Show Status Bar</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_pixel_grid">
<icon></icon>
<text>Show Pixel Grid</text>
<whatsThis></whatsThis>
<toolTip>Show Pixel Grid</toolTip>
<iconText>Show Pixel Grid</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>1000</activationConditions>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_grid">
<icon>view-grid</icon>
<text>Show &amp;Grid</text>
<whatsThis></whatsThis>
<toolTip>Show Grid</toolTip>
<iconText>Show Grid</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+Shift+'</shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_snap_to_grid">
<icon></icon>
<text>Snap To Grid</text>
<whatsThis></whatsThis>
<toolTip>Snap To Grid</toolTip>
<iconText>Snap To Grid</iconText>
<activationFlags>1000</activationFlags>
<shortcut>Ctrl+Shift+;</shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="show_snap_options_popup">
<icon></icon>
<text>Show Snap Options Popup</text>
<whatsThis></whatsThis>
<toolTip>Show Snap Options Popup</toolTip>
<iconText>Show Snap Options Popup</iconText>
<activationFlags>1000</activationFlags>
<shortcut>Shift+s</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_snap_orthogonal">
<icon></icon>
<text>Snap Orthogonal</text>
<whatsThis></whatsThis>
<toolTip>Snap Orthogonal</toolTip>
<iconText>Snap Orthogonal</iconText>
<activationFlags>1000</activationFlags>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_snap_node">
<icon></icon>
<text>Snap Node</text>
<whatsThis></whatsThis>
<toolTip>Snap Node</toolTip>
<iconText>Snap Node</iconText>
<activationFlags>1000</activationFlags>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_snap_extension">
<icon></icon>
<text>Snap Extension</text>
<whatsThis></whatsThis>
<toolTip>Snap Extension</toolTip>
<iconText>Snap Extension</iconText>
<activationFlags>1000</activationFlags>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_snap_to_pixel">
<icon></icon>
<text>Snap Pixel</text>
<whatsThis></whatsThis>
<toolTip>Snap Pixel</toolTip>
<iconText>Snap Pixel</iconText>
<activationFlags>1000</activationFlags>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_snap_intersection">
<icon></icon>
<text>Snap Intersection</text>
<whatsThis></whatsThis>
<toolTip>Snap Intersection</toolTip>
<iconText>Snap Intersection</iconText>
<activationFlags>1000</activationFlags>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_snap_bounding_box">
<icon></icon>
<text>Snap Bounding Box</text>
<whatsThis></whatsThis>
<toolTip>Snap Bounding Box</toolTip>
<iconText>Snap Bounding Box</iconText>
<activationFlags>1000</activationFlags>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_snap_image_bounds">
<icon></icon>
<text>Snap Image Bounds</text>
<whatsThis></whatsThis>
<toolTip>Snap Image Bounds</toolTip>
<iconText>Snap Image Bounds</iconText>
<activationFlags>1000</activationFlags>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_snap_image_center">
<icon></icon>
<text>Snap Image Center</text>
<whatsThis></whatsThis>
<toolTip>Snap Image Center</toolTip>
<iconText>Snap Image Center</iconText>
<activationFlags>1000</activationFlags>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_toggle_painting_assistants">
<icon></icon>
<text>S&amp;how Painting Assistants</text>
<whatsThis></whatsThis>
<toolTip>Show Painting Assistants</toolTip>
<iconText>Show Painting Assistants</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_toggle_assistant_previews">
<icon></icon>
<text>Show &amp;Assistant Previews</text>
<whatsThis></whatsThis>
<toolTip>Show Assistant Previews</toolTip>
<iconText>Show Assistant Previews</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_toggle_reference_images">
<icon></icon>
<text>S&amp;how Reference Images</text>
<whatsThis></whatsThis>
<toolTip>Show Reference Images</toolTip>
<iconText>Show Reference Images</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
</Actions>
<Actions category="Image">
<text>Image</text>
<Action name="image_properties">
<icon>document-properties</icon>
<text>&amp;Properties...</text>
<whatsThis></whatsThis>
<toolTip>Properties</toolTip>
<iconText>Properties</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="image_color">
<icon>format-stroke-color</icon>
<text>&amp;Image Background Color and Transparency...</text>
<whatsThis></whatsThis>
<toolTip>Change the background color of the image</toolTip>
<iconText>Image Background Color and Transparency</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="imagecolorspaceconversion">
<icon></icon>
<text>&amp;Convert Image Color Space...</text>
<whatsThis></whatsThis>
<toolTip>Convert Image Color Space</toolTip>
<iconText>Convert Image Color Space</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="trim_to_image">
<icon>trim-to-image</icon>
<text>&amp;Trim to Image Size</text>
<whatsThis></whatsThis>
<toolTip>Trim to Image Size</toolTip>
<iconText>Trim to Image Size</iconText>
<activationFlags>1</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="resizeimagetolayer">
<icon></icon>
<text>Trim to Current &amp;Layer</text>
<whatsThis></whatsThis>
<toolTip>Trim to Current Layer</toolTip>
<iconText>Trim to Current Layer</iconText>
<activationFlags>100000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="resizeimagetoselection">
<icon></icon>
<text>Trim to S&amp;election</text>
<whatsThis></whatsThis>
<toolTip>Trim to Selection</toolTip>
<iconText>Trim to Selection</iconText>
<activationFlags>100000000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="rotateimage">
<icon></icon>
<text>&amp;Rotate Image...</text>
<whatsThis></whatsThis>
<toolTip>Rotate Image</toolTip>
<iconText>Rotate Image</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="rotateImageCW90">
<icon>object-rotate-right</icon>
<text>Rotate &amp;Image 90° to the Right</text>
<whatsThis></whatsThis>
<toolTip>Rotate Image 90° to the Right</toolTip>
<iconText>Rotate Image 90° to the Right</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="rotateImageCCW90">
<icon>object-rotate-left</icon>
<text>Rotate Image &amp;90° to the Left</text>
<whatsThis></whatsThis>
<toolTip>Rotate Image 90° to the Left</toolTip>
<iconText>Rotate Image 90° to the Left</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="rotateImage180">
<icon></icon>
<text>Rotate Image &amp;180°</text>
<whatsThis></whatsThis>
<toolTip>Rotate Image 180°</toolTip>
<iconText>Rotate Image 180°</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="shearimage">
<icon></icon>
<text>&amp;Shear Image...</text>
<whatsThis></whatsThis>
<toolTip>Shear Image</toolTip>
<iconText>Shear Image</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="mirrorImageHorizontal">
<icon>symmetry-horizontal</icon>
<text>&amp;Mirror Image Horizontally</text>
<whatsThis></whatsThis>
<toolTip>Mirror Image Horizontally</toolTip>
<iconText>Mirror Image Horizontally</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="mirrorImageVertical">
<icon>symmetry-vertical</icon>
<text>Mirror Image &amp;Vertically</text>
<whatsThis></whatsThis>
<toolTip>Mirror Image Vertically</toolTip>
<iconText>Mirror Image Vertically</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="imagesize">
<icon></icon>
<text>Scale Image To &amp;New Size...</text>
<whatsThis></whatsThis>
<toolTip>Scale Image To New Size</toolTip>
<iconText>Scale Image To New Size</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+Alt+I</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="offsetimage">
<icon></icon>
<text>&amp;Offset Image...</text>
<whatsThis></whatsThis>
<toolTip>Offset Image</toolTip>
<iconText>Offset Image</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="canvassize">
<icon></icon>
<text>R&amp;esize Canvas...</text>
<whatsThis></whatsThis>
<toolTip>Resize Canvas</toolTip>
<iconText>Resize Canvas</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+Alt+C</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="imagesplit">
<icon></icon>
<text>Im&amp;age Split </text>
<whatsThis></whatsThis>
<toolTip>Image Split</toolTip>
<iconText>Image Split</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="separate">
<icon></icon>
<text>Separate Ima&amp;ge...</text>
<whatsThis></whatsThis>
<toolTip>Separate Image</toolTip>
<iconText>Separate Image</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
</Actions>
<Actions category="Select">
<text>Select</text>
<Action name="select_all">
<icon>edit-select-all</icon>
<text>Select &amp;All</text>
<whatsThis></whatsThis>
<toolTip>Select All</toolTip>
<iconText>Select All</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+A</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="deselect">
<icon>edit-select-none</icon>
<text>&amp;Deselect</text>
<whatsThis></whatsThis>
<toolTip>Deselect</toolTip>
<iconText>Deselect</iconText>
<activationFlags>1100000000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+Shift+A</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="reselect">
<icon></icon>
<text>&amp;Reselect</text>
<whatsThis></whatsThis>
<toolTip>Reselect</toolTip>
<iconText>Reselect</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+Shift+D</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="convert_to_vector_selection">
<icon></icon>
<text>&amp;Convert to Vector Selection</text>
<whatsThis></whatsThis>
<toolTip>Convert to Vector Selection</toolTip>
<iconText>Convert to Vector Selection</iconText>
<activationFlags>100000000000000000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="convert_to_raster_selection">
<icon></icon>
<text>&amp;Convert to Raster Selection</text>
<whatsThis></whatsThis>
<toolTip>Convert to Raster Selection</toolTip>
<iconText>Convert to Raster Selection</iconText>
<activationFlags>10000000000000000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="edit_selection">
<icon></icon>
<text>Edit Selection</text>
<whatsThis></whatsThis>
<toolTip>Edit Selection</toolTip>
<iconText>Edit Selection</iconText>
<activationFlags>10000000000</activationFlags>
<activationConditions>100</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="convert_shapes_to_vector_selection">
<icon></icon>
<text>Convert Shapes to &amp;Vector Selection</text>
<whatsThis></whatsThis>
<toolTip>Convert Shapes to Vector Selection</toolTip>
<iconText>Convert Shapes to Vector Selection</iconText>
<activationFlags>1000000000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="featherselection">
<icon></icon>
<text>&amp;Feather Selection...</text>
<whatsThis></whatsThis>
<toolTip>Feather Selection</toolTip>
<iconText>Feather Selection</iconText>
<activationFlags>10000000000</activationFlags>
<activationConditions>100</activationConditions>
<shortcut>Shift+F6</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="toggle_display_selection">
<icon></icon>
<text>Dis&amp;play Selection</text>
<whatsThis></whatsThis>
<toolTip>Display Selection</toolTip>
<iconText>Display Selection</iconText>
<activationFlags>1000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+H</shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="selectionscale">
<icon></icon>
<text>Sca&amp;le...</text>
<whatsThis></whatsThis>
<toolTip>Scale</toolTip>
<iconText>Scale</iconText>
<activationFlags>100000000</activationFlags>
<activationConditions>100</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="colorrange">
<icon></icon>
<text>S&amp;elect from Color Range...</text>
<whatsThis></whatsThis>
<toolTip>Select from Color Range</toolTip>
<iconText>Select from Color Range</iconText>
<activationFlags>10000</activationFlags>
<activationConditions>100</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="selectopaque">
<icon></icon>
<text>Select &amp;Opaque (Replace)</text>
<whatsThis></whatsThis>
<toolTip>Select Opaque</toolTip>
<iconText>Select Opaque</iconText>
<activationFlags>1</activationFlags>
<activationConditions>100</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="selectopaque_add">
<icon></icon>
<text>Select Opaque (&amp;Add)</text>
<whatsThis></whatsThis>
<toolTip>Select Opaque (Add)</toolTip>
<iconText>Select Opaque (Add)</iconText>
<activationFlags>1</activationFlags>
<activationConditions>100</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="selectopaque_subtract">
<icon></icon>
<text>Select Opaque (&amp;Subtract)</text>
<whatsThis></whatsThis>
<toolTip>Select Opaque (Subtract)</toolTip>
<iconText>Select Opaque (Subtract)</iconText>
<activationFlags>1</activationFlags>
<activationConditions>100</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="selectopaque_intersect">
<icon></icon>
<text>Select Opaque (&amp;Intersect)</text>
<whatsThis></whatsThis>
<toolTip>Select Opaque (Intersect)</toolTip>
<iconText>Select Opaque (Intersect)</iconText>
<activationFlags>1</activationFlags>
<activationConditions>100</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="growselection">
<icon></icon>
<text>&amp;Grow Selection...</text>
<whatsThis></whatsThis>
<toolTip>Grow Selection</toolTip>
<iconText>Grow Selection</iconText>
<activationFlags>10000000000</activationFlags>
<activationConditions>100</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="shrinkselection">
<icon></icon>
<text>S&amp;hrink Selection...</text>
<whatsThis></whatsThis>
<toolTip>Shrink Selection</toolTip>
<iconText>Shrink Selection</iconText>
<activationFlags>10000000000</activationFlags>
<activationConditions>100</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="borderselection">
<icon></icon>
<text>&amp;Border Selection...</text>
<whatsThis></whatsThis>
<toolTip>Border Selection</toolTip>
<iconText>Border Selection</iconText>
<activationFlags>10000000000</activationFlags>
<activationConditions>100</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="smoothselection">
<icon></icon>
<text>S&amp;mooth</text>
<whatsThis></whatsThis>
<toolTip>Smooth</toolTip>
<iconText>Smooth</iconText>
<activationFlags>10000000000</activationFlags>
<activationConditions>100</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
</Actions>
<Actions category="Filter">
<text>Filter</text>
<Action name="filter_apply_again">
<icon></icon>
<text>&amp;Apply Filter Again</text>
<whatsThis></whatsThis>
<toolTip>Apply Filter Again</toolTip>
<iconText>Apply Filter Again</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>Ctrl+F</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="adjust_filters">
<icon></icon>
<text>Adjust</text>
<whatsThis></whatsThis>
<toolTip>Adjust</toolTip>
<iconText>Adjust</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="artistic_filters">
<icon></icon>
<text>Artistic</text>
<whatsThis></whatsThis>
<toolTip>Artistic</toolTip>
<iconText>Artistic</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="blur_filters">
<icon></icon>
<text>Blur</text>
<whatsThis></whatsThis>
<toolTip>Blur</toolTip>
<iconText>Blur</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="color_filters">
<icon></icon>
<text>Colors</text>
<whatsThis></whatsThis>
<toolTip>Colors</toolTip>
<iconText>Colors</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="edge_filters">
<icon></icon>
<text>Edge Detection</text>
<whatsThis></whatsThis>
<toolTip>Edge Detection</toolTip>
<iconText>Edge Detection</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="enhance_filters">
<icon></icon>
<text>Enhance</text>
<whatsThis></whatsThis>
<toolTip>Enhance</toolTip>
<iconText>Enhance</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="emboss_filters">
<icon></icon>
<text>Emboss</text>
<whatsThis></whatsThis>
<toolTip>Emboss</toolTip>
<iconText>Emboss</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="map_filters">
<icon></icon>
<text>Map</text>
<whatsThis></whatsThis>
<toolTip>Map</toolTip>
<iconText>Map</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="other_filters">
<icon></icon>
<text>Other</text>
<whatsThis></whatsThis>
<toolTip>Other</toolTip>
<iconText>Other</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="QMic">
<icon>gmic</icon>
<text>Start G'MIC-Qt</text>
<whatsThis></whatsThis>
<toolTip>Start G'Mic-Qt</toolTip>
<iconText>Start G'Mic-Qt</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="QMicAgain">
<icon>gmic</icon>
<text>Re-apply the last G'MIC filter</text>
<whatsThis></whatsThis>
<toolTip>Apply the last G'Mic-Qt action again</toolTip>
<iconText>Apply the last G'Mic-Qt action again</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
</Actions>
<Actions category="Settings">
<text>Settings</text>
<Action name="options_configure">
<icon>configure</icon>
<text>&amp;Configure Krita...</text>
<whatsThis></whatsThis>
<toolTip>Configure Krita</toolTip>
<iconText>Configure Krita</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="manage_bundles">
<icon></icon>
<text>&amp;Manage Resources...</text>
<whatsThis></whatsThis>
<toolTip>Manage Resources</toolTip>
<iconText>Manage Resources</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="switch_application_language">
<icon>preferences-desktop-locale</icon>
<text>Switch Application &amp;Language...</text>
<whatsThis></whatsThis>
<toolTip>Switch Application Language</toolTip>
<iconText>Switch Application Language</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_toggledockers">
<icon></icon>
<text>&amp;Show Dockers</text>
<whatsThis></whatsThis>
<toolTip>Show Dockers</toolTip>
<iconText>Show Dockers</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="options_configure_toolbars">
<icon>configure</icon>
<text>Configure Tool&amp;bars...</text>
<whatsThis></whatsThis>
<toolTip>Configure Toolbars</toolTip>
<iconText>Configure Toolbars</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="settings_dockers_menu">
<icon></icon>
<text>Dockers</text>
<whatsThis></whatsThis>
<toolTip>Dockers</toolTip>
<iconText>Dockers</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="theme_menu">
<icon></icon>
<text>&amp;Themes</text>
<whatsThis></whatsThis>
<toolTip>Themes</toolTip>
<iconText>Themes</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
+ <Action name="style_menu">
+ <icon></icon>
+ <text>&amp;Styles</text>
+ <whatsThis></whatsThis>
+ <toolTip>Styles</toolTip>
+ <iconText>Styles</iconText>
+ <shortcut></shortcut>
+ <isCheckable>false</isCheckable>
+ <statusTip></statusTip>
+ </Action>
<Action name="settings_active_author">
<icon>im-user</icon>
<text>Active Author Profile</text>
<whatsThis></whatsThis>
<toolTip>Active Author Profile</toolTip>
<iconText>Active Author Profile</iconText>
<shortcut></shortcut>
<isCheckable></isCheckable>
<statusTip></statusTip>
</Action>
<Action name="reset_configurations">
<icon></icon>
<text>Reset Krita Configurations</text>
<whatsThis></whatsThis>
<toolTip>Reset Krita Configurations</toolTip>
<iconText>Reset Krita Configurations</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="options_configure_keybinding">
<icon>configure-shortcuts</icon>
<text>Configure S&amp;hortcuts...</text>
<whatsThis></whatsThis>
<toolTip>Configure Shortcuts</toolTip>
<iconText>Configure Shortcuts</iconText>
<activationFlags>0</activationFlags>
<activationConditions>0</activationConditions>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="window">
<icon></icon>
<text>&amp;Window</text>
<whatsThis></whatsThis>
<toolTip>Window</toolTip>
<iconText>Window</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
</Actions>
<Actions category="Help">
<text>Help</text>
<Action name="help_contents">
<icon>help-contents</icon>
<text>Krita &amp;Handbook</text>
<whatsThis></whatsThis>
<toolTip>Krita Handbook</toolTip>
<iconText>Krita Handbook</iconText>
<shortcut>F1</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="help_report_bug">
<icon>tools-report-bug</icon>
<text>&amp;Report Bug...</text>
<whatsThis></whatsThis>
<toolTip>Report Bug</toolTip>
<iconText>Report Bug</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="help_about_app">
<icon>krita</icon>
<text>&amp;About Krita</text>
<whatsThis></whatsThis>
<toolTip>About Krita</toolTip>
<iconText>About Krita</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="help_about_kde">
<icon>kde</icon>
<text>About &amp;KDE</text>
<whatsThis></whatsThis>
<toolTip>About KDE</toolTip>
<iconText>About KDE</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
</Actions>
<Actions category="BrushesAndStuff">
<text>Brushes and Stuff</text>
<Action name="gradients">
<icon></icon>
<text>&amp;Gradients</text>
<whatsThis></whatsThis>
<toolTip>Gradients</toolTip>
<iconText>Gradients</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="patterns">
<icon></icon>
<text>&amp;Patterns</text>
<whatsThis></whatsThis>
<toolTip>Patterns</toolTip>
<iconText>Patterns</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="dual">
<icon></icon>
<text>&amp;Color</text>
<whatsThis></whatsThis>
<toolTip>Color</toolTip>
<iconText>Color</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="paintops">
<icon></icon>
<text>&amp;Painter's Tools</text>
<whatsThis></whatsThis>
<toolTip>Painter's Tools</toolTip>
<iconText>Painter's Tools</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="composite_actions">
<icon></icon>
<text>Brush composite</text>
<whatsThis></whatsThis>
<toolTip>Brush composite</toolTip>
<iconText>Brush composite</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="brushslider1">
<icon></icon>
<text>Brush option slider 1</text>
<whatsThis></whatsThis>
<toolTip>Brush option slider 1</toolTip>
<iconText>Brush option slider 1</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="brushslider2">
<icon></icon>
<text>Brush option slider 2</text>
<whatsThis></whatsThis>
<toolTip>Brush option slider 2</toolTip>
<iconText>Brush option slider 2</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="brushslider3">
<icon></icon>
<text>Brush option slider 3</text>
<whatsThis></whatsThis>
<toolTip>Brush option slider 3</toolTip>
<iconText>Brush option slider 3</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="mirror_actions">
<icon></icon>
<text>Mirror</text>
<whatsThis></whatsThis>
<toolTip>Mirror</toolTip>
<iconText>Mirror</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="select_layout">
<icon></icon>
<text>Layouts</text>
<whatsThis></whatsThis>
<toolTip>Select layout</toolTip>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="workspaces">
<icon></icon>
<text>Workspaces</text>
<whatsThis></whatsThis>
<toolTip>Workspaces</toolTip>
<iconText>Workspaces</iconText>
<shortcut></shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
</Actions>
</ActionCollection>
diff --git a/krita/main.cc b/krita/main.cc
index 3f57d0d924..27302bc42e 100644
--- a/krita/main.cc
+++ b/krita/main.cc
@@ -1,602 +1,603 @@
/*
* Copyright (c) 1999 Matthias Elter <me@kde.org>
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
* Copyright (c) 2015 Boudewijn Rempt <boud@valdyas.org>
*
* 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 <stdlib.h>
#include <QString>
#include <QPixmap>
#include <kis_debug.h>
#include <QProcess>
#include <QProcessEnvironment>
#include <QStandardPaths>
#include <QDir>
#include <QDate>
#include <QLocale>
#include <QSettings>
#include <QByteArray>
#include <QMessageBox>
#include <QThread>
#include <QOperatingSystemVersion>
#include <time.h>
#include <KisApplication.h>
#include <KoConfig.h>
#include <KoResourcePaths.h>
#include <kis_config.h>
#include "data/splash/splash_screen.xpm"
#include "data/splash/splash_holidays.xpm"
#include "data/splash/splash_screen_x2.xpm"
#include "data/splash/splash_holidays_x2.xpm"
#include "KisDocument.h"
#include "kis_splash_screen.h"
#include "KisPart.h"
#include "KisApplicationArguments.h"
#include <opengl/kis_opengl.h>
#include "input/KisQtWidgetsTweaker.h"
#include <KisUsageLogger.h>
#include <kis_image_config.h>
#ifdef Q_OS_ANDROID
#include <QtAndroid>
#endif
#if defined Q_OS_WIN
#include "config_use_qt_tablet_windows.h"
#include <windows.h>
#ifndef USE_QT_TABLET_WINDOWS
#include <kis_tablet_support_win.h>
#include <kis_tablet_support_win8.h>
#else
#include <dialogs/KisDlgCustomTabletResolution.h>
#endif
#include "config-high-dpi-scale-factor-rounding-policy.h"
#include "config-set-has-border-in-full-screen-default.h"
#ifdef HAVE_SET_HAS_BORDER_IN_FULL_SCREEN_DEFAULT
#include <QtPlatformHeaders/QWindowsWindowFunctions>
#endif
#include <QLibrary>
#endif
#if defined HAVE_KCRASH
#include <kcrash.h>
#elif defined USE_DRMINGW
namespace
{
void tryInitDrMingw()
{
wchar_t path[MAX_PATH];
QString pathStr = QCoreApplication::applicationDirPath().replace(L'/', L'\\') + QStringLiteral("\\exchndl.dll");
if (pathStr.size() > MAX_PATH - 1) {
return;
}
int pathLen = pathStr.toWCharArray(path);
path[pathLen] = L'\0'; // toWCharArray doesn't add NULL terminator
HMODULE hMod = LoadLibraryW(path);
if (!hMod) {
return;
}
// No need to call ExcHndlInit since the crash handler is installed on DllMain
auto myExcHndlSetLogFileNameA = reinterpret_cast<BOOL (APIENTRY *)(const char *)>(GetProcAddress(hMod, "ExcHndlSetLogFileNameA"));
if (!myExcHndlSetLogFileNameA) {
return;
}
// Set the log file path to %LocalAppData%\kritacrash.log
QString logFile = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation).replace(L'/', L'\\') + QStringLiteral("\\kritacrash.log");
myExcHndlSetLogFileNameA(logFile.toLocal8Bit());
}
} // namespace
#endif
#ifdef Q_OS_WIN
namespace
{
typedef enum ORIENTATION_PREFERENCE {
ORIENTATION_PREFERENCE_NONE = 0x0,
ORIENTATION_PREFERENCE_LANDSCAPE = 0x1,
ORIENTATION_PREFERENCE_PORTRAIT = 0x2,
ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED = 0x4,
ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED = 0x8
} ORIENTATION_PREFERENCE;
typedef BOOL WINAPI (*pSetDisplayAutoRotationPreferences_t)(
ORIENTATION_PREFERENCE orientation
);
void resetRotation()
{
QLibrary user32Lib("user32");
if (!user32Lib.load()) {
qWarning() << "Failed to load user32.dll! This really should not happen.";
return;
}
pSetDisplayAutoRotationPreferences_t pSetDisplayAutoRotationPreferences
= reinterpret_cast<pSetDisplayAutoRotationPreferences_t>(user32Lib.resolve("SetDisplayAutoRotationPreferences"));
if (!pSetDisplayAutoRotationPreferences) {
dbgKrita << "Failed to load function SetDisplayAutoRotationPreferences";
return;
}
bool result = pSetDisplayAutoRotationPreferences(ORIENTATION_PREFERENCE_NONE);
dbgKrita << "SetDisplayAutoRotationPreferences(ORIENTATION_PREFERENCE_NONE) returned" << result;
}
} // namespace
#endif
#ifdef Q_OS_ANDROID
extern "C" JNIEXPORT void JNICALL
Java_org_krita_android_JNIWrappers_saveState(JNIEnv* /*env*/,
jobject /*obj*/,
jint /*n*/)
{
if (!KisPart::exists()) return;
KisPart *kisPart = KisPart::instance();
QList<QPointer<KisDocument>> list = kisPart->documents();
for (QPointer<KisDocument> &doc: list)
{
doc->autoSaveOnPause();
}
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
kritarc.setValue("canvasState", "OPENGL_SUCCESS");
}
extern "C" JNIEXPORT void JNICALL
Java_org_krita_android_JNIWrappers_exitFullScreen(JNIEnv* /*env*/,
jobject /*obj*/,
jint /*n*/)
{
if (!KisPart::exists()) return;
KisMainWindow *mainWindow = KisPart::instance()->currentMainwindow();
mainWindow->viewFullscreen(false);
}
__attribute__ ((visibility ("default")))
#endif
extern "C" int main(int argc, char **argv)
{
// The global initialization of the random generator
qsrand(time(0));
bool runningInKDE = !qgetenv("KDE_FULL_SESSION").isEmpty();
#if defined HAVE_X11
qputenv("QT_QPA_PLATFORM", "xcb");
#endif
// Workaround a bug in QNetworkManager
qputenv("QT_BEARER_POLL_TIMEOUT", QByteArray::number(-1));
// A per-user unique string, without /, because QLocalServer cannot use names with a / in it
QString key = "Krita4" + QStandardPaths::writableLocation(QStandardPaths::HomeLocation).replace("/", "_");
key = key.replace(":", "_").replace("\\","_");
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true);
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
QCoreApplication::setAttribute(Qt::AA_DisableShaderDiskCache, true);
#ifdef HAVE_HIGH_DPI_SCALE_FACTOR_ROUNDING_POLICY
// This rounding policy depends on a series of patches to Qt related to
// https://bugreports.qt.io/browse/QTBUG-53022. These patches are applied
// in ext_qt for WIndows (patches 0031-0036).
//
// The rounding policy can be set externally by setting the environment
// variable `QT_SCALE_FACTOR_ROUNDING_POLICY` to one of the following:
// Round: Round up for .5 and above.
// Ceil: Always round up.
// Floor: Always round down.
// RoundPreferFloor: Round up for .75 and above.
// PassThrough: Don't round.
//
// The default is set to RoundPreferFloor for better behaviour than before,
// but can be overridden by the above environment variable.
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor);
#endif
#ifdef Q_OS_ANDROID
const QString write_permission = "android.permission.WRITE_EXTERNAL_STORAGE";
const QStringList permissions = { write_permission };
const QtAndroid::PermissionResultMap resultHash =
QtAndroid::requestPermissionsSync(QStringList(permissions));
if (resultHash[write_permission] == QtAndroid::PermissionResult::Denied) {
// TODO: show a dialog and graciously exit
dbgKrita << "Permission denied by the user";
}
else {
dbgKrita << "Permission granted";
}
#endif
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
bool enableOpenGLDebug = false;
bool openGLDebugSynchronous = false;
bool logUsage = true;
{
if (kritarc.value("EnableHiDPI", true).toBool()) {
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
}
if (!qgetenv("KRITA_HIDPI").isEmpty()) {
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
}
#ifdef HAVE_HIGH_DPI_SCALE_FACTOR_ROUNDING_POLICY
if (kritarc.value("EnableHiDPIFractionalScaling", true).toBool()) {
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
}
#endif
if (!qgetenv("KRITA_OPENGL_DEBUG").isEmpty()) {
enableOpenGLDebug = true;
} else {
enableOpenGLDebug = kritarc.value("EnableOpenGLDebug", false).toBool();
}
if (enableOpenGLDebug && (qgetenv("KRITA_OPENGL_DEBUG") == "sync" || kritarc.value("OpenGLDebugSynchronous", false).toBool())) {
openGLDebugSynchronous = true;
}
KisConfig::RootSurfaceFormat rootSurfaceFormat = KisConfig::rootSurfaceFormat(&kritarc);
KisOpenGL::OpenGLRenderer preferredRenderer = KisOpenGL::RendererAuto;
logUsage = kritarc.value("LogUsage", true).toBool();
#ifdef Q_OS_WIN
const QString preferredRendererString = kritarc.value("OpenGLRenderer", "angle").toString();
#else
const QString preferredRendererString = kritarc.value("OpenGLRenderer", "auto").toString();
#endif
preferredRenderer = KisOpenGL::convertConfigToOpenGLRenderer(preferredRendererString);
const KisOpenGL::RendererConfig config =
KisOpenGL::selectSurfaceConfig(preferredRenderer, rootSurfaceFormat, enableOpenGLDebug);
KisOpenGL::setDefaultSurfaceConfig(config);
KisOpenGL::setDebugSynchronous(openGLDebugSynchronous);
#ifdef Q_OS_WIN
// HACK: https://bugs.kde.org/show_bug.cgi?id=390651
resetRotation();
#endif
}
if (logUsage) {
KisUsageLogger::initialize();
}
QString root;
QString language;
{
// Create a temporary application to get the root
QCoreApplication app(argc, argv);
Q_UNUSED(app);
root = KoResourcePaths::getApplicationRoot();
QSettings languageoverride(configPath + QStringLiteral("/klanguageoverridesrc"), QSettings::IniFormat);
languageoverride.beginGroup(QStringLiteral("Language"));
language = languageoverride.value(qAppName(), "").toString();
}
#ifdef Q_OS_LINUX
{
QByteArray originalXdgDataDirs = qgetenv("XDG_DATA_DIRS");
if (originalXdgDataDirs.isEmpty()) {
// We don't want to completely override the default
originalXdgDataDirs = "/usr/local/share/:/usr/share/";
}
qputenv("XDG_DATA_DIRS", QFile::encodeName(root + "share") + ":" + originalXdgDataDirs);
}
#else
qputenv("XDG_DATA_DIRS", QFile::encodeName(root + "share"));
#endif
dbgKrita << "Setting XDG_DATA_DIRS" << qgetenv("XDG_DATA_DIRS");
// Now that the paths are set, set the language. First check the override from the language
// selection dialog.
dbgKrita << "Override language:" << language;
bool rightToLeft = false;
if (!language.isEmpty()) {
KLocalizedString::setLanguages(language.split(":"));
// And override Qt's locale, too
QLocale locale(language.split(":").first());
QLocale::setDefault(locale);
#ifdef Q_OS_MAC
// prevents python >=3.7 nl_langinfo(CODESET) fail bug 417312.
qputenv("LANG", (locale.name() + ".UTF-8").toLocal8Bit());
#else
qputenv("LANG", locale.name().toLocal8Bit());
#endif
const QStringList rtlLanguages = QStringList()
<< "ar" << "dv" << "he" << "ha" << "ku" << "fa" << "ps" << "ur" << "yi";
if (rtlLanguages.contains(language.split(':').first())) {
rightToLeft = true;
}
}
else {
dbgKrita << "Qt UI languages:" << QLocale::system().uiLanguages() << qgetenv("LANG");
// And if there isn't one, check the one set by the system.
QLocale locale = QLocale::system();
if (locale.name() != QStringLiteral("en")) {
QStringList uiLanguages = locale.uiLanguages();
for (QString &uiLanguage : uiLanguages) {
// This list of language codes that can have a specifier should
// be extended whenever we have translations that need it; right
// now, only en, pt, zh are in this situation.
if (uiLanguage.startsWith("en") || uiLanguage.startsWith("pt")) {
uiLanguage.replace(QChar('-'), QChar('_'));
}
else if (uiLanguage.startsWith("zh-Hant") || uiLanguage.startsWith("zh-TW")) {
uiLanguage = "zh_TW";
}
else if (uiLanguage.startsWith("zh-Hans") || uiLanguage.startsWith("zh-CN")) {
uiLanguage = "zh_CN";
}
}
if (uiLanguages.size() > 0 ) {
QString envLanguage = uiLanguages.first();
envLanguage.replace(QChar('-'), QChar('_'));
for (int i = 0; i < uiLanguages.size(); i++) {
QString uiLanguage = uiLanguages[i];
// Strip the country code
int idx = uiLanguage.indexOf(QChar('-'));
if (idx != -1) {
uiLanguage = uiLanguage.left(idx);
uiLanguages.replace(i, uiLanguage);
}
}
dbgKrita << "Converted ui languages:" << uiLanguages;
#ifdef Q_OS_MAC
// See https://bugs.kde.org/show_bug.cgi?id=396370
KLocalizedString::setLanguages(QStringList() << uiLanguages.first());
qputenv("LANG", (envLanguage + ".UTF-8").toLocal8Bit());
#else
KLocalizedString::setLanguages(QStringList() << uiLanguages);
qputenv("LANG", envLanguage.toLocal8Bit());
#endif
}
}
}
#if defined Q_OS_WIN && defined USE_QT_TABLET_WINDOWS && defined QT_HAS_WINTAB_SWITCH
const bool forceWinTab = !KisConfig::useWin8PointerInputNoApp(&kritarc);
QCoreApplication::setAttribute(Qt::AA_MSWindowsUseWinTabAPI, forceWinTab);
if (qEnvironmentVariableIsEmpty("QT_WINTAB_DESKTOP_RECT") &&
qEnvironmentVariableIsEmpty("QT_IGNORE_WINTAB_MAPPING")) {
QRect customTabletRect;
KisDlgCustomTabletResolution::Mode tabletMode =
KisDlgCustomTabletResolution::getTabletMode(&customTabletRect);
KisDlgCustomTabletResolution::applyConfiguration(tabletMode, customTabletRect);
}
#endif
// first create the application so we can create a pixmap
KisApplication app(key, argc, argv);
KisUsageLogger::writeHeader();
KisOpenGL::initialize();
#ifdef HAVE_SET_HAS_BORDER_IN_FULL_SCREEN_DEFAULT
if (QCoreApplication::testAttribute(Qt::AA_UseDesktopOpenGL)) {
QWindowsWindowFunctions::setHasBorderInFullScreenDefault(true);
}
#endif
if (!language.isEmpty()) {
if (rightToLeft) {
app.setLayoutDirection(Qt::RightToLeft);
}
else {
app.setLayoutDirection(Qt::LeftToRight);
}
}
KLocalizedString::setApplicationDomain("krita");
dbgKrita << "Available translations" << KLocalizedString::availableApplicationTranslations();
dbgKrita << "Available domain translations" << KLocalizedString::availableDomainTranslations("krita");
#ifdef Q_OS_WIN
QDir appdir(KoResourcePaths::getApplicationRoot());
QString path = qgetenv("PATH");
qputenv("PATH", QFile::encodeName(appdir.absolutePath() + "/bin" + ";"
+ appdir.absolutePath() + "/lib" + ";"
+ appdir.absolutePath() + "/Frameworks" + ";"
+ appdir.absolutePath() + ";"
+ path));
dbgKrita << "PATH" << qgetenv("PATH");
#endif
if (qApp->applicationDirPath().contains(KRITA_BUILD_DIR)) {
qFatal("FATAL: You're trying to run krita from the build location. You can only run Krita from the installation location.");
}
#if defined HAVE_KCRASH
KCrash::initialize();
#elif defined USE_DRMINGW
tryInitDrMingw();
#endif
KisApplicationArguments args(app);
if (app.isRunning()) {
// only pass arguments to main instance if they are not for batch processing
// any batch processing would be done in this separate instance
const bool batchRun = args.exportAs() || args.exportSequence();
if (!batchRun) {
QByteArray ba = args.serialize();
if (app.sendMessage(ba)) {
return 0;
}
}
}
if (!runningInKDE) {
// Icons in menus are ugly and distracting
app.setAttribute(Qt::AA_DontShowIconsInMenus);
}
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
app.setAttribute(Qt::AA_DisableWindowContextHelpButton);
#endif
app.installEventFilter(KisQtWidgetsTweaker::instance());
if (!args.noSplash()) {
// then create the pixmap from an xpm: we cannot get the
// location of our datadir before we've started our components,
// so use an xpm.
QDate currentDate = QDate::currentDate();
QWidget *splash = 0;
if (currentDate > QDate(currentDate.year(), 12, 4) ||
currentDate < QDate(currentDate.year(), 1, 9)) {
splash = new KisSplashScreen(app.applicationVersion(), QPixmap(splash_holidays_xpm), QPixmap(splash_holidays_x2_xpm));
}
else {
splash = new KisSplashScreen(app.applicationVersion(), QPixmap(splash_screen_xpm), QPixmap(splash_screen_x2_xpm));
}
app.setSplashScreen(splash);
}
#if defined Q_OS_WIN
KisConfig cfg(false);
bool supportedWindowsVersion = true;
QOperatingSystemVersion osVersion = QOperatingSystemVersion::current();
if (osVersion.type() == QOperatingSystemVersion::Windows) {
if (osVersion.majorVersion() >= QOperatingSystemVersion::Windows7.majorVersion()) {
supportedWindowsVersion = true;
}
else {
supportedWindowsVersion = false;
if (cfg.readEntry("WarnedAboutUnsupportedWindows", false)) {
QMessageBox::information(0,
i18nc("@title:window", "Krita: Warning"),
i18n("You are running an unsupported version of Windows: %1.\n"
"This is not recommended. Do not report any bugs.\n"
"Please update to a supported version of Windows: Windows 7, 8, 8.1 or 10.", osVersion.name()));
cfg.writeEntry("WarnedAboutUnsupportedWindows", true);
}
}
}
#ifndef USE_QT_TABLET_WINDOWS
{
if (cfg.useWin8PointerInput() && !KisTabletSupportWin8::isAvailable()) {
cfg.setUseWin8PointerInput(false);
}
if (!cfg.useWin8PointerInput()) {
bool hasWinTab = KisTabletSupportWin::init();
if (!hasWinTab && supportedWindowsVersion) {
if (KisTabletSupportWin8::isPenDeviceAvailable()) {
// Use WinInk automatically
cfg.setUseWin8PointerInput(true);
} else if (!cfg.readEntry("WarnedAboutMissingWinTab", false)) {
if (KisTabletSupportWin8::isAvailable()) {
QMessageBox::information(nullptr,
i18n("Krita Tablet Support"),
i18n("Cannot load WinTab driver and no Windows Ink pen devices are found. If you have a drawing tablet, please make sure the tablet driver is properly installed."),
QMessageBox::Ok, QMessageBox::Ok);
} else {
QMessageBox::information(nullptr,
i18n("Krita Tablet Support"),
i18n("Cannot load WinTab driver. If you have a drawing tablet, please make sure the tablet driver is properly installed."),
QMessageBox::Ok, QMessageBox::Ok);
}
cfg.writeEntry("WarnedAboutMissingWinTab", true);
}
}
}
if (cfg.useWin8PointerInput()) {
KisTabletSupportWin8 *penFilter = new KisTabletSupportWin8();
if (penFilter->init()) {
// penFilter.registerPointerDeviceNotifications();
app.installNativeEventFilter(penFilter);
dbgKrita << "Using Win8 Pointer Input for tablet support";
} else {
dbgKrita << "No Win8 Pointer Input available";
delete penFilter;
}
}
}
#elif defined QT_HAS_WINTAB_SWITCH
// Check if WinTab/WinInk has actually activated
const bool useWinTabAPI = app.testAttribute(Qt::AA_MSWindowsUseWinTabAPI);
if (useWinTabAPI != !cfg.useWin8PointerInput()) {
cfg.setUseWin8PointerInput(useWinTabAPI);
}
#endif
#endif
app.setAttribute(Qt::AA_CompressHighFrequencyEvents, false);
// Set up remote arguments.
QObject::connect(&app, SIGNAL(messageReceived(QByteArray,QObject*)),
&app, SLOT(remoteArguments(QByteArray,QObject*)));
QObject::connect(&app, SIGNAL(fileOpenRequest(QString)),
&app, SLOT(fileOpenRequested(QString)));
// Hardware information
KisUsageLogger::writeSysInfo("\nHardware Information\n");
KisUsageLogger::writeSysInfo(QString(" GPU Acceleration: %1").arg(kritarc.value("OpenGLRenderer", "auto").toString()));
KisUsageLogger::writeSysInfo(QString(" Memory: %1 Mb").arg(KisImageConfig(true).totalRAM()));
KisUsageLogger::writeSysInfo(QString(" Number of Cores: %1").arg(QThread::idealThreadCount()));
KisUsageLogger::writeSysInfo(QString(" Swap Location: %1\n").arg(KisImageConfig(true).swapDir()));
KisConfig(true).logImportantSettings();
if (!app.start(args)) {
KisUsageLogger::log("Could not start Krita Application");
return 1;
}
+
int state = app.exec();
{
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
kritarc.setValue("canvasState", "OPENGL_SUCCESS");
}
if (logUsage) {
KisUsageLogger::close();
}
return state;
}
diff --git a/krita/org.kde.krita.appdata.xml b/krita/org.kde.krita.appdata.xml
index d0ab80a54e..e579137447 100644
--- a/krita/org.kde.krita.appdata.xml
+++ b/krita/org.kde.krita.appdata.xml
@@ -1,480 +1,486 @@
<?xml version="1.0" encoding="utf-8"?>
<component type="desktop">
<id>org.kde.krita</id>
<launchable type="desktop-id">org.kde.krita.desktop</launchable>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0-only</project_license>
<developer_name>Krita Foundation</developer_name>
<developer_name xml:lang="ca">Fundació Krita</developer_name>
<developer_name xml:lang="ca-valencia">Fundació Krita</developer_name>
<developer_name xml:lang="cs">Krita Foundation</developer_name>
<developer_name xml:lang="de">Krita Foundation</developer_name>
<developer_name xml:lang="en-GB">Krita Foundation</developer_name>
<developer_name xml:lang="es">Fundación Krita</developer_name>
<developer_name xml:lang="et">Krita sihtasutus</developer_name>
<developer_name xml:lang="eu">Krita Fundazioa</developer_name>
<developer_name xml:lang="fi">Krita Foundation</developer_name>
- <developer_name xml:lang="fr">La Fondation Krita</developer_name>
+ <developer_name xml:lang="fr">La fondation Krita</developer_name>
<developer_name xml:lang="gl">Fundación Krita</developer_name>
<developer_name xml:lang="ia">Krita Foundation (Fundatiomn de Krita)</developer_name>
<developer_name xml:lang="id">Asas Krita</developer_name>
<developer_name xml:lang="it">Fondazione Krita</developer_name>
<developer_name xml:lang="ko">Krita Foundation</developer_name>
<developer_name xml:lang="nl">Krita Foundation</developer_name>
<developer_name xml:lang="nn">Krita Foundation</developer_name>
<developer_name xml:lang="pl">Fundacja Krity</developer_name>
<developer_name xml:lang="pt">Fundação do Krita</developer_name>
<developer_name xml:lang="pt-BR">Krita Foundation</developer_name>
<developer_name xml:lang="sk">Nadácia Krita</developer_name>
<developer_name xml:lang="sv">Krita-stiftelsen</developer_name>
<developer_name xml:lang="tr">Krita Vakfı</developer_name>
<developer_name xml:lang="uk">Фундація Krita</developer_name>
<developer_name xml:lang="x-test">xxKrita Foundationxx</developer_name>
<developer_name xml:lang="zh-CN">Krita 基金会</developer_name>
<developer_name xml:lang="zh-TW">Krita 基金會</developer_name>
<update_contact>foundation@krita.org</update_contact>
<name>Krita</name>
<name xml:lang="ar">كريتا</name>
<name xml:lang="ca">Krita</name>
<name xml:lang="ca-valencia">Krita</name>
<name xml:lang="cs">Krita</name>
<name xml:lang="de">Krita</name>
<name xml:lang="el">Krita</name>
<name xml:lang="en-GB">Krita</name>
<name xml:lang="es">Krita</name>
<name xml:lang="et">Krita</name>
<name xml:lang="eu">Krita</name>
<name xml:lang="fi">Krita</name>
<name xml:lang="fr">Krita</name>
<name xml:lang="gl">Krita</name>
<name xml:lang="ia">Krita</name>
<name xml:lang="id">Krita</name>
<name xml:lang="it">Krita</name>
<name xml:lang="ko">Krita</name>
<name xml:lang="nl">Krita</name>
<name xml:lang="nn">Krita</name>
<name xml:lang="pl">Krita</name>
<name xml:lang="pt">Krita</name>
<name xml:lang="pt-BR">Krita</name>
<name xml:lang="ru">Krita</name>
<name xml:lang="sk">Krita</name>
<name xml:lang="sv">Krita</name>
<name xml:lang="tr">Krita</name>
<name xml:lang="uk">Krita</name>
<name xml:lang="x-test">xxKritaxx</name>
<name xml:lang="zh-CN">Krita</name>
<name xml:lang="zh-TW">Krita</name>
<summary>Digital Painting, Creative Freedom</summary>
<summary xml:lang="ar">رسم رقميّ، حريّة إبداعيّة</summary>
<summary xml:lang="bs">Digitalno crtanje, kreativna sloboda</summary>
<summary xml:lang="ca">Dibuix digital, Llibertat creativa</summary>
<summary xml:lang="ca-valencia">Dibuix digital, Llibertat creativa</summary>
<summary xml:lang="cs">Digitální malování, svoboda tvorby</summary>
<summary xml:lang="da">Digital tegning, kunstnerisk frihed</summary>
<summary xml:lang="de">Digitales Malen, kreative Freiheit</summary>
<summary xml:lang="el">Ψηφιακή ζωγραφική, δημιουργική ελευθερία</summary>
<summary xml:lang="en-GB">Digital Painting, Creative Freedom</summary>
<summary xml:lang="es">Pintura digital, libertad creativa</summary>
<summary xml:lang="et">Digitaalne joonistamine, loominguline vabadus</summary>
<summary xml:lang="eu">Margolan digitala, sormen askatasuna</summary>
<summary xml:lang="fi">Digitaalimaalaus, luova vapaus</summary>
<summary xml:lang="fr">Peinture numérique, liberté créatrice</summary>
<summary xml:lang="gl">Debuxo dixital, liberdade creativa</summary>
<summary xml:lang="ia">Pictura digital, Libertate creative</summary>
<summary xml:lang="id">Pelukisan Digital, Kebebasan Berkreatif</summary>
<summary xml:lang="it">Pittura digitale, libertà creativa</summary>
<summary xml:lang="ko">디지털 페인팅, 자유로운 창의성</summary>
<summary xml:lang="nl">Digital Painting, Creative Freedom</summary>
<summary xml:lang="nn">Digital teikning – kreativ fridom</summary>
<summary xml:lang="pl">Cyfrowe malowanie, Wolność Twórcza</summary>
<summary xml:lang="pt">Pintura Digital, Liberdade Criativa</summary>
<summary xml:lang="pt-BR">Pintura digital, liberdade criativa</summary>
<summary xml:lang="ru">Цифровое рисование. Творческая свобода</summary>
<summary xml:lang="sk">Digitálne maľovanie, kreatívna sloboda</summary>
<summary xml:lang="sv">Digital målning, kreativ frihet</summary>
<summary xml:lang="tr">Sayısal Boyama, Yaratıcı Özgürlük</summary>
<summary xml:lang="uk">Цифрове малювання, творча свобода</summary>
<summary xml:lang="x-test">xxDigital Painting, Creative Freedomxx</summary>
<summary xml:lang="zh-CN">自由挥洒数字绘画的无限创意</summary>
<summary xml:lang="zh-TW">數位繪畫,創作自由</summary>
<description>
<p>Krita is the full-featured digital art studio.</p>
<p xml:lang="bs">Krita je potpuni digitalni umjetnički studio.</p>
<p xml:lang="ca">El Krita és l'estudi d'art digital ple de funcionalitats.</p>
<p xml:lang="ca-valencia">El Krita és l'estudi d'art digital ple de funcionalitats.</p>
<p xml:lang="de">Krita ist ein digitales Designstudio mit umfangreichen Funktionen.</p>
<p xml:lang="el">Το Krita είναι ένα πλήρες χαρακτηριστικών ψηφιακό ατελιέ.</p>
<p xml:lang="en-GB">Krita is the full-featured digital art studio.</p>
<p xml:lang="es">Krita es un estudio de arte digital completo</p>
<p xml:lang="et">Krita on rohkete võimalustega digitaalkunstistuudio.</p>
<p xml:lang="eu">Krita arte lantegi digital osoa da.</p>
<p xml:lang="fi">Krita on täyspiirteinen digitaiteen ateljee.</p>
<p xml:lang="fr">Krita est le studio d'art numérique complet.</p>
<p xml:lang="gl">Krita é un estudio completo de arte dixital.</p>
<p xml:lang="ia">Krita es le studio de arte digital complete.</p>
<p xml:lang="id">Krita adalah studio seni digital yang penuh dengan fitur.</p>
<p xml:lang="it">Krita è uno studio d'arte digitale completo.</p>
<p xml:lang="ja">Krita は、フル機能を備えたデジタルなアートスタジオです。</p>
<p xml:lang="ko">Krita는 디지털 예술 스튜디오입니다.</p>
<p xml:lang="nl">Krita is de digitale kunststudio vol mogelijkheden.</p>
<p xml:lang="nn">Krita er ei funksjonsrik digital teiknestove.</p>
<p xml:lang="pl">Krita jest pełnowymiarowym, cyfrowym studiem artystycznym</p>
<p xml:lang="pt">O Krita é o estúdio de arte digital completo.</p>
<p xml:lang="pt-BR">O Krita é o estúdio de arte digital completo.</p>
<p xml:lang="ru">Krita — полнофункциональный инструмент для создания цифровой графики.</p>
<p xml:lang="sk">Krita je plne vybavené digitálne umelecké štúdio.</p>
<p xml:lang="sv">Krita är den fullfjädrade digitala konststudion.</p>
<p xml:lang="tr">Krita, tam özellikli dijital sanat stüdyosudur.</p>
<p xml:lang="uk">Krita — повноцінний комплекс для створення цифрових художніх творів.</p>
<p xml:lang="x-test">xxKrita is the full-featured digital art studio.xx</p>
<p xml:lang="zh-CN">Krita 是一款功能齐全的数字绘画工作室软件。</p>
<p xml:lang="zh-TW">Krita 是全功能的數位藝術工作室。</p>
<p>It is perfect for sketching and painting, and presents an end–to–end solution for creating digital painting files from scratch by masters.</p>
<p xml:lang="bs">On je savršen za skiciranje i slikanje i predstavlja finalno rješenje za kreiranje digitalnih slika od nule s majstorima</p>
<p xml:lang="ca">És perfecte per fer esbossos i pintar, i presenta una solució final per crear fitxers de dibuix digital des de zero per a mestres.</p>
<p xml:lang="ca-valencia">És perfecte per fer esbossos i pintar, i presenta una solució final per crear fitxers de dibuix digital des de zero per a mestres.</p>
<p xml:lang="el">Είναι ιδανικό για σκιτσογραφία και ζωγραφική, και παρουσιάζει μια από άκρη σε άκρη λύση για τη δημιουργία από το μηδέν αρχείων ψηφιακης ζωγραφικής από τους δασκάλους της τέχνης.</p>
<p xml:lang="en-GB">It is perfect for sketching and painting, and presents an end–to–end solution for creating digital painting files from scratch by masters.</p>
<p xml:lang="es">Es perfecto para diseñar y pintar, y ofrece una solución completa para crear desde cero archivos de pintura digital apta para profesionales.</p>
<p xml:lang="et">See on suurepärane töövahend visandite ja joonistuste valmistamiseks ning annab andekatele kunstnikele võimaluse luua digitaalpilt algusest lõpuni just oma käe järgi.</p>
<p xml:lang="eu">Zirriborratzeko eta margotzeko ezin hobea da, eta margolan digitalen fitxategiak hutsetik sortzeko muturretik-muturrera konponbide bat aurkezten du, maisuentzako mailakoa.</p>
<p xml:lang="fi">Se on täydellinen luonnosteluun ja maalaukseen ja tarjoaa kokonaisratkaisun digitaalisten kuvatiedostojen luomiseen alusta alkaen.</p>
<p xml:lang="fr">Il est parfait pour crayonner et peindre, et constitue une solution de bout en bout pour créer des fichier de peinture numérique depuis la feuille blanche jusqu'au épreuves finales.</p>
<p xml:lang="gl">Resulta perfecto para debuxar e pintar, e presenta unha solución completa que permite aos mestres crear ficheiros de debuxo dixital desde cero.</p>
<p xml:lang="ia">Illo es perfecte pro schizzar e pinger, e presenta un solution ab fin al fin pro crear files de pictura digital ab grattamentos per maestros.</p>
<p xml:lang="id">Ini adalah sempurna untuk mensketsa dan melukis, dan menghadirkan sebuah solusi untuk menciptakan file-file pelukisan digital dari goresan si pelukis ulung.</p>
<p xml:lang="it">Perfetto per fare schizzi e dipingere, prevede una soluzione completa che consente agli artisti di creare file di dipinti digitali partendo da zero.</p>
<p xml:lang="ko">스케치, 페인팅에 사용할 완벽한 도구이며, 생각으로부터 디지털 페인팅 파일을 만들어 낼 수 있는 종합적인 도구를 제공합니다.</p>
<p xml:lang="nl">Het is perfect voor schetsen en schilderen en zet een end–to–end oplossing voor het maken van digitale bestanden voor schilderingen vanuit het niets door meesters.</p>
<p xml:lang="nn">Passar perfekt til både teikning og måling, og dekkjer alle ledd i prosessen med å laga digitale måleri frå grunnen av.</p>
<p xml:lang="pl">Nadaje się perfekcyjnie do szkicowania i malowania i dostarcza zupełnego rozwiązania dla tworzenia plików malowideł cyfrowych od zalążka.</p>
<p xml:lang="pt">É perfeito para desenhos e pinturas, oferecendo uma solução final para criar ficheiros de pintura digital do zero por mestres.</p>
<p xml:lang="pt-BR">É perfeito para desenhos e pinturas, oferecendo uma solução final para criar arquivos de desenho digital feitos a partir do zero por mestres.</p>
<p xml:lang="ru">Она превосходно подходит для набросков и рисования, предоставляя мастерам самодостаточный инструмент для создания цифровой живописи с нуля.</p>
<p xml:lang="sk">Je ideálna na skicovanie a maľovanie a poskytuje end-to-end riešenie na vytváranie súborov digitálneho maľovania od základu od profesionálov.</p>
<p xml:lang="sv">Den är perfekt för att skissa och måla, samt erbjuder en helomfattande lösning för att skapa digitala målningsfiler från grunden av mästare.</p>
<p xml:lang="tr">Eskiz ve boyama için mükemmeldir ve ustaların sıfırdan dijital boyama dosyaları oluşturmak için uçtan-uca bir çözüm sunar.</p>
<p xml:lang="uk">Цей комплекс чудово пасує для створення ескізів та художніх зображень і є самодостатнім набором для створення файлів цифрових полотен «з нуля» для справжніх художників.</p>
<p xml:lang="x-test">xxIt is perfect for sketching and painting, and presents an end–to–end solution for creating digital painting files from scratch by masters.xx</p>
<p xml:lang="zh-CN">它专门为数字绘画设计,为美术工作者提供了一个从起草、上色到完成作品等整个创作流程的完整解决方案。</p>
<p xml:lang="zh-TW">它是素描和繪畫的完美選擇,並提供了一個從零開始建立數位繪畫檔的端到端解決方案。</p>
<p>
Krita is a great choice for creating concept art, comics, textures for rendering and matte paintings. Krita supports many colorspaces like RGB and CMYK
at 8 and 16 bits integer channels, as well as 16 and 32 bits floating point channels.
</p>
<p xml:lang="bs">Krita je odličan izbor za kreiranje konceptualne umjetnosti, stripove, teksture za obradu i mat slike. Krita podržava mnoge prostore boja kao RGB i CMIK na 8 i 16 bitnim cjelobrojnim kanalimaa, kao i 16 i 32 bita floating point kanalima.</p>
<p xml:lang="ca">El Krita és una gran elecció per crear art conceptual, còmics, textures per renderitzar i pintures «matte». El Krita permet molts espais de color com el RGB i el CMYK a 8 i 16 bits de canals sencers, així com 16 i 32 bits de canals de coma flotant.</p>
<p xml:lang="ca-valencia">El Krita és una gran elecció per crear art conceptual, còmics, textures per renderitzar i pintures «matte». El Krita permet molts espais de color com el RGB i el CMYK a 8 i 16 bits de canals sencers, així com 16 i 32 bits de canals de coma flotant.</p>
<p xml:lang="el">Το Krita είναι μια εξαιρετική επιλογή για τη δημιουργία αφηρημένης τέχνης, ιστοριών με εικόνες, υφής για ζωγραφική αποτύπωσης και διάχυσης φωτός. Το Krita υποστηρίζει πολλούς χρωματικούς χώρους όπως τα RGB και CMYK σε 8 και 16 bit κανάλια ακεραίων καθώς επίσης και σε 16 και 32 bit κανάλια κινητής υποδιαστολής,</p>
<p xml:lang="en-GB">Krita is a great choice for creating concept art, comics, textures for rendering and matte paintings. Krita supports many colourspaces like RGB and CMYK at 8 and 16 bits integer channels, as well as 16 and 32 bits floating point channels.</p>
<p xml:lang="es">Krita es una gran elección para crear arte conceptual, cómics, texturas para renderizar y «matte paintings». Krita permite el uso de muchos espacios de color, como, por ejemplo, RGB y CMYK, tanto en canales de enteros de 8 y 16 bits, así como en canales de coma flotante de 16 y 32 bits.</p>
<p xml:lang="et">Krita on üks paremaid valikuid kontseptuaalkunsti, koomiksite, tekstuuride ja digitaalmaalide loomiseks. Krita toetab paljusid värviruume, näiteks RGB ja CMYK 8 ja 16 täisarvulise bitiga kanali kohta, samuti 16 ja 32 ujukomabitiga kanali kohta.</p>
<p xml:lang="eu">Krita aukera bikaina da kontzeptuzko artea, komikiak, errendatzeko ehundurak eta «matte» margolanak sortzeko. Kritak kolore-espazio ugari onartzen ditu hala nola GBU eta CMYK, 8 eta 16 biteko osoko kanaletan, baita 16 eta 32 biteko koma-higikorreko kanaletan.</p>
<p xml:lang="fi">Krita on hyvä valinta konseptikuvituksen, sarjakuvien, pintakuvioiden ja maalausten luomiseen. Krita tukee useita väriavaruuksia kuten RGB:tä ja CMYK:ta 8 ja 16 bitin kokonaisluku- samoin kuin 16 ja 32 bitin liukulukukanavin.</p>
- <p xml:lang="fr">Krita est un très bon choix pour créer des concepts arts, des bandes-dessinées, des textures de rendu et des peintures. Krita prend en charge plusieurs espaces de couleurs comme RVB et CMJN avec les canaux de 8 et 16 bits entiers ainsi que les canaux de 16 et 32 bits flottants.</p>
+ <p xml:lang="fr">Krita est un très bon choix pour créer des concepts arts, des bandes-dessinées, des textures de rendu et des peintures. Krita prend en charge plusieurs espaces de couleurs comme « RVB » et « CMJN » avec les canaux de 8 et 16 bits entiers ainsi que les canaux de 16 et 32 bits flottants.</p>
<p xml:lang="gl">Krita é unha gran opción para crear arte conceptual, texturas para renderización e pinturas mate. Krita permite usar moitos espazos de cores como RGB e CMYK con canles de 8 e 16 bits, así como canles de coma flotante de 16 e 32 bits.</p>
<p xml:lang="ia">Krita es un grande selection pro crear arte de concepto, comics, texturas pro rendering e picturas opac. Krita supporta multe spatios de colores como RGB e CMYK con canales de integer a 8 e 16 bits, como anque canales floating point a 16 e 32 bits.</p>
<p xml:lang="id">Krita adalah pilihan yang cocok untuk menciptakan konsep seni, komik, tekstur untuk rendering dan lukisan matte. Krita mendukung banyak ruang warna seperti RGB dan CMYK pada channel integer 8 dan 16 bit, serta channel floating point 16 dan 32 bit.</p>
<p xml:lang="it">Krita rappresenta una scelta ottimale per la creazione di arte concettuale, fumetti e texture per il rendering e il matte painting. Krita supporta molti spazi colori come RGB e CMYK a 8 e 16 bit per canali interi e 16 e 32 bit per canali a virgola mobile.</p>
<p xml:lang="ja">コンセプトアート、コミック、3DCG 用テクスチャ、マットペイントを制作する方にとって、Krita は最適な選択です。Krita は、8/16 ビット整数/チャンネル、および 16/32 ビット浮動小数点/チャンネルの RGB や CMYK をはじめ、さまざまな色空間をサポートしています。</p>
<p xml:lang="ko">Krita는 컨셉 아트, 만화, 렌더링용 텍스처, 풍경화 등을 그릴 때 사용할 수 있는 완벽한 도구입니다. RGB, CMYK와 같은 여러 색 공간 및 8비트/16비트 정수 채널, 16비트/32비트 부동 소수점 채널을 지원합니다.</p>
<p xml:lang="nl">Krita is een goede keuze voor het maken van kunstconcepten, strips, textuur voor weergeven en matte schilderijen. Krita ondersteunt vele kleurruimten zoals RGB en CMYK in 8 en 16 bits kanalen met gehele getallen, evenals 16 en 32 bits kanalen met drijvende komma.</p>
<p xml:lang="nn">Krita er det ideelle valet dersom du vil laga konseptskisser, teikneseriar, teksturar for 3D-rendering eller «matte paintings». Programmet støttar fleire fargerom, både RGB- og CMYK-baserte, med 8- og 16-bits heiltals- eller flyttalskanalar.</p>
<p xml:lang="pl">Krita jest świetnym wyborem przy tworzeniu koncepcyjnej sztuki, komiksów, tekstur do wyświetlania i kaszet. Krita obsługuje wiele przestrzeni barw takich jak RGB oraz CMYK dla kanałów 8 oraz 16 bitowych wyrażonych w l. całkowitych, a także 16 oraz 32 bitowych wyrażonych w l. zmiennoprzecinkowych.</p>
<p xml:lang="pt">O Krita é uma óptima escolha para criar arte conceptual, banda desenhada, texturas para desenho e pinturas. O Krita suporta diversos espaços de cores como o RGB e o CMYK com canais de cores inteiros a 8 e 16 bits, assim como canais de vírgula flutuante a 16 e a 32 bits.</p>
<p xml:lang="pt-BR">O Krita é uma ótima escolha para criação de arte conceitual, histórias em quadrinhos, texturas para desenhos e pinturas. O Krita tem suporte a diversos espaços de cores como RGB e CMYK com canais de cores inteiros de 8 e 16 bits, assim como canais de ponto flutuante de 16 e 32 bits.</p>
<p xml:lang="ru">Krita — отличный выбор для создания концепт-артов, комиксов, текстур для рендеринга и рисования. Она поддерживает множество цветовых пространств включая RGB и CMYK с 8 и 16 целыми битами на канал, а также 16 и 32 битами с плавающей запятой на канал.</p>
<p xml:lang="sk">Krita je výborná voľba pre vytváranie konceptového umenia, textúr na renderovanie a matné kresby. Krita podporuje mnoho farebných priestorov ako RGB a CMYK na 8 a 16 bitových celočíselných kanáloch ako aj 16 a 32 bitových reálnych kanáloch.</p>
<p xml:lang="sv">Krita är ett utmärkt val för att skapa concept art, serier, strukturer för återgivning och bakgrundsmålningar. Krita stöder många färgrymder som RGB och CMYK med 8- och 16-bitars heltal, samt 16- och 32-bitars flyttal.</p>
<p xml:lang="tr">Krita, konsept sanat, çizgi roman, kaplama ve mat resimler için dokular oluşturmak için mükemmel bir seçimdir. Krita, 8 ve 16 bit tamsayı kanallarında RGB ve CMYK gibi birçok renk alanını ve 16 ve 32 bit kayan nokta kanallarını desteklemektedir.</p>
<p xml:lang="uk">Krita — чудовий інструмент для створення концептуального живопису, коміксів, текстур для моделей та декорацій. У Krita передбачено підтримку багатьох просторів кольорів, зокрема RGB та CMYK з 8-бітовими та 16-бітовими цілими значеннями, а також 16-бітовими та 32-бітовими значеннями з рухомою крапкою для каналів кольорів.</p>
<p xml:lang="x-test">xxKrita is a great choice for creating concept art, comics, textures for rendering and matte paintings. Krita supports many colorspaces like RGB and CMYK at 8 and 16 bits integer channels, as well as 16 and 32 bits floating point channels.xx</p>
<p xml:lang="zh-CN">Krita 是绘制概念美术、漫画、纹理和接景的理想选择。Krita 支持多种色彩空间,如 8 位和 16 位整数及 16 位和 32 位浮点的 RGB 和 CMYK 颜色模型。</p>
<p xml:lang="zh-TW">Krita 是創造概念藝術、漫畫、彩現紋理和場景繪畫的絕佳選擇。Krita 在 8 位元和 16 位元整數色版,以及 16 位元和 32 位元浮點色板中支援 RGB 和 CMYK 等多種色彩空間。</p>
<p>Have fun painting with the advanced brush engines, amazing filters and many handy features that make Krita enormously productive.</p>
<p xml:lang="bs">Zabavite se kreirajući napredne pogone četki, filtere i mnoge praktične osobine koje čine Krita vrlo produktivnim.</p>
<p xml:lang="ca">Gaudiu pintant amb els motors avançats de pinzells, filtres impressionants i moltes característiques útils que fan el Krita molt productiu.</p>
<p xml:lang="ca-valencia">Gaudiu pintant amb els motors avançats de pinzells, filtres impressionants i moltes característiques útils que fan el Krita molt productiu.</p>
<p xml:lang="el">Διασκεδάστε ζωγραφίζοντας με τις προηγμένες μηχανές πινέλων, με εκπληκτικά φίλτρα και πολλά εύκολης χρήσης χαρακτηριστικά που παρέχουν στο Krita εξαιρετικά αυξημένη παραγωγικότητα.</p>
<p xml:lang="en-GB">Have fun painting with the advanced brush engines, amazing filters and many handy features that make Krita enormously productive.</p>
<p xml:lang="es">Diviértase pintando con los avanzados motores de pinceles, los espectaculares filtros y muchas funcionalidades prácticas que hacen que Krita sea enormemente productivo.</p>
<p xml:lang="et">Joonistamise muudavad tunduvalt lõbusamaks võimsad pintslimootorid, imetabased filtrid ja veel paljud käepärased võimalused, mis muudavad Krita kasutaja tohutult tootlikuks.</p>
<p xml:lang="eu">Marrazten ondo pasa ezazu, isipu motor aurreratuekin, iragazki txundigarriekin eta eginbide praktiko ugariekin, zeintzuek Krita ikaragarri emankorra egiten duten.</p>
<p xml:lang="fi">Pidä hauskaa maalatessasi edistyneillä sivellinmoottoreilla, hämmästyttävillä suotimilla ja monilla muilla kätevillä ominaisuuksilla, jotka tekevät Kritasta tavattoman tehokkaan.</p>
<p xml:lang="fr">Amusez-vous à peindre avec les outils de brosse avancés, les filtres incroyables et les nombreuses fonctionnalités pratiques qui rendent Krita extrêmement productif.</p>
<p xml:lang="gl">Goza debuxando con motores de pincel avanzados, filtros fantásticos e moitas outras funcionalidades útiles que fan de Krita un programa extremadamente produtivo.</p>
<p xml:lang="ia">Amusa te a pinger con le motores de pincel avantiate, filtros stupende e multe characteristicas amical que face Krita enormemente productive.</p>
<p xml:lang="id">Bersenang-senanglah melukis dengan mesin kuas canggih, filter luar biasa dan banyak fitur berguna yang membuat Krita sangat produktif.</p>
<p xml:lang="it">Divertiti a dipingere con gli avanzati sistemi di pennelli, i sorprendenti filtri e molte altre utili caratteristiche che fanno di Krita un software enormemente produttivo.</p>
<p xml:lang="ja">Krita のソフトウェアとしての生産性を高めている先進的なブラシエンジンや素晴らしいフィルタのほか、便利な機能の数々をお楽しみください。</p>
<p xml:lang="ko">Krita의 고급 브러시 엔진, 다양한 필터, 여러 도움이 되는 기능으로 생산성을 즐겁게 향상시킬 수 있습니다.</p>
<p xml:lang="nl">Veel plezier met schilderen met the geavanceerde penseel-engines, filters vol verbazing en vele handige mogelijkheden die maken dat Krita enorm productief is.</p>
<p xml:lang="nn">Leik deg med avanserte penselmotorar og fantastiske biletfilter – og mange andre nyttige funksjonar som gjer deg produktiv med Krita.</p>
<p xml:lang="pl">Baw się przy malowaniu przy użyciu zaawansowanych silników pędzli, zadziwiających filtrów i wielu innych przydatnych cech, które czynią z Krity bardzo produktywną.</p>
<p xml:lang="pt">Divirta-se a pintar com os motores de pincéis avançados, os filtros espantosos e muitas outras funcionalidades úteis que tornam o Krita altamente produtivo.</p>
<p xml:lang="pt-BR">Divirta-se pintando com os mecanismos de pincéis avançados, filtros maravilhosos e muitas outras funcionalidades úteis que tornam o Krita altamente produtivo.</p>
<p xml:lang="ru">Получайте удовольствие от использования особых кистевых движков, впечатляющих фильтров и множества других функций, делающих Krita сверхпродуктивной.</p>
<p xml:lang="sk">Užívajte si maľovanie s pokročilými kresliacimi enginmi, úžasnými filtrami a mnohými užitočnými funkciami, ktoré robia Kritu veľmi produktívnu.</p>
<p xml:lang="sv">Ha det så kul vid målning med de avancerade penselfunktionerna, fantastiska filtren och många praktiska funktioner som gör Krita så enormt produktiv.</p>
<p xml:lang="tr">Gelişmiş fırça motorları, şaşırtıcı filtreler ve Krita'yı son derece üretken yapan bir çok kullanışlı özellikli boya ile iyi eğlenceler.</p>
<p xml:lang="uk">Отримуйте задоволення від малювання за допомогою пензлів з найширшими можливостями, чудових фільтрів та багатьох зручних можливостей, які роблять Krita надзвичайно продуктивним засобом малювання.</p>
<p xml:lang="x-test">xxHave fun painting with the advanced brush engines, amazing filters and many handy features that make Krita enormously productive.xx</p>
<p xml:lang="zh-CN">Krita 具有功能强大的笔刷引擎、种类繁多的滤镜以及便于操作的交互设计,可让你尽情、高效地挥洒无限创意。</p>
<p xml:lang="zh-TW">使用先進的筆刷引擎、驚人的濾鏡和許多方便的功能來開心地繪畫,讓 Krita 擁有巨大的生產力。</p>
</description>
<url type="homepage">https://www.krita.org/</url>
<url type="faq">https://docs.krita.org/KritaFAQ.html</url>
<url type="donation">https://krita.org/support-us/donations/</url>
<url type="help">https://docs.krita.org/</url>
<url type="bugtracker">https://docs.krita.org/en/untranslatable_pages/reporting_bugs.html</url>
<screenshots>
<screenshot type="default">
<caption>Krita is a full-featured digital painting studio</caption>
<caption xml:lang="ca">El Krita és un estudi de pintura digital ple de funcionalitats</caption>
<caption xml:lang="ca-valencia">El Krita és un estudi de pintura digital ple de funcionalitats</caption>
<caption xml:lang="en-GB">Krita is a full-featured digital painting studio</caption>
<caption xml:lang="es">Krita es un completo estudio de dibujo digital</caption>
<caption xml:lang="et">Krita on rohkete võimalustega digitaalkunstistuudio</caption>
<caption xml:lang="eu">Krita pintura-digital lantegi osoa bat da</caption>
+ <caption xml:lang="fr">Krita est un studio d'art numérique complet.</caption>
<caption xml:lang="it">Krita è uno studio d'arte digitale completo</caption>
<caption xml:lang="ko">Krita는 다기능 디지털 예술 스튜디오입니다</caption>
<caption xml:lang="nl">Krita is een digitale schilderstudio vol mogelijkheden</caption>
<caption xml:lang="nn">Krita er ei funksjonsrik digital teiknestove.</caption>
<caption xml:lang="pt">O Krita é um estúdio de arte digital completo</caption>
<caption xml:lang="pt-BR">O Krita é um estúdio de pintura digital completo</caption>
<caption xml:lang="sv">Krita är en fullfjädrad digital konststudio</caption>
<caption xml:lang="uk">Krita — повноцінний комплекс для цифрового малювання</caption>
<caption xml:lang="x-test">xxKrita is a full-featured digital painting studioxx</caption>
<caption xml:lang="zh-CN">Krita 是一款功能齐全的数字绘画软件。</caption>
<caption xml:lang="zh-TW">Krita 是全功能的數位繪圖工作室</caption>
<image>https://cdn.kde.org/screenshots/krita/2018-03-17_screenshot_001.png</image>
</screenshot>
<screenshot type="default">
<caption>The startup window now also gives you the latest news about Krita</caption>
<caption xml:lang="ca">La finestra d'inici també ofereix les últimes notícies sobre el Krita</caption>
<caption xml:lang="ca-valencia">La finestra d'inici també ofereix les últimes notícies sobre el Krita</caption>
<caption xml:lang="en-GB">The startup window now also gives you the latest news about Krita</caption>
<caption xml:lang="es">La ventana de bienvenida también le proporciona ahora las últimas noticias sobre Krita</caption>
<caption xml:lang="et">Käivitusaken jagab nüüd ka Krita värskemaid uudiseid</caption>
<caption xml:lang="eu">Abioko leihoak orain Krita-ri buruzko albiste berrienak ematen dizkizu</caption>
+ <caption xml:lang="fr">Maintenant, la fenêtre de démarrage vous donne aussi les dernières informations concernant Krita</caption>
<caption xml:lang="it">La finestra di avvio ora fornisce anche le ultime novità su Krita</caption>
<caption xml:lang="ko">시작 창에서 Krita의 최신 소식을 볼 수 있습니다</caption>
<caption xml:lang="nl">Het opstartvenster geeft u nu ook you het laatste nieuws over Krita</caption>
<caption xml:lang="nn">Oppstartsvindauget viser no siste nytt om Krita.</caption>
<caption xml:lang="pt">A janela inicial agora também lhe dá as últimas notícias sobre o Krita</caption>
<caption xml:lang="pt-BR">A janela de inicialização agora também mostra as últimas notícias sobre o Krita</caption>
<caption xml:lang="sv">Startfönstret ger nu också senaste nytt om Krita</caption>
<caption xml:lang="uk">У початковому вікні програми ви можете бачити найсвіжіші новини щодо Krita</caption>
<caption xml:lang="x-test">xxThe startup window now also gives you the latest news about Kritaxx</caption>
<caption xml:lang="zh-CN">它的启动画面可以向你展示 Krita 的最新官方新闻。</caption>
<caption xml:lang="zh-TW">開始視窗也提供給您關於 Krita 的最新消息</caption>
<image>https://cdn.kde.org/screenshots/krita/2018-03-17_screenshot_002.png</image>
</screenshot>
<screenshot type="default">
<caption>There are over ten immensely powerful brush engines</caption>
<caption xml:lang="ca">Hi ha més de deu motors de pinzell immensament potents</caption>
<caption xml:lang="ca-valencia">Hi ha més de deu motors de pinzell immensament potents</caption>
<caption xml:lang="en-GB">There are over ten immensely powerful brush engines</caption>
<caption xml:lang="es">Existen unos diez inmensamente potentes motores de pinceles</caption>
<caption xml:lang="et">Üle kümne ääretult võimeka pintslimootori</caption>
<caption xml:lang="eu">Hamarretik gora isipu motor ikaragarri ahaltsu daude</caption>
+ <caption xml:lang="fr">Il y a plus de 10 moteurs de brosse, tous extrêmement puissants</caption>
<caption xml:lang="it">Ci sono oltre dieci motori di pennelli incredibilmente potenti</caption>
<caption xml:lang="ko">10가지 종류의 강력한 브러시 엔진을 사용할 수 있습니다</caption>
<caption xml:lang="nl">Er zijn meer dan tien immens krachtige penseelengines</caption>
<caption xml:lang="nn">Det finst meir enn ti enormt kraftige penselmotorar.</caption>
<caption xml:lang="pt">Existem mais de dez motores de pincéis extremamente poderosos</caption>
<caption xml:lang="pt-BR">Mais de dez engines de pincéis incrivelmente poderosos disponíveis</caption>
<caption xml:lang="sv">Det finns mer än tio enormt kraftfulla penselgränssnitt</caption>
<caption xml:lang="uk">У програмі передбачено понад десяток надзвичайно потужних рушіїв пензлів</caption>
<caption xml:lang="x-test">xxThere are over ten immensely powerful brush enginesxx</caption>
<caption xml:lang="zh-CN">它内建了超过十种功能强大的笔刷引擎。</caption>
<image>https://cdn.kde.org/screenshots/krita/2018-03-17_screenshot_003.png</image>
</screenshot>
<screenshot type="default">
<caption>Create and use gamut masks to give your images a coherent feel</caption>
<caption xml:lang="ca">Creeu i useu màscares de gamma per donar a les imatges una aparença coherent</caption>
<caption xml:lang="ca-valencia">Creeu i useu màscares de gamma per donar a les imatges una aparença coherent</caption>
<caption xml:lang="en-GB">Create and use gamut masks to give your images a coherent feel</caption>
<caption xml:lang="es">Cree y use gamas para proporcionar a sus imágenes un aspecto coherente</caption>
<caption xml:lang="et">Värviulatuse maskide loomine ja kasutamine piltidele kooskõlalise välimuse andmiseks</caption>
<caption xml:lang="eu">Sortu eta erabili gama-maskarak zure irudiei izaera koherentea emateko</caption>
+ <caption xml:lang="fr">Créer et utiiser les masques de Gamut pour donner à vos images une apparence cohérente</caption>
<caption xml:lang="it">Crea e utilizza maschere gamut per dare alle tue immagini un aspetto coerente</caption>
<caption xml:lang="ko">색역 마스크를 만들고 사용할 수 있습니다</caption>
<caption xml:lang="nl">Maak en gebruik gamut-maskers om uw afbeeldingen een coherent gevoel te geven</caption>
<caption xml:lang="nn">Bruk fargeområde-masker for å gje bileta eit heilsleg uttrykk.</caption>
<caption xml:lang="pt">Crie e use máscaras de gamute para dar às suas imagens uma aparência coerente</caption>
<caption xml:lang="pt-BR">Crie e use máscaras de gama para dar um senso de coerência às suas imagens</caption>
<caption xml:lang="sv">Att skapa och använda färgomfångsmasker ger bilder en sammanhängande känsla</caption>
<caption xml:lang="uk">Створюйте маски палітри і користуйтеся ними для надання вашим малюнкам однорідного вигляду</caption>
<caption xml:lang="x-test">xxCreate and use gamut masks to give your images a coherent feelxx</caption>
<caption xml:lang="zh-CN">它支持建立并使用色域蒙版,让图像的颜色选用更有条理。</caption>
<image>https://cdn.kde.org/screenshots/krita/2018-03-17_screenshot_004.png</image>
</screenshot>
<screenshot type="default">
<caption>Into animation? Krita provides everything you need for traditional, hand-drawn animation</caption>
<caption xml:lang="ca">Esteu amb animacions? El Krita proporciona tot el que cal per a l'animació a mà tradicional</caption>
<caption xml:lang="ca-valencia">Esteu amb animacions? El Krita proporciona tot el que cal per a l'animació a mà tradicional</caption>
<caption xml:lang="en-GB">Into animation? Krita provides everything you need for traditional, hand-drawn animation</caption>
<caption xml:lang="es">¿Trabaja con animación? Krita proporciona todo lo necesario para la animación manual tradicional</caption>
<caption xml:lang="et">Sind huvitab animatsioon? Krita pakub kõike, mida läheb tarvis traditsioonilise käsitsi loodud animatsiooni jaoks</caption>
<caption xml:lang="eu">Animaziorako? Krita-k ohiko eskuz-marraztutako animazioetarako behar duzun guztia dakar</caption>
+ <caption xml:lang="fr">Vous réalisez des animations ? Krita vous fournit tout ce dont vous avez besoin pour l'animation traditionnelle et dessinée à la main</caption>
<caption xml:lang="it">Per le animazioni? Krita fornisce tutto ciò che ti server per l'animazione tradizionale, disegnata a mano</caption>
<caption xml:lang="ko">애니메이션을 만들 계획이 있으신가요? Krita를 통해서 수작업 애니메이션을 작업할 수 있습니다</caption>
<caption xml:lang="nl">Naar animatie? Krita biedt alles wat u nodig hebt voor traditionele, met de hand getekende animatie</caption>
<caption xml:lang="nn">Interessert i animasjon? Krita har alt du treng for tradisjonelle, handteikna animasjonar.</caption>
<caption xml:lang="pt">Gosta de animação? O Krita oferece tudo o que precisa para o desenho animado tradicional e desenhado à mão</caption>
<caption xml:lang="pt-BR">Curte animação? O Krita fornece tudo necessário para você poder trabalhar com animação tradicional ou feita à mão</caption>
<caption xml:lang="sv">Gillar du animering? Krita tillhandahåller allt som behövs för traditionella, handritade animeringar</caption>
<caption xml:lang="uk">Працюєте із анімацією? У Krita ви знайдете усе, що потрібно для створення традиційної, намальованої вручну анімації</caption>
<caption xml:lang="x-test">xxInto animation? Krita provides everything you need for traditional, hand-drawn animationxx</caption>
<caption xml:lang="zh-CN">Krita 还提供了手绘动画制作所需的全套工具和面板。</caption>
<caption xml:lang="zh-TW">想做動畫?Krita 提供您在傳統、手繪動畫所需的任何東西</caption>
<image>https://cdn.kde.org/screenshots/krita/2018-03-17_screenshot_005.png</image>
</screenshot>
<screenshot type="default">
<caption>If you're new to digital painting, there's an extensive, up-to-date manual</caption>
<caption xml:lang="ca">Si sou nou a la pintura digital, hi ha un manual extens i actualitzat</caption>
<caption xml:lang="ca-valencia">Si sou nou a la pintura digital, hi ha un manual extens i actualitzat</caption>
<caption xml:lang="en-GB">If you're new to digital painting, there's an extensive, up-to-date manual</caption>
<caption xml:lang="es">Si está empezando con el dibujo digital, dispone de un extenso y actualizado manual</caption>
<caption xml:lang="et">Kui oled digitaalkunstis alles uustulnuk, on meil välja pakkuda mahukas ajakohane käsiraamat</caption>
<caption xml:lang="eu">Pintura digitalean berria bazara, gaurkotutako eskuliburu zabal bat dago</caption>
+ <caption xml:lang="fr">Si vous êtes nouveau en art graphique, il y a un manuel à jour et très fourni</caption>
<caption xml:lang="it">Se sei nuovo del disegno digitale è disponibile un manuale completo e aggiornato</caption>
<caption xml:lang="ko">디지털 페인팅을 처음 시작하시거나, Krita의 기능을 더 알아 보려면 사용 설명서를 참조하십시오</caption>
<caption xml:lang="nl">Als u nieuw bent in digitaal schilderen, dan is er een uitgebreide, bijgewerkte handleiding.</caption>
<caption xml:lang="nn">Viss du er nybegynnar innan digital teikning, finst det ei omfattande og oppdatert brukarhandbok.</caption>
<caption xml:lang="pt">Se é novo na pintura digital, ou deseja saber mais sobre as possibilidades do Krita, existe um manual extenso e actualizado</caption>
<caption xml:lang="pt-BR">Se você for iniciante em pintura digital, há um extenso e atualizado manual</caption>
<caption xml:lang="sv">Om digital målning är nytt för dig, finns en omfattande, aktuell handbok</caption>
<caption xml:lang="uk">Якщо ви не маєте достатнього досвіду у цифровому малюванні, скористайтеся нашим докладним і актуальним підручником</caption>
<caption xml:lang="x-test">xxIf you're new to digital painting, there's an extensive, up-to-date manualxx</caption>
<caption xml:lang="zh-CN">如果你是数字绘画的初学者,我们还准备了内容详尽,及时更新的使用手册。</caption>
<image>https://cdn.kde.org/screenshots/krita/2018-03-17_screenshot_006.png</image>
</screenshot>
</screenshots>
<categories>
<category>Graphics</category>
<category>2DGraphics</category>
<category>RasterGraphics</category>
</categories>
<project_group>KDE</project_group>
<provides>
<binary>krita</binary>
<id>org.kde.krita.desktop</id>
</provides>
<content_rating type="oars-1.1"/>
<releases>
<!-- Note: website infrastructure uses the appstream file from the master branch
to determine the last release, so this entry must always reflect the
last actual release -->
<release date="2020-03-26" version="4.2.9.0">
<url>https://krita.org/en/item/krita-4-2-9-released/</url>
<artifacts>
<artifact type="binary" platform="x86_64-appimage">
<location>https://download.kde.org/stable/krita/4.2.9/krita-4.2.9-x86_64.appimage</location>
<checksum type="sha256">4b23574456338b4f5e2d7e6ba66ca5dce2d6924468fe6613bc468674ebec77d4</checksum>
<size type="download">207515688</size>
<bundle type="appimage">krita-4.2-9</bundle>
</artifact>
<artifact type="binary" platform="x86_64-appimage">
<location>https://download.kde.org/stable/krita/4.2.9/gmic_krita_qt-x86_64.appimage</location>
<checksum type="sha256">5182b77ff35de7d9aa850ffbe6fd953b2eb7c20d39cf56302a938cab9c2497a0</checksum>
<size type="download">32002088</size>
<bundle type="appimage">gmic_krita_qt-4.2-9</bundle>
</artifact>
<artifact type="binary" platform="macOS">
<location>https://download.kde.org/stable/krita/4.2.9/krita-4.2.9.dmg</location>
<checksum type="sha256">34b606dcdbdf1c3702cebc924b9c11e1c9181ca6a9d5fa91e605bbfca554df9b</checksum>
<size type="download">195113969</size>
</artifact>
<artifact type="binary" platform="win64">
<location>https://download.kde.org/stable/krita/4.2.9/krita-x64-4.2.9-setup.exe</location>
<checksum type="sha256">fd8345a4d4170c62e410f8cfe1547bb811eb312de953a540b3bf12bb79137b9f</checksum>
<size type="download">110753224</size>
</artifact>
<artifact type="binary" platform="win32">
<location>https://download.kde.org/stable/krita/4.2.9/krita-x86-4.2.9-setup.exe</location>
<checksum type="sha256">c8efe945804ec9f08f019853c60895e390edfeb03bde13874b4d05231c03261d</checksum>
<size type="download">110315944</size>
</artifact>
<artifact type="source">
<location>https://download.kde.org/stable/krita/4.2.9/krita-4.2.9.tar.xz</location>
<checksum type="sha256">4ef711887dd3ec5f2a1c42a80f2fd0fec1de0d4f3d0147b0efd418ac6e4d7567</checksum>
<size type="download">170082028</size>
</artifact>
</artifacts>
</release>
<release date="2019-11-27" version="4.2.8.0">
<url>https://krita.org/en/item/krita-4-2-8-released/</url>
<artifacts>
<artifact type="binary" platform="x86_64-linux-gnu">
<location>https://download.kde.org/stable/krita/4.2.8/krita-4.2.8-x86_64.appimage</location>
<checksum type="sha256">4b23574456338b4f5e2d7e6ba66ca5dce2d6924468fe6613bc468674ebec77d4</checksum>
<size type="download">207515688</size>
<bundle type="appimage">krita-4.2-8</bundle>
</artifact>
<artifact type="binary" platform="x86_64-linux-gnu">
<location>https://download.kde.org/stable/krita/4.2.8/gmic_krita_qt-x86_64.appimage</location>
<checksum type="sha256">e48ac43f86a22b7015ee2dc5ce4f35a72f22070150d926553ab0aafc8616a08f</checksum>
<size type="download">32944104</size>
<bundle type="appimage">gmic_krita_qt-4.2-8</bundle>
</artifact>
<artifact type="binary" platform="macOS">
<location>https://download.kde.org/stable/krita/4.2.9/krita-4.2.9.dmg</location>
<checksum type="sha256">34b606dcdbdf1c3702cebc924b9c11e1c9181ca6a9d5fa91e605bbfca554df9b</checksum>
<size type="download">195113969</size>
</artifact>
<artifact type="binary" platform="win64">
<location>https://download.kde.org/stable/krita/4.2.8/krita-x64-4.2.8-setup.exe</location>
<checksum type="sha256">dca15dad13684622ae2704d77b34f0662bc109b7b6e3e7393a549b6418fcd419</checksum>
<size type="download">109267000</size>
</artifact>
<artifact type="binary" platform="win32">
<location>https://download.kde.org/stable/krita/4.2.8/krita-x86-4.2.8-setup.exe</location>
<checksum type="sha256">94fbdee4a923682fd64c0010b17ebd002e52de8f2ae239e611f3bda60d8abdee</checksum>
<size type="download">107842760</size>
</artifact>
<artifact type="source">
<location>https://download.kde.org/stable/krita/4.2.8/krita-4.2.8.2.tar.xz</location>
<checksum type="sha256">1c3bb8a28ef8f7945e5f21f9ad87e01d8b831eea3487ff92742c930f3b7f744a</checksum>
<size type="download">169994064</size>
</artifact>
</artifacts>
</release>
<release date="2019-03-10" version="4.2.7.1">
<url>https://krita.org/en/item/krita-4-2-7-released/</url>
<artifacts>
<artifact type="binary" platform="x86_64-linux-gnu">
<location>https://download.kde.org/stable/krita/4.2.7.1/krita-4.2.7.1b-x86_64.appimage</location>
<checksum type="sha256">ddaeb8e02bad9d09fd3fc2d4ecf7ee677c3786cb13bb8e50eeaebf00e573f2d9</checksum>
<size type="download">192188392</size>
<bundle type="appimage">krita-4.2-7-1</bundle>
</artifact>
<artifact type="binary" platform="x86_64-linux-gnu">
<location>https://download.kde.org/stable/krita/4.2.7.1/gmic_krita_qt-x86_64.appimage</location>
<checksum type="sha256">ea6e151399e850feb6e177ab52a40b32d9070888339f0c35c92ceff17816cae1</checksum>
<size type="download">32968680</size>
<bundle type="appimage">gmic_krita_qt-4-2-7-1</bundle>
</artifact>
<artifact type="binary" platform="macOS">
<location>https://download.kde.org/stable/krita/4.2.7.1/krita-4.2.7.1.dmg</location>
<checksum type="sha256">eca62444e27ed51b177e75e9e674d726285e58483b41a37fa2b0d0ad2a8b34ba</checksum>
<size type="download">173627205</size>
</artifact>
<artifact type="binary" platform="win64">
<location>https://download.kde.org/stable/krita/4.2.7.1/krita-x64-4.2.7.1-setup.exe</location>
<checksum type="sha256">31538a959e7b271cf7c166f4e1e6162e5958e9b54055c4ecb1f50335fab2f01f</checksum>
<size type="download">109190240</size>
</artifact>
<artifact type="binary" platform="win32">
<location>https://download.kde.org/stable/krita/4.2.8/krita-x86-4.2.8-setup.exe</location>
<checksum type="sha256">3cb92f77e0913a20e2e02a0ba953460a7e39ad0e7a24b9530fc707f6808e8fec</checksum>
<size type="download">107846008</size>
</artifact>
</artifacts>
</release>
</releases>
<custom>
<value key="KDE::windows_store">https://www.microsoft.com/store/apps/9n6x57zgrw96</value>
</custom>
</component>
diff --git a/krita/pics/svg/dark_python.svg b/krita/pics/svg/dark_python.svg
new file mode 100644
index 0000000000..72fbb7f2e9
--- /dev/null
+++ b/krita/pics/svg/dark_python.svg
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="../light_animation_play.png"
+ sodipodi:docname="dark_python.svg"
+ inkscape:version="1.0 (6e3e5246a0, 2020-05-07)"
+ id="svg6190"
+ height="22"
+ width="22"
+ version="1.1">
+ <sodipodi:namedview
+ inkscape:document-rotation="0"
+ inkscape:snap-bbox-edge-midpoints="true"
+ inkscape:snap-bbox="true"
+ inkscape:current-layer="svg6190"
+ inkscape:window-maximized="1"
+ inkscape:window-y="34"
+ inkscape:window-x="72"
+ inkscape:cy="11.8982"
+ inkscape:cx="11.405336"
+ inkscape:zoom="60.68262"
+ showgrid="true"
+ id="namedview4440"
+ inkscape:window-height="2089"
+ inkscape:window-width="3768"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0"
+ guidetolerance="10"
+ gridtolerance="10"
+ objecttolerance="10"
+ borderopacity="1"
+ bordercolor="#666666"
+ pagecolor="#ffffff">
+ <inkscape:grid
+ id="grid3250"
+ type="xygrid" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata6196">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <dc:date>2015</dc:date>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Timothée Giet</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Reproduction" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Distribution" />
+ <cc:requires
+ rdf:resource="http://creativecommons.org/ns#Notice" />
+ <cc:requires
+ rdf:resource="http://creativecommons.org/ns#Attribution" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://creativecommons.org/ns#ShareAlike" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs6194" />
+ <path
+ id="rect12"
+ style="fill:#373737;fill-opacity:1;stroke-width:0.476881"
+ d="m 10.986152,1.693434 c -2.6419309,0 -4.76881,1.0634398 -4.76881,2.384405 v 1.8800632 l 4.775026,0.018807 -0.02007,0.4855411 H 3.8329364 c -1.3209646,0 -2.3844046,2.1268795 -2.3844046,4.7688107 0,2.64193 1.06344,4.768807 2.3844046,4.768807 H 5.740476 c 0,-1.202141 0.073615,-2.11196 0.2493316,-2.814832 0.1757184,-0.702869 0.4624441,-1.207361 0.8834493,-1.544166 0.8420075,-0.673609 2.0861095,-0.648122 3.8744201,-0.648122 2.026753,0 3.295721,-0.02708 4.000898,-0.54943 0.352588,-0.261178 0.598255,-0.647959 0.764449,-1.2844437 0.166191,-0.6364857 0.241854,-1.5141935 0.241854,-2.6964645 h 0.477103 c 0,1.20214 -0.07358,2.1122133 -0.257597,2.8169592 -0.184017,0.704746 -0.489618,1.212152 -0.941767,1.547076 -0.904303,0.669857 -2.258187,0.643087 -4.28494,0.643087 -1.7883106,0 -2.9284363,0.02515 -3.576684,0.543764 -0.3241261,0.259298 -0.5590533,0.649069 -0.7186428,1.287433 -0.1595922,0.638363 -0.235011,1.516868 -0.235011,2.699139 v 2.384408 c 0,1.320962 2.1268792,2.38448 4.7688108,2.38448 2.64193,0 4.768806,-1.063518 4.768806,-2.38448 V 16.48521 L 11,16.486113 V 16 h 7.13944 c 1.320967,0 2.384407,-2.126876 2.384407,-4.768807 0,-2.6419306 -1.06344,-4.7688101 -2.384404,-4.7688101 h -2.384484 v -2.384393 c 0,-1.3209653 -2.126876,-2.384405 -4.768807,-2.384405 z M 8.356901,3.1955696 c 0.00212,-6.1e-6 0.00424,-6.1e-6 0.00635,0 0.4872707,-1.8e-5 0.8822873,0.3949981 0.8822689,0.8822694 C 9.2454991,4.5650773 8.8504954,4.9600453 8.3632542,4.9600273 7.8760462,4.9600031 7.4810895,4.5650472 7.4810655,4.077839 7.4810361,3.5930773 7.8721311,3.1990993 8.3568807,3.1955696 Z m 5.245674,14.3065094 c 0.0021,-9e-6 0.0043,-9e-6 0.0064,0 0.487208,2.4e-5 0.882165,0.394977 0.882189,0.882188 1.7e-5,0.487238 -0.394951,0.882242 -0.882189,0.882266 -0.487272,2.1e-5 -0.882287,-0.394995 -0.882266,-0.882266 9e-6,-0.484732 0.391095,-0.878662 0.875811,-0.882188 z"
+ sodipodi:nodetypes="sscccssscsssssccscssssssscccssscsssccccssscsscss" />
+</svg>
diff --git a/krita/pics/svg/light_python.svg b/krita/pics/svg/light_python.svg
new file mode 100644
index 0000000000..9617a92a0c
--- /dev/null
+++ b/krita/pics/svg/light_python.svg
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="22"
+ height="22"
+ id="svg6190"
+ inkscape:version="1.0 (6e3e5246a0, 2020-05-07)"
+ sodipodi:docname="light_python.svg"
+ inkscape:export-filename="../light_animation_play.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="2275"
+ inkscape:window-height="1644"
+ id="namedview4440"
+ showgrid="true"
+ inkscape:zoom="60.68262"
+ inkscape:cx="14.741948"
+ inkscape:cy="11.084622"
+ inkscape:window-x="1178"
+ inkscape:window-y="101"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg6190"
+ inkscape:snap-bbox="true"
+ inkscape:snap-bbox-edge-midpoints="true"
+ inkscape:document-rotation="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid3250" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata6196">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <dc:date>2015</dc:date>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Timothée Giet</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Reproduction" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Distribution" />
+ <cc:requires
+ rdf:resource="http://creativecommons.org/ns#Notice" />
+ <cc:requires
+ rdf:resource="http://creativecommons.org/ns#Attribution" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://creativecommons.org/ns#ShareAlike" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs6194" />
+ <path
+ sodipodi:nodetypes="sscccssscsssssccscssssssscccssscsssccccssscsscss"
+ d="m 10.986152,1.693434 c -2.6419309,0 -4.76881,1.0634398 -4.76881,2.384405 v 1.8800632 l 4.775026,0.018807 -0.02007,0.4855411 H 3.8329364 c -1.3209646,0 -2.3844046,2.1268795 -2.3844046,4.7688107 0,2.64193 1.06344,4.768807 2.3844046,4.768807 H 5.740476 c 0,-1.202141 0.073615,-2.11196 0.2493316,-2.814832 0.1757184,-0.702869 0.4624441,-1.207361 0.8834493,-1.544166 0.8420075,-0.673609 2.0861095,-0.648122 3.8744201,-0.648122 2.026753,0 3.295721,-0.02708 4.000898,-0.54943 0.352588,-0.261178 0.598255,-0.647959 0.764449,-1.2844437 0.166191,-0.6364857 0.241854,-1.5141935 0.241854,-2.6964645 h 0.477103 c 0,1.20214 -0.07358,2.1122133 -0.257597,2.8169592 -0.184017,0.704746 -0.489618,1.212152 -0.941767,1.547076 -0.904303,0.669857 -2.258187,0.643087 -4.28494,0.643087 -1.7883106,0 -2.9284363,0.02515 -3.576684,0.543764 -0.3241261,0.259298 -0.5590533,0.649069 -0.7186428,1.287433 -0.1595922,0.638363 -0.235011,1.516868 -0.235011,2.699139 v 2.384408 c 0,1.320962 2.1268792,2.38448 4.7688108,2.38448 2.64193,0 4.768806,-1.063518 4.768806,-2.38448 V 16.48521 L 11,16.486113 V 16 h 7.13944 c 1.320967,0 2.384407,-2.126876 2.384407,-4.768807 0,-2.6419306 -1.06344,-4.7688101 -2.384404,-4.7688101 h -2.384484 v -2.384393 c 0,-1.3209653 -2.126876,-2.384405 -4.768807,-2.384405 z M 8.356901,3.1955696 c 0.00212,-6.1e-6 0.00424,-6.1e-6 0.00635,0 0.4872707,-1.8e-5 0.8822873,0.3949981 0.8822689,0.8822694 C 9.2454991,4.5650773 8.8504954,4.9600453 8.3632542,4.9600273 7.8760462,4.9600031 7.4810895,4.5650472 7.4810655,4.077839 7.4810361,3.5930773 7.8721311,3.1990993 8.3568807,3.1955696 Z m 5.245674,14.3065094 c 0.0021,-9e-6 0.0043,-9e-6 0.0064,0 0.487208,2.4e-5 0.882165,0.394977 0.882189,0.882188 1.7e-5,0.487238 -0.394951,0.882242 -0.882189,0.882266 -0.487272,2.1e-5 -0.882287,-0.394995 -0.882266,-0.882266 9e-6,-0.484732 0.391095,-0.878662 0.875811,-0.882188 z"
+ style="fill:#cacaca;fill-opacity:1;stroke-width:0.476881"
+ id="rect12" />
+ <g
+ inkscape:label="Capa 1"
+ id="layer1"
+ transform="translate(-19.784894,-1031.1484)" />
+</svg>
diff --git a/krita/pics/svg/svg-icons.qrc b/krita/pics/svg/svg-icons.qrc
index 13f02593e8..3efa01283a 100644
--- a/krita/pics/svg/svg-icons.qrc
+++ b/krita/pics/svg/svg-icons.qrc
@@ -1,159 +1,161 @@
<RCC>
<qresource prefix="/">
<file>broken-preset.svgz</file>
<file>dark_addblankframe.svg</file>
<file>dark_addcolor.svg</file>
<file>dark_addduplicateframe.svg</file>
<file>dark_deletekeyframe.svg</file>
<file>dark_docker_lock_a.svg</file>
<file>dark_docker_lock_b.svg</file>
<file>dark_layer-locked.svg</file>
<file>dark_layer-unlocked.svg</file>
<file>dark_nextframe.svg</file>
<file>dark_nextkeyframe.svg</file>
<file>dark_lastframe.svg</file>
<file>dark_prevkeyframe.svg</file>
<file>dark_firstframe.svg</file>
<file>dark_pallete_librarysvg.svg</file>
<file>dark_passthrough-disabled.svg</file>
<file>dark_passthrough-enabled.svg</file>
<file>dark_prevframe.svg</file>
<file>dark_selection-mode_ants.svg</file>
<file>dark_selection-mode_invisible.svg</file>
<file>dark_selection-mode_mask.svg</file>
<file>dark_transparency-disabled.svg</file>
<file>dark_transparency-enabled.svg</file>
<file>dark_trim-to-image.svg</file>
<file>dark_warning.svg</file>
<file>delete.svgz</file>
<file>layer-style-disabled.svg</file>
<file>layer-style-enabled.svg</file>
<file>light_addblankframe.svg</file>
<file>light_addcolor.svg</file>
<file>light_addduplicateframe.svg</file>
<file>light_deletekeyframe.svg</file>
<file>light_docker_lock_a.svg</file>
<file>light_docker_lock_b.svg</file>
<file>light_layer-locked.svg</file>
<file>light_layer-unlocked.svg</file>
<file>light_nextframe.svg</file>
<file>light_pallete_library.svg</file>
<file>light_passthrough-disabled.svgz</file>
<file>light_passthrough-enabled.svgz</file>
<file>light_prevframe.svg</file>
<file>light_nextkeyframe.svg</file>
<file>light_lastframe.svg</file>
<file>light_prevkeyframe.svg</file>
<file>light_firstframe.svg</file>
<file>light_selection-mode_ants.svg</file>
<file>light_selection-mode_invisible.svg</file>
<file>light_selection-mode_mask.svg</file>
<file>light_timeline_keyframe.svg</file>
<file>light_transparency-disabled.svg</file>
<file>light_transparency-enabled.svg</file>
<file>light_trim-to-image.svg</file>
<file>light_warning.svg</file>
<file>paintop_presets_disabled.svgz</file>
<file>paintop_settings_01.svgz</file>
<file>selection-info.svg</file>
<file>selection-mode_invisible.svg</file>
<file>svg-icons.qrc</file>
<file>transparency-locked.svg</file>
<file>transparency-unlocked.svg</file>
<file>workspace-chooser.svg</file>
<file>light_lazyframeOn.svg</file>
<file>light_lazyframeOff.svg</file>
<file>dark_lazyframeOn.svg</file>
<file>dark_lazyframeOff.svg</file>
<file>dark_mirror-view.svg</file>
<file>light_mirror-view.svg</file>
<file>dark_rotation-reset.svg</file>
<file>light_rotation-reset.svg</file>
<file>light_smoothing-basic.svg</file>
<file>light_smoothing-no.svg</file>
<file>light_smoothing-stabilizer.svg</file>
<file>light_smoothing-weighted.svg</file>
<file>dark_smoothing-basic.svg</file>
<file>dark_smoothing-no.svg</file>
<file>dark_smoothing-stabilizer.svg</file>
<file>dark_smoothing-weighted.svg</file>
<file>light_merge-layer-below.svg</file>
<file>dark_merge-layer-below.svg</file>
<file>light_rotate-canvas-left.svg</file>
<file>light_rotate-canvas-right.svg</file>
<file>dark_rotate-canvas-left.svg</file>
<file>dark_rotate-canvas-right.svg</file>
<file>light_gmic.svg</file>
<file>dark_gmic.svg</file>
<file>light_split-layer.svg</file>
<file>dark_split-layer.svg</file>
<file>light_color-to-alpha.svg</file>
<file>dark_color-to-alpha.svg</file>
<file>light_preset-switcher.svg</file>
<file>dark_preset-switcher.svg</file>
<file>dark_animation_play.svg</file>
<file>dark_animation_stop.svg</file>
<file>dark_dropframe.svg</file>
<file>dark_droppedframes.svg</file>
<file>light_animation_play.svg</file>
<file>light_animation_stop.svg</file>
<file>light_dropframe.svg</file>
<file>light_droppedframes.svg</file>
<file>dark_landscape.svg</file>
<file>dark_portrait.svg</file>
<file>light_landscape.svg</file>
<file>light_portrait.svg</file>
<file>dark_interpolation_constant.svg</file>
<file>dark_interpolation_linear.svg</file>
<file>dark_interpolation_bezier.svg</file>
<file>dark_interpolation_sharp.svg</file>
<file>dark_interpolation_smooth.svg</file>
<file>light_interpolation_bezier.svg</file>
<file>light_interpolation_constant.svg</file>
<file>light_interpolation_linear.svg</file>
<file>light_interpolation_sharp.svg</file>
<file>light_interpolation_smooth.svg</file>
<file>dark_audio-none.svg</file>
<file>dark_audio-volume-high.svg</file>
<file>dark_audio-volume-mute.svg</file>
<file>dark_keyframe-add.svg</file>
<file>dark_keyframe-remove.svg</file>
<file>dark_zoom-fit.svg</file>
<file>dark_zoom-horizontal.svg</file>
<file>dark_zoom-vertical.svg</file>
<file>light_audio-none.svg</file>
<file>light_audio-volume-high.svg</file>
<file>light_audio-volume-mute.svg</file>
<file>light_keyframe-add.svg</file>
<file>light_keyframe-remove.svg</file>
<file>light_zoom-fit.svg</file>
<file>light_zoom-horizontal.svg</file>
<file>light_zoom-vertical.svg</file>
<file>dark_showColoring.svg</file>
<file>dark_showMarks.svg</file>
<file>dark_showColoringOff.svg</file>
<file>dark_showMarksOff.svg</file>
<file>dark_updateColorize.svg</file>
<file>light_showColoring.svg</file>
<file>light_showMarks.svg</file>
<file>light_showColoringOff.svg</file>
<file>light_showMarksOff.svg</file>
<file>light_updateColorize.svg</file>
<file>light_wheel-light.svg</file>
<file>light_wheel-rings.svg</file>
<file>light_wheel-sectors.svg</file>
<file>dark_wheel-light.svg</file>
<file>dark_wheel-rings.svg</file>
<file>dark_wheel-sectors.svg</file>
<file>dark_infinity.svg</file>
<file>light_infinity.svg</file>
<file>dark_gamut-mask-on.svg</file>
<file>dark_gamut-mask-off.svg</file>
<file>light_gamut-mask-off.svg</file>
<file>light_gamut-mask-on.svg</file>
<file>dark_ratio.svg</file>
<file>light_ratio.svg</file>
<file>dark_bundle_archive.svg</file>
<file>light_bundle_archive.svg</file>
+ <file>dark_python.svg</file>
+ <file>light_python.svg</file>
</qresource>
</RCC>
diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt
index b9bb8ac7ef..f7ceccb84b 100644
--- a/libs/CMakeLists.txt
+++ b/libs/CMakeLists.txt
@@ -1,24 +1,23 @@
add_subdirectory( version )
add_subdirectory( global )
add_subdirectory( koplugin )
add_subdirectory( widgetutils )
add_subdirectory( widgets )
add_subdirectory( store )
-add_subdirectory( odf )
add_subdirectory( flake )
add_subdirectory( basicflakes )
add_subdirectory( pigment )
add_subdirectory( command )
add_subdirectory( brush )
add_subdirectory( psd )
add_subdirectory( color )
add_subdirectory( image )
add_subdirectory( ui )
add_subdirectory( impex )
add_subdirectory( libkis )
if (NOT APPLE AND HAVE_QT_QUICK)
add_subdirectory( libqml )
endif()
add_subdirectory( resources )
add_subdirectory( metadata )
add_subdirectory( resourcewidgets )
diff --git a/libs/command/kis_command_utils.cpp b/libs/command/kis_command_utils.cpp
index 5a78d82b83..d6224a87e5 100644
--- a/libs/command/kis_command_utils.cpp
+++ b/libs/command/kis_command_utils.cpp
@@ -1,207 +1,207 @@
/*
* Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_command_utils.h"
namespace KisCommandUtils
{
AggregateCommand::AggregateCommand(KUndo2Command *parent)
: KUndo2Command(parent),
m_firstRedo(true) {}
AggregateCommand::AggregateCommand(const KUndo2MagicString &text, KUndo2Command *parent)
: KUndo2Command(text, parent),
m_firstRedo(true) {}
void AggregateCommand::redo()
{
if (m_firstRedo) {
m_firstRedo = false;
populateChildCommands();
}
m_store.redoAll();
}
void AggregateCommand::undo()
{
m_store.undoAll();
}
void AggregateCommand::addCommand(KUndo2Command *cmd)
{
if (!cmd) return;
m_store.addCommand(cmd);
}
LambdaCommand::LambdaCommand(std::function<KUndo2Command*()> createCommandFunc)
: m_createCommandFunc(createCommandFunc)
{
}
LambdaCommand::LambdaCommand(const KUndo2MagicString &text,
std::function<KUndo2Command*()> createCommandFunc)
: AggregateCommand(text),
m_createCommandFunc(createCommandFunc)
{
}
LambdaCommand::LambdaCommand(const KUndo2MagicString &text,
KUndo2Command *parent,
std::function<KUndo2Command*()> createCommandFunc)
: AggregateCommand(text, parent),
m_createCommandFunc(createCommandFunc)
{
}
LambdaCommand::LambdaCommand(KUndo2Command *parent,
std::function<KUndo2Command*()> createCommandFunc)
: AggregateCommand(parent),
m_createCommandFunc(createCommandFunc)
{
}
void LambdaCommand::populateChildCommands()
{
if (m_createCommandFunc) {
addCommand(m_createCommandFunc());
}
}
SkipFirstRedoWrapper::SkipFirstRedoWrapper(KUndo2Command *child, KUndo2Command *parent)
: KUndo2Command(child ? child->text() : kundo2_noi18n("<bug: unnamed command>"), parent), m_firstRedo(true), m_child(child) {}
void SkipFirstRedoWrapper::redo()
{
if (m_firstRedo) {
m_firstRedo = false;
} else {
if (m_child) {
m_child->redo();
}
KUndo2Command::redo();
}
}
void SkipFirstRedoWrapper::undo()
{
KUndo2Command::undo();
if (m_child) {
m_child->undo();
}
}
SkipFirstRedoBase::SkipFirstRedoBase(bool skipFirstRedo, KUndo2Command *parent)
: KUndo2Command(parent),
m_firstRedo(skipFirstRedo)
{
}
SkipFirstRedoBase::SkipFirstRedoBase(bool skipFirstRedo, const KUndo2MagicString &text, KUndo2Command *parent)
: KUndo2Command(text, parent),
m_firstRedo(skipFirstRedo)
{
}
void SkipFirstRedoBase::redo()
{
if (m_firstRedo) {
m_firstRedo = false;
} else {
redoImpl();
KUndo2Command::redo();
}
}
void SkipFirstRedoBase::undo()
{
KUndo2Command::undo();
undoImpl();
}
void SkipFirstRedoBase::setSkipOneRedo(bool value)
{
m_firstRedo = value;
}
FlipFlopCommand::FlipFlopCommand(bool finalizing, KUndo2Command *parent)
: KUndo2Command(parent),
m_firstRedo(true)
{
m_currentState = finalizing ? State::FINALIZING : State::INITIALIZING;
}
FlipFlopCommand::FlipFlopCommand(State initialState, KUndo2Command *parent)
: KUndo2Command(parent),
m_currentState(initialState)
{}
void FlipFlopCommand::redo()
{
if (m_currentState == FlipFlopCommand::State::INITIALIZING) {
partA();
} else {
partB();
}
m_firstRedo = false;
}
void FlipFlopCommand::undo()
{
if (m_currentState == FlipFlopCommand::State::FINALIZING) {
partA();
} else {
partB();
}
}
void FlipFlopCommand::partA() {}
void FlipFlopCommand::partB() {}
CompositeCommand::CompositeCommand(KUndo2Command *parent)
: KUndo2Command(parent) {}
CompositeCommand::~CompositeCommand() {
qDeleteAll(m_commands);
}
void CompositeCommand::addCommand(KUndo2Command *cmd) {
if (cmd) {
m_commands << cmd;
}
}
void CompositeCommand::redo() {
KUndo2Command::redo();
Q_FOREACH (KUndo2Command *cmd, m_commands) {
cmd->redo();
}
}
void CompositeCommand::undo() {
KUndo2Command::undo();
- Q_FOREACH (KUndo2Command *cmd, m_commands) {
- cmd->undo();
+ for (auto it = m_commands.rbegin(); it != m_commands.rend(); ++it) {
+ (*it)->undo();
}
}
}
diff --git a/libs/flake/CMakeLists.txt b/libs/flake/CMakeLists.txt
index d1bec01e65..1793a0d3ef 100644
--- a/libs/flake/CMakeLists.txt
+++ b/libs/flake/CMakeLists.txt
@@ -1,248 +1,236 @@
project(kritaflake)
include_directories(
${CMAKE_SOURCE_DIR}/libs/flake/commands
${CMAKE_SOURCE_DIR}/libs/flake/tools
${CMAKE_SOURCE_DIR}/libs/flake/svg
${CMAKE_SOURCE_DIR}/libs/flake/text
${CMAKE_BINARY_DIR}/libs/flake
)
add_subdirectory(styles)
add_subdirectory(tests)
add_subdirectory(resources/tests)
set(kritaflake_SRCS
KoGradientHelper.cpp
KoFlake.cpp
KoCanvasBase.cpp
KoResourceManager_p.cpp
KoDerivedResourceConverter.cpp
KoResourceUpdateMediator.cpp
KoCanvasResourceProvider.cpp
KoDocumentResourceManager.cpp
KoCanvasObserverBase.cpp
KoCanvasSupervisor.cpp
KoDockFactoryBase.cpp
KoDockRegistry.cpp
KoDataCenterBase.cpp
KoInsets.cpp
KoPathShape.cpp
KoPathPoint.cpp
KoPathSegment.cpp
KoSelection.cpp
KoSelectedShapesProxy.cpp
KoSelectedShapesProxySimple.cpp
KoShape.cpp
KoShapeAnchor.cpp
KoShapeControllerBase.cpp
KoShapeApplicationData.cpp
KoShapeContainer.cpp
KoShapeContainerModel.cpp
KoShapeGroup.cpp
KoShapeManager.cpp
KoShapePaintingContext.cpp
KoFrameShape.cpp
KoMarker.cpp
KoMarkerCollection.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
KoVectorPatternBackground.cpp
KoShapeFillWrapper.cpp
KoShapeFillResourceConnector.cpp
KoShapeConfigWidgetBase.cpp
KoDrag.cpp
KoSvgPaste.cpp
- KoDragOdfSaveHelper.cpp
- KoShapeOdfSaveHelper.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
KoClipMask.cpp
KoClipMaskPainter.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/KoShapeResizeCommand.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
commands/KoMultiPathPointMergeCommand.cpp
commands/KoMultiPathPointJoinCommand.cpp
commands/KoKeepShapesSelectedCommand.cpp
commands/KoPathMergeUtils.cpp
+ commands/KoAddRemoveShapeCommands.cpp
html/HtmlSavingContext.cpp
html/HtmlWriter.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/KoInteractionTool.cpp
tools/KoInteractionStrategy.cpp
tools/KoInteractionStrategyFactory.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/SvgFilterHelper.cpp
svg/SvgCssHelper.cpp
svg/SvgClipPathHelper.cpp
svg/SvgLoadingContext.cpp
svg/SvgShapeFactory.cpp
svg/parsers/SvgTransformParser.cpp
text/KoSvgText.cpp
text/KoSvgTextProperties.cpp
text/KoSvgTextChunkShape.cpp
text/KoSvgTextShape.cpp
text/KoSvgTextShapeMarkupConverter.cpp
resources/KoSvgSymbolCollectionResource.cpp
resources/KoGamutMask.cpp
FlakeDebug.cpp
tests/MockShapes.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
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/commands>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/tools>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/svg>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/text>
)
-target_link_libraries(kritaflake kritapigment kritawidgetutils kritaodf kritacommand KF5::WidgetsAddons Qt5::Svg)
+target_link_libraries(kritaflake kritapigment kritawidgetutils kritacommand KF5::WidgetsAddons Qt5::Svg KF5::CoreAddons KF5::ConfigCore KF5::I18n Qt5::Gui Qt5::Xml)
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/KoColorBackground.cpp b/libs/flake/KoColorBackground.cpp
index 2eacb4790a..b52fdef943 100644
--- a/libs/flake/KoColorBackground.cpp
+++ b/libs/flake/KoColorBackground.cpp
@@ -1,117 +1,93 @@
/* This file is part of the KDE project
* Copyright (C) 2008 Jan Hambrecht <jaham@gmx.net>
*
* 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 "KoColorBackground.h"
#include "KoShapeSavingContext.h"
-#include <KoOdfGraphicStyles.h>
-#include <KoOdfLoadingContext.h>
#include <KoXmlNS.h>
-#include <KoStyleStack.h>
#include <QColor>
#include <QPainter>
class KoColorBackground::Private : public QSharedData
{
public:
Private()
: QSharedData()
, color(Qt::black)
, style(Qt::SolidPattern)
{}
QColor color;
Qt::BrushStyle style;
};
KoColorBackground::KoColorBackground()
: KoShapeBackground()
, d(new Private)
{
}
KoColorBackground::KoColorBackground(const QColor &color, Qt::BrushStyle style)
: KoShapeBackground()
, d(new Private)
{
if (style < Qt::SolidPattern || style >= Qt::LinearGradientPattern) {
style = Qt::SolidPattern;
}
d->style = style;
d->color = color;
}
KoColorBackground::~KoColorBackground()
{
}
bool KoColorBackground::compareTo(const KoShapeBackground *other) const
{
const KoColorBackground *bg = dynamic_cast<const KoColorBackground*>(other);
return bg && bg->color() == d->color;
}
QColor KoColorBackground::color() const
{
return d->color;
}
void KoColorBackground::setColor(const QColor &color)
{
d->color = color;
}
Qt::BrushStyle KoColorBackground::style() const
{
return d->style;
}
QBrush KoColorBackground::brush() const
{
return QBrush(d->color, d->style);
}
void KoColorBackground::paint(QPainter &painter, KoShapePaintingContext &/*context*/, const QPainterPath &fillPath) const
{
painter.setBrush(brush());
painter.drawPath(fillPath);
}
-void KoColorBackground::fillStyle(KoGenStyle &style, KoShapeSavingContext &context)
-{
- KoOdfGraphicStyles::saveOdfFillStyle(style, context.mainStyles(), QBrush(d->color, d->style));
-}
-
-bool KoColorBackground::loadStyle(KoOdfLoadingContext & context, const QSizeF &)
-{
- KoStyleStack &styleStack = context.styleStack();
- if (! styleStack.hasProperty(KoXmlNS::draw, "fill"))
- return false;
-
- QString fillStyle = styleStack.property(KoXmlNS::draw, "fill");
- if (fillStyle == "solid" || fillStyle == "hatch") {
- QBrush brush = KoOdfGraphicStyles::loadOdfFillStyle(styleStack, fillStyle, context.stylesReader());
- d->color = brush.color();
- d->style = brush.style();
- return true;
- }
-
- return false;
-}
diff --git a/libs/flake/KoColorBackground.h b/libs/flake/KoColorBackground.h
index 474db8efa0..0732ae0a5e 100644
--- a/libs/flake/KoColorBackground.h
+++ b/libs/flake/KoColorBackground.h
@@ -1,67 +1,64 @@
/* This file is part of the KDE project
* Copyright (C) 2008 Jan Hambrecht <jaham@gmx.net>
*
* 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 KOCOLORBACKGROUND_H
#define KOCOLORBACKGROUND_H
#include "KoShapeBackground.h"
#include "kritaflake_export.h"
#include <Qt>
#include <QSharedDataPointer>
class KoColorBackgroundPrivate;
class QColor;
class QBrush;
/// A simple solid color shape background
class KRITAFLAKE_EXPORT KoColorBackground : public KoShapeBackground
{
public:
KoColorBackground();
/// Creates background from given color and style
explicit KoColorBackground(const QColor &color, Qt::BrushStyle style = Qt::SolidPattern);
~KoColorBackground() override;
bool compareTo(const KoShapeBackground *other) const override;
/// Returns the background color
QColor color() const;
/// Sets the background color
void setColor(const QColor &color);
/// Returns the background style
Qt::BrushStyle style() const;
QBrush brush() const;
// reimplemented from KoShapeBackground
void paint(QPainter &painter, KoShapePaintingContext &context, const QPainterPath &fillPath) const override;
- // reimplemented from KoShapeBackground
- void fillStyle(KoGenStyle &style, KoShapeSavingContext &context) override;
- // reimplemented from KoShapeBackground
- bool loadStyle(KoOdfLoadingContext & context, const QSizeF &shapeSize) override;
+
private:
class Private;
QSharedDataPointer<Private> d;
};
#endif // KOCOLORBACKGROUND_H
diff --git a/libs/flake/KoConnectionPoint.cpp b/libs/flake/KoConnectionPoint.cpp
deleted file mode 100644
index d328caa305..0000000000
--- a/libs/flake/KoConnectionPoint.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "KoConnectionPoint.h"
-
-KoConnectionPoint::KoConnectionPoint()
-: position(0, 0), escapeDirection(AllDirections), alignment(AlignNone)
-{
-}
-
-KoConnectionPoint::KoConnectionPoint(const QPointF& pos)
-: position(pos), escapeDirection(AllDirections), alignment(AlignNone)
-{
-}
-
-KoConnectionPoint::KoConnectionPoint(const QPointF& pos, EscapeDirection direction)
-: position(pos), escapeDirection(direction), alignment(AlignNone)
-{
-}
-
-KoConnectionPoint::KoConnectionPoint(const QPointF &pos, EscapeDirection direction, Alignment alignment)
-: position(pos), escapeDirection(direction), alignment(alignment)
-{
-}
-
-KoConnectionPoint KoConnectionPoint::defaultConnectionPoint(PointId connectionPointId)
-{
- switch(connectionPointId)
- {
- case TopConnectionPoint:
- return KoConnectionPoint(QPointF(0.5, 0.0));
- case RightConnectionPoint:
- return KoConnectionPoint(QPointF(1.0, 0.5));
- case BottomConnectionPoint:
- return KoConnectionPoint(QPointF(0.5, 1.0));
- case LeftConnectionPoint:
- return KoConnectionPoint(QPointF(0.0, 0.5));
- default:
- return KoConnectionPoint();
- }
-}
diff --git a/libs/flake/KoConnectionPoint.h b/libs/flake/KoConnectionPoint.h
deleted file mode 100644
index 892c9c7877..0000000000
--- a/libs/flake/KoConnectionPoint.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 KOCONNECTIONPOINT_H
-#define KOCONNECTIONPOINT_H
-
-#include "kritaflake_export.h"
-#include <QPointF>
-#include <QMap>
-
-/// Data of a single connection point
-struct KRITAFLAKE_EXPORT KoConnectionPoint
-{
- /// Default connection point ids
- enum PointId {
- TopConnectionPoint = 0, ///< default connection point on the middle of the top edge
- RightConnectionPoint = 1, ///< default connection point on the middle of the right edge
- BottomConnectionPoint = 2, ///< default connection point on the middle of the bottom edge
- LeftConnectionPoint = 3, ///< default connection point on the middle of the left edge
- FirstCustomConnectionPoint = 4 ///< first custom connection point id
- };
-
- /// Escape directions for connections connected to connection points
- enum EscapeDirection {
- AllDirections, ///< connection can escape in all directions
- HorizontalDirections, ///< connection can escape left and right
- VerticalDirections, ///< connection can escape top and down
- LeftDirection, ///< connection can escape left
- RightDirection, ///< connection can escape right
- UpDirection, ///< connection can escape up
- DownDirection ///< connection can escape down
- };
-
- /// Alignments for connection points for shape resizing
- enum Alignment {
- AlignNone, ///< align to nothing
- AlignTopLeft, ///< align to top and left edge
- AlignTop, ///< align to top edge
- AlignTopRight, ///< align to top and right edge
- AlignLeft, ///< align to left edge
- AlignCenter, ///< align to center
- AlignRight, ///< align to right edge
- AlignBottomLeft, ///< align to bottom and left edge
- AlignBottom, ///< align to bottom edge
- AlignBottomRight ///< align to bottom and right edge
- };
-
- /// Default constructor
- KoConnectionPoint();
-
- /// Creates connection point with specified position
- KoConnectionPoint(const QPointF &position);
-
- /// Creates connection point with specified position and escape direction
- KoConnectionPoint(const QPointF &position, EscapeDirection escapeDirection);
-
- /// Creates connection point with specified position, escape direction and alignment
- KoConnectionPoint(const QPointF &position, EscapeDirection escapeDirection, Alignment alignment);
-
- /// Returns default connection point with specified id
- static KoConnectionPoint defaultConnectionPoint(KoConnectionPoint::PointId connectionPointId);
-
- QPointF position; ///< the position of the connection point in shape coordinates
- EscapeDirection escapeDirection; ///< the escape direction for connection attached to that connection point
- Alignment alignment; ///< specifies to which edge the connection point is aligned to
-};
-
-/// Connection point container storing connection point data along their id
-typedef QMap<int, KoConnectionPoint> KoConnectionPoints;
-
-#endif // KOCONNECTIONPOINT_H
diff --git a/libs/flake/KoConnectionShape.cpp b/libs/flake/KoConnectionShape.cpp
deleted file mode 100644
index b8083d548d..0000000000
--- a/libs/flake/KoConnectionShape.cpp
+++ /dev/null
@@ -1,779 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Boudewijn Rempt <boud@kde.org>
- * Copyright (C) 2007,2009 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2007,2009,2010 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "KoConnectionShape.h"
-#include "KoConnectionShape_p.h"
-
-#include "KoShapeLoadingContext.h"
-#include "KoShapeSavingContext.h"
-#include "KoConnectionShapeLoadingUpdater.h"
-#include "KoPathShapeLoader.h"
-#include "KoPathPoint.h"
-#include "KoShapeBackground.h"
-#include <KoXmlReader.h>
-#include <KoXmlWriter.h>
-#include <KoXmlNS.h>
-#include <KoUnit.h>
-#include <QPainter>
-#include <QPainterPath>
-
-#include <FlakeDebug.h>
-
-KoConnectionShape::Private::Private()
- : QSharedData()
- , shape1(0)
- , shape2(0)
- , connectionPointId1(-1)
- , connectionPointId2(-1)
- , connectionType(KoConnectionShape::Standard)
- , forceUpdate(false)
- , hasCustomPath(false)
-{
-}
-
-KoConnectionShape::Private::Private(const KoConnectionShape::Private &rhs)
- : QSharedData()
- , path(rhs.path)
- , shape1(0) // FIXME: it should point to the new shapes!!!
- , shape2(0) // FIXME: it should point to the new shapes!!!
- , connectionPointId1(rhs.connectionPointId1)
- , connectionPointId2(rhs.connectionPointId2)
- , connectionType(rhs.connectionType)
- , forceUpdate(rhs.forceUpdate)
- , hasCustomPath(rhs.hasCustomPath)
-{
-
-}
-
-QPointF KoConnectionShape::escapeDirection(int handleId) const
-{
- QPointF direction;
- if (d->handleConnected(handleId)) {
- KoShape *attachedShape = handleId == KoConnectionShape::StartHandle ? d->shape1 : d->shape2;
- int connectionPointId = handleId == KoConnectionShape::StartHandle ? d->connectionPointId1 : d->connectionPointId2;
- KoConnectionPoint::EscapeDirection ed = attachedShape->connectionPoint(connectionPointId).escapeDirection;
- if (ed == KoConnectionPoint::AllDirections) {
- QPointF handlePoint = shapeToDocument(handles()[handleId]);
- QPointF centerPoint = attachedShape->absolutePosition(KoFlake::Center);
-
- /*
- * Determine the best escape direction from the position of the handle point
- * and the position and orientation of the attached shape.
- * The idea is to define 4 sectors, one for each edge of the attached shape.
- * Each sector starts at the center point of the attached shape and has it
- * left and right edge going through the two points which define the edge.
- * Then we check which sector contains our handle point, for which we can
- * simply calculate the corresponding direction which is orthogonal to the
- * corresponding bounding box edge.
- * From that we derive the escape direction from looking at the main coordinate
- * of the orthogonal direction.
- */
- // define our edge points in the right order
- const KoFlake::AnchorPosition corners[4] = {
- KoFlake::BottomRight,
- KoFlake::BottomLeft,
- KoFlake::TopLeft,
- KoFlake::TopRight
- };
-
- QPointF vHandle = handlePoint-centerPoint;
- for (int i = 0; i < 4; ++i) {
- // first point of bounding box edge
- QPointF p1 = attachedShape->absolutePosition(corners[i]);
- // second point of bounding box edge
- QPointF p2 = attachedShape->absolutePosition(corners[(i+1)%4]);
- // check on which side of the first sector edge our second sector edge is
- const qreal c0 = d->crossProd(p1-centerPoint, p2-centerPoint);
- // check on which side of the first sector edge our handle point is
- const qreal c1 = d->crossProd(p1-centerPoint, vHandle);
- // second edge and handle point must be on the same side of first edge
- if ((c0 < 0 && c1 > 0) || (c0 > 0 && c1 < 0))
- continue;
- // check on which side of the handle point our second sector edge is
- const qreal c2 = d->crossProd(vHandle, p2-centerPoint);
- // second edge must be on the same side of the handle point as on first edge
- if ((c0 < 0 && c2 > 0) || (c0 > 0 && c2 < 0))
- continue;
- // now we found the correct edge
- QPointF vDir = 0.5 *(p1+p2) - centerPoint;
- // look at coordinate with the greatest absolute value
- // and construct our escape direction accordingly
- const qreal xabs = qAbs<qreal>(vDir.x());
- const qreal yabs = qAbs<qreal>(vDir.y());
- if (xabs > yabs) {
- direction.rx() = vDir.x() > 0 ? 1.0 : -1.0;
- direction.ry() = 0.0;
- } else {
- direction.rx() = 0.0;
- direction.ry() = vDir.y() > 0 ? 1.0 : -1.0;
- }
- break;
- }
- } else if (ed == KoConnectionPoint::HorizontalDirections) {
- QPointF handlePoint = shapeToDocument(handles()[handleId]);
- QPointF centerPoint = attachedShape->absolutePosition(KoFlake::Center);
- // use horizontal direction pointing away from center point
- if (handlePoint.x() < centerPoint.x())
- direction = QPointF(-1.0, 0.0);
- else
- direction = QPointF(1.0, 0.0);
- } else if (ed == KoConnectionPoint::VerticalDirections) {
- QPointF handlePoint = shapeToDocument(handles()[handleId]);
- QPointF centerPoint = attachedShape->absolutePosition(KoFlake::Center);
- // use vertical direction pointing away from center point
- if (handlePoint.y() < centerPoint.y())
- direction = QPointF(0.0, -1.0);
- else
- direction = QPointF(0.0, 1.0);
- } else if (ed == KoConnectionPoint::LeftDirection) {
- direction = QPointF(-1.0, 0.0);
- } else if (ed == KoConnectionPoint::RightDirection) {
- direction = QPointF(1.0, 0.0);
- } else if (ed == KoConnectionPoint::UpDirection) {
- direction = QPointF(0.0, -1.0);
- } else if (ed == KoConnectionPoint::DownDirection) {
- direction = QPointF(0.0, 1.0);
- }
-
- // transform escape direction by using our own transformation matrix
- QTransform invMatrix = absoluteTransformation().inverted();
- direction = invMatrix.map(direction) - invMatrix.map(QPointF());
- direction /= sqrt(direction.x() * direction.x() + direction.y() * direction.y());
- }
-
- return direction;
-}
-
-bool KoConnectionShape::Private::intersects(const QPointF &p1, const QPointF &d1, const QPointF &p2, const QPointF &d2, QPointF &isect)
-{
- qreal sp1 = scalarProd(d1, p2 - p1);
- if (sp1 < 0.0)
- return false;
-
- qreal sp2 = scalarProd(d2, p1 - p2);
- if (sp2 < 0.0)
- return false;
-
- // use cross product to check if rays intersects at all
- qreal cp = crossProd(d1, d2);
- if (cp == 0.0) {
- // rays are parallel or coincident
- if (p1.x() == p2.x() && d1.x() == 0.0 && d1.y() != d2.y()) {
- // vertical, coincident
- isect = 0.5 * (p1 + p2);
- } else if (p1.y() == p2.y() && d1.y() == 0.0 && d1.x() != d2.x()) {
- // horizontal, coincident
- isect = 0.5 * (p1 + p2);
- } else {
- return false;
- }
- } else {
- // they are intersecting normally
- isect = p1 + sp1 * d1;
- }
-
- return true;
-}
-
-QPointF KoConnectionShape::Private::perpendicularDirection(const QPointF &p1, const QPointF &d1, const QPointF &p2)
-{
- QPointF perpendicular(d1.y(), -d1.x());
- qreal sp = scalarProd(perpendicular, p2 - p1);
- if (sp < 0.0)
- perpendicular *= -1.0;
-
- return perpendicular;
-}
-
-void KoConnectionShape::normalPath(const qreal MinimumEscapeLength)
-{
- // Clear the path to build it again.
- d->path.clear();
- d->path.append(handles()[KoConnectionShape::StartHandle]);
-
- QList<QPointF> edges1;
- QList<QPointF> edges2;
-
- QPointF direction1 = escapeDirection(KoConnectionShape::StartHandle);
- QPointF direction2 = escapeDirection(KoConnectionShape::EndHandle);
-
- QPointF edgePoint1 = handles()[KoConnectionShape::StartHandle] + MinimumEscapeLength * direction1;
- QPointF edgePoint2 = handles()[KoConnectionShape::EndHandle] + MinimumEscapeLength * direction2;
-
- edges1.append(edgePoint1);
- edges2.prepend(edgePoint2);
-
- if (d->handleConnected(KoConnectionShape::StartHandle) && d->handleConnected(KoConnectionShape::EndHandle)) {
- QPointF intersection;
-
- // TODO: check if this loop actually ever exits? (DK)
- while (true) {
- // first check if directions from current edge points intersect
- if (d->intersects(edgePoint1, direction1, edgePoint2, direction2, intersection)) {
- // directions intersect, we have another edge point and be done
- edges1.append(intersection);
- break;
- }
-
- // check if we are going toward the other handle
- qreal sp = d->scalarProd(direction1, edgePoint2 - edgePoint1);
- if (sp >= 0.0) {
- // if we are having the same direction, go all the way toward
- // the other handle, else only go half the way
- if (direction1 == direction2)
- edgePoint1 += sp * direction1;
- else
- edgePoint1 += 0.5 * sp * direction1;
- edges1.append(edgePoint1);
- // switch direction
- direction1 = d->perpendicularDirection(edgePoint1, direction1, edgePoint2);
- } else {
- // we are not going into the same direction, so switch direction
- direction1 = d->perpendicularDirection(edgePoint1, direction1, edgePoint2);
- }
- }
- }
-
- d->path.append(edges1);
- d->path.append(edges2);
-
- d->path.append(handles()[KoConnectionShape::EndHandle]);
-}
-
-qreal KoConnectionShape::Private::scalarProd(const QPointF &v1, const QPointF &v2) const
-{
- return v1.x() * v2.x() + v1.y() * v2.y();
-}
-
-qreal KoConnectionShape::Private::crossProd(const QPointF &v1, const QPointF &v2) const
-{
- return v1.x() * v2.y() - v1.y() * v2.x();
-}
-
-bool KoConnectionShape::Private::handleConnected(int handleId) const
-{
- if (handleId == KoConnectionShape::StartHandle && shape1 && connectionPointId1 >= 0)
- return true;
- if (handleId == KoConnectionShape::EndHandle && shape2 && connectionPointId2 >= 0)
- return true;
-
- return false;
-}
-
-void KoConnectionShape::updateConnections()
-{
- bool updateHandles = false;
-
- if (d->handleConnected(StartHandle)) {
- if (d->shape1->hasConnectionPoint(d->connectionPointId1)) {
- // map connection point into our shape coordinates
- QPointF p = documentToShape(d->shape1->absoluteTransformation().map(d->shape1->connectionPoint(d->connectionPointId1).position));
- if (handles()[StartHandle] != p) {
- handles()[StartHandle] = p;
- updateHandles = true;
- }
- }
- }
- if (d->handleConnected(EndHandle)) {
- if (d->shape2->hasConnectionPoint(d->connectionPointId2)) {
- // map connection point into our shape coordinates
- QPointF p = documentToShape(d->shape2->absoluteTransformation().map(d->shape2->connectionPoint(d->connectionPointId2).position));
- if (handles()[EndHandle] != p) {
- handles()[EndHandle] = p;
- updateHandles = true;
- }
- }
- }
-
- if (updateHandles || d->forceUpdate) {
- update(); // ugly, for repainting the connection we just changed
- updatePath(QSizeF());
- update(); // ugly, for repainting the connection we just changed
- d->forceUpdate = false;
- }
-}
-
-KoConnectionShape::KoConnectionShape()
- : KoParameterShape()
- , d(new Private)
-{
- handles().push_back(QPointF(0, 0));
- handles().push_back(QPointF(140, 140));
-
- moveTo(handles()[StartHandle]);
- lineTo(handles()[EndHandle]);
-
- updatePath(QSizeF(140, 140));
-
- clearConnectionPoints();
-}
-
-KoConnectionShape::KoConnectionShape(const KoConnectionShape &rhs)
- : KoParameterShape(rhs)
- , d(rhs.d)
-{
-}
-
-
-KoConnectionShape::~KoConnectionShape()
-{
-
- if (d->shape1)
- d->shape1->removeDependee(this);
- if (d->shape2)
- d->shape2->removeDependee(this);
-}
-
-KoShape *KoConnectionShape::cloneShape() const
-{
- return new KoConnectionShape(*this);
-}
-
-void KoConnectionShape::saveOdf(KoShapeSavingContext & context) const
-{
-
- context.xmlWriter().startElement("draw:connector");
- saveOdfAttributes(context, OdfMandatories | OdfAdditionalAttributes);
-
- switch (d->connectionType) {
- case Lines:
- context.xmlWriter().addAttribute("draw:type", "lines");
- break;
- case Straight:
- context.xmlWriter().addAttribute("draw:type", "line");
- break;
- case Curve:
- context.xmlWriter().addAttribute("draw:type", "curve");
- break;
- default:
- context.xmlWriter().addAttribute("draw:type", "standard");
- break;
- }
-
- if (d->shape1) {
- context.xmlWriter().addAttribute("draw:start-shape", context.xmlid(d->shape1, "shape", KoElementReference::Counter).toString());
- context.xmlWriter().addAttribute("draw:start-glue-point", d->connectionPointId1);
- } else {
- QPointF p(shapeToDocument(handles()[StartHandle]) * context.shapeOffset(this));
- context.xmlWriter().addAttribute("svg:x1", p.x());
- context.xmlWriter().addAttribute("svg:y1", p.y());
- }
- if (d->shape2) {
- context.xmlWriter().addAttribute("draw:end-shape", context.xmlid(d->shape2, "shape", KoElementReference::Counter).toString());
- context.xmlWriter().addAttribute("draw:end-glue-point", d->connectionPointId2);
- } else {
- QPointF p(shapeToDocument(handles()[EndHandle]) * context.shapeOffset(this));
- context.xmlWriter().addAttribute("svg:x2", p.x());
- context.xmlWriter().addAttribute("svg:y2", p.y());
- }
-
- // write the path data
- context.xmlWriter().addAttribute("svg:d", toString());
- saveOdfAttributes(context, OdfViewbox);
-
- saveOdfCommonChildElements(context);
- saveText(context);
-
- context.xmlWriter().endElement();
-}
-
-bool KoConnectionShape::loadOdf(const KoXmlElement & element, KoShapeLoadingContext &context)
-{
-
- loadOdfAttributes(element, context, OdfMandatories | OdfCommonChildElements | OdfAdditionalAttributes);
-
- QString type = element.attributeNS(KoXmlNS::draw, "type", "standard");
- if (type == "lines")
- d->connectionType = Lines;
- else if (type == "line")
- d->connectionType = Straight;
- else if (type == "curve")
- d->connectionType = Curve;
- else
- d->connectionType = Standard;
-
- // reset connection point indices
- d->connectionPointId1 = -1;
- d->connectionPointId2 = -1;
- // reset connected shapes
- d->shape1 = 0;
- d->shape2 = 0;
-
- if (element.hasAttributeNS(KoXmlNS::draw, "start-shape")) {
- d->connectionPointId1 = element.attributeNS(KoXmlNS::draw, "start-glue-point", QString()).toInt();
- QString shapeId1 = element.attributeNS(KoXmlNS::draw, "start-shape", QString());
- debugFlake << "references start-shape" << shapeId1 << "at glue-point" << d->connectionPointId1;
- d->shape1 = context.shapeById(shapeId1);
- if (d->shape1) {
- debugFlake << "start-shape was already loaded";
- d->shape1->addDependee(this);
- if (d->shape1->hasConnectionPoint(d->connectionPointId1)) {
- debugFlake << "connecting to start-shape";
- handles()[StartHandle] = d->shape1->absoluteTransformation().map(d->shape1->connectionPoint(d->connectionPointId1).position);
- debugFlake << "start handle position =" << handles()[StartHandle];
- }
- } else {
- debugFlake << "start-shape not loaded yet, deferring connection";
- context.updateShape(shapeId1, new KoConnectionShapeLoadingUpdater(this, KoConnectionShapeLoadingUpdater::First));
- }
- } else {
- handles()[StartHandle].setX(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "x1", QString())));
- handles()[StartHandle].setY(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "y1", QString())));
- }
-
- if (element.hasAttributeNS(KoXmlNS::draw, "end-shape")) {
- d->connectionPointId2 = element.attributeNS(KoXmlNS::draw, "end-glue-point", "").toInt();
- QString shapeId2 = element.attributeNS(KoXmlNS::draw, "end-shape", "");
- debugFlake << "references end-shape " << shapeId2 << "at glue-point" << d->connectionPointId2;
- d->shape2 = context.shapeById(shapeId2);
- if (d->shape2) {
- debugFlake << "end-shape was already loaded";
- d->shape2->addDependee(this);
- if (d->shape2->hasConnectionPoint(d->connectionPointId2)) {
- debugFlake << "connecting to end-shape";
- handles()[EndHandle] = d->shape2->absoluteTransformation().map(d->shape2->connectionPoint(d->connectionPointId2).position);
- debugFlake << "end handle position =" << handles()[EndHandle];
- }
- } else {
- debugFlake << "end-shape not loaded yet, deferring connection";
- context.updateShape(shapeId2, new KoConnectionShapeLoadingUpdater(this, KoConnectionShapeLoadingUpdater::Second));
- }
- } else {
- handles()[EndHandle].setX(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "x2", QString())));
- handles()[EndHandle].setY(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "y2", QString())));
- }
-
- QString skew = element.attributeNS(KoXmlNS::draw, "line-skew", QString());
- QStringList skewValues = skew.simplified().split(' ', QString::SkipEmptyParts);
- // TODO apply skew values once we support them
-
- // load the path data if there is any
- d->hasCustomPath = element.hasAttributeNS(KoXmlNS::svg, "d");
- if (d->hasCustomPath) {
- KoPathShapeLoader loader(this);
- loader.parseSvg(element.attributeNS(KoXmlNS::svg, "d"), true);
- if (subpaths().size() > 0) {
- QRectF viewBox = loadOdfViewbox(element);
- if (viewBox.isEmpty()) {
- // there should be a viewBox to transform the path data
- // if there is none, use the bounding rectangle of the parsed path
- viewBox = outline().boundingRect();
- }
- // convert path to viewbox coordinates to have a bounding rect of (0,0 1x1)
- // which can later be fitted back into the target rect once we have all
- // the required information
- QTransform viewMatrix;
- viewMatrix.scale(viewBox.width() ? static_cast<qreal>(1.0) / viewBox.width() : 1.0,
- viewBox.height() ? static_cast<qreal>(1.0) / viewBox.height() : 1.0);
- viewMatrix.translate(-viewBox.left(), -viewBox.top());
- map(viewMatrix);
-
- // trigger finishing the connections in case we have all data
- // otherwise it gets called again once the shapes we are
- // connected to are loaded
- }
- else {
- d->hasCustomPath = false;
- }
- finishLoadingConnection();
- } else {
- d->forceUpdate = true;
- updateConnections();
- }
-
- loadText(element, context);
-
- return true;
-}
-
-void KoConnectionShape::finishLoadingConnection()
-{
-
-
- if (d->hasCustomPath) {
- const bool loadingFinished1 = d->connectionPointId1 >= 0 ? d->shape1 != 0 : true;
- const bool loadingFinished2 = d->connectionPointId2 >= 0 ? d->shape2 != 0 : true;
- if (loadingFinished1 && loadingFinished2) {
- QPointF p1, p2;
- if (d->handleConnected(StartHandle)) {
- if (d->shape1->hasConnectionPoint(d->connectionPointId1)) {
- p1 = d->shape1->absoluteTransformation().map(d->shape1->connectionPoint(d->connectionPointId1).position);
- }
- } else {
- p1 = handles()[StartHandle];
- }
- if (d->handleConnected(EndHandle)) {
- if (d->shape2->hasConnectionPoint(d->connectionPointId2)) {
- p2 = d->shape2->absoluteTransformation().map(d->shape2->connectionPoint(d->connectionPointId2).position);
- }
- } else {
- p2 = handles()[EndHandle];
- }
-
- QPointF relativeBegin = subpaths().first()->first()->point();
- QPointF relativeEnd = subpaths().last()->last()->point();
-
- QPointF diffRelative(relativeBegin - relativeEnd);
- QPointF diffAbsolute(p1 - p2);
-
- qreal factorX = diffRelative.x() ? diffAbsolute.x() / diffRelative.x(): 1.0;
- qreal factorY = diffRelative.y() ? diffAbsolute.y() / diffRelative.y(): 1.0;
-
- p1.setX(p1.x() - relativeBegin.x() * factorX);
- p1.setY(p1.y() - relativeBegin.y() * factorY);
- p2.setX(p2.x() + (1 - relativeEnd.x()) * factorX);
- p2.setY(p2.y() + (1 - relativeEnd.y()) * factorY);
-
- QRectF targetRect = QRectF(p1, p2).normalized();
-
- // transform the normalized coordinates back to our target rectangle
- QTransform viewMatrix;
- viewMatrix.translate(targetRect.x(), targetRect.y());
- viewMatrix.scale(targetRect.width(), targetRect.height());
- map(viewMatrix);
-
- // pretend we are during a forced update, so normalize()
- // will not trigger an updateConnections() call
- d->forceUpdate = true;
- normalize();
- d->forceUpdate = false;
- }
- } else {
- updateConnections();
- }
-}
-
-void KoConnectionShape::moveHandleAction(int handleId, const QPointF &point, Qt::KeyboardModifiers modifiers)
-{
- Q_UNUSED(modifiers);
-
-
- if (handleId >= handles().size())
- return;
-
- handles()[handleId] = point;
-}
-
-void KoConnectionShape::updatePath(const QSizeF &size)
-{
- Q_UNUSED(size);
-
-
- const qreal MinimumEscapeLength = (qreal)20.;
- clear();
- switch (d->connectionType) {
- case Standard: {
- normalPath(MinimumEscapeLength);
- if (d->path.count() != 0){
- moveTo(d->path[0]);
- for (int index = 1; index < d->path.count(); ++index)
- lineTo(d->path[index]);
- }
-
- break;
- }
- case Lines: {
- QPointF direction1 = escapeDirection(0);
- QPointF direction2 = escapeDirection(handles().count() - 1);
- moveTo(handles()[StartHandle]);
- if (! direction1.isNull())
- lineTo(handles()[StartHandle] + MinimumEscapeLength * direction1);
- if (! direction2.isNull())
- lineTo(handles()[EndHandle] + MinimumEscapeLength * direction2);
- lineTo(handles()[EndHandle]);
- break;
- }
- case Straight:
- moveTo(handles()[StartHandle]);
- lineTo(handles()[EndHandle]);
- break;
- case Curve:
- // TODO
- QPointF direction1 = escapeDirection(0);
- QPointF direction2 = escapeDirection(handles().count() - 1);
- moveTo(handles()[StartHandle]);
- if (! direction1.isNull() && ! direction2.isNull()) {
- QPointF curvePoint1 = handles()[StartHandle] + 5.0 * MinimumEscapeLength * direction1;
- QPointF curvePoint2 = handles()[EndHandle] + 5.0 * MinimumEscapeLength * direction2;
- curveTo(curvePoint1, curvePoint2, handles()[EndHandle]);
- } else {
- lineTo(handles()[EndHandle]);
- }
- break;
- }
- normalize();
-}
-
-bool KoConnectionShape::connectFirst(KoShape * shape1, int connectionPointId)
-{
-
- // refuse to connect to a shape that depends on us (e.g. a artistic text shape)
- if (hasDependee(shape1))
- return false;
-
- if (shape1) {
- // check if the connection point does exist
- if (!shape1->hasConnectionPoint(connectionPointId))
- return false;
- // do not connect to the same connection point twice
- if (d->shape2 == shape1 && d->connectionPointId2 == connectionPointId)
- return false;
- }
-
- if (d->shape1)
- d->shape1->removeDependee(this);
- d->shape1 = shape1;
- if (d->shape1)
- d->shape1->addDependee(this);
-
- d->connectionPointId1 = connectionPointId;
-
- return true;
-}
-
-bool KoConnectionShape::connectSecond(KoShape * shape2, int connectionPointId)
-{
-
- // refuse to connect to a shape that depends on us (e.g. a artistic text shape)
- if (hasDependee(shape2))
- return false;
-
- if (shape2) {
- // check if the connection point does exist
- if (!shape2->hasConnectionPoint(connectionPointId))
- return false;
- // do not connect to the same connection point twice
- if (d->shape1 == shape2 && d->connectionPointId1 == connectionPointId)
- return false;
- }
-
- if (d->shape2)
- d->shape2->removeDependee(this);
- d->shape2 = shape2;
- if (d->shape2)
- d->shape2->addDependee(this);
-
- d->connectionPointId2 = connectionPointId;
-
- return true;
-}
-
-KoShape *KoConnectionShape::firstShape() const
-{
-
- return d->shape1;
-}
-
-int KoConnectionShape::firstConnectionId() const
-{
-
- return d->connectionPointId1;
-}
-
-KoShape *KoConnectionShape::secondShape() const
-{
-
- return d->shape2;
-}
-
-int KoConnectionShape::secondConnectionId() const
-{
-
- return d->connectionPointId2;
-}
-
-KoConnectionShape::Type KoConnectionShape::type() const
-{
-
- return d->connectionType;
-}
-
-void KoConnectionShape::setType(Type connectionType)
-{
-
- d->connectionType = connectionType;
- updatePath(size());
-}
-
-void KoConnectionShape::shapeChanged(ChangeType type, KoShape *shape)
-{
-
-
- KoTosContainer::shapeChanged(type, shape);
- // check if we are during a forced update
- const bool updateIsActive = d->forceUpdate;
-
- switch (type) {
- case PositionChanged:
- case RotationChanged:
- case ShearChanged:
- case ScaleChanged:
- case GenericMatrixChange:
- case ParameterChanged:
- if (isParametricShape() && shape == 0)
- d->forceUpdate = true;
- break;
- case Deleted:
- if (shape != d->shape1 && shape != d->shape2)
- return;
- if (shape == d->shape1)
- connectFirst(0, -1);
- if (shape == d->shape2)
- connectSecond(0, -1);
- break;
- case ConnectionPointChanged:
- if (shape == d->shape1 && !shape->hasConnectionPoint(d->connectionPointId1)) {
- connectFirst(0, -1);
- } else if ( shape == d->shape2 && !shape->hasConnectionPoint(d->connectionPointId2)){
- connectSecond(0, -1);
- } else {
- d->forceUpdate = true;
- }
- break;
- case BackgroundChanged:
- {
- // connection shape should not have a background
- QSharedPointer<KoShapeBackground> fill = background();
- if (fill) {
- setBackground(QSharedPointer<KoShapeBackground>(0));
- }
- return;
- }
- default:
- return;
- }
-
- // the connection was moved while it is connected to some other shapes
- const bool connectionChanged = !shape && (d->shape1 || d->shape2);
- // one of the connected shape has moved
- const bool connectedShapeChanged = shape && (shape == d->shape1 || shape == d->shape2);
-
- if (!updateIsActive && (connectionChanged || connectedShapeChanged) && isParametricShape())
- updateConnections();
-
- // reset the forced update flag
- d->forceUpdate = false;
-}
-
-QString KoConnectionShape::pathShapeId() const
-{
- return KOCONNECTIONSHAPEID;
-}
diff --git a/libs/flake/KoConnectionShape.h b/libs/flake/KoConnectionShape.h
deleted file mode 100644
index 1bd18948b6..0000000000
--- a/libs/flake/KoConnectionShape.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Boudewijn Rempt <boud@kde.org>
- * Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- * Copyright (C) 2009 Thomas Zander <zander@kde.org>
- *
- * 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_CONNECTION_SHAPE_H
-#define KO_CONNECTION_SHAPE_H
-
-#include "KoParameterShape.h"
-
-#include "kritaflake_export.h"
-
-#define KOCONNECTIONSHAPEID "KoConnectionShape"
-
-class KoConnectionShapePrivate;
-
-/// API docs go here
-class KRITAFLAKE_EXPORT KoConnectionShape : public KoParameterShape
-{
-public:
- enum Type {
- Standard, ///< escapes connected shapes with straight lines, connects with perpendicular lines
- Lines, ///< escapes connected shapes with straight lines, connects with straight line
- Straight, ///< one straight line between connected shapes
- Curve ///< a single curved line between connected shapes
- };
-
- // IDs of the connecting handles
- enum HandleId {
- StartHandle,
- EndHandle,
- ControlHandle_1,
- ControlHandle_2,
- ControlHandle_3
- };
-
- KoConnectionShape();
- ~KoConnectionShape() override;
-
- KoShape* cloneShape() const override;
-
- // reimplemented
- void saveOdf(KoShapeSavingContext &context) const override;
-
- // reimplemented
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
-
- // reimplemented
- QString pathShapeId() const override;
-
- /**
- * Sets the first shape this connector is connected to
- *
- * Passing a null pointer as the first parameter will sever the connection.
- *
- * @param shape the shape to connect to or null to reset the connection
- * @param connectionPointId the id of the connection point to connect to
- * @return true if connection could be established, otherwise false
- */
- bool connectFirst(KoShape *shape, int connectionPointId);
-
- /**
- * Sets the second shape the connector is connected to
- *
- * Passing a null pointer as the first parameter will sever the connection.
- *
- * @param shape the shape to connect to or null to reset the connection
- * @param connectionPointId the id of the connection point to connect to
- * @return true if connection could be established, otherwise false
- */
- bool connectSecond(KoShape *shape, int connectionPointId);
-
- /**
- * Return the first shape this connection is attached to, or null if none.
- */
- KoShape *firstShape() const;
-
- /**
- * Return the connection point id of the first shape we are connected to.
- * In case we are not connected to a first shape the return value is undefined.
- * @see firstShape(), KoShape::connectionPoints()
- */
- int firstConnectionId() const;
-
- /**
- * Return the second shape this connection is attached to, or null if none.
- */
- KoShape *secondShape() const;
-
- /**
- * Return the connection point id of the second shape we are connected to.
- * In case we are not connected to a second shape the return value is undefined.
- * @see firstShape(), KoShape::connectionPoints()
- */
- int secondConnectionId() const;
-
- /**
- * Finishes the loading of a connection.
- */
- void finishLoadingConnection();
-
- /// Returns connection type
- Type type() const;
-
- /// Sets the connection type
- void setType(Type connectionType);
-
- /// Updates connections to shapes
- void updateConnections();
-
-protected:
- KoConnectionShape(const KoConnectionShape &rhs);
-
-
- /// reimplemented
- void moveHandleAction(int handleId, const QPointF &point, Qt::KeyboardModifiers modifiers = Qt::NoModifier) override;
-
- /// reimplemented
- void updatePath(const QSizeF &size) override;
-
- /// reimplemented
- void shapeChanged(ChangeType type, KoShape *shape) override;
-private:
- QPointF escapeDirection(int handleId) const;
-
- /// Populate the path list by a normal way
- void normalPath(const qreal MinimumEscapeLength);
-
-private:
- class Private;
- QSharedDataPointer<Private> d;
-};
-
-#endif
diff --git a/libs/flake/KoConnectionShapeConfigWidget.cpp b/libs/flake/KoConnectionShapeConfigWidget.cpp
deleted file mode 100644
index 5c704b396a..0000000000
--- a/libs/flake/KoConnectionShapeConfigWidget.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "KoConnectionShapeConfigWidget.h"
-#include "commands/KoConnectionShapeTypeCommand.h"
-#include <KoIcon.h>
-#include <klocalizedstring.h>
-
-KoConnectionShapeConfigWidget::KoConnectionShapeConfigWidget()
-{
- widget.setupUi(this);
-
- widget.connectionType->clear();
- widget.connectionType->addItem(koIcon("standard-connector"), i18n("Standard"));
- widget.connectionType->addItem(koIcon("lines-connector"), i18n("Lines"));
- widget.connectionType->addItem(koIcon("straight-connector"), i18n("Straight"));
- widget.connectionType->addItem(koIcon("curve-connector"), i18n("Curve"));
-
- connect(widget.connectionType, SIGNAL(currentIndexChanged(int)), this, SIGNAL(propertyChanged()));
- connect(widget.connectionType, SIGNAL(currentIndexChanged(int)), this, SIGNAL(connectionTypeChanged(int)));
-}
-
-void KoConnectionShapeConfigWidget::setConnectionType(int type)
-{
- widget.connectionType->blockSignals(true);
- widget.connectionType->setCurrentIndex(type);
- widget.connectionType->blockSignals(false);
-}
-
-void KoConnectionShapeConfigWidget::open(KoShape *shape)
-{
- m_connection = dynamic_cast<KoConnectionShape*>(shape);
- if (! m_connection)
- return;
-
- widget.connectionType->blockSignals(true);
- widget.connectionType->setCurrentIndex(m_connection->type());
- widget.connectionType->blockSignals(false);
-}
-
-void KoConnectionShapeConfigWidget::save()
-{
- if (!m_connection) {
- return;
- }
- m_connection->setType(static_cast<KoConnectionShape::Type>(widget.connectionType->currentIndex()));
-}
-
-KUndo2Command * KoConnectionShapeConfigWidget::createCommand()
-{
- if (!m_connection) {
- return 0;
- } else {
- KoConnectionShape::Type type = static_cast<KoConnectionShape::Type>(widget.connectionType->currentIndex());
- return new KoConnectionShapeTypeCommand(m_connection, type);
- }
-}
diff --git a/libs/flake/KoConnectionShapeConfigWidget.h b/libs/flake/KoConnectionShapeConfigWidget.h
deleted file mode 100644
index 109d025e72..0000000000
--- a/libs/flake/KoConnectionShapeConfigWidget.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 KOCONNECTIONSHAPECONFIGWIDGET_H
-#define KOCONNECTIONSHAPECONFIGWIDGET_H
-
-#include "ui_KoConnectionShapeConfigWidget.h"
-
-#include <KoShapeConfigWidgetBase.h>
-
-class KoConnectionShape;
-
-class KoConnectionShapeConfigWidget : public KoShapeConfigWidgetBase
-{
- Q_OBJECT
-public:
- KoConnectionShapeConfigWidget();
- /// reimplemented
- void open(KoShape *shape) override;
- /// reimplemented
- void save() override;
- /// reimplemented
- bool showOnShapeCreate() override {
- return false;
- }
- /// reimplemented
- KUndo2Command *createCommand() override;
-
-Q_SIGNALS:
- void connectionTypeChanged(int type);
-
-public Q_SLOTS:
- void setConnectionType(int type);
-
-private:
- Ui::KoConnectionShapeConfigWidget widget;
- KoConnectionShape *m_connection;
-};
-
-#endif // KOCONNECTIONSHAPECONFIGWIDGET_H
diff --git a/libs/flake/KoConnectionShapeConfigWidget.ui b/libs/flake/KoConnectionShapeConfigWidget.ui
deleted file mode 100644
index 4b5903630b..0000000000
--- a/libs/flake/KoConnectionShapeConfigWidget.ui
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>KoConnectionShapeConfigWidget</class>
- <widget class="QWidget" name="KoConnectionShapeConfigWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>187</width>
- <height>46</height>
- </rect>
- </property>
- <layout class="QFormLayout">
- <item row="0" column="0">
- <widget class="QLabel">
- <property name="text">
- <string>Type:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QComboBox" name="connectionType"/>
- </item>
- <item row="1" column="1">
- <widget class="QWidget" name="SpecialSpacer">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/libs/flake/KoConnectionShapeFactory.cpp b/libs/flake/KoConnectionShapeFactory.cpp
deleted file mode 100644
index bbb03e193d..0000000000
--- a/libs/flake/KoConnectionShapeFactory.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2007 Boudewijn Rempt <boud@kde.org>
- * Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "KoConnectionShapeFactory.h"
-
-#include "KoConnectionShape.h"
-#include "KoConnectionShapeConfigWidget.h"
-
-#include <KoXmlNS.h>
-#include <KoIcon.h>
-#include <klocalizedstring.h>
-#include <KoShapeStroke.h>
-#include <KoShapeLoadingContext.h>
-
-#include "kis_pointer_utils.h"
-
-KoConnectionShapeFactory::KoConnectionShapeFactory()
- : KoShapeFactoryBase(KOCONNECTIONSHAPEID, i18n("Tie"))
-{
- setToolTip(i18n("A connection between two other shapes"));
- setIconName(koIconNameCStr("x-shape-connection"));
- setXmlElementNames(KoXmlNS::draw, QStringList("connector"));
- setLoadingPriority(1);
- setHidden(true); // Don't show this shape in collections. Only ConnectionTool should create
-}
-
-KoShape* KoConnectionShapeFactory::createDefaultShape(KoDocumentResourceManager *) const
-{
- KoConnectionShape * shape = new KoConnectionShape();
- shape->setStroke(toQShared(new KoShapeStroke()));
- shape->setShapeId(KoPathShapeId);
- return shape;
-}
-
-bool KoConnectionShapeFactory::supports(const KoXmlElement & e, KoShapeLoadingContext &context) const
-{
- Q_UNUSED(context);
- return (e.localName() == "connector" && e.namespaceURI() == KoXmlNS::draw);
-}
-
-QList<KoShapeConfigWidgetBase*> KoConnectionShapeFactory::createShapeOptionPanels()
-{
- QList<KoShapeConfigWidgetBase*> panels;
- panels.append(new KoConnectionShapeConfigWidget());
- return panels;
-}
diff --git a/libs/flake/KoConnectionShapeFactory.h b/libs/flake/KoConnectionShapeFactory.h
deleted file mode 100644
index dde8a6bb0e..0000000000
--- a/libs/flake/KoConnectionShapeFactory.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Boudewijn Rempt <boud@kde.org>
- * Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 CONNECTIONSHAPEFACTORY_H
-#define CONNECTIONSHAPEFACTORY_H
-
-#include <KoShapeFactoryBase.h>
-
-class KoShape;
-
-class KoConnectionShapeFactory : public KoShapeFactoryBase
-{
-public:
- KoConnectionShapeFactory();
- ~KoConnectionShapeFactory() override {}
-
- KoShape *createDefaultShape(KoDocumentResourceManager *documentResources = 0) const override;
- bool supports(const KoXmlElement &e, KoShapeLoadingContext &context) const override;
- QList<KoShapeConfigWidgetBase*> createShapeOptionPanels() override;
-};
-
-#endif
diff --git a/libs/flake/KoConnectionShapeLoadingUpdater.cpp b/libs/flake/KoConnectionShapeLoadingUpdater.cpp
deleted file mode 100644
index 1ed7aa8ef7..0000000000
--- a/libs/flake/KoConnectionShapeLoadingUpdater.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2009 Thorsten Zachmann <zachmann@kde.org>
-
- 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 "KoConnectionShapeLoadingUpdater.h"
-
-#include "KoConnectionShape.h"
-
-KoConnectionShapeLoadingUpdater::KoConnectionShapeLoadingUpdater(KoConnectionShape * connectionShape, ConnectionPosition position)
-: m_connectionShape(connectionShape)
-, m_position(position)
-{
-}
-
-KoConnectionShapeLoadingUpdater::~KoConnectionShapeLoadingUpdater()
-{
-}
-
-void KoConnectionShapeLoadingUpdater::update(KoShape * shape)
-{
- if (m_position == First) {
- m_connectionShape->connectFirst(shape, m_connectionShape->firstConnectionId());
- } else {
- m_connectionShape->connectSecond(shape, m_connectionShape->secondConnectionId());
- }
- m_connectionShape->finishLoadingConnection();
-}
diff --git a/libs/flake/KoConnectionShapeLoadingUpdater.h b/libs/flake/KoConnectionShapeLoadingUpdater.h
deleted file mode 100644
index 01cb1ab819..0000000000
--- a/libs/flake/KoConnectionShapeLoadingUpdater.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2009 Thorsten Zachmann <zachmann@kde.org>
-
- 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 KOCONNECTIONSHAPELOADINGUPDATER_H
-#define KOCONNECTIONSHAPELOADINGUPDATER_H
-
-#include <KoLoadingShapeUpdater.h>
-
-class KoConnectionShape;
-class KoShape;
-
-class KoConnectionShapeLoadingUpdater : public KoLoadingShapeUpdater
-{
-public:
- enum ConnectionPosition
- {
- First,
- Second
- };
-
- KoConnectionShapeLoadingUpdater(KoConnectionShape *connectionShape, ConnectionPosition position);
- ~KoConnectionShapeLoadingUpdater() override;
-
- void update(KoShape *shape) override;
-
-private:
- KoConnectionShape *m_connectionShape;
- ConnectionPosition m_position;
-};
-
-#endif /* KOCONNECTIONSHAPELOADINGUPDATER_H */
diff --git a/libs/flake/KoConnectionShape_p.h b/libs/flake/KoConnectionShape_p.h
deleted file mode 100644
index 4ae71ee25d..0000000000
--- a/libs/flake/KoConnectionShape_p.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2009 Thomas Zander <zander@kde.org>
- *
- * 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 KOCONNECTIONSHAPEPRIVATE_P
-#define KOCONNECTIONSHAPEPRIVATE_P
-
-#include <QSharedData>
-#include "KoConnectionShape.h"
-
-class KoConnectionShape::Private : public QSharedData
-{
-public:
- explicit Private();
- explicit Private(const Private &rhs);
-
- /// Checks if rays from given points into given directions intersect
- bool intersects(const QPointF &p1, const QPointF &d1, const QPointF &p2, const QPointF &d2, QPointF &isect);
-
- /// Returns perpendicular direction from given point p1 and direction d1 toward point p2
- QPointF perpendicularDirection(const QPointF &p1, const QPointF &d1, const QPointF &p2);
-
- qreal scalarProd(const QPointF &v1, const QPointF &v2) const;
- qreal crossProd(const QPointF &v1, const QPointF &v2) const;
-
- /// Returns if given handle is connected to a shape
- bool handleConnected(int handleId) const;
-
- QList<QPointF> path;
-
- KoShape *shape1;
- KoShape *shape2;
- int connectionPointId1;
- int connectionPointId2;
- KoConnectionShape::Type connectionType;
- bool forceUpdate;
- bool hasCustomPath;
-};
-
-#endif
diff --git a/libs/flake/KoDocumentResourceManager.cpp b/libs/flake/KoDocumentResourceManager.cpp
index 553f3f8785..d917b81342 100644
--- a/libs/flake/KoDocumentResourceManager.cpp
+++ b/libs/flake/KoDocumentResourceManager.cpp
@@ -1,214 +1,200 @@
/*
Copyright (c) 2006 Boudewijn Rempt (boud@valdyas.org)
Copyright (C) 2007, 2010 Thomas Zander <zander@kde.org>
Copyright (c) 2008 Carlos Licea <carlos.licea@kdemail.net>
Copyright (c) 2011 Jan Hambrecht <jaham@gmx.net>
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 "KoDocumentResourceManager.h"
#include <QVariant>
#include <kundo2stack.h>
#include <FlakeDebug.h>
#include "KoShape.h"
#include "KoShapeController.h"
#include "KoResourceManager_p.h"
class Q_DECL_HIDDEN KoDocumentResourceManager::Private
{
public:
KoResourceManager manager;
};
KoDocumentResourceManager::KoDocumentResourceManager(QObject *parent)
: QObject(parent),
d(new Private())
{
connect(&d->manager, &KoResourceManager::resourceChanged,
this, &KoDocumentResourceManager::resourceChanged);
}
KoDocumentResourceManager::~KoDocumentResourceManager()
{
delete d;
}
void KoDocumentResourceManager::setResource(int key, const QVariant &value)
{
d->manager.setResource(key, value);
}
QVariant KoDocumentResourceManager::resource(int key) const
{
return d->manager.resource(key);
}
void KoDocumentResourceManager::setResource(int key, const KoColor &color)
{
QVariant v;
v.setValue(color);
setResource(key, v);
}
void KoDocumentResourceManager::setResource(int key, KoShape *shape)
{
QVariant v;
v.setValue(shape);
setResource(key, v);
}
void KoDocumentResourceManager::setResource(int key, const KoUnit &unit)
{
QVariant v;
v.setValue(unit);
setResource(key, v);
}
KoColor KoDocumentResourceManager::koColorResource(int key) const
{
return d->manager.koColorResource(key);
}
bool KoDocumentResourceManager::boolResource(int key) const
{
return d->manager.boolResource(key);
}
int KoDocumentResourceManager::intResource(int key) const
{
return d->manager.intResource(key);
}
QString KoDocumentResourceManager::stringResource(int key) const
{
return d->manager.stringResource(key);
}
QSizeF KoDocumentResourceManager::sizeResource(int key) const
{
return d->manager.sizeResource(key);
}
bool KoDocumentResourceManager::hasResource(int key) const
{
return d->manager.hasResource(key);
}
void KoDocumentResourceManager::clearResource(int key)
{
d->manager.clearResource(key);
}
KUndo2Stack *KoDocumentResourceManager::undoStack() const
{
if (!hasResource(UndoStack))
return 0;
return static_cast<KUndo2Stack*>(resource(UndoStack).value<void*>());
}
void KoDocumentResourceManager::setHandleRadius(int handleRadius)
{
// do not allow arbitrary small handles
if (handleRadius < 5)
handleRadius = 5;
setResource(HandleRadius, QVariant(handleRadius));
}
int KoDocumentResourceManager::handleRadius() const
{
if (hasResource(HandleRadius))
return intResource(HandleRadius);
return 5; // default value (and is used just about everywhere)
}
void KoDocumentResourceManager::setGrabSensitivity(int grabSensitivity)
{
// do not allow arbitrary small grab sensitivity
if (grabSensitivity < 5)
grabSensitivity = 5;
setResource(GrabSensitivity, QVariant(grabSensitivity));
}
int KoDocumentResourceManager::grabSensitivity() const
{
if (hasResource(GrabSensitivity))
return intResource(GrabSensitivity);
return 5; // default value (and is used just about everywhere)
}
void KoDocumentResourceManager::setUndoStack(KUndo2Stack *undoStack)
{
QVariant variant;
variant.setValue<void*>(undoStack);
setResource(UndoStack, variant);
}
KoImageCollection *KoDocumentResourceManager::imageCollection() const
{
if (!hasResource(ImageCollection))
return 0;
return static_cast<KoImageCollection*>(resource(ImageCollection).value<void*>());
}
void KoDocumentResourceManager::setImageCollection(KoImageCollection *ic)
{
QVariant variant;
variant.setValue<void*>(ic);
setResource(ImageCollection, variant);
}
-KoDocumentBase *KoDocumentResourceManager::odfDocument() const
-{
- if (!hasResource(OdfDocument))
- return 0;
- return static_cast<KoDocumentBase*>(resource(OdfDocument).value<void*>());
-}
-
-void KoDocumentResourceManager::setOdfDocument(KoDocumentBase *currentDocument)
-{
- QVariant variant;
- variant.setValue<void*>(currentDocument);
- setResource(OdfDocument, variant);
-}
-
qreal KoDocumentResourceManager::documentResolution() const
{
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(hasResource(DocumentResolution), 72.0);
return resource(DocumentResolution).toReal();
}
QRectF KoDocumentResourceManager::documentRectInPixels() const
{
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(hasResource(DocumentRectInPixels), QRectF(0,0, 777, 666));
return resource(DocumentRectInPixels).toRectF();
}
KoShapeController *KoDocumentResourceManager::globalShapeController() const
{
if (!hasResource(GlobalShapeController))
return 0;
return resource(GlobalShapeController).value<KoShapeController *>();
}
void KoDocumentResourceManager::setGlobalShapeController(KoShapeController *shapeController)
{
QVariant variant;
variant.setValue<KoShapeController *>(shapeController);
setResource(GlobalShapeController, variant);
}
diff --git a/libs/flake/KoDocumentResourceManager.h b/libs/flake/KoDocumentResourceManager.h
index 7c44583f58..7ef045df86 100644
--- a/libs/flake/KoDocumentResourceManager.h
+++ b/libs/flake/KoDocumentResourceManager.h
@@ -1,263 +1,259 @@
/*
Copyright (c) 2006 Boudewijn Rempt (boud@valdyas.org)
Copyright (C) 2007, 2009, 2010 Thomas Zander <zander@kde.org>
Copyright (c) 2008 Carlos Licea <carlos.licea@kdemail.net>
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_DOCUMENTRESOURCEMANAGER_H
#define KO_DOCUMENTRESOURCEMANAGER_H
#include <QObject>
#include "kritaflake_export.h"
class KoShape;
class KUndo2Stack;
class KoImageCollection;
-class KoDocumentBase;
class KoShapeController;
class KoColor;
class KoUnit;
class QVariant;
class QSizeF;
/**
* The KoResourceManager contains a set of per-canvas <i>or</i> per-document
* 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 properties come from the KoDocumentResourceManager::DocumentResource
* See KoShapeController::resourceManager
*
* 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 arbitrary data objects that are stored as pointers you can use
* the following code snippets;
* @code
* QVariant variant;
* variant.setValue<void*>(textShapeData->document());
* resourceManager->setResource(KoText::CurrentTextDocument, variant);
* // and get it out again.
* QVariant var = resourceManager->resource(KoText::CurrentTextDocument);
* document = static_cast<QTextDocument*>(var.value<void*>());
* @endcode
*/
class KRITAFLAKE_EXPORT KoDocumentResourceManager : public QObject
{
Q_OBJECT
public:
/**
* This enum holds identifiers to the resources that can be stored in here.
*/
enum DocumentResource {
UndoStack, ///< The document-wide undo stack (KUndo2Stack)
ImageCollection, ///< The KoImageCollection for the document
- OdfDocument, ///< The document this canvas shows (KoDocumentBase)
+ OdfDocument, ///< OBSOLETE The document this canvas shows
HandleRadius, ///< The handle radius used for drawing handles of any kind
GrabSensitivity, ///< The grab sensitivity used for grabbing handles of any kind
MarkerCollection, ///< The collection holding all markers
GlobalShapeController, ///< The KoShapeController for the document
DocumentResolution, ///< Pixels-per-inch resoluton of the document
DocumentRectInPixels, ///< Bounds of the document in pixels
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.
KoTextStart = 10000 ///< Base number for KoText specific values.
};
/**
* Constructor.
* @param parent the parent QObject, used for memory management.
*/
explicit KoDocumentResourceManager(QObject *parent = 0);
~KoDocumentResourceManager() override;
/**
* Set a resource of any type.
* @param key the integer key
* @param value the new value for the key.
* @see 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 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 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 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 KoDocumentResourceManager::DocumentResource
*/
QVariant resource(int key) const;
/**
* Return the resource determined by param key as a boolean.
* @param key the identifying key for the resource
* @see KoDocumentResourceManager::DocumentResource
*/
bool boolResource(int key) const;
/**
* Return the resource determined by param key as an integer.
* @param key the identifying key for the resource
* @see KoDocumentResourceManager::DocumentResource
*/
int intResource(int key) const;
/**
* Return the resource determined by param key as a KoColor.
* @param key the identifying key for the resource
* @see KoDocumentResourceManager::DocumentResource
*/
KoColor koColorResource(int key) const;
/**
* Return the resource determined by param key as a pointer to a KoShape.
* @param key the identifying key for the resource
* @see KoDocumentResourceManager::DocumentResource
*/
KoShape *koShapeResource(int key) const;
/**
* Return the resource determined by param key as a QString .
* @param key the identifying key for the resource
* @see KoDocumentResourceManager::DocumentResource
*/
QString stringResource(int key) const;
/**
* Return the resource determined by param key as a QSizeF.
* @param key the identifying key for the resource
* @see KoDocumentResourceManager::DocumentResource
*/
QSizeF sizeResource(int key) const;
/**
* Return the resource determined by param key as a KoUnit.
* @param key the identifying key for the resource
* @see KoDocumentResourceManager::DocumentResource
*/
KoUnit unitResource(int key) const;
/**
* Returns true if there is a resource set with the requested key.
* @param key the identifying key for the resource
* @see 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
* There will be a signal emitted with a variable that will return true on QVariable::isNull();
* @see KoDocumentResourceManager::DocumentResource
*/
void clearResource(int key);
/**
* Tools that provide a handle for controlling the content that the tool can edit can
* use this property to alter the radius that a circular handle should have on screen.
* @param handleSize the radius in pixels.
*/
void setHandleRadius(int handleSize);
/// Returns the actual handle radius
int handleRadius() const;
/**
* Tools that are used to grab handles or similar with the mouse
* should use this value to determine if the mouse is near enough
* @param grabSensitivity the grab sensitivity in pixels
*/
void setGrabSensitivity(int grabSensitivity);
/// Returns the actual grab sensitivity
int grabSensitivity() const;
KUndo2Stack *undoStack() const;
void setUndoStack(KUndo2Stack *undoStack);
KoImageCollection *imageCollection() const;
void setImageCollection(KoImageCollection *ic);
- KoDocumentBase *odfDocument() const;
- void setOdfDocument(KoDocumentBase *currentDocument);
-
qreal documentResolution() const;
QRectF documentRectInPixels() const;
/**
* TODO: remove these methods after legacy ODF text shape is removed.
* New code must use documentResolution() and documentRectInPixels()
* instead.
*/
Q_DECL_DEPRECATED KoShapeController *globalShapeController() const;
Q_DECL_DEPRECATED void setGlobalShapeController(KoShapeController *globalShapeController);
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 identifying key for the resource
* @param value the variants new value.
* @see KoDocumentResourceManager::DocumentResource
*/
void resourceChanged(int key, const QVariant &value);
private:
KoDocumentResourceManager(const KoDocumentResourceManager&);
KoDocumentResourceManager& operator=(const KoDocumentResourceManager&);
class Private;
Private *const d;
};
#endif
diff --git a/libs/flake/KoDrag.cpp b/libs/flake/KoDrag.cpp
index 5b4a68246b..6cc805e620 100644
--- a/libs/flake/KoDrag.cpp
+++ b/libs/flake/KoDrag.cpp
@@ -1,128 +1,123 @@
/* This file is part of the KDE project
* Copyright (C) 2007-2008 Thorsten Zachmann <zachmann@kde.org>
* Copyright (C) 2009 Thomas Zander <zander@kde.org>
*
* 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 "KoDrag.h"
-#include "KoDragOdfSaveHelper.h"
#include <QApplication>
#include <QBuffer>
#include <QByteArray>
#include <QClipboard>
#include <QMimeData>
#include <QString>
#include <QTransform>
#include <FlakeDebug.h>
#include <KoStore.h>
-#include <KoGenStyles.h>
-#include <KoOdfWriteStore.h>
#include <KoXmlWriter.h>
-#include <KoDocumentBase.h>
-#include <KoEmbeddedDocumentSaver.h>
#include "KoShapeSavingContext.h"
#include <KoShapeContainer.h>
#include <KoShape.h>
#include <QRect>
#include <SvgWriter.h>
class KoDragPrivate {
public:
KoDragPrivate() : mimeData(0) { }
~KoDragPrivate() { delete mimeData; }
QMimeData *mimeData;
};
KoDrag::KoDrag()
: d(new KoDragPrivate())
{
}
KoDrag::~KoDrag()
{
delete d;
}
bool KoDrag::setSvg(const QList<KoShape *> originalShapes)
{
QRectF boundingRect;
QList<KoShape*> shapes;
Q_FOREACH (KoShape *shape, originalShapes) {
boundingRect |= shape->boundingRect();
KoShape *clonedShape = shape->cloneShape();
/**
* The shape is cloned without its parent's transformation, so we should
* adjust it manually.
*/
KoShape *oldParentShape = shape->parent();
if (oldParentShape) {
clonedShape->applyAbsoluteTransformation(oldParentShape->absoluteTransformation());
}
shapes.append(clonedShape);
}
std::sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
QBuffer buffer;
QLatin1String mimeType("image/svg+xml");
buffer.open(QIODevice::WriteOnly);
const QSizeF pageSize(boundingRect.right(), boundingRect.bottom());
SvgWriter writer(shapes);
writer.save(buffer, pageSize);
buffer.close();
qDeleteAll(shapes);
setData(mimeType, buffer.data());
return true;
}
void KoDrag::setData(const QString &mimeType, const QByteArray &data)
{
if (d->mimeData == 0) {
d->mimeData = new QMimeData();
}
d->mimeData->setData(mimeType, data);
}
void KoDrag::addToClipboard()
{
if (d->mimeData) {
QApplication::clipboard()->setMimeData(d->mimeData);
d->mimeData = 0;
}
}
QMimeData * KoDrag::mimeData()
{
QMimeData *mimeData = d->mimeData;
d->mimeData = 0;
return mimeData;
}
diff --git a/libs/flake/KoDrag.h b/libs/flake/KoDrag.h
index a5a8823305..d034c4600e 100644
--- a/libs/flake/KoDrag.h
+++ b/libs/flake/KoDrag.h
@@ -1,77 +1,76 @@
/* This file is part of the KDE project
* Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
*
* 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 KODRAG_H
#define KODRAG_H
#include "kritaflake_export.h"
#include <QList>
class QMimeData;
class QString;
class QByteArray;
-class KoDragOdfSaveHelper;
class KoDragPrivate;
class KoShape;
/**
* Class for simplifying adding a odf to the clip board
*
* For saving the odf a KoDragOdfSaveHelper class is used.
* It implements the writing of the body of the document. The
* setOdf takes care of saving styles and all the other
* common stuff.
*/
class KRITAFLAKE_EXPORT KoDrag
{
public:
KoDrag();
~KoDrag();
/**
* Load SVG data into the current mime data
*/
bool setSvg(const QList<KoShape*> shapes);
/**
* Add additional mimeTypes
*/
void setData(const QString &mimeType, const QByteArray &data);
/**
* Add the mimeData to the clipboard
*/
void addToClipboard();
/**
* Get the mime data
*
* This transfers the ownership of the mimeData to the caller
*
* This function is for use in automated tests
*/
QMimeData *mimeData();
private:
KoDragPrivate * const d;
};
#endif /* KODRAG_H */
diff --git a/libs/flake/KoDragOdfSaveHelper.cpp b/libs/flake/KoDragOdfSaveHelper.cpp
deleted file mode 100644
index 727e6c57b0..0000000000
--- a/libs/flake/KoDragOdfSaveHelper.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 "KoDragOdfSaveHelper.h"
-#include "KoDragOdfSaveHelper_p.h"
-
-KoDragOdfSaveHelper::KoDragOdfSaveHelper()
- : d_ptr(new KoDragOdfSaveHelperPrivate())
-{
-}
-
-KoDragOdfSaveHelper::KoDragOdfSaveHelper(KoDragOdfSaveHelperPrivate &dd)
- : d_ptr(&dd)
-{
-}
-
-KoDragOdfSaveHelper::~KoDragOdfSaveHelper()
-{
- delete d_ptr;
-}
-
-KoShapeSavingContext *KoDragOdfSaveHelper::context(KoXmlWriter * bodyWriter, KoGenStyles & mainStyles,
- KoEmbeddedDocumentSaver & embeddedSaver)
-{
- Q_D(KoDragOdfSaveHelper);
- Q_ASSERT(d->context == 0);
- d->context = new KoShapeSavingContext(*bodyWriter, mainStyles, embeddedSaver);
- return d->context;
-}
diff --git a/libs/flake/KoDragOdfSaveHelper.h b/libs/flake/KoDragOdfSaveHelper.h
deleted file mode 100644
index 7d126f18d0..0000000000
--- a/libs/flake/KoDragOdfSaveHelper.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* This file is part of the KDE project
- * Copyright ( C ) 2007 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 KODRAGODFSAVEHELPER_H
-#define KODRAGODFSAVEHELPER_H
-
-#include "kritaflake_export.h"
-
-#include <QtGlobal>
-
-class KoShapeSavingContext;
-class KoXmlWriter;
-class KoGenStyles;
-class KoEmbeddedDocumentSaver;
-class KoDragOdfSaveHelperPrivate;
-
-class KRITAFLAKE_EXPORT KoDragOdfSaveHelper
-{
-public:
- KoDragOdfSaveHelper();
- virtual ~KoDragOdfSaveHelper();
-
- /**
- * Create and return the context used for saving
- *
- * If you need a special context for saving you can reimplement this function.
- * The default implementation return a KoShapeSavingContext.
- *
- * The returned context is valid as long as the KoDragOdfSaveHelper is existing
- */
- virtual KoShapeSavingContext *context(KoXmlWriter *bodyWriter, KoGenStyles &mainStyles, KoEmbeddedDocumentSaver &embeddedSaver);
-
- /**
- * This method is called for writing the body of odf document.
- *
- * You need to have created a context before calling this function
- */
- virtual bool writeBody() = 0;
-
-protected:
- /// constructor
- KoDragOdfSaveHelper(KoDragOdfSaveHelperPrivate &);
-
- KoDragOdfSaveHelperPrivate *d_ptr;
-
-private:
- Q_DECLARE_PRIVATE(KoDragOdfSaveHelper)
-};
-
-#endif /* KODRAGODFSAVEHELPER_H */
diff --git a/libs/flake/KoDragOdfSaveHelper_p.h b/libs/flake/KoDragOdfSaveHelper_p.h
deleted file mode 100644
index e2cec41a16..0000000000
--- a/libs/flake/KoDragOdfSaveHelper_p.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2009 Thomas Zander <zander@kde.org>
- *
- * 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 KODRAGODFSAVEHELPER_P_H
-#define KODRAGODFSAVEHELPER_P_H
-
-#include <KoShapeSavingContext.h>
-
-class KoDragOdfSaveHelperPrivate
-{
-public:
- KoDragOdfSaveHelperPrivate() : context(0) { }
- ~KoDragOdfSaveHelperPrivate()
- {
- delete context;
- }
-
- KoShapeSavingContext *context;
-};
-
-#endif
diff --git a/libs/flake/KoFrameShape.h b/libs/flake/KoFrameShape.h
index e067e2b689..1437576fb6 100644
--- a/libs/flake/KoFrameShape.h
+++ b/libs/flake/KoFrameShape.h
@@ -1,99 +1,87 @@
/* This file is part of the KDE project
Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
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 KOFRAMESHAPE_H
#define KOFRAMESHAPE_H
#include "kritaflake_export.h"
class KoShapeLoadingContext;
#include <KoXmlReaderForward.h>
class QString;
/**
* @brief Base class for shapes that are saved as a part of a draw:frame.
*
* Shapes like the TextShape or the PictureShape are implementing this
* class to deal with frames and their attributes.
*
* What follows is a sample taken out of an ODT-file that shows how this works
* together;
* @code
* <draw:frame draw:style-name="fr1" text:anchor-type="paragraph" svg:x="0.6429in" svg:y="0.1409in" svg:width="4.7638in" svg:height="3.3335in">
* <draw:image xlink:href="Pictures/imagename.jpg" />
* </draw:frame>
* @endcode
- *
- * The loading code of the shape gets passed the draw:frame element. Out of this element the
- * odf attributes can be loaded. Then it calls loadOdfFrame which loads the correct frame element
- * the object supports. The loading of the frame element is done in the loadOdfFrameElement.
- *
- * @code
- * bool PictureShape::loadOdf( const KoXmlElement & element, KoShapeLoadingContext &context )
- * {
- * loadOdfAttributes( element, context, OdfAllAttributes );
- * return loadOdfFrame( element, context );
- * }
- * @endcode
*/
class KRITAFLAKE_EXPORT KoFrameShape
{
public:
/**
* Constructor.
*
* \param ns The namespace. E.g. KoXmlNS::draw
* \param element The tag-name. E.g. "image"
*/
KoFrameShape(const QString &ns, const QString &tag);
/**
* Copy contrustor
*/
KoFrameShape(const KoFrameShape &rhs);
/**
* Destructor.
*/
virtual ~KoFrameShape();
/**
* Loads the content of the draw:frame element and it's children. This
* method calls the abstract loadOdfFrameElement() method.
*
* @return false if loading failed
*/
virtual bool loadOdfFrame(const KoXmlElement &element, KoShapeLoadingContext &context);
protected:
/**
* Abstract method to handle loading of the defined inner element like
* e.g. the draw:image element.
* @return false if loading failed
*/
virtual bool loadOdfFrameElement(const KoXmlElement &element, KoShapeLoadingContext &context) = 0;
private:
class Private;
Private * const d;
};
#endif /* KOFRAMESHAPE_H */
diff --git a/libs/flake/KoGradientBackground.cpp b/libs/flake/KoGradientBackground.cpp
index fc9fbf8109..85a42231cc 100644
--- a/libs/flake/KoGradientBackground.cpp
+++ b/libs/flake/KoGradientBackground.cpp
@@ -1,184 +1,138 @@
/* This file is part of the KDE project
* Copyright (C) 2008 Jan Hambrecht <jaham@gmx.net>
*
* 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 "KoGradientBackground.h"
#include "KoFlake.h"
-#include <KoStyleStack.h>
#include <KoXmlNS.h>
-#include <KoOdfLoadingContext.h>
-#include <KoOdfGraphicStyles.h>
#include <KoShapeSavingContext.h>
#include <FlakeDebug.h>
#include <QSharedPointer>
#include <QBrush>
#include <QPainter>
#include <QSharedData>
#include <QPainterPath>
class KoGradientBackground::Private : public QSharedData
{
public:
Private()
: QSharedData()
, gradient(0)
{}
QGradient *gradient;
QTransform matrix;
};
KoGradientBackground::KoGradientBackground(QGradient * gradient, const QTransform &matrix)
: KoShapeBackground()
, d(new Private)
{
d->gradient = gradient;
d->matrix = matrix;
Q_ASSERT(d->gradient);
}
KoGradientBackground::KoGradientBackground(const QGradient & gradient, const QTransform &matrix)
: KoShapeBackground()
, d(new Private)
{
d->gradient = KoFlake::cloneGradient(&gradient);
d->matrix = matrix;
Q_ASSERT(d->gradient);
}
KoGradientBackground::~KoGradientBackground()
{
delete d->gradient;
}
bool KoGradientBackground::compareTo(const KoShapeBackground *other) const
{
const KoGradientBackground *otherGradient = dynamic_cast<const KoGradientBackground*>(other);
return otherGradient &&
d->matrix == otherGradient->d->matrix &&
*d->gradient == *otherGradient->d->gradient;
}
void KoGradientBackground::setTransform(const QTransform &matrix)
{
d->matrix = matrix;
}
QTransform KoGradientBackground::transform() const
{
return d->matrix;
}
void KoGradientBackground::setGradient(const QGradient &gradient)
{
delete d->gradient;
d->gradient = KoFlake::cloneGradient(&gradient);
Q_ASSERT(d->gradient);
}
const QGradient * KoGradientBackground::gradient() const
{
return d->gradient;
}
void KoGradientBackground::paint(QPainter &painter, KoShapePaintingContext &/*context*/, const QPainterPath &fillPath) const
{
if (!d->gradient) return;
if (d->gradient->coordinateMode() == QGradient::ObjectBoundingMode) {
/**
* NOTE: important hack!
*
* Qt has different notation of QBrush::setTransform() in comparison
* to what SVG defines. SVG defines gradientToUser matrix to be postmultiplied
* by QBrush::transform(), but Qt does exactly reverse!
*
* That most probably has beed caused by the fact that Qt uses transposed
* matrices and someone just mistyped the stuff long ago :(
*
* So here we basically emulate this feature by converting the gradient into
* QGradient::LogicalMode and doing transformations manually.
*/
const QRectF boundingRect = fillPath.boundingRect();
QTransform gradientToUser(boundingRect.width(), 0, 0, boundingRect.height(),
boundingRect.x(), boundingRect.y());
// TODO: how about slicing the object?
QGradient g = *d->gradient;
g.setCoordinateMode(QGradient::LogicalMode);
QBrush b(g);
b.setTransform(d->matrix * gradientToUser);
painter.setBrush(b);
} else {
QBrush b(*d->gradient);
b.setTransform(d->matrix);
painter.setBrush(b);
}
painter.drawPath(fillPath);
}
-
-void KoGradientBackground::fillStyle(KoGenStyle &style, KoShapeSavingContext &context)
-{
- if (!d->gradient) return;
- QBrush brush(*d->gradient);
- brush.setTransform(d->matrix);
- KoOdfGraphicStyles::saveOdfFillStyle(style, context.mainStyles(), brush);
-}
-
-bool KoGradientBackground::loadStyle(KoOdfLoadingContext &context, const QSizeF &shapeSize)
-{
- KoStyleStack &styleStack = context.styleStack();
- if (! styleStack.hasProperty(KoXmlNS::draw, "fill"))
- return false;
-
- QString fillStyle = styleStack.property(KoXmlNS::draw, "fill");
- if (fillStyle == "gradient") {
- QBrush brush = KoOdfGraphicStyles::loadOdfGradientStyle(styleStack, context.stylesReader(), shapeSize);
- const QGradient * gradient = brush.gradient();
- if (gradient) {
- d->gradient = KoFlake::cloneGradient(gradient);
- d->matrix = brush.transform();
-
- //Gopalakrishna Bhat: If the brush has transparency then we ignore the draw:opacity property and use the brush transparency.
- // Brush will have transparency if the svg:linearGradient stop point has stop-opacity property otherwise it is opaque
- if (brush.isOpaque() && styleStack.hasProperty(KoXmlNS::draw, "opacity")) {
- QString opacityPercent = styleStack.property(KoXmlNS::draw, "opacity");
- if (! opacityPercent.isEmpty() && opacityPercent.right(1) == "%") {
- float opacity = qMin(opacityPercent.left(opacityPercent.length() - 1).toDouble(), 100.0) / 100;
- QGradientStops stops;
- Q_FOREACH (QGradientStop stop, d->gradient->stops()) {
- stop.second.setAlphaF(opacity);
- stops << stop;
- }
- d->gradient->setStops(stops);
- }
- }
-
- return true;
- }
- }
- return false;
-}
diff --git a/libs/flake/KoGradientBackground.h b/libs/flake/KoGradientBackground.h
index 71955abafe..452866e1f4 100644
--- a/libs/flake/KoGradientBackground.h
+++ b/libs/flake/KoGradientBackground.h
@@ -1,78 +1,74 @@
/* This file is part of the KDE project
* Copyright (C) 2008 Jan Hambrecht <jaham@gmx.net>
*
* 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 KOGRADIENTBACKGROUND_H
#define KOGRADIENTBACKGROUND_H
#include "KoShapeBackground.h"
#include "kritaflake_export.h"
#include <QTransform>
#include <QSharedDataPointer>
class QGradient;
/// A gradient shape background
class KRITAFLAKE_EXPORT KoGradientBackground : public KoShapeBackground
{
public:
/**
* Creates new gradient background from given gradient.
* The background takes ownership of the given gradient.
*/
explicit KoGradientBackground(QGradient *gradient, const QTransform &matrix = QTransform());
/**
* Create new gradient background from the given gradient.
* A clone of the given gradient is used.
*/
explicit KoGradientBackground(const QGradient &gradient, const QTransform &matrix = QTransform());
/// Destroys the background
~KoGradientBackground() override;
bool compareTo(const KoShapeBackground *other) const override;
/// Sets the transform matrix
void setTransform(const QTransform &matrix);
/// Returns the transform matrix
QTransform transform() const;
/**
* Sets a new gradient.
* A clone of the given gradient is used.
*/
void setGradient(const QGradient &gradient);
/// Returns the gradient
const QGradient *gradient() const;
/// reimplemented from KoShapeBackground
void paint(QPainter &painter, KoShapePaintingContext &context, const QPainterPath &fillPath) const override;
- /// reimplemented from KoShapeBackground
- void fillStyle(KoGenStyle &style, KoShapeSavingContext &context) override;
- /// reimplemented from KoShapeBackground
- bool loadStyle(KoOdfLoadingContext &context, const QSizeF &shapeSize) override;
private:
class Private;
QSharedDataPointer<Private> d;
};
#endif // KOGRADIENTBACKGROUND_H
diff --git a/libs/flake/KoHatchBackground.cpp b/libs/flake/KoHatchBackground.cpp
index 3275a590d2..4369d6bbe5 100644
--- a/libs/flake/KoHatchBackground.cpp
+++ b/libs/flake/KoHatchBackground.cpp
@@ -1,238 +1,127 @@
/* This file is part of the KDE project
*
* Copyright (C) 2012 Thorsten Zachmann <zachmann@kde.org>
*
* 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 "KoHatchBackground.h"
-#include <KoOdfLoadingContext.h>
-#include <KoStyleStack.h>
#include <KoShapeSavingContext.h>
-#include <KoGenStyles.h>
-#include <KoGenStyle.h>
+
#include <KoXmlNS.h>
#include <KoUnit.h>
-#include <KoOdfStylesReader.h>
#include <KoXmlReader.h>
#include <FlakeDebug.h>
#include <QColor>
#include <QString>
#include <QPainter>
#include <QPainterPath>
class KoHatchBackground::Private : public QSharedData
{
public:
Private()
: QSharedData()
, angle(0.0)
, distance(1.0)
, style(KoHatchBackground::Single)
{}
QColor lineColor;
int angle;
qreal distance;
KoHatchBackground::HatchStyle style;
QString name;
};
KoHatchBackground::KoHatchBackground()
: KoColorBackground()
, d(new Private)
{
}
KoHatchBackground::~KoHatchBackground()
{
}
void KoHatchBackground::paint(QPainter &painter, KoShapePaintingContext &context, const QPainterPath &fillPath) const
{
if (color().isValid()) {
// paint background color if set by using the color background
KoColorBackground::paint(painter, context, fillPath);
}
const QRectF targetRect = fillPath.boundingRect();
painter.save();
painter.setClipPath(fillPath);
QPen pen(d->lineColor);
// we set the pen width to 0.5 pt for the hatch. This is not defined in the spec.
pen.setWidthF(0.5);
painter.setPen(pen);
QVector<QLineF> lines;
// The different styles are handled by painting the lines multiple times with a different
// angel offset as basically it just means we paint the lines also at a different angle.
// This are the angle offsets we need to apply to the different lines of a style.
// -90 is for single, 0 for the 2nd line in double and -45 for the 3th line in triple.
const int angleOffset[] = {-90, 0, -45 };
// The number of loops is defined by the style.
int loops = (d->style == Single) ? 1 : (d->style == Double) ? 2 : 3;
for (int i = 0; i < loops; ++i) {
int angle = d->angle - angleOffset[i];
qreal cosAngle = ::cos(angle/180.0*M_PI);
// if cos is nearly 0 the lines are horizontal. Use a special case for that
if (qAbs(cosAngle) > 0.00001) {
qreal xDiff = tan(angle/180.0*M_PI) * targetRect.height();
// calculate the distance we need to increase x when creating the lines so that the
// distance between the lines is also correct for rotated lines.
qreal xOffset = qAbs(d->distance / cosAngle);
// if the lines go to the right we need to start more to the left. Get the correct start.
qreal xStart = 0;
while (-xDiff < xStart) {
xStart -= xOffset;
}
// if the lines go to the left we need to stop more at the right. Get the correct end offset
qreal xEndOffset = 0;
if (xDiff < 0) {
while (xDiff < -xEndOffset) {
xEndOffset += xOffset;
}
}
// create line objects.
lines.reserve(lines.size() + int((targetRect.width() + xEndOffset - xStart) / xOffset) + 1);
for (qreal x = xStart; x < targetRect.width() + xEndOffset; x += xOffset) {
lines.append(QLineF(x, 0, x + xDiff, targetRect.height()));
}
}
else {
// horizontal lines
lines.reserve(lines.size() + int(targetRect.height()/d->distance) + 1);
for (qreal y = 0; y < targetRect.height(); y += d->distance) {
lines.append(QLineF(0, y, targetRect.width(), y));
}
}
}
painter.drawLines(lines);
painter.restore();
}
-
-void KoHatchBackground::fillStyle(KoGenStyle &style, KoShapeSavingContext &context)
-{
- KoGenStyle::Type type = style.type();
- KoGenStyle::PropertyType propertyType = (type == KoGenStyle::GraphicStyle || type == KoGenStyle::GraphicAutoStyle ||
- type == KoGenStyle::DrawingPageStyle || type == KoGenStyle::DrawingPageAutoStyle )
- ? KoGenStyle::DefaultType : KoGenStyle::GraphicType;
-
- style.addProperty("draw:fill", "hatch", propertyType);
- style.addProperty("draw:fill-hatch-name", saveHatchStyle(context), propertyType);
- bool fillHatchSolid = color().isValid();
- style.addProperty("draw:fill-hatch-solid", fillHatchSolid, propertyType);
- if (fillHatchSolid) {
- style.addProperty("draw:fill-color", color().name(), propertyType);
- }
-}
-
-QString KoHatchBackground::saveHatchStyle(KoShapeSavingContext &context) const
-{
- KoGenStyle hatchStyle(KoGenStyle::HatchStyle /*no family name*/);
- hatchStyle.addAttribute("draw:display-name", d->name);
- hatchStyle.addAttribute("draw:color", d->lineColor.name());
-
- hatchStyle.addAttribute("draw:distance", d->distance);
-
- hatchStyle.addAttribute("draw:rotation", QString("%1").arg(d->angle * 10));
-
- switch (d->style) {
- case Single:
- hatchStyle.addAttribute("draw:style", "single");
- break;
- case Double:
- hatchStyle.addAttribute("draw:style", "double");
- break;
- case Triple:
- hatchStyle.addAttribute("draw:style", "triple");
- break;
- }
-
- return context.mainStyles().insert(hatchStyle, "hatch");
-}
-
-bool KoHatchBackground::loadStyle(KoOdfLoadingContext &context, const QSizeF &shapeSize)
-{
- // <draw:hatch draw:name="hatchStyle3" draw:color="#000000" draw:display-name="#000000 Vertical" draw:distance="0.102cm" draw:rotation="900" draw:style="single"/>
- Q_UNUSED(shapeSize);
-
- KoStyleStack &styleStack = context.styleStack();
- QString fillStyle = styleStack.property(KoXmlNS::draw, "fill");
- if (fillStyle == "hatch") {
- QString style = styleStack.property(KoXmlNS::draw, "fill-hatch-name");
- debugFlake << " hatch style is :" << style;
-
- KoXmlElement* draw = context.stylesReader().drawStyles("hatch")[style];
- if (draw) {
- debugFlake << "Hatch style found for:" << style;
-
- QString angle = draw->attributeNS(KoXmlNS::draw, "rotation", QString("0"));
- if (angle.at(angle.size()-1).isLetter()) {
- d->angle = KoUnit::parseAngle(angle);
- }
- else {
- // OO saves the angle value without unit and multiplied by a factor of 10
- d->angle = int(angle.toInt() / 10);
- }
-
- debugFlake << "angle :" << d->angle;
-
- d->name = draw->attributeNS(KoXmlNS::draw, "display-name");
-
- // use 2mm as default, just in case it is not given in a document so we show something sensible.
- d->distance = KoUnit::parseValue(draw->attributeNS(KoXmlNS::draw, "distance", "2mm"));
-
- bool fillHatchSolid = styleStack.property(KoXmlNS::draw, "fill-hatch-solid") == QLatin1String("true");
- if (fillHatchSolid) {
- QString fillColor = styleStack.property(KoXmlNS::draw, "fill-color");
- if (!fillColor.isEmpty()) {
- QColor c = color();
- c.setNamedColor(fillColor);
- setColor(c);
- }
- else {
- setColor(QColor());
- }
- }
- else {
- setColor(QColor());
- }
- d->lineColor.setNamedColor(draw->attributeNS(KoXmlNS::draw, "color", QString("#000000")));
-
- QString style = draw->attributeNS(KoXmlNS::draw, "style", QString());
- if (style == "double") {
- d->style = Double;
- }
- else if (style == "triple") {
- d->style = Triple;
- }
- else {
- d->style = Single;
- }
- }
-
- return true;
- }
-
- return false;
-}
diff --git a/libs/flake/KoHatchBackground.h b/libs/flake/KoHatchBackground.h
index 3f50301c17..2252b36aa0 100644
--- a/libs/flake/KoHatchBackground.h
+++ b/libs/flake/KoHatchBackground.h
@@ -1,58 +1,49 @@
/* This file is part of the KDE project
*
* Copyright (C) 2012 Thorsten Zachmann <zachmann@kde.org>
*
* 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 KOHATCHBACKGROUND_H
#define KOHATCHBACKGROUND_H
#include "KoColorBackground.h"
/**
* A hatch shape background
*/
class KoHatchBackground : public KoColorBackground
{
public:
enum HatchStyle {
Single,
Double,
Triple
};
KoHatchBackground();
~KoHatchBackground() override;
// reimplemented
void paint(QPainter &painter, KoShapePaintingContext &context, const QPainterPath &fillPath) const override;
- // reimplemented
- void fillStyle(KoGenStyle &style, KoShapeSavingContext &context) override;
-
- // reimplemented
- bool loadStyle(KoOdfLoadingContext &context, const QSizeF &shapeSize) override;
-
-private:
- QString saveHatchStyle(KoShapeSavingContext &context) const;
-
private:
class Private;
QSharedDataPointer<Private> d;
};
#endif /* KOHATCHBACKGROUND_H */
diff --git a/libs/flake/KoMarker.cpp b/libs/flake/KoMarker.cpp
index a27b20a915..c099d02c2d 100644
--- a/libs/flake/KoMarker.cpp
+++ b/libs/flake/KoMarker.cpp
@@ -1,416 +1,413 @@
/* This file is part of the KDE project
Copyright (C) 2011 Thorsten Zachmann <zachmann@kde.org>
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 "KoMarker.h"
#include <KoXmlReader.h>
#include <KoXmlNS.h>
-#include <KoGenStyle.h>
-#include <KoGenStyles.h>
#include "KoPathShape.h"
#include "KoPathShapeLoader.h"
#include "KoShapeLoadingContext.h"
#include "KoShapeSavingContext.h"
-#include "KoOdfWorkaround.h"
#include "KoShapePainter.h"
#include <KoShapeStroke.h>
#include <KoGradientBackground.h>
#include <KoColorBackground.h>
#include <QString>
#include <QUrl>
#include <QPainterPath>
#include <QPainter>
#include "kis_global.h"
#include "kis_algebra_2d.h"
class Q_DECL_HIDDEN KoMarker::Private
{
public:
Private()
: coordinateSystem(StrokeWidth),
referenceSize(3,3),
hasAutoOrientation(false),
explicitOrientation(0)
{}
~Private() {
// shape manager that is stored in the painter should be destroyed
// before the shapes themselves
shapePainter.reset();
qDeleteAll(shapes);
}
bool operator==(const KoMarker::Private &other) const
{
// WARNING: comparison of shapes is extremely fuzzy! Don't
// trust it in life-critical cases!
return name == other.name &&
coordinateSystem == other.coordinateSystem &&
referencePoint == other.referencePoint &&
referenceSize == other.referenceSize &&
hasAutoOrientation == other.hasAutoOrientation &&
explicitOrientation == other.explicitOrientation &&
compareShapesTo(other.shapes);
}
Private(const Private &rhs)
: name(rhs.name),
coordinateSystem(rhs.coordinateSystem),
referencePoint(rhs.referencePoint),
referenceSize(rhs.referenceSize),
hasAutoOrientation(rhs.hasAutoOrientation),
explicitOrientation(rhs.explicitOrientation)
{
Q_FOREACH (KoShape *shape, rhs.shapes) {
shapes << shape->cloneShape();
}
}
QString name;
MarkerCoordinateSystem coordinateSystem;
QPointF referencePoint;
QSizeF referenceSize;
bool hasAutoOrientation;
qreal explicitOrientation;
QList<KoShape*> shapes;
QScopedPointer<KoShapePainter> shapePainter;
bool compareShapesTo(const QList<KoShape*> other) const {
if (shapes.size() != other.size()) return false;
for (int i = 0; i < shapes.size(); i++) {
if (shapes[i]->outline() != other[i]->outline() ||
shapes[i]->absoluteTransformation() != other[i]->absoluteTransformation()) {
return false;
}
}
return true;
}
QTransform markerTransform(qreal strokeWidth, qreal nodeAngle, const QPointF &pos = QPointF()) {
const QTransform translate = QTransform::fromTranslate(-referencePoint.x(), -referencePoint.y());
QTransform t = translate;
if (coordinateSystem == StrokeWidth) {
t *= QTransform::fromScale(strokeWidth, strokeWidth);
}
const qreal angle = hasAutoOrientation ? nodeAngle : explicitOrientation;
if (angle != 0.0) {
QTransform r;
r.rotateRadians(angle);
t *= r;
}
t *= QTransform::fromTranslate(pos.x(), pos.y());
return t;
}
};
KoMarker::KoMarker()
: d(new Private())
{
}
KoMarker::~KoMarker()
{
delete d;
}
QString KoMarker::name() const
{
return d->name;
}
KoMarker::KoMarker(const KoMarker &rhs)
: QSharedData(rhs),
d(new Private(*rhs.d))
{
}
bool KoMarker::operator==(const KoMarker &other) const
{
return *d == *other.d;
}
void KoMarker::setCoordinateSystem(KoMarker::MarkerCoordinateSystem value)
{
d->coordinateSystem = value;
}
KoMarker::MarkerCoordinateSystem KoMarker::coordinateSystem() const
{
return d->coordinateSystem;
}
KoMarker::MarkerCoordinateSystem KoMarker::coordinateSystemFromString(const QString &value)
{
MarkerCoordinateSystem result = StrokeWidth;
if (value == "userSpaceOnUse") {
result = UserSpaceOnUse;
}
return result;
}
QString KoMarker::coordinateSystemToString(KoMarker::MarkerCoordinateSystem value)
{
return
value == StrokeWidth ?
"strokeWidth" :
"userSpaceOnUse";
}
void KoMarker::setReferencePoint(const QPointF &value)
{
d->referencePoint = value;
}
QPointF KoMarker::referencePoint() const
{
return d->referencePoint;
}
void KoMarker::setReferenceSize(const QSizeF &size)
{
d->referenceSize = size;
}
QSizeF KoMarker::referenceSize() const
{
return d->referenceSize;
}
bool KoMarker::hasAutoOtientation() const
{
return d->hasAutoOrientation;
}
void KoMarker::setAutoOrientation(bool value)
{
d->hasAutoOrientation = value;
}
qreal KoMarker::explicitOrientation() const
{
return d->explicitOrientation;
}
void KoMarker::setExplicitOrientation(qreal value)
{
d->explicitOrientation = value;
}
void KoMarker::setShapes(const QList<KoShape *> &shapes)
{
d->shapes = shapes;
if (d->shapePainter) {
d->shapePainter->setShapes(shapes);
}
}
QList<KoShape *> KoMarker::shapes() const
{
return d->shapes;
}
void KoMarker::paintAtPosition(QPainter *painter, const QPointF &pos, qreal strokeWidth, qreal nodeAngle)
{
QTransform oldTransform = painter->transform();
if (!d->shapePainter) {
d->shapePainter.reset(new KoShapePainter());
d->shapePainter->setShapes(d->shapes);
}
painter->setTransform(d->markerTransform(strokeWidth, nodeAngle, pos), true);
d->shapePainter->paint(*painter);
painter->setTransform(oldTransform);
}
qreal KoMarker::maxInset(qreal strokeWidth) const
{
QRectF shapesBounds = boundingRect(strokeWidth, 0.0); // normalized to 0,0
qreal result = 0.0;
result = qMax(KisAlgebra2D::norm(shapesBounds.topLeft()), result);
result = qMax(KisAlgebra2D::norm(shapesBounds.topRight()), result);
result = qMax(KisAlgebra2D::norm(shapesBounds.bottomLeft()), result);
result = qMax(KisAlgebra2D::norm(shapesBounds.bottomRight()), result);
if (d->coordinateSystem == StrokeWidth) {
result *= strokeWidth;
}
return result;
}
QRectF KoMarker::boundingRect(qreal strokeWidth, qreal nodeAngle) const
{
QRectF shapesBounds = KoShape::boundingRect(d->shapes);
const QTransform t = d->markerTransform(strokeWidth, nodeAngle);
if (!t.isIdentity()) {
shapesBounds = t.mapRect(shapesBounds);
}
return shapesBounds;
}
QPainterPath KoMarker::outline(qreal strokeWidth, qreal nodeAngle) const
{
QPainterPath outline;
Q_FOREACH (KoShape *shape, d->shapes) {
outline |= shape->absoluteTransformation().map(shape->outline());
}
const QTransform t = d->markerTransform(strokeWidth, nodeAngle);
if (!t.isIdentity()) {
outline = t.map(outline);
}
return outline;
}
void KoMarker::drawPreview(QPainter *painter, const QRectF &previewRect, const QPen &pen, KoFlake::MarkerPosition position)
{
const QRectF outlineRect = outline(pen.widthF(), 0).boundingRect(); // normalized to 0,0
QPointF marker;
QPointF start;
QPointF end;
if (position == KoFlake::StartMarker) {
marker = QPointF(-outlineRect.left() + previewRect.left(), previewRect.center().y());
start = marker;
end = QPointF(previewRect.right(), start.y());
} else if (position == KoFlake::MidMarker) {
start = QPointF(previewRect.left(), previewRect.center().y());
marker = QPointF(-outlineRect.center().x() + previewRect.center().x(), start.y());
end = QPointF(previewRect.right(), start.y());
} else if (position == KoFlake::EndMarker) {
start = QPointF(previewRect.left(), previewRect.center().y());
marker = QPointF(-outlineRect.right() + previewRect.right(), start.y());
end = marker;
}
painter->save();
painter->setPen(pen);
painter->setClipRect(previewRect);
painter->drawLine(start, end);
paintAtPosition(painter, marker, pen.widthF(), 0);
painter->restore();
}
void KoMarker::applyShapeStroke(const KoShape *parentShape, KoShapeStroke *stroke, const QPointF &pos, qreal strokeWidth, qreal nodeAngle)
{
const QGradient *originalGradient = stroke->lineBrush().gradient();
if (!originalGradient) {
QList<KoShape*> linearizedShapes = KoShape::linearizeSubtree(d->shapes);
Q_FOREACH(KoShape *shape, linearizedShapes) {
// update the stroke
KoShapeStrokeSP shapeStroke = shape->stroke() ?
qSharedPointerDynamicCast<KoShapeStroke>(shape->stroke()) :
KoShapeStrokeSP();
if (shapeStroke) {
shapeStroke = toQShared(new KoShapeStroke(*shapeStroke));
shapeStroke->setLineBrush(QBrush());
shapeStroke->setColor(stroke->color());
shape->setStroke(shapeStroke);
}
// update the background
if (shape->background()) {
QSharedPointer<KoColorBackground> bg(new KoColorBackground(stroke->color()));
shape->setBackground(bg);
}
}
} else {
QScopedPointer<QGradient> g(KoFlake::cloneGradient(originalGradient));
KIS_ASSERT_RECOVER_RETURN(g);
const QTransform markerTransformInverted =
d->markerTransform(strokeWidth, nodeAngle, pos).inverted();
QTransform gradientToUser;
// Unwrap the gradient to work in global mode
if (g->coordinateMode() == QGradient::ObjectBoundingMode) {
QRectF boundingRect =
parentShape ?
parentShape->outline().boundingRect() :
this->boundingRect(strokeWidth, nodeAngle);
boundingRect = KisAlgebra2D::ensureRectNotSmaller(boundingRect, QSizeF(1.0, 1.0));
gradientToUser = QTransform(boundingRect.width(), 0, 0, boundingRect.height(),
boundingRect.x(), boundingRect.y());
g->setCoordinateMode(QGradient::LogicalMode);
}
QList<KoShape*> linearizedShapes = KoShape::linearizeSubtree(d->shapes);
Q_FOREACH(KoShape *shape, linearizedShapes) {
// shape-unwinding transform
QTransform t = gradientToUser * markerTransformInverted * shape->absoluteTransformation().inverted();
// update the stroke
KoShapeStrokeSP shapeStroke = shape->stroke() ?
qSharedPointerDynamicCast<KoShapeStroke>(shape->stroke()) :
KoShapeStrokeSP();
if (shapeStroke) {
shapeStroke = toQShared(new KoShapeStroke(*shapeStroke));
QBrush brush(*g);
brush.setTransform(t);
shapeStroke->setLineBrush(brush);
shapeStroke->setColor(Qt::transparent);
shape->setStroke(shapeStroke);
}
// update the background
if (shape->background()) {
QSharedPointer<KoGradientBackground> bg(new KoGradientBackground(KoFlake::cloneGradient(g.data()), t));
shape->setBackground(bg);
}
}
}
}
diff --git a/libs/flake/KoOdfGradientBackground.cpp b/libs/flake/KoOdfGradientBackground.cpp
deleted file mode 100644
index fe0f561bc4..0000000000
--- a/libs/flake/KoOdfGradientBackground.cpp
+++ /dev/null
@@ -1,380 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2011 Lukáš Tvrdý <lukas.tvrdy@ixonos.com>
- *
- * 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 "KoOdfGradientBackground.h"
-
-#include "KoShapeSavingContext.h"
-
-#include <KoUnit.h>
-#include <KoXmlNS.h>
-#include <KoXmlReader.h>
-#include <KoGenStyles.h>
-#include <KoOdfLoadingContext.h>
-#include <KoStyleStack.h>
-#include <KoOdfStylesReader.h>
-
-#include <QPainter>
-#include <QPainterPath>
-#include <QColor>
-#include <QImage>
-#include <qmath.h>
-#include <QSharedData>
-
-#include "FlakeDebug.h"
-
-class KoOdfGradientBackground::Private : public QSharedData
-{
-public:
- Private()
- : QSharedData()
- , style()
- , cx(0)
- , cy(0)
- , startColor()
- , endColor()
- , angle(0)
- , border(0)
- , opacity(1.0)
- {}
- ~Private() = default;
- //data
- QString style;
- int cx;
- int cy;
- QColor startColor;
- QColor endColor;
- qreal angle;
- qreal border;
- qreal opacity;
-};
-
-
-KoOdfGradientBackground::KoOdfGradientBackground()
- : KoShapeBackground()
- , d(new Private)
-{
-
-}
-
-KoOdfGradientBackground::~KoOdfGradientBackground()
-{
-
-}
-
-bool KoOdfGradientBackground::compareTo(const KoShapeBackground *other) const
-{
- Q_UNUSED(other);
- return false;
-}
-
-
-bool KoOdfGradientBackground::loadOdf(const KoXmlElement& e)
-{
- d->style = e.attributeNS(KoXmlNS::draw, "style", QString());
- //TODO: support ellipsoid here too
- if ((d->style != "rectangular") && (d->style != "square")) {
- return false;
- }
-
- d->cx = KoUnit::parseValue(e.attributeNS(KoXmlNS::draw, "cx", QString()).remove('%'));
- d->cy = KoUnit::parseValue(e.attributeNS(KoXmlNS::draw, "cy", QString()).remove('%'));
-
- d->border = qBound(0.0,0.01 * e.attributeNS(KoXmlNS::draw, "border", "0").remove('%').toDouble(),1.0);
-
- d->startColor = QColor(e.attributeNS(KoXmlNS::draw, "start-color", QString()));
- d->startColor.setAlphaF((0.01 * e.attributeNS(KoXmlNS::draw, "start-intensity", "100").remove('%').toDouble()));
-
- d->endColor = QColor(e.attributeNS(KoXmlNS::draw, "end-color", QString()));
- d->endColor.setAlphaF(0.01 * e.attributeNS(KoXmlNS::draw, "end-intensity", "100").remove('%').toDouble());
- d->angle = e.attributeNS(KoXmlNS::draw, "angle", "0").toDouble() / 10;
-
- return true;
-}
-
-
-void KoOdfGradientBackground::saveOdf(KoGenStyle& styleFill, KoGenStyles& mainStyles) const
-{
- KoGenStyle::Type type = styleFill.type();
- KoGenStyle::PropertyType propertyType = (type == KoGenStyle::GraphicStyle || type == KoGenStyle::GraphicAutoStyle ||
- type == KoGenStyle::DrawingPageStyle || type == KoGenStyle::DrawingPageAutoStyle )
- ? KoGenStyle::DefaultType : KoGenStyle::GraphicType;
-
- KoGenStyle gradientStyle(KoGenStyle::GradientStyle);
-
- gradientStyle.addAttribute("draw:style", d->style); // draw:style="square"
- gradientStyle.addAttribute("draw:cx", QString("%1%").arg(d->cx));
- gradientStyle.addAttribute("draw:cy", QString("%1%").arg(d->cy));
- gradientStyle.addAttribute("draw:start-color", d->startColor.name());
- gradientStyle.addAttribute("draw:end-color", d->endColor.name());
- gradientStyle.addAttribute("draw:start-intensity", QString("%1%").arg(qRound(d->startColor.alphaF() * 100)) );
- gradientStyle.addAttribute("draw:end-intensity", QString("%1%").arg(qRound(d->endColor.alphaF() * 100)) );
- gradientStyle.addAttribute("draw:angle", QString("%1").arg(d->angle * 10));
- gradientStyle.addAttribute("draw:border", QString("%1%").arg(qRound(d->border * 100.0)));
-
- QString gradientStyleName = mainStyles.insert(gradientStyle, "gradient");
-
- styleFill.addProperty("draw:fill", "gradient", propertyType);
- styleFill.addProperty("draw:fill-gradient-name", gradientStyleName, propertyType);
- if (d->opacity <= 1.0) {
- styleFill.addProperty("draw:opacity", QString("%1%").arg(d->opacity * 100.0), propertyType);
- }
-}
-
-void KoOdfGradientBackground::paint(QPainter& painter, KoShapePaintingContext &/*context*/, const QPainterPath& fillPath) const
-{
- QImage buffer;
-
- QRectF targetRect = fillPath.boundingRect();
- QRectF pixels = painter.transform().mapRect(QRectF(0,0,targetRect.width(), targetRect.height()));
- QSize currentSize( qCeil(pixels.size().width()), qCeil(pixels.size().height()) );
- if (buffer.isNull() || buffer.size() != currentSize){
- buffer = QImage(currentSize, QImage::Format_ARGB32_Premultiplied);
- if (d->style == "square") {
- renderSquareGradient(buffer);
- } else {
- renderRectangleGradient(buffer);
- }
- }
-
- painter.setClipPath(fillPath);
-
- painter.setOpacity(d->opacity);
- painter.drawImage(targetRect, buffer, QRectF(QPointF(0,0), buffer.size()));
-}
-
-void KoOdfGradientBackground::fillStyle(KoGenStyle& style, KoShapeSavingContext& context)
-{
- saveOdf(style, context.mainStyles());
-}
-
-bool KoOdfGradientBackground::loadStyle(KoOdfLoadingContext& context, const QSizeF& shapeSize)
-{
- Q_UNUSED(shapeSize);
-
- KoStyleStack &styleStack = context.styleStack();
- if (!styleStack.hasProperty(KoXmlNS::draw, "fill")) {
- return false;
- }
-
- QString fillStyle = styleStack.property(KoXmlNS::draw, "fill");
- if (fillStyle == "gradient") {
-
- if (styleStack.hasProperty(KoXmlNS::draw, "opacity")) {
- QString opacity = styleStack.property(KoXmlNS::draw, "opacity");
- if (! opacity.isEmpty() && opacity.right(1) == "%") {
- d->opacity = qMin(opacity.left(opacity.length() - 1).toDouble(), 100.0) / 100;
- }
- }
-
- QString styleName = styleStack.property(KoXmlNS::draw, "fill-gradient-name");
- KoXmlElement * e = context.stylesReader().drawStyles("gradient")[styleName];
- return loadOdf(*e);
- }
-
- return false;
-}
-
-
-void KoOdfGradientBackground::renderSquareGradient(QImage& buffer) const
-{
- buffer.fill(d->startColor.rgba());
-
- QPainter painter(&buffer);
- painter.setPen(Qt::NoPen);
- painter.setRenderHint(QPainter::Antialiasing, false);
-
- int width = buffer.width();
- int height = buffer.height();
-
- qreal gradientCenterX = qRound(width * d->cx * 0.01);
- qreal gradientCenterY = qRound(height * d->cy * 0.01);
- qreal centerX = width * 0.5;
- qreal centerY = height * 0.5;
-
- qreal areaCenterX = qRound(centerX);
- qreal areaCenterY = qRound(centerY);
-
- QTransform m;
- m.translate(gradientCenterX, gradientCenterY);
- m.rotate(-d->angle);
- m.scale(1.0 - d->border, 1.0 - d->border);
- m.translate(-gradientCenterX, -gradientCenterY);
- m.translate(gradientCenterX - areaCenterX,gradientCenterY - areaCenterY);
- painter.setTransform(m);
-
- QLinearGradient linearGradient;
- linearGradient.setColorAt(1, d->startColor);
- linearGradient.setColorAt(0, d->endColor);
-
- // from center going North
- linearGradient.setStart(centerX, centerY);
- linearGradient.setFinalStop(centerX, 0);
- painter.setBrush(linearGradient);
- painter.drawRect(0, 0, width, centerY);
-
- // from center going South
- linearGradient.setFinalStop(centerX, height);
- painter.setBrush(linearGradient);
- painter.drawRect(0, centerY, width, centerY);
-
- // clip the East and West portion
- QPainterPath clip;
- clip.moveTo(width, 0);
- clip.lineTo(width, height);
- clip.lineTo(0, 0);
- clip.lineTo(0, height);
- clip.closeSubpath();
- painter.setClipPath(clip);
-
- // from center going East
- linearGradient.setFinalStop(width, centerY);
- painter.setBrush(linearGradient);
- painter.drawRect(centerX, 0, width, height);
-
- // from center going West
- linearGradient.setFinalStop( 0, centerY);
- painter.setBrush(linearGradient);
- painter.drawRect(0, 0, centerX, height);
-}
-
-
-void KoOdfGradientBackground::renderRectangleGradient(QImage& buffer) const
-{
- buffer.fill(d->startColor.rgba());
-
- QPainter painter(&buffer);
- painter.setPen(Qt::NoPen);
- painter.setRenderHint(QPainter::Antialiasing, false);
-
- int width = buffer.width();
- int height = buffer.height();
-
- qreal gradientCenterX = qRound(width * d->cx * 0.01);
- qreal gradientCenterY = qRound(height * d->cy * 0.01);
- qreal centerX = width * 0.5;
- qreal centerY = height * 0.5;
-
- qreal areaCenterY = qRound(centerY);
- qreal areaCenterX = qRound(centerX);
-
- QTransform m;
- m.translate(gradientCenterX, gradientCenterY);
- // m.rotate(-d->angle); // OOo rotates the gradient differently
- m.scale(1.0 - d->border, 1.0 - d->border);
- m.translate(-gradientCenterX, -gradientCenterY);
- m.translate(gradientCenterX - areaCenterX,gradientCenterY - areaCenterY);
- painter.setTransform(m);
-
- QLinearGradient linearGradient;
- linearGradient.setColorAt(1, d->startColor);
- linearGradient.setColorAt(0, d->endColor);
-
- // render background
- QPainterPath clipPath;
- if (width < height) {
- QRectF west(0,0,centerX, height);
- QRectF east(centerX, 0, centerX, height);
-
- linearGradient.setStart(centerX, centerY);
- linearGradient.setFinalStop(0, centerY);
- painter.setBrush(linearGradient);
- painter.drawRect(west);
-
- linearGradient.setFinalStop(width, centerY);
- painter.setBrush(linearGradient);
- painter.drawRect(east);
-
- QRectF north(0,0,width, centerX);
- QRectF south(0,height - centerX, width, centerX);
-
- clipPath.moveTo(0,0);
- clipPath.lineTo(width, 0);
- clipPath.lineTo(centerX, centerX);
- clipPath.closeSubpath();
-
- clipPath.moveTo(width, height);
- clipPath.lineTo(0, height);
- clipPath.lineTo(centerX, south.y());
- clipPath.closeSubpath();
-
- linearGradient.setStart(centerX, centerX);
- linearGradient.setFinalStop(centerX, 0);
-
- painter.setClipPath(clipPath);
- painter.setBrush(linearGradient);
- painter.drawRect(north);
-
- linearGradient.setStart(centerX, south.y());
- linearGradient.setFinalStop(centerX, height);
-
- painter.setBrush(linearGradient);
- painter.drawRect(south);
- } else {
- QRectF north(0,0,width, centerY);
- QRectF south(0, centerY, width, centerY);
-
- linearGradient.setStart(centerX, centerY);
- linearGradient.setFinalStop(centerX, 0);
-
- painter.setBrush(linearGradient);
- painter.drawRect(north);
-
- linearGradient.setFinalStop(centerX, height);
- painter.setBrush(linearGradient);
- painter.drawRect(south);
-
-
- QRectF west(0,0,centerY, height);
- QRectF east(width - centerY, 0, centerY, height);
-
- clipPath.moveTo(0,0);
- clipPath.lineTo(centerY, centerY);
- clipPath.lineTo(0,height);
- clipPath.closeSubpath();
-
- clipPath.moveTo(width, height);
- clipPath.lineTo(east.x(), centerY);
- clipPath.lineTo(width,0);
- clipPath.closeSubpath();
-
- linearGradient.setStart(centerY, centerY);
- linearGradient.setFinalStop(0, centerY);
-
- painter.setClipPath(clipPath);
- painter.setBrush(linearGradient);
- painter.drawRect(west);
-
- linearGradient.setStart(east.x(), centerY);
- linearGradient.setFinalStop(width, centerY);
-
- painter.setBrush(linearGradient);
- painter.drawRect(east);
- }
-}
-
-
-void KoOdfGradientBackground::debug() const
-{
- debugFlake << "cx,cy: "<< d->cx << d->cy;
- debugFlake << "style" << d->style;
- debugFlake << "colors" << d->startColor << d->endColor;
- debugFlake << "angle:" << d->angle;
- debugFlake << "border" << d->border;
-}
diff --git a/libs/flake/KoOdfGradientBackground.h b/libs/flake/KoOdfGradientBackground.h
deleted file mode 100644
index 19a94f6832..0000000000
--- a/libs/flake/KoOdfGradientBackground.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2011 Lukáš Tvrdý <lukas.tvrdy@ixonos.com>
- *
- * 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 KOODFGRADIENTBACKGROUND_H
-#define KOODFGRADIENTBACKGROUND_H
-
-#include "KoShapeBackground.h"
-#include "kritaflake_export.h"
-
-class QImage;
-
-#include <KoXmlReaderForward.h>
-
-#include <QSharedDataPointer>
-class KoGenStyles;
-class KoGenStyle;
-
-/// Gradients from odf that are not native to Qt
-class KoOdfGradientBackground : public KoShapeBackground {
-public:
- // constructor
- KoOdfGradientBackground();
- // destructor
- ~KoOdfGradientBackground() override;
-
- bool compareTo(const KoShapeBackground *other) const override;
-
- /// reimplemented from KoShapeBackground
- void fillStyle(KoGenStyle& style, KoShapeSavingContext& context) override;
- /// reimplemented from KoShapeBackground
- bool loadStyle(KoOdfLoadingContext& context, const QSizeF& shapeSize) override;
- /// reimplemented from KoShapeBackground
- void paint(QPainter& painter, KoShapePaintingContext &context, const QPainterPath& fillPath) const override;
-
-private:
- bool loadOdf(const KoXmlElement &element);
- void saveOdf(KoGenStyle& styleFill, KoGenStyles& mainStyles) const;
-
- void renderSquareGradient(QImage &buffer) const;
- void renderRectangleGradient(QImage &buffer) const;
-
-private:
- void debug() const;
-private:
- class Private;
- QSharedDataPointer<Private> d;
-};
-
-#endif
diff --git a/libs/flake/KoOdfWorkaround.cpp b/libs/flake/KoOdfWorkaround.cpp
deleted file mode 100644
index b726dad385..0000000000
--- a/libs/flake/KoOdfWorkaround.cpp
+++ /dev/null
@@ -1,380 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2009 Thorsten Zachmann <zachmann@kde.org>
- Copyright (C) 2009 Johannes Simon <johannes.simon@gmail.com>
- Copyright (C) 2010,2011 Jan Hambrecht <jaham@gmx.net>
- Copyright 2012 Friedrich W. H. Kossebau <kossebau@kde.org>
-
- 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 "KoOdfWorkaround.h"
-
-#include "KoShapeLoadingContext.h"
-#include "KoShape.h"
-#include "KoPathShape.h"
-#include "KoColorBackground.h"
-#include <KoOdfLoadingContext.h>
-#include <KoXmlReader.h>
-#include <KoXmlNS.h>
-#include <KoStyleStack.h>
-#include <KoUnit.h>
-
-#include <QPen>
-#include <QColor>
-
-#include <FlakeDebug.h>
-
-static bool s_workaroundPresentationPlaceholderBug = false;
-
-void KoOdfWorkaround::fixPenWidth(QPen & pen, KoShapeLoadingContext &context)
-{
- if (context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice && pen.widthF() == 0.0) {
- pen.setWidthF(0.5);
- debugFlake << "Work around OO bug with pen width 0";
- }
-}
-
-void KoOdfWorkaround::fixEnhancedPath(QString & path, const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- if (context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice) {
- if (path.isEmpty() && element.attributeNS(KoXmlNS::draw, "type", "") == "ellipse") {
- path = "U 10800 10800 10800 10800 0 360 Z N";
- }
- }
-}
-
-void KoOdfWorkaround::fixEnhancedPathPolarHandlePosition(QString &position, const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- if (context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice) {
- if (element.hasAttributeNS(KoXmlNS::draw, "handle-polar")) {
- QStringList tokens = position.simplified().split(' ');
- if (tokens.count() == 2) {
- position = tokens[1] + ' ' + tokens[0];
- }
- }
- }
-}
-
-QColor KoOdfWorkaround::fixMissingFillColor(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- // Default to an invalid color
- QColor color;
-
- if (element.prefix() == "chart") {
- KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
- styleStack.save();
-
- bool hasStyle = element.hasAttributeNS(KoXmlNS::chart, "style-name");
- if (hasStyle) {
- context.odfLoadingContext().fillStyleStack(element, KoXmlNS::chart, "style-name", "chart");
- styleStack.setTypeProperties("graphic");
- }
-
- if (context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice) {
- if (hasStyle && !styleStack.hasProperty(KoXmlNS::draw, "fill") &&
- styleStack.hasProperty(KoXmlNS::draw, "fill-color")) {
- color = QColor(styleStack.property(KoXmlNS::draw, "fill-color"));
- } else if (!hasStyle || (!styleStack.hasProperty(KoXmlNS::draw, "fill")
- && !styleStack.hasProperty(KoXmlNS::draw, "fill-color"))) {
- KoXmlElement plotAreaElement = element.parentNode().toElement();
- KoXmlElement chartElement = plotAreaElement.parentNode().toElement();
-
- if (element.tagName() == "wall") {
- if (chartElement.hasAttributeNS(KoXmlNS::chart, "class")) {
- QString chartType = chartElement.attributeNS(KoXmlNS::chart, "class");
- // TODO: Check what default backgrounds for surface, stock and gantt charts are
- if (chartType == "chart:line" ||
- chartType == "chart:area" ||
- chartType == "chart:bar" ||
- chartType == "chart:scatter")
- color = QColor(0xe0e0e0);
- }
- } else if (element.tagName() == "series") {
- if (chartElement.hasAttributeNS(KoXmlNS::chart, "class")) {
- QString chartType = chartElement.attributeNS(KoXmlNS::chart, "class");
- // TODO: Check what default backgrounds for surface, stock and gantt charts are
- if (chartType == "chart:area" ||
- chartType == "chart:bar")
- color = QColor(0x99ccff);
- }
- }
- else if (element.tagName() == "chart")
- color = QColor(0xffffff);
- }
- }
-
- styleStack.restore();
- }
-
- return color;
-}
-
-bool KoOdfWorkaround::fixMissingStroke(QPen &pen, const KoXmlElement &element, KoShapeLoadingContext &context, const KoShape *shape)
-{
- bool fixed = false;
-
- if (context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice) {
- KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
- if (element.prefix() == "chart") {
- styleStack.save();
-
- bool hasStyle = element.hasAttributeNS(KoXmlNS::chart, "style-name");
- if (hasStyle) {
- context.odfLoadingContext().fillStyleStack(element, KoXmlNS::chart, "style-name", "chart");
- styleStack.setTypeProperties("graphic");
- }
-
- if (hasStyle && styleStack.hasProperty(KoXmlNS::draw, "stroke") &&
- !styleStack.hasProperty(KoXmlNS::svg, "stroke-color")) {
- fixed = true;
- pen.setColor(Qt::black);
- } else if (!hasStyle) {
- KoXmlElement plotAreaElement = element.parentNode().toElement();
- KoXmlElement chartElement = plotAreaElement.parentNode().toElement();
-
- if (element.tagName() == "series") {
- QString chartType = chartElement.attributeNS(KoXmlNS::chart, "class");
- if (!chartType.isEmpty()) {
- // TODO: Check what default backgrounds for surface, stock and gantt charts are
- if (chartType == "chart:line" ||
- chartType == "chart:scatter") {
- fixed = true;
- pen = QPen(0x99ccff);
- }
- }
- } else if (element.tagName() == "legend") {
- fixed = true;
- pen = QPen(Qt::black);
- }
- }
- styleStack.restore();
- }
- else {
- const KoPathShape *pathShape = dynamic_cast<const KoPathShape*>(shape);
- if (pathShape) {
- const QString strokeColor(styleStack.property(KoXmlNS::svg, "stroke-color"));
- if (strokeColor.isEmpty()) {
- pen.setColor(Qt::black);
- } else {
- pen.setColor(strokeColor);
- }
- fixed = true;
- }
- }
- }
-
- return fixed;
-}
-
-bool KoOdfWorkaround::fixMissingStyle_DisplayLabel(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- Q_UNUSED(element);
- // If no axis style is specified, OpenOffice.org hides the axis' data labels
- if (context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice)
- return false;
-
- // In all other cases, they're visible
- return true;
-}
-
-void KoOdfWorkaround::setFixPresentationPlaceholder(bool fix, KoShapeLoadingContext &context)
-{
- KoOdfLoadingContext::GeneratorType type(context.odfLoadingContext().generatorType());
- if (type == KoOdfLoadingContext::OpenOffice || type == KoOdfLoadingContext::MicrosoftOffice) {
- s_workaroundPresentationPlaceholderBug = fix;
- }
-}
-
-bool KoOdfWorkaround::fixPresentationPlaceholder()
-{
- return s_workaroundPresentationPlaceholderBug;
-}
-
-void KoOdfWorkaround::fixPresentationPlaceholder(KoShape *shape)
-{
- if (s_workaroundPresentationPlaceholderBug && !shape->hasAdditionalAttribute("presentation:placeholder")) {
- shape->setAdditionalAttribute("presentation:placeholder", "true");
- }
-}
-
-QSharedPointer<KoColorBackground> KoOdfWorkaround::fixBackgroundColor(const KoShape *shape, KoShapeLoadingContext &context)
-{
- QSharedPointer<KoColorBackground> colorBackground;
- KoOdfLoadingContext &odfContext = context.odfLoadingContext();
- if (odfContext.generatorType() == KoOdfLoadingContext::OpenOffice) {
- const KoPathShape *pathShape = dynamic_cast<const KoPathShape*>(shape);
- //check shape type
- if (pathShape) {
- KoStyleStack &styleStack = odfContext.styleStack();
- const QString color(styleStack.property(KoXmlNS::draw, "fill-color"));
- if (color.isEmpty()) {
- colorBackground = QSharedPointer<KoColorBackground>(new KoColorBackground(QColor(153, 204, 255)));
- } else {
- colorBackground = QSharedPointer<KoColorBackground>(new KoColorBackground(color));
- }
- }
- }
- return colorBackground;
-}
-
-void KoOdfWorkaround::fixGluePointPosition(QString &positionString, KoShapeLoadingContext &context)
-{
- KoOdfLoadingContext::GeneratorType type(context.odfLoadingContext().generatorType());
- if (type == KoOdfLoadingContext::OpenOffice && !positionString.endsWith('%')) {
- const qreal pos = KoUnit::parseValue(positionString);
- positionString = QString("%1%%").arg(KoUnit(KoUnit::Millimeter).toUserValue(pos));
- }
-}
-
-void KoOdfWorkaround::fixMissingFillRule(Qt::FillRule& fillRule, KoShapeLoadingContext& context)
-{
- if ((context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice)) {
- fillRule = Qt::OddEvenFill;
- }
-}
-
-bool KoOdfWorkaround::fixAutoGrow(KoTextShapeDataBase::ResizeMethod method, KoShapeLoadingContext &context)
-{
- bool fix = false;
- if (context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice) {
- if (method == KoTextShapeDataBase::AutoGrowWidth || method == KoTextShapeDataBase::AutoGrowHeight || method == KoTextShapeDataBase::AutoGrowWidthAndHeight) {
- fix = true;
- }
- }
- return fix;
-}
-
-bool KoOdfWorkaround::fixEllipse(const QString &kind, KoShapeLoadingContext &context)
-{
- bool radiusGiven = false;
- if (context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice) {
- if (kind == "section" || kind == "arc") {
- radiusGiven = true;
- }
- }
- return radiusGiven;
-}
-
-void KoOdfWorkaround::fixBadFormulaHiddenForStyleCellProtect(QString& value)
-{
- if (value.endsWith(QLatin1String("Formula.hidden"))) {
- const int length = value.length();
- value[length-14] = QLatin1Char('f');
- value[length-7] = QLatin1Char('-');
- }
-}
-
-void KoOdfWorkaround::fixBadDateForTextTime(QString &value)
-{
- if (value.startsWith(QLatin1String("0-00-00T"))) {
- value.remove(0, 8);
- }
-}
-
-void KoOdfWorkaround::fixClipRectOffsetValuesString(QString &offsetValuesString)
-{
- if (! offsetValuesString.contains(QLatin1Char(','))) {
- // assumes no spaces existing between values and units
- offsetValuesString = offsetValuesString.simplified().replace(QLatin1Char(' '), QLatin1Char(','));
- }
-}
-
-QString KoOdfWorkaround::fixTableTemplateName(const KoXmlElement &e)
-{
- return e.attributeNS(KoXmlNS::text, "style-name", QString());
-}
-
-QString KoOdfWorkaround::fixTableTemplateCellStyleName(const KoXmlElement &e)
-{
- return e.attributeNS(KoXmlNS::text, "style-name", QString());
-}
-
-static const struct {
- const char* oldPath;
- const char* newPath;
-} markerPathMapping[] = {
- // Arrow
- {"m10 0-10 30h20z",
- "M10 0l-10 30h20z"},
- // Square
- {"m0 0h10v10h-10",
- "M0 0h10v10h-10z"},
- // Small Arrow
- {"m1321 3493h-1321l702-3493z",
- "M1321 3493h-1321l702-3493z"},
- // Dimension Lines
- {"M0 0h278 278 280v36 36 38h-278-278-280v-36-36z",
- "m0 0h278 278 280v36 36 38h-278-278-280v-36-36z"},
- // Double Arrow
- {"m737 1131h394l-564-1131-567 1131h398l-398 787h1131z",
- "M737 1131h394l-564-1131-567 1131h398l-398 787h1131z"},
- // Rounded short Arrow
- {"m1009 1050-449-1008-22-30-29-12-34 12-21 26-449 1012-5 13v8l5 21 12 21 17 13 21 4h903l21-4 21-13 9-21 4-21v-8z",
- "M1009 1050l-449-1008-22-30-29-12-34 12-21 26-449 1012-5 13v8l5 21 12 21 17 13 21 4h903l21-4 21-13 9-21 4-21v-8z"},
- // Symmetric Arrow
- {"m564 0-564 902h1131z",
- "M564 0l-564 902h1131z"},
- // Line Arrow
- {"m0 2108v17 17l12 42 30 34 38 21 43 4 29-8 30-21 25-26 13-34 343-1532 339 1520 13 42 29 34 39 21 42 4 42-12 34-30 21-42v-39-12l-4 4-440-1998-9-42-25-39-38-25-43-8-42 8-38 25-26 39-8 42z",
- "M0 2108v17 17l12 42 30 34 38 21 43 4 29-8 30-21 25-26 13-34 343-1532 339 1520 13 42 29 34 39 21 42 4 42-12 34-30 21-42v-39-12l-4 4-440-1998-9-42-25-39-38-25-43-8-42 8-38 25-26 39-8 42z"},
- // Rounded large Arrow
- {"m1127 2120-449-2006-9-42-25-39-38-25-38-8-43 8-38 25-25 39-9 42-449 2006v13l-4 9 9 42 25 38 38 25 42 9h903l42-9 38-25 26-38 8-42v-9z",
- "M1127 2120l-449-2006-9-42-25-39-38-25-38-8-43 8-38 25-25 39-9 42-449 2006v13l-4 9 9 42 25 38 38 25 42 9h903l42-9 38-25 26-38 8-42v-9z"},
- // Circle
- {"m462 1118-102-29-102-51-93-72-72-93-51-102-29-102-13-105 13-102 29-106 51-102 72-89 93-72 102-50 102-34 106-9 101 9 106 34 98 50 93 72 72 89 51 102 29 106 13 102-13 105-29 102-51 102-72 93-93 72-98 51-106 29-101 13z",
- "M462 1118l-102-29-102-51-93-72-72-93-51-102-29-102-13-105 13-102 29-106 51-102 72-89 93-72 102-50 102-34 106-9 101 9 106 34 98 50 93 72 72 89 51 102 29 106 13 102-13 105-29 102-51 102-72 93-93 72-98 51-106 29-101 13z"},
- // Square 45
- {"m0 564 564 567 567-567-567-564z",
- "M0 564l564 567 567-567-567-564z"},
- // Arrow concave
- {"m1013 1491 118 89-567-1580-564 1580 114-85 136-68 148-46 161-17 161 13 153 46z",
- "M1013 1491l118 89-567-1580-564 1580 114-85 136-68 148-46 161-17 161 13 153 46z"},
- // Short line Arrow
- {"m1500 0 1500 2789v211h-114l-1286-2392v2392h-200v-2392l-1286 2392h-114v-211z",
- "M1500 0l1500 2789v211h-114l-1286-2392v2392h-200v-2392l-1286 2392h-114v-211z"},
- // Triangle unfilled
- {"m1500 0 1500 3000h-3000zm1500-2553-1176 2353h2353z",
- "M1500 0l1500 3000h-3000zM1500 447l-1176 2353h2353z"},
- // Diamond unfilled
- {"m1500 0 1500 3000-1500 3000-1500-3000zm1500-2553-1276 2553 1276 2553 1276-2553z",
- "M1500 0l1500 3000-1500 3000-1500-3000zM1500 447l-1276 2553 1276 2553 1276-2553z"},
- // Diamond
- {"m1500 0 1500 3000-1500 3000-1500-3000z",
- "M1500 0l1500 3000-1500 3000-1500-3000z"},
- // Circle unfilled
- {"m1500 3000c-276 0-511-63-750-201s-411-310-549-549-201-474-201-750 63-511 201-750 310-411 549-549 474-201 750-201 511 63 750 201 411 310 549 549 201 474 201 750-63 511-201 750-310 411-549 549-474 201-750 201zm0-200c-239 0-443-55-650-174s-356-269-476-476-174-411-174-650 55-443 174-650 269-356 476-476c207-119 411-174 650-174s443 55 650 174c207 120 356 269 476 476s174 411 174 650-55 443-174 650-269 356-476 476c-207 119-411 174-650 174z",
- "M1500 3000c-276 0-511-63-750-201s-411-310-549-549-201-474-201-750 63-511 201-750 310-411 549-549 474-201 750-201 511 63 750 201 411 310 549 549 201 474 201 750-63 511-201 750-310 411-549 549-474 201-750 201zM1500 2800c-239 0-443-55-650-174s-356-269-476-476-174-411-174-650 55-443 174-650 269-356 476-476c207-119 411-174 650-174s443 55 650 174c207 120 356 269 476 476s174 411 174 650-55 443-174 650-269 356-476 476c-207 119-411 174-650 174z"},
- // Square 45 unfilled
- {"m1500 3000-1500-1500 1500-1500 1500 1500zm-1500 1215-1215-1215 1215-1215 1215 1215z",
- "M1500 3000l-1500-1500 1500-1500 1500 1500zM1500 2715l-1215-1215 1215-1215 1215 1215z"},
- // Square unfilled
- {"m0 0h300v300h-300zm20-280h260v260h-260z",
- "M0 0h300v300h-300zM20 20h260v260h-260z"},
- // Half Circle unfilled
- {"m14971 0c21 229 29 423 29 653 0 690-79 1328-244 1943-165 614-416 1206-761 1804-345 597-733 1110-1183 1560-451 450-964 837-1562 1182-598 345-1190 596-1806 760-600 161-1223 240-1894 244v600h-100v-600c-671-4-1294-83-1894-244-616-164-1208-415-1806-760-598-345-1111-732-1562-1182-450-450-838-963-1183-1560-345-598-596-1190-761-1804-165-615-244-1253-244-1943 0-230 8-424 29-653l298 26 299 26c-18 211-26 390-26 601 0 635 72 1222 224 1787 151 566 383 1110 700 1659 318 550 674 1022 1088 1437 415 414 888 769 1438 1087 550 317 1095 548 1661 700 566 151 1154 223 1789 223s1223-72 1789-223c566-152 1111-383 1661-700 550-318 1023-673 1438-1087 414-415 770-887 1088-1437 317-549 549-1093 700-1659 152-565 224-1152 224-1787 0-211-8-390-26-601l299-26z",
- "M14971 0c21 229 29 423 29 653 0 690-79 1328-244 1943-165 614-416 1206-761 1804-345 597-733 1110-1183 1560-451 450-964 837-1562 1182s-1190 596-1806 760c-600 161-1223 240-1894 244v600h-100v-600c-671-4-1294-83-1894-244-616-164-1208-415-1806-760s-1111-732-1562-1182c-450-450-838-963-1183-1560-345-598-596-1190-761-1804-165-615-244-1253-244-1943 0-230 8-424 29-653l298 26 299 26c-18 211-26 390-26 601 0 635 72 1222 224 1787 151 566 383 1110 700 1659 318 550 674 1022 1088 1437 415 414 888 769 1438 1087 550 317 1095 548 1661 700 566 151 1154 223 1789 223s1223-72 1789-223c566-152 1111-383 1661-700 550-318 1023-673 1438-1087 414-415 770-887 1088-1437 317-549 549-1093 700-1659 152-565 224-1152 224-1787 0-211-8-390-26-601l299-26z"}
-};
-static const int markerPathMappingSize = sizeof(markerPathMapping)/sizeof(markerPathMapping[0]);
-
-void KoOdfWorkaround::fixMarkerPath(QString& path)
-{
- for (int i = 0; i < markerPathMappingSize; ++i) {
- if (path == QLatin1String(markerPathMapping[i].oldPath)) {
- path = QLatin1String(markerPathMapping[i].newPath);
- break;
- }
- }
-}
diff --git a/libs/flake/KoOdfWorkaround.h b/libs/flake/KoOdfWorkaround.h
deleted file mode 100644
index 9bf9e91d95..0000000000
--- a/libs/flake/KoOdfWorkaround.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2009 Thorsten Zachmann <zachmann@kde.org>
- Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- Copyright (C) 2011 Lukáš Tvrdý <lukas.tvrdy@ixonos.com>
-
- 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 KOODFWORKAROUND_H
-#define KOODFWORKAROUND_H
-
-#include "kritaflake_export.h"
-#include "KoTextShapeDataBase.h"
-#include <qnamespace.h>
-
-#include <QSharedPointer>
-
-#include <KoXmlReaderForward.h>
-class KoShape;
-class KoShapeLoadingContext;
-class QPen;
-class QColor;
-class QString;
-class KoColorBackground;
-
-/**
- * This class should contain all workarounds to correct problems with different ODF
- * implementations. If you need to access application specific things please create a
- * new namespace in the application you need it in
- * All calls to methods of this class should be wrapped into ifndefs like e.g.
- *
- * @code
- * #ifndef NWORKAROUND_ODF_BUGS
- * KoOdfWorkaround::fixPenWidth(pen, context);
- * #endif
- * @endcode
- */
-namespace KoOdfWorkaround
-{
- /**
- * OpenOffice handles a line with the width of 0 as a cosmetic line but in svg it makes the line invisible.
- * To show it in calligra use a very small line width. However this is not a cosmetic line.
- */
- KRITAFLAKE_EXPORT void fixPenWidth(QPen &pen, KoShapeLoadingContext &context);
-
- /**
- * OpenOffice < 3.0 does not store the draw:enhanced-path for draw:type="ellipse"
- * Add the path needed for the ellipse
- */
- KRITAFLAKE_EXPORT void fixEnhancedPath(QString &path, const KoXmlElement &element, KoShapeLoadingContext &context);
-
- /**
- * OpenOffice interchanges the position coordinates for polar handles.
- * According to the specification the first coordinate is the angle, the
- * second coordinates is the radius. OpenOffice does it the other way around.
- */
- KRITAFLAKE_EXPORT void fixEnhancedPathPolarHandlePosition(QString &position, const KoXmlElement &element, KoShapeLoadingContext &context);
-
- KRITAFLAKE_EXPORT bool fixMissingStroke(QPen &pen, const KoXmlElement &element, KoShapeLoadingContext &context, const KoShape *shape = 0);
- KRITAFLAKE_EXPORT QColor fixMissingFillColor(const KoXmlElement &element, KoShapeLoadingContext &context);
- KRITAFLAKE_EXPORT bool fixMissingStyle_DisplayLabel(const KoXmlElement &element, KoShapeLoadingContext &context);
-
- KRITAFLAKE_EXPORT QSharedPointer<KoColorBackground> fixBackgroundColor(const KoShape *shape, KoShapeLoadingContext &context);
-
- /**
- * Old versions of ooimpress does not set the placeholder for shapes that should have it set
- * See open office issue https://bz.apache.org/ooo/show_bug.cgi?id=96406
- * And kde bug https://bugs.kde.org/show_bug.cgi?id=185354
- */
- KRITAFLAKE_EXPORT void setFixPresentationPlaceholder(bool fix, KoShapeLoadingContext &context);
- KRITAFLAKE_EXPORT bool fixPresentationPlaceholder();
- KRITAFLAKE_EXPORT void fixPresentationPlaceholder(KoShape *shape);
-
- /**
- * OpenOffice and LibreOffice save gluepoint positions wrong when no align is specified.
- * According to the specification for the above situation, the position should be saved
- * as percent values relative to the shapes center point. OpenOffice seems to write
- * these percent values converted to length units, where the millimeter value corresponds
- * to the correct percent value (i.e. -5cm = -50mm = -50%).
- */
- KRITAFLAKE_EXPORT void fixGluePointPosition(QString &positionString, KoShapeLoadingContext &context);
-
- /**
- * OpenOffice and LibreOffice does not conform to the specification about default value
- * of the svg:fill-rule. If this attribute is missing, according the spec, the initial
- * value is nonzero, but OOo uses evenodd. Because we are conform to the spec, we need
- * to set what OOo display.
- * See http://www.w3.org/TR/SVG/painting.html#FillRuleProperty
- */
- KRITAFLAKE_EXPORT void fixMissingFillRule(Qt::FillRule &fillRule, KoShapeLoadingContext &context);
-
- /**
- * OpenOffice resizes text shapes with autogrow in both directions. If the text box is saved to
- * small the text will not fit and it needs to be adjusted during the first layout.
- * This methods returns true if we need to adjust the layout. The adjusting is handled at a different place.
- */
- KRITAFLAKE_EXPORT bool fixAutoGrow(KoTextShapeDataBase::ResizeMethod method, KoShapeLoadingContext &context);
-
- /**
- * OpenOffice and LibreOffice do not set the svg:width, svg:height, svg:x and svg:y correctly when saving
- * parts of draw:ellipses or draw:circle
- * This method returns true when the width, height, x and y is given for the full circle
- */
- KRITAFLAKE_EXPORT bool fixEllipse(const QString &kind, KoShapeLoadingContext &context);
-
- /**
- * Calligra did use the bad strings "Formula.hidden" and "protected Formula.hidden" as values
- * for style:cell-protect, instead of "formula-hidden" and "protected formula-hidden".
- * This method fixes the bad strings to the correct ones.
- */
- KRITAFLAKE_EXPORT void fixBadFormulaHiddenForStyleCellProtect(QString &value);
-
- /**
- * Calligra used to store text:time-value with a "0-00-00T" prefix
- * This method removes that prefix.
- */
- KRITAFLAKE_EXPORT void fixBadDateForTextTime(QString &value);
-
- /**
- * OpenOffice.org used to write the "rect(...)" value for fo:clip without
- * separating the 4 offset values by commas.
- * This method changes the string with the offset values to have commas as separators.
- */
- KRITAFLAKE_EXPORT void fixClipRectOffsetValuesString(QString &offsetValuesString);
-
- /**
- * LibreOffice used to write text:style-name attribute for table:table-template element,
- * which is not a valid attribute for the element.
- */
- KRITAFLAKE_EXPORT QString fixTableTemplateName(const KoXmlElement &e);
-
- /**
- * LibreOffice used to write text:style-name attribute for
- * table:first-row, table:last-row, table:first-column,
- * table:last-column, table:odd-rows, table:odd-columns,
- * table:body elements, which is not a valid attribute for the element.
- */
- KRITAFLAKE_EXPORT QString fixTableTemplateCellStyleName(const KoXmlElement &e);
-
- /**
- * LibreOffice used to have a bug with handling of z command in svg path.
- * This resulted in broken marker path used (and copied also to Calligra).
- * This methods substitutes known old marker paths with the latest (fixed)
- * path variant.
- */
- KRITAFLAKE_EXPORT void fixMarkerPath(QString &path);
-}
-
-#endif /* KOODFWORKAROUND_H */
diff --git a/libs/flake/KoPathShape.cpp b/libs/flake/KoPathShape.cpp
index 092d9ccf66..feb185fbad 100644
--- a/libs/flake/KoPathShape.cpp
+++ b/libs/flake/KoPathShape.cpp
@@ -1,1668 +1,1401 @@
/* This file is part of the KDE project
Copyright (C) 2006-2008, 2010-2011 Thorsten Zachmann <zachmann@kde.org>
Copyright (C) 2006-2011 Jan Hambrecht <jaham@gmx.net>
Copyright (C) 2007-2009 Thomas Zander <zander@kde.org>
Copyright (C) 2011 Jean-Nicolas Artaud <jeannicolasartaud@gmail.com>
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 "KoPathShape.h"
#include "KoPathShape_p.h"
#include "KoPathSegment.h"
-#include "KoOdfWorkaround.h"
#include "KoPathPoint.h"
#include "KoShapeStrokeModel.h"
#include "KoPathShapeLoader.h"
#include "KoShapeSavingContext.h"
#include "KoShapeLoadingContext.h"
#include "KoShapeShadow.h"
#include "KoShapeBackground.h"
#include "KoShapeContainer.h"
#include "KoFilterEffectStack.h"
#include "KoMarker.h"
#include "KoShapeStroke.h"
#include "KoInsets.h"
#include <KoXmlReader.h>
#include <KoXmlWriter.h>
#include <KoXmlNS.h>
#include <KoUnit.h>
-#include <KoGenStyle.h>
-#include <KoStyleStack.h>
-#include <KoOdfLoadingContext.h>
#include "KisQPainterStateSaver.h"
#include <FlakeDebug.h>
#include <QPainter>
#include <QPainterPath>
#include "kis_global.h"
#include <qnumeric.h> // for qIsNaN
static bool qIsNaNPoint(const QPointF &p) {
return qIsNaN(p.x()) || qIsNaN(p.y());
}
KoPathShape::Private::Private()
: fillRule(Qt::OddEvenFill)
, autoFillMarkers(false)
{
}
KoPathShape::Private::Private(const Private &rhs)
: fillRule(rhs.fillRule)
, markersNew(rhs.markersNew)
, autoFillMarkers(rhs.autoFillMarkers)
{
}
QRectF KoPathShape::Private::handleRect(const QPointF &p, qreal radius) const
{
return QRectF(p.x() - radius, p.y() - radius, 2*radius, 2*radius);
}
-void KoPathShape::Private::applyViewboxTransformation(const KoXmlElement &element)
-{
- // apply viewbox transformation
- const QRect viewBox = KoPathShape::loadOdfViewbox(element);
- if (! viewBox.isEmpty()) {
- // load the desired size
- QSizeF size;
- size.setWidth(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "width", QString())));
- size.setHeight(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "height", QString())));
-
- // load the desired position
- QPointF pos;
- pos.setX(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "x", QString())));
- pos.setY(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "y", QString())));
-
- // create matrix to transform original path data into desired size and position
- QTransform viewMatrix;
- viewMatrix.translate(-viewBox.left(), -viewBox.top());
- viewMatrix.scale(size.width() / viewBox.width(), size.height() / viewBox.height());
- viewMatrix.translate(pos.x(), pos.y());
-
- // transform the path data
- map(viewMatrix);
- }
-}
KoPathShape::KoPathShape()
: KoTosContainer()
, d(new Private)
{
}
KoPathShape::KoPathShape(const KoPathShape &rhs)
: KoTosContainer(rhs)
, d(new Private(*rhs.d))
{
// local data cannot be shared via QSharedData because
// every path point holds a pointer to the parent shape
KoSubpathList subpaths;
Q_FOREACH (KoSubpath *subPath, rhs.d->subpaths) {
KoSubpath *clonedSubPath = new KoSubpath();
Q_FOREACH (KoPathPoint *point, *subPath) {
*clonedSubPath << new KoPathPoint(*point, this);
}
subpaths << clonedSubPath;
}
d->subpaths = subpaths;
}
KoPathShape::~KoPathShape()
{
clear();
}
KoShape *KoPathShape::cloneShape() const
{
return new KoPathShape(*this);
}
-void KoPathShape::saveContourOdf(KoShapeSavingContext &context, const QSizeF &scaleFactor) const
-{
- if (d->subpaths.length() <= 1) {
- QTransform matrix;
- matrix.scale(scaleFactor.width(), scaleFactor.height());
- QString points;
- KoSubpath *subPath = d->subpaths.first();
- KoSubpath::const_iterator pointIt(subPath->constBegin());
-
- KoPathPoint *currPoint= 0;
- // iterate over all points
- for (; pointIt != subPath->constEnd(); ++pointIt) {
- currPoint = *pointIt;
-
- if (currPoint->activeControlPoint1() || currPoint->activeControlPoint2()) {
- break;
- }
- const QPointF p = matrix.map(currPoint->point());
- points += QString("%1,%2 ").arg(qRound(1000*p.x())).arg(qRound(1000*p.y()));
- }
-
- if (currPoint && !(currPoint->activeControlPoint1() || currPoint->activeControlPoint2())) {
- context.xmlWriter().startElement("draw:contour-polygon");
- context.xmlWriter().addAttribute("svg:width", size().width());
- context.xmlWriter().addAttribute("svg:height", size().height());
-
- const QSizeF s(size());
- QString viewBox = QString("0 0 %1 %2").arg(qRound(1000*s.width())).arg(qRound(1000*s.height()));
- context.xmlWriter().addAttribute("svg:viewBox", viewBox);
-
- context.xmlWriter().addAttribute("draw:points", points);
-
- context.xmlWriter().addAttribute("draw:recreate-on-edit", "true");
- context.xmlWriter().endElement();
-
- return;
- }
- }
-
- // if we get here we couldn't save as polygon - let-s try contour-path
- context.xmlWriter().startElement("draw:contour-path");
- saveOdfAttributes(context, OdfViewbox);
-
- context.xmlWriter().addAttribute("svg:d", toString());
- context.xmlWriter().addAttribute("calligra:nodeTypes", d->nodeTypes());
- context.xmlWriter().addAttribute("draw:recreate-on-edit", "true");
- context.xmlWriter().endElement();
-}
-
-void KoPathShape::saveOdf(KoShapeSavingContext & context) const
-{
- context.xmlWriter().startElement("draw:path");
- saveOdfAttributes(context, OdfAllAttributes | OdfViewbox);
-
- context.xmlWriter().addAttribute("svg:d", toString());
- context.xmlWriter().addAttribute("calligra:nodeTypes", d->nodeTypes());
-
- saveOdfCommonChildElements(context);
- saveText(context);
- context.xmlWriter().endElement();
-}
-
-bool KoPathShape::loadContourOdf(const KoXmlElement &element, KoShapeLoadingContext &, const QSizeF &scaleFactor)
-{
- // first clear the path data from the default path
- clear();
-
- if (element.localName() == "contour-polygon") {
- QString points = element.attributeNS(KoXmlNS::draw, "points").simplified();
- points.replace(',', ' ');
- points.remove('\r');
- points.remove('\n');
- bool firstPoint = true;
- const QStringList coordinateList = points.split(' ');
- for (QStringList::ConstIterator it = coordinateList.constBegin(); it != coordinateList.constEnd(); ++it) {
- QPointF point;
- point.setX((*it).toDouble());
- ++it;
- point.setY((*it).toDouble());
- if (firstPoint) {
- moveTo(point);
- firstPoint = false;
- } else
- lineTo(point);
- }
- close();
- } else if (element.localName() == "contour-path") {
- KoPathShapeLoader loader(this);
- loader.parseSvg(element.attributeNS(KoXmlNS::svg, "d"), true);
- d->loadNodeTypes(element);
- }
-
- // apply viewbox transformation
- const QRect viewBox = KoPathShape::loadOdfViewbox(element);
- if (! viewBox.isEmpty()) {
- QSizeF size;
- size.setWidth(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "width", QString())));
- size.setHeight(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "height", QString())));
-
- // create matrix to transform original path data into desired size and position
- QTransform viewMatrix;
- viewMatrix.translate(-viewBox.left(), -viewBox.top());
- viewMatrix.scale(scaleFactor.width(), scaleFactor.height());
- viewMatrix.scale(size.width() / viewBox.width(), size.height() / viewBox.height());
-
- // transform the path data
- d->map(viewMatrix);
- }
- setTransformation(QTransform());
-
- return true;
-}
-
-bool KoPathShape::loadOdf(const KoXmlElement & element, KoShapeLoadingContext &context)
-{
- loadOdfAttributes(element, context, OdfMandatories | OdfAdditionalAttributes | OdfCommonChildElements);
-
- // first clear the path data from the default path
- clear();
-
- if (element.localName() == "line") {
- QPointF start;
- start.setX(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "x1", "")));
- start.setY(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "y1", "")));
- QPointF end;
- end.setX(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "x2", "")));
- end.setY(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "y2", "")));
- moveTo(start);
- lineTo(end);
- } else if (element.localName() == "polyline" || element.localName() == "polygon") {
- QString points = element.attributeNS(KoXmlNS::draw, "points").simplified();
- points.replace(',', ' ');
- points.remove('\r');
- points.remove('\n');
- bool firstPoint = true;
- const QStringList coordinateList = points.split(' ');
- for (QStringList::ConstIterator it = coordinateList.constBegin(); it != coordinateList.constEnd(); ++it) {
- QPointF point;
- point.setX((*it).toDouble());
- ++it;
- point.setY((*it).toDouble());
- if (firstPoint) {
- moveTo(point);
- firstPoint = false;
- } else
- lineTo(point);
- }
- if (element.localName() == "polygon")
- close();
- } else { // path loading
- KoPathShapeLoader loader(this);
- loader.parseSvg(element.attributeNS(KoXmlNS::svg, "d"), true);
- d->loadNodeTypes(element);
- }
-
- d->applyViewboxTransformation(element);
- QPointF pos = normalize();
- setTransformation(QTransform());
-
- if (element.hasAttributeNS(KoXmlNS::svg, "x") || element.hasAttributeNS(KoXmlNS::svg, "y")) {
- pos.setX(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "x", QString())));
- pos.setY(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "y", QString())));
- }
-
- setPosition(pos);
-
- loadOdfAttributes(element, context, OdfTransformation);
-
- // now that the correct transformation is set up
- // apply that matrix to the path geometry so that
- // we don't transform the stroke
- d->map(transformation());
- setTransformation(QTransform());
- normalize();
-
- loadText(element, context);
-
- return true;
-}
-
-QString KoPathShape::saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const
-{
- style.addProperty("svg:fill-rule", d->fillRule == Qt::OddEvenFill ? "evenodd" : "nonzero");
-
- QSharedPointer<KoShapeStroke> lineBorder = qSharedPointerDynamicCast<KoShapeStroke>(stroke());
- qreal lineWidth = 0;
- if (lineBorder) {
- lineWidth = lineBorder->lineWidth();
- }
-
- Q_UNUSED(lineWidth)
-
- return KoTosContainer::saveStyle(style, context);
-}
-
-void KoPathShape::loadStyle(const KoXmlElement & element, KoShapeLoadingContext &context)
-{
- KoTosContainer::loadStyle(element, context);
-
- KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
- styleStack.setTypeProperties("graphic");
-
- if (styleStack.hasProperty(KoXmlNS::svg, "fill-rule")) {
- QString rule = styleStack.property(KoXmlNS::svg, "fill-rule");
- d->fillRule = (rule == "nonzero") ? Qt::WindingFill : Qt::OddEvenFill;
- } else {
- d->fillRule = Qt::WindingFill;
-#ifndef NWORKAROUND_ODF_BUGS
- KoOdfWorkaround::fixMissingFillRule(d->fillRule, context);
-#endif
- }
-
- QSharedPointer<KoShapeStroke> lineBorder = qSharedPointerDynamicCast<KoShapeStroke>(stroke());
- qreal lineWidth = 0;
- if (lineBorder) {
- lineWidth = lineBorder->lineWidth();
- }
-
- Q_UNUSED(lineWidth);
-}
-
-QRect KoPathShape::loadOdfViewbox(const KoXmlElement & element)
-{
- QRect viewbox;
-
- QString data = element.attributeNS(KoXmlNS::svg, QLatin1String("viewBox"));
- if (! data.isEmpty()) {
- data.replace(QLatin1Char(','), QLatin1Char(' '));
- const QStringList coordinates = data.simplified().split(QLatin1Char(' '), QString::SkipEmptyParts);
- if (coordinates.count() == 4) {
- viewbox.setRect(coordinates.at(0).toInt(), coordinates.at(1).toInt(),
- coordinates.at(2).toInt(), coordinates.at(3).toInt());
- }
- }
-
- return viewbox;
-}
-
void KoPathShape::clear()
{
Q_FOREACH (KoSubpath *subpath, d->subpaths) {
Q_FOREACH (KoPathPoint *point, *subpath)
delete point;
delete subpath;
}
d->subpaths.clear();
notifyPointsChanged();
}
void KoPathShape::paint(QPainter &painter, KoShapePaintingContext &paintContext) const
{
KisQPainterStateSaver saver(&painter);
QPainterPath path(outline());
path.setFillRule(d->fillRule);
if (background()) {
background()->paint(painter, paintContext, path);
}
//d->paintDebug(painter);
}
#ifndef NDEBUG
void KoPathShape::Private::paintDebug(QPainter &painter)
{
KoSubpathList::const_iterator pathIt(subpaths.constBegin());
int i = 0;
QPen pen(Qt::black, 0);
painter.save();
painter.setPen(pen);
for (; pathIt != subpaths.constEnd(); ++pathIt) {
KoSubpath::const_iterator it((*pathIt)->constBegin());
for (; it != (*pathIt)->constEnd(); ++it) {
++i;
KoPathPoint *point = (*it);
QRectF r(point->point(), QSizeF(5, 5));
r.translate(-2.5, -2.5);
QPen pen(Qt::black, 0);
painter.setPen(pen);
if (point->activeControlPoint1() && point->activeControlPoint2()) {
QBrush b(Qt::red);
painter.setBrush(b);
} else if (point->activeControlPoint1()) {
QBrush b(Qt::yellow);
painter.setBrush(b);
} else if (point->activeControlPoint2()) {
QBrush b(Qt::darkYellow);
painter.setBrush(b);
}
painter.drawEllipse(r);
}
}
painter.restore();
debugFlake << "nop =" << i;
}
void KoPathShape::Private::debugPath() const
{
KoSubpathList::const_iterator pathIt(subpaths.constBegin());
for (; pathIt != subpaths.constEnd(); ++pathIt) {
KoSubpath::const_iterator it((*pathIt)->constBegin());
for (; it != (*pathIt)->constEnd(); ++it) {
debugFlake << "p:" << (*pathIt) << "," << *it << "," << (*it)->point() << "," << (*it)->properties();
}
}
}
#endif
void KoPathShape::paintPoints(KisHandlePainterHelper &handlesHelper)
{
KoSubpathList::const_iterator pathIt(d->subpaths.constBegin());
for (; pathIt != d->subpaths.constEnd(); ++pathIt) {
KoSubpath::const_iterator it((*pathIt)->constBegin());
for (; it != (*pathIt)->constEnd(); ++it)
(*it)->paint(handlesHelper, KoPathPoint::Node);
}
}
QRectF KoPathShape::outlineRect() const
{
return outline().boundingRect();
}
QPainterPath KoPathShape::outline() const
{
QPainterPath path;
for (auto subpathIt = d->subpaths.constBegin(); subpathIt != d->subpaths.constEnd(); ++subpathIt) {
const KoSubpath * subpath = *subpathIt;
const KoPathPoint * lastPoint = subpath->constFirst();
bool activeCP = false;
for (auto pointIt = subpath->constBegin(); pointIt != subpath->constEnd(); ++pointIt) {
const KoPathPoint * currPoint = *pointIt;
KoPathPoint::PointProperties currProperties = currPoint->properties();
if (currPoint == subpath->constFirst()) {
if (currProperties & KoPathPoint::StartSubpath) {
Q_ASSERT(!qIsNaNPoint(currPoint->point()));
path.moveTo(currPoint->point());
}
} else if (activeCP && currPoint->activeControlPoint1()) {
Q_ASSERT(!qIsNaNPoint(lastPoint->controlPoint2()));
Q_ASSERT(!qIsNaNPoint(currPoint->controlPoint1()));
Q_ASSERT(!qIsNaNPoint(currPoint->point()));
path.cubicTo(
lastPoint->controlPoint2(),
currPoint->controlPoint1(),
currPoint->point());
} else if (activeCP || currPoint->activeControlPoint1()) {
Q_ASSERT(!qIsNaNPoint(lastPoint->controlPoint2()));
Q_ASSERT(!qIsNaNPoint(currPoint->controlPoint1()));
path.quadTo(
activeCP ? lastPoint->controlPoint2() : currPoint->controlPoint1(),
currPoint->point());
} else {
Q_ASSERT(!qIsNaNPoint(currPoint->point()));
path.lineTo(currPoint->point());
}
if (currProperties & KoPathPoint::CloseSubpath && currProperties & KoPathPoint::StopSubpath) {
// add curve when there is a curve on the way to the first point
KoPathPoint * firstPoint = subpath->first();
Q_ASSERT(!qIsNaNPoint(firstPoint->point()));
if (currPoint->activeControlPoint2() && firstPoint->activeControlPoint1()) {
path.cubicTo(
currPoint->controlPoint2(),
firstPoint->controlPoint1(),
firstPoint->point());
}
else if (currPoint->activeControlPoint2() || firstPoint->activeControlPoint1()) {
Q_ASSERT(!qIsNaNPoint(currPoint->point()));
Q_ASSERT(!qIsNaNPoint(currPoint->controlPoint1()));
path.quadTo(
currPoint->activeControlPoint2() ? currPoint->controlPoint2() : firstPoint->controlPoint1(),
firstPoint->point());
}
path.closeSubpath();
}
if (currPoint->activeControlPoint2()) {
activeCP = true;
} else {
activeCP = false;
}
lastPoint = currPoint;
}
}
return path;
}
QRectF KoPathShape::boundingRect() const
{
const QTransform transform = absoluteTransformation();
/**
* First we approximate the insets of the stroke by rendering a fat bezier curve
* with width set to the maximum inset of miters and markers. The are swept by this
* curve will be a good approximation of the real curve bounding rect.
*/
qreal outlineSweepWidth = 0;
const QSharedPointer<KoShapeStroke> lineBorder = qSharedPointerDynamicCast<KoShapeStroke>(stroke());
if (lineBorder) {
outlineSweepWidth = lineBorder->lineWidth();
}
if (stroke()) {
KoInsets inset;
stroke()->strokeInsets(this, inset);
const qreal maxInset = std::max({inset.left, inset.top, inset.right, inset.bottom});
// insets extend outside the shape, but width extends both inside and outside,
// so we should multiply insets by 2.0
outlineSweepWidth = std::max({outlineSweepWidth,
2.0 * maxInset,
2.0 * stroke()->strokeMaxMarkersInset(this)});
}
/// NOTE: stroking the entire shape might be too expensive, so try to
/// estimate the bounds using insets only...
#if 0
QPen pen(Qt::black, outlineSweepWidth);
// select round joins and caps to ensure it sweeps exactly
// 'outlineSweepWidth' pixels in every possible
pen.setJoinStyle(Qt::RoundJoin);
pen.setCapStyle(Qt::RoundCap);
QRectF bb = transform.map(pathStroke(pen)).boundingRect();
#endif
QRectF bb = transform.mapRect(kisGrowRect(outline().boundingRect(), outlineSweepWidth));
if (shadow()) {
KoInsets insets;
shadow()->insets(insets);
bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
}
if (filterEffectStack()) {
QRectF clipRect = filterEffectStack()->clipRectForBoundingRect(QRectF(QPointF(), size()));
bb |= transform.mapRect(clipRect);
}
return bb;
}
QSizeF KoPathShape::size() const
{
// don't call boundingRect here as it uses absoluteTransformation
// which itself uses size() -> leads to infinite recursion
return outlineRect().size();
}
void KoPathShape::setSize(const QSizeF &newSize)
{
QTransform matrix(resizeMatrix(newSize));
KoShape::setSize(newSize);
d->map(matrix);
}
QTransform KoPathShape::resizeMatrix(const QSizeF & newSize) const
{
QSizeF oldSize = size();
if (oldSize.width() == 0.0) {
oldSize.setWidth(0.000001);
}
if (oldSize.height() == 0.0) {
oldSize.setHeight(0.000001);
}
QSizeF sizeNew(newSize);
if (sizeNew.width() == 0.0) {
sizeNew.setWidth(0.000001);
}
if (sizeNew.height() == 0.0) {
sizeNew.setHeight(0.000001);
}
return QTransform(sizeNew.width() / oldSize.width(), 0, 0, sizeNew.height() / oldSize.height(), 0, 0);
}
KoPathPoint * KoPathShape::moveTo(const QPointF &p)
{
KoPathPoint * point = new KoPathPoint(this, p, KoPathPoint::StartSubpath | KoPathPoint::StopSubpath);
KoSubpath * path = new KoSubpath;
path->push_back(point);
d->subpaths.push_back(path);
notifyPointsChanged();
return point;
}
KoPathPoint * KoPathShape::lineTo(const QPointF &p)
{
if (d->subpaths.empty()) {
moveTo(QPointF(0, 0));
}
KoPathPoint * point = new KoPathPoint(this, p, KoPathPoint::StopSubpath);
KoPathPoint * lastPoint = d->subpaths.last()->last();
updateLastPriv(&lastPoint);
d->subpaths.last()->push_back(point);
notifyPointsChanged();
return point;
}
KoPathPoint * KoPathShape::curveTo(const QPointF &c1, const QPointF &c2, const QPointF &p)
{
if (d->subpaths.empty()) {
moveTo(QPointF(0, 0));
}
KoPathPoint * lastPoint = d->subpaths.last()->last();
updateLastPriv(&lastPoint);
lastPoint->setControlPoint2(c1);
KoPathPoint * point = new KoPathPoint(this, p, KoPathPoint::StopSubpath);
point->setControlPoint1(c2);
d->subpaths.last()->push_back(point);
notifyPointsChanged();
return point;
}
KoPathPoint * KoPathShape::curveTo(const QPointF &c, const QPointF &p)
{
if (d->subpaths.empty())
moveTo(QPointF(0, 0));
KoPathPoint * lastPoint = d->subpaths.last()->last();
updateLastPriv(&lastPoint);
lastPoint->setControlPoint2(c);
KoPathPoint * point = new KoPathPoint(this, p, KoPathPoint::StopSubpath);
d->subpaths.last()->push_back(point);
notifyPointsChanged();
return point;
}
KoPathPoint * KoPathShape::arcTo(qreal rx, qreal ry, qreal startAngle, qreal sweepAngle)
{
if (d->subpaths.empty()) {
moveTo(QPointF(0, 0));
}
KoPathPoint * lastPoint = d->subpaths.last()->last();
if (lastPoint->properties() & KoPathPoint::CloseSubpath) {
lastPoint = d->subpaths.last()->first();
}
QPointF startpoint(lastPoint->point());
KoPathPoint * newEndPoint = lastPoint;
QPointF curvePoints[12];
int pointCnt = arcToCurve(rx, ry, startAngle, sweepAngle, startpoint, curvePoints);
for (int i = 0; i < pointCnt; i += 3) {
newEndPoint = curveTo(curvePoints[i], curvePoints[i+1], curvePoints[i+2]);
}
return newEndPoint;
}
int KoPathShape::arcToCurve(qreal rx, qreal ry, qreal startAngle, qreal sweepAngle, const QPointF & offset, QPointF * curvePoints) const
{
int pointCnt = 0;
// check Parameters
if (sweepAngle == 0.0)
return pointCnt;
sweepAngle = qBound(-360.0, sweepAngle, 360.0);
if (rx == 0 || ry == 0) {
//TODO
}
// split angles bigger than 90° so that it gives a good approximation to the circle
qreal parts = ceil(qAbs(sweepAngle / 90.0));
qreal sa_rad = startAngle * M_PI / 180.0;
qreal partangle = sweepAngle / parts;
qreal endangle = startAngle + partangle;
qreal se_rad = endangle * M_PI / 180.0;
qreal sinsa = sin(sa_rad);
qreal cossa = cos(sa_rad);
qreal kappa = 4.0 / 3.0 * tan((se_rad - sa_rad) / 4);
// startpoint is at the last point is the path but when it is closed
// it is at the first point
QPointF startpoint(offset);
//center berechnen
QPointF center(startpoint - QPointF(cossa * rx, -sinsa * ry));
//debugFlake <<"kappa" << kappa <<"parts" << parts;
for (int part = 0; part < parts; ++part) {
// start tangent
curvePoints[pointCnt++] = QPointF(startpoint - QPointF(sinsa * rx * kappa, cossa * ry * kappa));
qreal sinse = sin(se_rad);
qreal cosse = cos(se_rad);
// end point
QPointF endpoint(center + QPointF(cosse * rx, -sinse * ry));
// end tangent
curvePoints[pointCnt++] = QPointF(endpoint - QPointF(-sinse * rx * kappa, -cosse * ry * kappa));
curvePoints[pointCnt++] = endpoint;
// set the endpoint as next start point
startpoint = endpoint;
sinsa = sinse;
cossa = cosse;
endangle += partangle;
se_rad = endangle * M_PI / 180.0;
}
return pointCnt;
}
void KoPathShape::close()
{
if (d->subpaths.empty()) {
return;
}
closeSubpathPriv(d->subpaths.last());
}
void KoPathShape::closeMerge()
{
if (d->subpaths.empty()) {
return;
}
closeMergeSubpathPriv(d->subpaths.last());
}
QPointF KoPathShape::normalize()
{
QPointF tl(outline().boundingRect().topLeft());
QTransform matrix;
matrix.translate(-tl.x(), -tl.y());
d->map(matrix);
// keep the top left point of the object
applyTransformation(matrix.inverted());
shapeChangedPriv(ContentChanged);
return tl;
}
void KoPathShape::Private::map(const QTransform &matrix)
{
KoSubpathList::const_iterator pathIt(subpaths.constBegin());
for (; pathIt != subpaths.constEnd(); ++pathIt) {
KoSubpath::const_iterator it((*pathIt)->constBegin());
for (; it != (*pathIt)->constEnd(); ++it) {
// It's possible there are null points in the map...
if (*it) {
(*it)->map(matrix);
}
}
}
}
void KoPathShape::updateLastPriv(KoPathPoint **lastPoint)
{
// check if we are about to add a new point to a closed subpath
if ((*lastPoint)->properties() & KoPathPoint::StopSubpath
&& (*lastPoint)->properties() & KoPathPoint::CloseSubpath) {
// get the first point of the subpath
KoPathPoint *subpathStart = d->subpaths.last()->first();
// clone the first point of the subpath...
KoPathPoint * newLastPoint = new KoPathPoint(*subpathStart, this);
// ... and make it a normal point
newLastPoint->setProperties(KoPathPoint::Normal);
// now start a new subpath with the cloned start point
KoSubpath *path = new KoSubpath;
path->push_back(newLastPoint);
d->subpaths.push_back(path);
*lastPoint = newLastPoint;
} else {
// the subpath was not closed so the formerly last point
// of the subpath is no end point anymore
(*lastPoint)->unsetProperty(KoPathPoint::StopSubpath);
}
(*lastPoint)->unsetProperty(KoPathPoint::CloseSubpath);
}
QList<KoPathPoint*> KoPathShape::pointsAt(const QRectF &r) const
{
QList<KoPathPoint*> result;
KoSubpathList::const_iterator pathIt(d->subpaths.constBegin());
for (; pathIt != d->subpaths.constEnd(); ++pathIt) {
KoSubpath::const_iterator it((*pathIt)->constBegin());
for (; it != (*pathIt)->constEnd(); ++it) {
if (r.contains((*it)->point()))
result.append(*it);
else if ((*it)->activeControlPoint1() && r.contains((*it)->controlPoint1()))
result.append(*it);
else if ((*it)->activeControlPoint2() && r.contains((*it)->controlPoint2()))
result.append(*it);
}
}
return result;
}
QList<KoPathSegment> KoPathShape::segmentsAt(const QRectF &r) const
{
QList<KoPathSegment> segments;
int subpathCount = d->subpaths.count();
for (int subpathIndex = 0; subpathIndex < subpathCount; ++subpathIndex) {
KoSubpath * subpath = d->subpaths[subpathIndex];
int pointCount = subpath->count();
bool subpathClosed = isClosedSubpath(subpathIndex);
for (int pointIndex = 0; pointIndex < pointCount; ++pointIndex) {
if (pointIndex == (pointCount - 1) && ! subpathClosed)
break;
KoPathSegment s(subpath->at(pointIndex), subpath->at((pointIndex + 1) % pointCount));
QRectF controlRect = s.controlPointRect();
if (! r.intersects(controlRect) && ! controlRect.contains(r))
continue;
QRectF bound = s.boundingRect();
if (! r.intersects(bound) && ! bound.contains(r))
continue;
segments.append(s);
}
}
return segments;
}
KoPathPointIndex KoPathShape::pathPointIndex(const KoPathPoint *point) const
{
for (int subpathIndex = 0; subpathIndex < d->subpaths.size(); ++subpathIndex) {
KoSubpath * subpath = d->subpaths.at(subpathIndex);
for (int pointPos = 0; pointPos < subpath->size(); ++pointPos) {
if (subpath->at(pointPos) == point) {
return KoPathPointIndex(subpathIndex, pointPos);
}
}
}
return KoPathPointIndex(-1, -1);
}
KoPathPoint * KoPathShape::pointByIndex(const KoPathPointIndex &pointIndex) const
{
KoSubpath *subpath = d->subPath(pointIndex.first);
if (subpath == 0 || pointIndex.second < 0 || pointIndex.second >= subpath->size())
return 0;
return subpath->at(pointIndex.second);
}
KoPathSegment KoPathShape::segmentByIndex(const KoPathPointIndex &pointIndex) const
{
KoPathSegment segment(0, 0);
KoSubpath *subpath = d->subPath(pointIndex.first);
if (subpath != 0 && pointIndex.second >= 0 && pointIndex.second < subpath->size()) {
KoPathPoint * point = subpath->at(pointIndex.second);
int index = pointIndex.second;
// check if we have a (closing) segment starting from the last point
if ((index == subpath->size() - 1) && point->properties() & KoPathPoint::CloseSubpath)
index = 0;
else
++index;
if (index < subpath->size()) {
segment = KoPathSegment(point, subpath->at(index));
}
}
return segment;
}
int KoPathShape::pointCount() const
{
int i = 0;
KoSubpathList::const_iterator pathIt(d->subpaths.constBegin());
for (; pathIt != d->subpaths.constEnd(); ++pathIt) {
i += (*pathIt)->size();
}
return i;
}
int KoPathShape::subpathCount() const
{
return d->subpaths.count();
}
int KoPathShape::subpathPointCount(int subpathIndex) const
{
KoSubpath *subpath = d->subPath(subpathIndex);
if (subpath == 0)
return -1;
return subpath->size();
}
bool KoPathShape::isClosedSubpath(int subpathIndex) const
{
KoSubpath *subpath = d->subPath(subpathIndex);
if (subpath == 0)
return false;
const bool firstClosed = subpath->first()->properties() & KoPathPoint::CloseSubpath;
const bool lastClosed = subpath->last()->properties() & KoPathPoint::CloseSubpath;
return firstClosed && lastClosed;
}
bool KoPathShape::insertPoint(KoPathPoint* point, const KoPathPointIndex &pointIndex)
{
KoSubpath *subpath = d->subPath(pointIndex.first);
if (subpath == 0 || pointIndex.second < 0 || pointIndex.second > subpath->size())
return false;
KoPathPoint::PointProperties properties = point->properties();
properties &= ~KoPathPoint::StartSubpath;
properties &= ~KoPathPoint::StopSubpath;
properties &= ~KoPathPoint::CloseSubpath;
// check if new point starts subpath
if (pointIndex.second == 0) {
properties |= KoPathPoint::StartSubpath;
// subpath was closed
if (subpath->last()->properties() & KoPathPoint::CloseSubpath) {
// keep the path closed
properties |= KoPathPoint::CloseSubpath;
}
// old first point does not start the subpath anymore
subpath->first()->unsetProperty(KoPathPoint::StartSubpath);
}
// check if new point stops subpath
else if (pointIndex.second == subpath->size()) {
properties |= KoPathPoint::StopSubpath;
// subpath was closed
if (subpath->last()->properties() & KoPathPoint::CloseSubpath) {
// keep the path closed
properties = properties | KoPathPoint::CloseSubpath;
}
// old last point does not end subpath anymore
subpath->last()->unsetProperty(KoPathPoint::StopSubpath);
}
point->setProperties(properties);
point->setParent(this);
subpath->insert(pointIndex.second , point);
notifyPointsChanged();
return true;
}
KoPathPoint * KoPathShape::removePoint(const KoPathPointIndex &pointIndex)
{
KoSubpath *subpath = d->subPath(pointIndex.first);
if (subpath == 0 || pointIndex.second < 0 || pointIndex.second >= subpath->size())
return 0;
KoPathPoint * point = subpath->takeAt(pointIndex.second);
point->setParent(0);
//don't do anything (not even crash), if there was only one point
if (pointCount()==0) {
return point;
}
// check if we removed the first point
else if (pointIndex.second == 0) {
// first point removed, set new StartSubpath
subpath->first()->setProperty(KoPathPoint::StartSubpath);
// check if path was closed
if (subpath->last()->properties() & KoPathPoint::CloseSubpath) {
// keep path closed
subpath->first()->setProperty(KoPathPoint::CloseSubpath);
}
}
// check if we removed the last point
else if (pointIndex.second == subpath->size()) { // use size as point is already removed
// last point removed, set new StopSubpath
subpath->last()->setProperty(KoPathPoint::StopSubpath);
// check if path was closed
if (point->properties() & KoPathPoint::CloseSubpath) {
// keep path closed
subpath->last()->setProperty(KoPathPoint::CloseSubpath);
}
}
notifyPointsChanged();
return point;
}
bool KoPathShape::breakAfter(const KoPathPointIndex &pointIndex)
{
KoSubpath *subpath = d->subPath(pointIndex.first);
if (!subpath || pointIndex.second < 0 || pointIndex.second > subpath->size() - 2
|| isClosedSubpath(pointIndex.first))
return false;
KoSubpath * newSubpath = new KoSubpath;
int size = subpath->size();
for (int i = pointIndex.second + 1; i < size; ++i) {
newSubpath->append(subpath->takeAt(pointIndex.second + 1));
}
// now make the first point of the new subpath a starting node
newSubpath->first()->setProperty(KoPathPoint::StartSubpath);
// the last point of the old subpath is now an ending node
subpath->last()->setProperty(KoPathPoint::StopSubpath);
// insert the new subpath after the broken one
d->subpaths.insert(pointIndex.first + 1, newSubpath);
notifyPointsChanged();
return true;
}
bool KoPathShape::join(int subpathIndex)
{
KoSubpath *subpath = d->subPath(subpathIndex);
KoSubpath *nextSubpath = d->subPath(subpathIndex + 1);
if (!subpath || !nextSubpath || isClosedSubpath(subpathIndex)
|| isClosedSubpath(subpathIndex+1))
return false;
// the last point of the subpath does not end the subpath anymore
subpath->last()->unsetProperty(KoPathPoint::StopSubpath);
// the first point of the next subpath does not start a subpath anymore
nextSubpath->first()->unsetProperty(KoPathPoint::StartSubpath);
// append the second subpath to the first
Q_FOREACH (KoPathPoint * p, *nextSubpath)
subpath->append(p);
// remove the nextSubpath from path
d->subpaths.removeAt(subpathIndex + 1);
// delete it as it is no longer possible to use it
delete nextSubpath;
notifyPointsChanged();
return true;
}
bool KoPathShape::moveSubpath(int oldSubpathIndex, int newSubpathIndex)
{
KoSubpath *subpath = d->subPath(oldSubpathIndex);
if (subpath == 0 || newSubpathIndex >= d->subpaths.size())
return false;
if (oldSubpathIndex == newSubpathIndex)
return true;
d->subpaths.removeAt(oldSubpathIndex);
d->subpaths.insert(newSubpathIndex, subpath);
notifyPointsChanged();
return true;
}
KoPathPointIndex KoPathShape::openSubpath(const KoPathPointIndex &pointIndex)
{
KoSubpath *subpath = d->subPath(pointIndex.first);
if (!subpath || pointIndex.second < 0 || pointIndex.second >= subpath->size()
|| !isClosedSubpath(pointIndex.first))
return KoPathPointIndex(-1, -1);
KoPathPoint * oldStartPoint = subpath->first();
// the old starting node no longer starts the subpath
oldStartPoint->unsetProperty(KoPathPoint::StartSubpath);
// the old end node no longer closes the subpath
subpath->last()->unsetProperty(KoPathPoint::StopSubpath);
// reorder the subpath
for (int i = 0; i < pointIndex.second; ++i) {
subpath->append(subpath->takeFirst());
}
// make the first point a start node
subpath->first()->setProperty(KoPathPoint::StartSubpath);
// make the last point an end node
subpath->last()->setProperty(KoPathPoint::StopSubpath);
notifyPointsChanged();
return pathPointIndex(oldStartPoint);
}
KoPathPointIndex KoPathShape::closeSubpath(const KoPathPointIndex &pointIndex)
{
KoSubpath *subpath = d->subPath(pointIndex.first);
if (!subpath || pointIndex.second < 0 || pointIndex.second >= subpath->size()
|| isClosedSubpath(pointIndex.first))
return KoPathPointIndex(-1, -1);
KoPathPoint * oldStartPoint = subpath->first();
// the old starting node no longer starts the subpath
oldStartPoint->unsetProperty(KoPathPoint::StartSubpath);
// the old end node no longer ends the subpath
subpath->last()->unsetProperty(KoPathPoint::StopSubpath);
// reorder the subpath
for (int i = 0; i < pointIndex.second; ++i) {
subpath->append(subpath->takeFirst());
}
subpath->first()->setProperty(KoPathPoint::StartSubpath);
subpath->last()->setProperty(KoPathPoint::StopSubpath);
closeSubpathPriv(subpath);
notifyPointsChanged();
return pathPointIndex(oldStartPoint);
}
bool KoPathShape::reverseSubpath(int subpathIndex)
{
KoSubpath *subpath = d->subPath(subpathIndex);
if (subpath == 0)
return false;
int size = subpath->size();
for (int i = 0; i < size; ++i) {
KoPathPoint *p = subpath->takeAt(i);
p->reverse();
subpath->prepend(p);
}
// adjust the position dependent properties
KoPathPoint *first = subpath->first();
KoPathPoint *last = subpath->last();
KoPathPoint::PointProperties firstProps = first->properties();
KoPathPoint::PointProperties lastProps = last->properties();
firstProps |= KoPathPoint::StartSubpath;
firstProps &= ~KoPathPoint::StopSubpath;
lastProps |= KoPathPoint::StopSubpath;
lastProps &= ~KoPathPoint::StartSubpath;
if (firstProps & KoPathPoint::CloseSubpath) {
firstProps |= KoPathPoint::CloseSubpath;
lastProps |= KoPathPoint::CloseSubpath;
}
first->setProperties(firstProps);
last->setProperties(lastProps);
notifyPointsChanged();
return true;
}
KoSubpath * KoPathShape::removeSubpath(int subpathIndex)
{
KoSubpath *subpath = d->subPath(subpathIndex);
if (subpath != 0) {
Q_FOREACH (KoPathPoint* point, *subpath) {
point->setParent(this);
}
d->subpaths.removeAt(subpathIndex);
}
notifyPointsChanged();
return subpath;
}
bool KoPathShape::addSubpath(KoSubpath * subpath, int subpathIndex)
{
if (subpathIndex < 0 || subpathIndex > d->subpaths.size())
return false;
Q_FOREACH (KoPathPoint* point, *subpath) {
point->setParent(this);
}
d->subpaths.insert(subpathIndex, subpath);
notifyPointsChanged();
return true;
}
int KoPathShape::combine(KoPathShape *path)
{
int insertSegmentPosition = -1;
if (!path) return insertSegmentPosition;
QTransform pathMatrix = path->absoluteTransformation();
QTransform myMatrix = absoluteTransformation().inverted();
Q_FOREACH (KoSubpath* subpath, path->d->subpaths) {
KoSubpath *newSubpath = new KoSubpath();
Q_FOREACH (KoPathPoint* point, *subpath) {
KoPathPoint *newPoint = new KoPathPoint(*point, this);
newPoint->map(pathMatrix);
newPoint->map(myMatrix);
newSubpath->append(newPoint);
}
d->subpaths.append(newSubpath);
if (insertSegmentPosition < 0) {
insertSegmentPosition = d->subpaths.size() - 1;
}
}
normalize();
notifyPointsChanged();
return insertSegmentPosition;
}
bool KoPathShape::separate(QList<KoPathShape*> & separatedPaths)
{
if (! d->subpaths.size())
return false;
QTransform myMatrix = absoluteTransformation();
Q_FOREACH (KoSubpath* subpath, d->subpaths) {
KoPathShape *shape = new KoPathShape();
shape->setStroke(stroke());
shape->setBackground(background());
shape->setShapeId(shapeId());
shape->setZIndex(zIndex());
KoSubpath *newSubpath = new KoSubpath();
Q_FOREACH (KoPathPoint* point, *subpath) {
KoPathPoint *newPoint = new KoPathPoint(*point, shape);
newPoint->map(myMatrix);
newSubpath->append(newPoint);
}
shape->d->subpaths.append(newSubpath);
shape->normalize();
// NOTE: shape cannot have any listeners yet, so no notification about
// points modification is needed
separatedPaths.append(shape);
}
return true;
}
void KoPathShape::closeSubpathPriv(KoSubpath *subpath)
{
if (! subpath)
return;
subpath->last()->setProperty(KoPathPoint::CloseSubpath);
subpath->first()->setProperty(KoPathPoint::CloseSubpath);
notifyPointsChanged();
}
void KoPathShape::closeMergeSubpathPriv(KoSubpath *subpath)
{
if (! subpath || subpath->size() < 2)
return;
KoPathPoint * lastPoint = subpath->last();
KoPathPoint * firstPoint = subpath->first();
// check if first and last points are coincident
if (lastPoint->point() == firstPoint->point()) {
// we are removing the current last point and
// reuse its first control point if active
firstPoint->setProperty(KoPathPoint::StartSubpath);
firstPoint->setProperty(KoPathPoint::CloseSubpath);
if (lastPoint->activeControlPoint1())
firstPoint->setControlPoint1(lastPoint->controlPoint1());
// remove last point
delete subpath->takeLast();
// the new last point closes the subpath now
lastPoint = subpath->last();
lastPoint->setProperty(KoPathPoint::StopSubpath);
lastPoint->setProperty(KoPathPoint::CloseSubpath);
notifyPointsChanged();
} else {
closeSubpathPriv(subpath);
}
}
const KoSubpathList &KoPathShape::subpaths() const
{
return d->subpaths;
}
KoSubpathList &KoPathShape::subpaths()
{
return d->subpaths;
}
void KoPathShape::map(const QTransform &matrix)
{
return d->map(matrix);
}
KoSubpath *KoPathShape::Private::subPath(int subpathIndex) const
{
if (subpathIndex < 0 || subpathIndex >= subpaths.size())
return 0;
return subpaths.at(subpathIndex);
}
QString KoPathShape::pathShapeId() const
{
return KoPathShapeId;
}
QString KoPathShape::toString(const QTransform &matrix) const
{
QString pathString;
// iterate over all subpaths
KoSubpathList::const_iterator pathIt(d->subpaths.constBegin());
for (; pathIt != d->subpaths.constEnd(); ++pathIt) {
KoSubpath::const_iterator pointIt((*pathIt)->constBegin());
// keep a pointer to the first point of the subpath
KoPathPoint *firstPoint(*pointIt);
// keep a pointer to the previous point of the subpath
KoPathPoint *lastPoint = firstPoint;
// keep track if the previous point has an active control point 2
bool activeControlPoint2 = false;
// iterate over all points of the current subpath
for (; pointIt != (*pathIt)->constEnd(); ++pointIt) {
KoPathPoint *currPoint(*pointIt);
if (!currPoint) {
qWarning() << "Found a zero point in the shape's path!";
continue;
}
// first point of subpath ?
if (currPoint == firstPoint) {
// are we starting a subpath ?
if (currPoint->properties() & KoPathPoint::StartSubpath) {
const QPointF p = matrix.map(currPoint->point());
pathString += QString("M%1 %2").arg(p.x()).arg(p.y());
}
}
// end point of curve segment ?
else if (activeControlPoint2 || currPoint->activeControlPoint1()) {
// check if we have a cubic or quadratic curve
const bool isCubic = activeControlPoint2 && currPoint->activeControlPoint1();
KoPathSegment cubicSeg = isCubic ? KoPathSegment(lastPoint, currPoint)
: KoPathSegment(lastPoint, currPoint).toCubic();
if (cubicSeg.first() && cubicSeg.second()) {
const QPointF cp1 = matrix.map(cubicSeg.first()->controlPoint2());
const QPointF cp2 = matrix.map(cubicSeg.second()->controlPoint1());
const QPointF p = matrix.map(cubicSeg.second()->point());
pathString += QString("C%1 %2 %3 %4 %5 %6")
.arg(cp1.x()).arg(cp1.y())
.arg(cp2.x()).arg(cp2.y())
.arg(p.x()).arg(p.y());
}
}
// end point of line segment!
else {
const QPointF p = matrix.map(currPoint->point());
pathString += QString("L%1 %2").arg(p.x()).arg(p.y());
}
// last point closes subpath ?
if (currPoint->properties() & KoPathPoint::StopSubpath
&& currPoint->properties() & KoPathPoint::CloseSubpath) {
// add curve when there is a curve on the way to the first point
if (currPoint->activeControlPoint2() || firstPoint->activeControlPoint1()) {
// check if we have a cubic or quadratic curve
const bool isCubic = currPoint->activeControlPoint2() && firstPoint->activeControlPoint1();
KoPathSegment cubicSeg = isCubic ? KoPathSegment(currPoint, firstPoint)
: KoPathSegment(currPoint, firstPoint).toCubic();
if (cubicSeg.first() && cubicSeg.second()) {
const QPointF cp1 = matrix.map(cubicSeg.first()->controlPoint2());
const QPointF cp2 = matrix.map(cubicSeg.second()->controlPoint1());
const QPointF p = matrix.map(cubicSeg.second()->point());
pathString += QString("C%1 %2 %3 %4 %5 %6")
.arg(cp1.x()).arg(cp1.y())
.arg(cp2.x()).arg(cp2.y())
.arg(p.x()).arg(p.y());
}
}
pathString += QString("Z");
}
activeControlPoint2 = currPoint->activeControlPoint2();
lastPoint = currPoint;
}
}
return pathString;
}
char nodeType(const KoPathPoint * point)
{
if (point->properties() & KoPathPoint::IsSmooth) {
return 's';
}
else if (point->properties() & KoPathPoint::IsSymmetric) {
return 'z';
}
else {
return 'c';
}
}
QString KoPathShape::Private::nodeTypes() const
{
QString types;
KoSubpathList::const_iterator pathIt(subpaths.constBegin());
for (; pathIt != subpaths.constEnd(); ++pathIt) {
KoSubpath::const_iterator it((*pathIt)->constBegin());
for (; it != (*pathIt)->constEnd(); ++it) {
if (it == (*pathIt)->constBegin()) {
types.append('c');
}
else {
types.append(nodeType(*it));
}
if ((*it)->properties() & KoPathPoint::StopSubpath
&& (*it)->properties() & KoPathPoint::CloseSubpath) {
KoPathPoint * firstPoint = (*pathIt)->first();
types.append(nodeType(firstPoint));
}
}
}
return types;
}
void updateNodeType(KoPathPoint * point, const QChar & nodeType)
{
if (nodeType == 's') {
point->setProperty(KoPathPoint::IsSmooth);
}
else if (nodeType == 'z') {
point->setProperty(KoPathPoint::IsSymmetric);
}
}
void KoPathShape::Private::loadNodeTypes(const KoXmlElement &element)
{
if (element.hasAttributeNS(KoXmlNS::calligra, "nodeTypes")) {
QString nodeTypes = element.attributeNS(KoXmlNS::calligra, "nodeTypes");
QString::const_iterator nIt(nodeTypes.constBegin());
KoSubpathList::const_iterator pathIt(subpaths.constBegin());
for (; pathIt != subpaths.constEnd(); ++pathIt) {
KoSubpath::const_iterator it((*pathIt)->constBegin());
for (; it != (*pathIt)->constEnd(); ++it, nIt++) {
// be sure not to crash if there are not enough nodes in nodeTypes
if (nIt == nodeTypes.constEnd()) {
warnFlake << "not enough nodes in calligra:nodeTypes";
return;
}
// the first node is always of type 'c'
if (it != (*pathIt)->constBegin()) {
updateNodeType(*it, *nIt);
}
if ((*it)->properties() & KoPathPoint::StopSubpath
&& (*it)->properties() & KoPathPoint::CloseSubpath) {
++nIt;
updateNodeType((*pathIt)->first(), *nIt);
}
}
}
}
}
Qt::FillRule KoPathShape::fillRule() const
{
return d->fillRule;
}
void KoPathShape::setFillRule(Qt::FillRule fillRule)
{
d->fillRule = fillRule;
}
KoPathShape * KoPathShape::createShapeFromPainterPath(const QPainterPath &path)
{
KoPathShape * shape = new KoPathShape();
int elementCount = path.elementCount();
for (int i = 0; i < elementCount; i++) {
QPainterPath::Element element = path.elementAt(i);
switch (element.type) {
case QPainterPath::MoveToElement:
shape->moveTo(QPointF(element.x, element.y));
break;
case QPainterPath::LineToElement:
shape->lineTo(QPointF(element.x, element.y));
break;
case QPainterPath::CurveToElement:
shape->curveTo(QPointF(element.x, element.y),
QPointF(path.elementAt(i + 1).x, path.elementAt(i + 1).y),
QPointF(path.elementAt(i + 2).x, path.elementAt(i + 2).y));
break;
default:
continue;
}
}
shape->setShapeId(KoPathShapeId);
//shape->normalize();
return shape;
}
bool KoPathShape::hitTest(const QPointF &position) const
{
if (parent() && parent()->isClipped(this) && ! parent()->hitTest(position))
return false;
QPointF point = absoluteTransformation().inverted().map(position);
const QPainterPath outlinePath = outline();
if (stroke()) {
KoInsets insets;
stroke()->strokeInsets(this, insets);
QRectF roi(QPointF(-insets.left, -insets.top), QPointF(insets.right, insets.bottom));
roi.moveCenter(point);
if (outlinePath.intersects(roi) || outlinePath.contains(roi))
return true;
} else {
if (outlinePath.contains(point))
return true;
}
// if there is no shadow we can as well just leave
if (! shadow())
return false;
// the shadow has an offset to the shape, so we simply
// check if the position minus the shadow offset hits the shape
point = absoluteTransformation().inverted().map(position - shadow()->offset());
return outlinePath.contains(point);
}
void KoPathShape::setMarker(KoMarker *marker, KoFlake::MarkerPosition pos)
{
if (!marker && d->markersNew.contains(pos)) {
d->markersNew.remove(pos);
} else {
d->markersNew[pos] = marker;
}
}
KoMarker *KoPathShape::marker(KoFlake::MarkerPosition pos) const
{
return d->markersNew[pos].data();
}
bool KoPathShape::hasMarkers() const
{
return !d->markersNew.isEmpty();
}
bool KoPathShape::autoFillMarkers() const
{
return d->autoFillMarkers;
}
void KoPathShape::setAutoFillMarkers(bool value)
{
d->autoFillMarkers = value;
}
void KoPathShape::recommendPointSelectionChange(const QList<KoPathPointIndex> &newSelection)
{
Q_FOREACH (KoShape::ShapeChangeListener *listener, listeners()) {
PointSelectionChangeListener *pointListener = dynamic_cast<PointSelectionChangeListener*>(listener);
if (pointListener) {
pointListener->recommendPointSelectionChange(this, newSelection);
}
}
}
void KoPathShape::notifyPointsChanged()
{
Q_FOREACH (KoShape::ShapeChangeListener *listener, listeners()) {
PointSelectionChangeListener *pointListener = dynamic_cast<PointSelectionChangeListener*>(listener);
if (pointListener) {
pointListener->notifyPathPointsChanged(this);
}
}
}
QPainterPath KoPathShape::pathStroke(const QPen &pen) const
{
if (d->subpaths.isEmpty()) {
return QPainterPath();
}
QPainterPath pathOutline;
QPainterPathStroker stroker;
stroker.setWidth(0);
stroker.setJoinStyle(Qt::MiterJoin);
stroker.setWidth(pen.widthF());
stroker.setJoinStyle(pen.joinStyle());
stroker.setMiterLimit(pen.miterLimit());
stroker.setCapStyle(pen.capStyle());
stroker.setDashOffset(pen.dashOffset());
stroker.setDashPattern(pen.dashPattern());
QPainterPath path = stroker.createStroke(outline());
pathOutline.addPath(path);
pathOutline.setFillRule(Qt::WindingFill);
return pathOutline;
}
void KoPathShape::PointSelectionChangeListener::notifyShapeChanged(KoShape::ChangeType type, KoShape *shape)
{
Q_UNUSED(type);
Q_UNUSED(shape);
}
diff --git a/libs/flake/KoPathShape.h b/libs/flake/KoPathShape.h
index 44b7fb994b..fee23212a8 100644
--- a/libs/flake/KoPathShape.h
+++ b/libs/flake/KoPathShape.h
@@ -1,534 +1,513 @@
/* This file is part of the KDE project
Copyright (C) 2006, 2011 Thorsten Zachmann <zachmann@kde.org>
Copyright (C) 2007,2009 Thomas Zander <zander@kde.org>
Copyright (C) 2006-2008 Jan Hambrecht <jaham@gmx.net>
Copyright (C) 2011 Jean-Nicolas Artaud <jeannicolasartaud@gmail.com>
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 KOPATHSHAPE_H
#define KOPATHSHAPE_H
#include "kritaflake_export.h"
#include <QMetaType>
#include <QTransform>
#include "KoTosContainer.h"
#define KoPathShapeId "KoPathShape"
class KoPathSegment;
class KoPathPoint;
class KoPathShapePrivate;
class KoMarker;
class KisHandlePainterHelper;
typedef QPair<int, int> KoPathPointIndex;
/// a KoSubpath contains a path from a moveTo until a close or a new moveTo
typedef QList<KoPathPoint *> KoSubpath;
typedef QList<KoSubpath *> KoSubpathList;
/// The position of a path point within a path shape
/**
* @brief This is the base for all graphical objects.
*
* All graphical objects are based on this object e.g. lines, rectangulars, pies
* and so on.
*
* The KoPathShape uses KoPathPoint's to describe the path of the shape.
*
* Here a short example:
* 3 points connected by a curveTo's described by the following svg:
* M 100,200 C 100,100 250,100 250,200 C 250,200 400,300 400,200.
*
* This will be stored in 3 KoPathPoint's as
* The first point contains in
* point 100,200
* controlPoint2 100,100
* The second point contains in
* point 250,200
* controlPoint1 250,100
* controlPoint2 250,300
* The third point contains in
* point 400,300
* controlPoint1 400,200
*
* Not the segments are stored but the points. Out of the points the segments are
* generated. See the outline method. The reason for storing it like that is that
* it is the points that are modified by the user and not the segments.
*/
class KRITAFLAKE_EXPORT KoPathShape : public KoTosContainer
{
public:
/**
* @brief constructor
*/
KoPathShape();
/**
* @brief
*/
~KoPathShape() override;
KoShape *cloneShape() const override;
/// reimplemented
void paint(QPainter &painter, KoShapePaintingContext &paintContext) const override;
virtual void paintPoints(KisHandlePainterHelper &handlesHelper);
/// reimplemented
QRectF outlineRect() const override;
/// reimplemented
QPainterPath outline() const override;
/// reimplemented
QRectF boundingRect() const override;
/// reimplemented
QSizeF size() const override;
QPainterPath pathStroke(const QPen &pen) const;
/**
* Resize the shape
*
* This makes sure that the pathshape will not be resized to 0 if the new size
* is null as that makes it impossible to undo the change.
*
* All functions that overwrite this function should also use the resizeMatrix
* function to get and use the same data in resizing.
*
* @see resizeMatrix()
*/
void setSize(const QSizeF &size) override;
+
/// reimplemented
bool hitTest(const QPointF &position) const override;
- // reimplemented
- void saveOdf(KoShapeSavingContext &context) const override;
- // reimplemented
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
-
- // basically the same as loadOdf but adapted to the contour cases
- // tag needs to be either contour-polygon or contour-path from another shape
- bool loadContourOdf(const KoXmlElement & element, KoShapeLoadingContext &context, const QSizeF &scaleFactor);
-
- /** basically the equivalent saveOdf but adapted to the contour cases
- * @param context the saving context
- * @param originalSize the original size of the unscaled image.
- */
- void saveContourOdf(KoShapeSavingContext &context, const QSizeF &originalSize) const;
-
/// Removes all subpaths and their points from the path
void clear();
/**
* @brief Starts a new Subpath
*
* Moves the pen to p and starts a new subpath.
*
* @return the newly created point
*/
KoPathPoint *moveTo(const QPointF &p);
/**
* @brief Adds a new line segment
*
* Adds a straight line between the last point and the given point p.
*
* @return the newly created point
*/
KoPathPoint *lineTo(const QPointF &p);
/**
* @brief Adds a new cubic Bezier curve segment.
*
* Adds a cubic Bezier curve between the last point and the given point p,
* using the control points specified by c1 and c2.
*
* @param c1 control point1
* @param c2 control point2
* @param p the endpoint of this curve segment
*
* @return The newly created point
*/
KoPathPoint *curveTo(const QPointF &c1, const QPointF &c2, const QPointF &p);
/**
* @brief Adds a new quadratic Bezier curve segment.
*
* Adds a quadratic Bezier curve between the last point and the given point p,
* using the control point specified by c.
*
* @param c control point
* @param p the endpoint of this curve segment
*
* @return The newly created point
*/
KoPathPoint *curveTo(const QPointF &c, const QPointF &p);
/**
* @brief Add an arc.
*
* Adds an arc starting at the current point. The arc will be converted to bezier curves.
*
* @param rx x radius of the ellipse
* @param ry y radius of the ellipse
* @param startAngle the angle where the arc will be started
* @param sweepAngle the length of the angle
* TODO add param to have angle of the ellipse
*
* @return The newly created point
*/
KoPathPoint *arcTo(qreal rx, qreal ry, qreal startAngle, qreal sweepAngle);
/**
* @brief Closes the current subpath
*/
void close();
/**
* @brief Closes the current subpath
*
* It tries to merge the last and first point of the subpath
* to one point and then closes the subpath. If merging is not
* possible as the two point are to far from each other a close
* will be done.
* TODO define a maximum distance between the two points until this is working
*/
void closeMerge();
/**
* @brief Normalizes the path data.
*
* The path points are transformed so that the top-left corner
* of the bounding rect is at (0,0).
* This should be called after adding points to the path or changing
* positions of path points.
* @return the offset by which the points are moved in shape coordinates.
*/
virtual QPointF normalize();
/**
* @brief Returns the path points within the given rectangle.
* @param rect the rectangle the requested points are in
* @return list of points within the rectangle
*/
QList<KoPathPoint*> pointsAt(const QRectF &rect) const;
/**
* @brief Returns the list of path segments within the given rectangle.
* @param rect the rectangle the requested segments are in
* @return list of segments within the rectangle
*/
QList<KoPathSegment> segmentsAt(const QRectF &rect) const;
/**
* @brief Returns the path point index of a given path point
*
* @param point the point for which you want to get the index
* @return path point index of the point if it exists
* otherwise KoPathPointIndex( -1, -1 )
*/
KoPathPointIndex pathPointIndex(const KoPathPoint *point) const;
/**
* @brief Returns the path point specified by a path point index
*
* @param pointIndex index of the point to get
*
* @return KoPathPoint on success, 0 otherwise e.g. out of bounds
*/
KoPathPoint *pointByIndex(const KoPathPointIndex &pointIndex) const;
/**
* @brief Returns the segment specified by a path point index
*
* A segment is defined by the point index of the first point in the segment.
* A segment contains the defined point and its following point. If the subpath is
* closed and the and the pointIndex point to the last point in the subpath, the
* following point is the first point in the subpath.
*
* @param pointIndex index of the first point of the segment
*
* @return Segment containing both points of the segment or KoPathSegment( 0, 0 ) on error e.g. out of bounds
*/
KoPathSegment segmentByIndex(const KoPathPointIndex &pointIndex) const;
/**
* @brief Returns the number of points in the path
*
* @return The number of points in the path
*/
int pointCount() const;
/**
* @brief Returns the number of subpaths in the path
*
* @return The number of subpaths in the path
*/
int subpathCount() const;
/**
* @brief Returns the number of points in a subpath
*
* @return The number of points in the subpath or -1 if subpath out of bounds
*/
int subpathPointCount(int subpathIndex) const;
/**
* @brief Checks if a subpath is closed
*
* @param subpathIndex index of the subpath to check
*
* @return true when the subpath is closed, false otherwise
*/
bool isClosedSubpath(int subpathIndex) const;
/**
* @brief Inserts a new point into the given subpath at the specified position
*
* This method keeps the subpath closed if it is closed, and open when it was
* open. So it can change the properties of the point inserted.
* You might need to update the point before/after to get the desired result
* e.g. when you insert the point into a curve.
*
* @param point to insert
* @param pointIndex index at which the point should be inserted
*
* @return true on success,
* false when pointIndex is out of bounds
*/
bool insertPoint(KoPathPoint *point, const KoPathPointIndex &pointIndex);
/**
* @brief Removes a point from the path.
*
* Note that the ownership of the point will pass to the caller.
*
* @param pointIndex index of the point which should be removed
*
* @return The removed point on success,
* otherwise 0
*/
KoPathPoint *removePoint(const KoPathPointIndex &pointIndex);
/**
* @brief Breaks the path after the point index
*
* The new subpath will be behind the one that was broken. The segment between
* the given point and the one behind will be removed. If you want to split at
* one point insert first a copy of the point behind it.
* This does not work when the subpath is closed. Use openSubpath for this.
* It does not break at the last position of a subpath or if there is only one
* point in the subpath.
*
* @param pointIndex index of the point after which the path should be broken
*
* @return true if the subpath was broken, otherwise false
*/
bool breakAfter(const KoPathPointIndex &pointIndex);
/**
* @brief Joins the given subpath with the following one
*
* Joins the given subpath with the following one by inserting a segment between
* the two subpaths.
* This does nothing if the specified subpath is the last subpath
* or one of both subpaths is closed.
*
* @param subpathIndex index of the subpath being joined with the following subpath
*
* @return true if the subpath was joined, otherwise false
*/
bool join(int subpathIndex);
/**
* @brief Moves the position of a subpath within a path
*
* @param oldSubpathIndex old index of the subpath
* @param newSubpathIndex new index of the subpath
*
* @return true if the subpath was moved, otherwise false e.g. if an index is out of bounds
*/
bool moveSubpath(int oldSubpathIndex, int newSubpathIndex);
/**
* @brief Opens a closed subpath
*
* The subpath is opened by removing the segment before the given point, making
* the given point the new start point of the subpath.
*
* @param pointIndex the index of the point at which to open the closed subpath
* @return the new position of the old first point in the subpath
* otherwise KoPathPointIndex( -1, -1 )
*/
KoPathPointIndex openSubpath(const KoPathPointIndex &pointIndex);
/**
* @brief Close a open subpath
*
* The subpath is closed be inserting a segment between the start and end point, making
* the given point the new start point of the subpath.
*
* @return the new position of the old first point in the subpath
* otherwise KoPathPointIndex( -1, -1 )
*/
KoPathPointIndex closeSubpath(const KoPathPointIndex &pointIndex);
/**
* @brief Reverse subpath
*
* The last point becomes the first point and the first one becomes the last one.
*
* @param subpathIndex the index of the subpath to reverse
*/
bool reverseSubpath(int subpathIndex);
/**
* @brief Removes subpath from the path
* @param subpathIndex the index of the subpath to remove
* @return the removed subpath on success, 0 otherwise.
*/
KoSubpath *removeSubpath(int subpathIndex);
/**
* @brief Adds a subpath at the given index to the path
* @param subpath the subpath to add
* @param subpathIndex the index at which the new subpath should be inserted
* @return true on success, false otherwise e.g. subpathIndex out of bounds
*/
bool addSubpath(KoSubpath *subpath, int subpathIndex);
/**
* @brief Combines two path shapes by appending the data of the specified path.
* @param path the path to combine with
* @return index of the first segment inserted or -1 on failure
*/
int combine(KoPathShape *path);
/**
* @brief Creates separate path shapes, one for each existing subpath.
* @param separatedPaths the list which contains the separated path shapes
* @return true if separating the path was successful, false otherwise
*/
bool separate(QList<KoPathShape*> &separatedPaths);
/**
* Returns the specific path shape id.
*
* Path shape derived shapes have a different shape id which link them
* to their respective shape factories. In most cases they do not have
* a special tool for editing them.
* This function returns the specific shape id for finding the shape
* factory from KoShapeRegistry. The default KoPathShapeId is returned
* from KoShape::shapeId() so that the generic path editing tool gets
* activated when the shape is selected.
*
* @return the specific shape id
*/
virtual QString pathShapeId() const;
/// Returns a odf/svg string representation of the path data with the given matrix applied.
QString toString(const QTransform &matrix = QTransform()) const;
/// Returns the fill rule for the path object
Qt::FillRule fillRule() const;
/// Sets the fill rule to be used for painting the background
void setFillRule(Qt::FillRule fillRule);
/// Creates path shape from given QPainterPath
static KoPathShape *createShapeFromPainterPath(const QPainterPath &path);
- /// Returns the viewbox from the given xml element.
- static QRect loadOdfViewbox(const KoXmlElement &element);
-
void setMarker(KoMarker *marker, KoFlake::MarkerPosition pos);
KoMarker* marker(KoFlake::MarkerPosition pos) const;
bool hasMarkers() const;
bool autoFillMarkers() const;
void setAutoFillMarkers(bool value);
public:
struct KRITAFLAKE_EXPORT PointSelectionChangeListener : public ShapeChangeListener {
void notifyShapeChanged(ChangeType type, KoShape *shape) override;
virtual void recommendPointSelectionChange(KoPathShape *shape, const QList<KoPathPointIndex> &newSelection) = 0;
virtual void notifyPathPointsChanged(KoPathShape *shape) = 0;
};
void recommendPointSelectionChange(const QList<KoPathPointIndex> &newSelection);
protected:
void notifyPointsChanged();
protected:
/// constructor: to be used in cloneShape(), not in descendants!
/// \internal
/// XXX private?
KoPathShape(const KoPathShape &rhs);
protected:
- /// reimplemented
- QString saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const override;
- /// reimplemented
- void loadStyle(const KoXmlElement &element, KoShapeLoadingContext &context) override;
/**
* @brief Add an arc.
*
* Adds an arc starting at the current point. The arc will be converted to bezier curves.
* @param rx x radius of the ellipse
* @param ry y radius of the ellipse
* @param startAngle the angle where the arc will be started
* @param sweepAngle the length of the angle
* TODO add param to have angle of the ellipse
* @param offset to the first point in the arc
* @param curvePoints a array which take the curve points, pass a 'QPointF curvePoins[12]';
*
* @return number of points created by the curve
*/
int arcToCurve(qreal rx, qreal ry, qreal startAngle, qreal sweepAngle, const QPointF &offset, QPointF *curvePoints) const;
/**
* Get the resize matrix
*
* This makes sure that also if the newSize isNull that there will be a
* very small size of 0.000001 pixels
*/
QTransform resizeMatrix( const QSizeF &newSize ) const;
private:
/// close-merges specified subpath
void closeMergeSubpathPriv(KoSubpath *subpath);
/// closes specified subpath
void closeSubpathPriv(KoSubpath *subpath);
void updateLastPriv(KoPathPoint **lastPoint);
protected:
const KoSubpathList &subpaths() const;
/// XXX: refactor this using setter?
KoSubpathList &subpaths();
void map(const QTransform &matrix);
private:
class Private;
QScopedPointer<Private> d;
};
Q_DECLARE_METATYPE(KoPathShape*)
#endif /* KOPATHSHAPE_H */
diff --git a/libs/flake/KoPathShape_p.h b/libs/flake/KoPathShape_p.h
index 0105a935e0..828a87e4b1 100644
--- a/libs/flake/KoPathShape_p.h
+++ b/libs/flake/KoPathShape_p.h
@@ -1,92 +1,90 @@
/* This file is part of the KDE project
* Copyright (C) 2009 Thomas Zander <zander@kde.org>
*
* 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 KOPATHSHAPEPRIVATE_H
#define KOPATHSHAPEPRIVATE_H
#include "KoPathShape.h"
#include "KoMarker.h"
#include <QSharedData>
class KoPathShape::Private
{
public:
explicit Private();
explicit Private(const Private &rhs);
QRectF handleRect(const QPointF &p, qreal radius) const;
- /// Applies the viewbox transformation defined in the given element
- void applyViewboxTransformation(const KoXmlElement &element);
void map(const QTransform &matrix);
/**
* @brief Saves the node types
*
* This is inspired by inkscape and uses the same mechanism as they do.
* The only difference is that they use sodipodi:nodeTypes as element and
* we use calligra:nodeTyes as attribute.
* This attribute contains of a string which has the node type of each point
* in it. The following node types exist:
*
* c corner
* s smooth
* z symmetric
*
* The first point of a path is always of the type c.
* If the path is closed the type of the first point is saved in the last element
* E.g. you have a closed path with 2 points in it. The first one (start/end of path)
* is symmetric and the second one is smooth that will result in the nodeType="czs"
* So if there is a closed sub path the nodeTypes contain one more entry then there
* are points. That is due to the first and the last point of a closed sub path get
* merged into one when they are on the same position.
*
* @return The node types as string
*/
QString nodeTypes() const;
/**
* @brief Loads node types
*/
void loadNodeTypes(const KoXmlElement &element);
/**
* @brief Returns subpath at given index
* @param subpathIndex the index of the subpath to return
* @return subPath on success, or 0 when subpathIndex is out of bounds
*/
KoSubpath *subPath(int subpathIndex) const;
#ifndef NDEBUG
/// \internal
void paintDebug(QPainter &painter);
/**
* @brief print debug information about a the points of the path
*/
void debugPath() const;
#endif
Qt::FillRule fillRule;
KoSubpathList subpaths;
QMap<KoFlake::MarkerPosition, QExplicitlySharedDataPointer<KoMarker>> markersNew;
bool autoFillMarkers;
};
#endif
diff --git a/libs/flake/KoPatternBackground.cpp b/libs/flake/KoPatternBackground.cpp
index 3193f5062c..84c268a3d7 100644
--- a/libs/flake/KoPatternBackground.cpp
+++ b/libs/flake/KoPatternBackground.cpp
@@ -1,478 +1,309 @@
/* This file is part of the KDE project
* Copyright (C) 2008 Jan Hambrecht <jaham@gmx.net>
*
* 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 "KoPatternBackground.h"
#include "KoShapeSavingContext.h"
#include "KoImageData.h"
#include "KoImageCollection.h"
-#include <KoStyleStack.h>
-#include <KoGenStyle.h>
-#include <KoGenStyles.h>
#include <KoXmlNS.h>
-#include <KoOdfLoadingContext.h>
-#include <KoOdfGraphicStyles.h>
-#include <KoOdfStylesReader.h>
#include <KoUnit.h>
#include <KoXmlReader.h>
#include <FlakeDebug.h>
#include <QBrush>
#include <QPainter>
#include <QPainterPath>
#include <QPointer>
#include <QSharedData>
class KoPatternBackground::Private : public QSharedData
{
public:
Private()
: QSharedData()
, repeat(KoPatternBackground::Tiled)
, refPoint(KoPatternBackground::TopLeft)
, imageCollection(0)
, imageData(0)
{
}
~Private()
{
delete imageData;
}
QSizeF targetSize() const {
QSizeF size = imageData->imageSize();
if (targetImageSizePercent.width() > 0.0)
size.setWidth(0.01 * targetImageSizePercent.width() * size.width());
else if (targetImageSize.width() > 0.0)
size.setWidth(targetImageSize.width());
if (targetImageSizePercent.height() > 0.0)
size.setHeight(0.01 * targetImageSizePercent.height() * size.height());
else if (targetImageSize.height() > 0.0)
size.setHeight(targetImageSize.height());
return size;
}
QPointF offsetFromRect(const QRectF &fillRect, const QSizeF &imageSize) const {
QPointF offset;
switch (refPoint) {
case KoPatternBackground::TopLeft:
offset = fillRect.topLeft();
break;
case KoPatternBackground::Top:
offset.setX(fillRect.center().x() - 0.5 * imageSize.width());
offset.setY(fillRect.top());
break;
case KoPatternBackground::TopRight:
offset.setX(fillRect.right() - imageSize.width());
offset.setY(fillRect.top());
break;
case KoPatternBackground::Left:
offset.setX(fillRect.left());
offset.setY(fillRect.center().y() - 0.5 * imageSize.height());
break;
case KoPatternBackground::Center:
offset.setX(fillRect.center().x() - 0.5 * imageSize.width());
offset.setY(fillRect.center().y() - 0.5 * imageSize.height());
break;
case KoPatternBackground::Right:
offset.setX(fillRect.right() - imageSize.width());
offset.setY(fillRect.center().y() - 0.5 * imageSize.height());
break;
case KoPatternBackground::BottomLeft:
offset.setX(fillRect.left());
offset.setY(fillRect.bottom() - imageSize.height());
break;
case KoPatternBackground::Bottom:
offset.setX(fillRect.center().x() - 0.5 * imageSize.width());
offset.setY(fillRect.bottom() - imageSize.height());
break;
case KoPatternBackground::BottomRight:
offset.setX(fillRect.right() - imageSize.width());
offset.setY(fillRect.bottom() - imageSize.height());
break;
default:
break;
}
if (refPointOffsetPercent.x() > 0.0)
offset += QPointF(0.01 * refPointOffsetPercent.x() * imageSize.width(), 0);
if (refPointOffsetPercent.y() > 0.0)
offset += QPointF(0, 0.01 * refPointOffsetPercent.y() * imageSize.height());
return offset;
}
QTransform matrix;
KoPatternBackground::PatternRepeat repeat;
KoPatternBackground::ReferencePoint refPoint;
QSizeF targetImageSize;
QSizeF targetImageSizePercent;
QPointF refPointOffsetPercent;
QPointF tileRepeatOffsetPercent;
QPointer<KoImageCollection> imageCollection;
KoImageData * imageData;
};
// ----------------------------------------------------------------
KoPatternBackground::KoPatternBackground(KoImageCollection *imageCollection)
: KoShapeBackground()
, d(new Private)
{
d->imageCollection = imageCollection;
Q_ASSERT(d->imageCollection);
}
KoPatternBackground::~KoPatternBackground()
{
}
bool KoPatternBackground::compareTo(const KoShapeBackground *other) const
{
Q_UNUSED(other);
return false;
}
void KoPatternBackground::setTransform(const QTransform &matrix)
{
d->matrix = matrix;
}
QTransform KoPatternBackground::transform() const
{
return d->matrix;
}
void KoPatternBackground::setPattern(const QImage &pattern)
{
delete d->imageData;
if (d->imageCollection) {
d->imageData = d->imageCollection->createImageData(pattern);
}
}
void KoPatternBackground::setPattern(KoImageData *imageData)
{
delete d->imageData;
d->imageData = imageData;
}
QImage KoPatternBackground::pattern() const
{
if (d->imageData)
return d->imageData->image();
return QImage();
}
void KoPatternBackground::setRepeat(PatternRepeat repeat)
{
d->repeat = repeat;
}
KoPatternBackground::PatternRepeat KoPatternBackground::repeat() const
{
return d->repeat;
}
KoPatternBackground::ReferencePoint KoPatternBackground::referencePoint() const
{
return d->refPoint;
}
void KoPatternBackground::setReferencePoint(ReferencePoint referencePoint)
{
d->refPoint = referencePoint;
}
QPointF KoPatternBackground::referencePointOffset() const
{
return d->refPointOffsetPercent;
}
void KoPatternBackground::setReferencePointOffset(const QPointF &offset)
{
qreal ox = qMax(qreal(0.0), qMin(qreal(100.0), offset.x()));
qreal oy = qMax(qreal(0.0), qMin(qreal(100.0), offset.y()));
d->refPointOffsetPercent = QPointF(ox, oy);
}
QPointF KoPatternBackground::tileRepeatOffset() const
{
return d->tileRepeatOffsetPercent;
}
void KoPatternBackground::setTileRepeatOffset(const QPointF &offset)
{
d->tileRepeatOffsetPercent = offset;
}
QSizeF KoPatternBackground::patternDisplaySize() const
{
return d->targetSize();
}
void KoPatternBackground::setPatternDisplaySize(const QSizeF &size)
{
d->targetImageSizePercent = QSizeF();
d->targetImageSize = size;
}
QSizeF KoPatternBackground::patternOriginalSize() const
{
return d->imageData->imageSize();
}
void KoPatternBackground::paint(QPainter &painter, KoShapePaintingContext &/*context*/, const QPainterPath &fillPath) const
{
if (! d->imageData)
return;
painter.save();
if (d->repeat == Tiled) {
// calculate scaling of pixmap
QSizeF targetSize = d->targetSize();
QSizeF imageSize = d->imageData->imageSize();
qreal scaleX = targetSize.width() / imageSize.width();
qreal scaleY = targetSize.height() / imageSize.height();
QRectF targetRect = fillPath.boundingRect();
// undo scaling on target rectangle
targetRect.setWidth(targetRect.width() / scaleX);
targetRect.setHeight(targetRect.height() / scaleY);
// determine pattern offset
QPointF offset = d->offsetFromRect(targetRect, imageSize);
// create matrix for pixmap scaling
QTransform matrix;
matrix.scale(scaleX, scaleY);
painter.setClipPath(fillPath);
painter.setWorldTransform(matrix, true);
painter.drawTiledPixmap(targetRect, d->imageData->pixmap(imageSize.toSize()), -offset);
} else if (d->repeat == Original) {
QRectF sourceRect(QPointF(0, 0), d->imageData->imageSize());
QRectF targetRect(QPoint(0, 0), d->targetSize());
targetRect.moveCenter(fillPath.boundingRect().center());
painter.setClipPath(fillPath);
painter.drawPixmap(targetRect, d->imageData->pixmap(sourceRect.size().toSize()), sourceRect);
} else if (d->repeat == Stretched) {
painter.setClipPath(fillPath);
// undo conversion of the scaling so that we can use a nicely scaled image of the correct size
qWarning() << "WARNING: stretched KoPatternBackground painting code is abandoned. The result might be not correct";
const QRectF targetRect = fillPath.boundingRect();
painter.drawPixmap(targetRect.topLeft(), d->imageData->pixmap(targetRect.size().toSize()));
}
painter.restore();
}
-void KoPatternBackground::fillStyle(KoGenStyle &style, KoShapeSavingContext &context)
-{
- if (! d->imageData)
- return;
-
- switch (d->repeat) {
- case Original:
- style.addProperty("style:repeat", "no-repeat");
- break;
- case Tiled:
- style.addProperty("style:repeat", "repeat");
- break;
- case Stretched:
- style.addProperty("style:repeat", "stretch");
- break;
- }
-
- if (d->repeat == Tiled) {
- QString refPointId = "top-left";
- switch (d->refPoint) {
- case TopLeft: refPointId = "top-left"; break;
- case Top: refPointId = "top"; break;
- case TopRight: refPointId = "top-right"; break;
- case Left: refPointId = "left"; break;
- case Center: refPointId = "center"; break;
- case Right: refPointId = "right"; break;
- case BottomLeft: refPointId = "bottom-left"; break;
- case Bottom: refPointId = "bottom"; break;
- case BottomRight: refPointId = "bottom-right"; break;
- }
- style.addProperty("draw:fill-image-ref-point", refPointId);
- if (d->refPointOffsetPercent.x() > 0.0)
- style.addProperty("draw:fill-image-ref-point-x", QString("%1%").arg(d->refPointOffsetPercent.x()));
- if (d->refPointOffsetPercent.y() > 0.0)
- style.addProperty("draw:fill-image-ref-point-y", QString("%1%").arg(d->refPointOffsetPercent.y()));
- }
-
- if (d->repeat != Stretched) {
- QSizeF targetSize = d->targetSize();
- QSizeF imageSize = d->imageData->imageSize();
- if (targetSize.height() != imageSize.height())
- style.addPropertyPt("draw:fill-image-height", targetSize.height());
- if (targetSize.width() != imageSize.width())
- style.addPropertyPt("draw:fill-image-width", targetSize.width());
- }
-
- KoGenStyle patternStyle(KoGenStyle::FillImageStyle /*no family name*/);
- patternStyle.addAttribute("xlink:show", "embed");
- patternStyle.addAttribute("xlink:actuate", "onLoad");
- patternStyle.addAttribute("xlink:type", "simple");
- patternStyle.addAttribute("xlink:href", context.imageHref(d->imageData));
-
- QString patternStyleName = context.mainStyles().insert(patternStyle, "picture");
- style.addProperty("draw:fill", "bitmap");
- style.addProperty("draw:fill-image-name", patternStyleName);
-
- if (d->imageCollection) {
- context.addDataCenter(d->imageCollection);
- }
-}
-
-bool KoPatternBackground::loadStyle(KoOdfLoadingContext &context, const QSizeF &)
-{
- KoStyleStack &styleStack = context.styleStack();
- if (! styleStack.hasProperty(KoXmlNS::draw, "fill"))
- return false;
-
- QString fillStyle = styleStack.property(KoXmlNS::draw, "fill");
- if (fillStyle != "bitmap")
- return false;
-
- QString styleName = styleStack.property(KoXmlNS::draw, "fill-image-name");
-
- KoXmlElement* e = context.stylesReader().drawStyles("fill-image")[styleName];
- if (! e)
- return false;
-
- const QString href = e->attributeNS(KoXmlNS::xlink, "href", QString());
- if (href.isEmpty())
- return false;
-
- delete d->imageData;
- d->imageData = 0;
- if (d->imageCollection) {
- d->imageData = d->imageCollection->createImageData(href, context.store());
- }
- if (! d->imageData) {
- return false;
- }
-
- // read the pattern repeat style
- QString style = styleStack.property(KoXmlNS::style, "repeat");
- if (style == "stretch")
- d->repeat = Stretched;
- else if (style == "no-repeat")
- d->repeat = Original;
- else
- d->repeat = Tiled;
-
- if (style != "stretch") {
- // optional attributes which can override original image size
- if (styleStack.hasProperty(KoXmlNS::draw, "fill-image-height")) {
- QString height = styleStack.property(KoXmlNS::draw, "fill-image-height");
- if (height.endsWith('%'))
- d->targetImageSizePercent.setHeight(height.remove('%').toDouble());
- else
- d->targetImageSize.setHeight(KoUnit::parseValue(height));
- }
- if (styleStack.hasProperty(KoXmlNS::draw, "fill-image-width")) {
- QString width = styleStack.property(KoXmlNS::draw, "fill-image-width");
- if (width.endsWith('%'))
- d->targetImageSizePercent.setWidth(width.remove('%').toDouble());
- else
- d->targetImageSize.setWidth(KoUnit::parseValue(width));
- }
- }
-
- if (style == "repeat") {
- if (styleStack.hasProperty(KoXmlNS::draw, "fill-image-ref-point")) {
- // align pattern to the given size
- QString align = styleStack.property(KoXmlNS::draw, "fill-image-ref-point");
- if (align == "top-left")
- d->refPoint = TopLeft;
- else if (align == "top")
- d->refPoint = Top;
- else if (align == "top-right")
- d->refPoint = TopRight;
- else if (align == "left")
- d->refPoint = Left;
- else if (align == "center")
- d->refPoint = Center;
- else if (align == "right")
- d->refPoint = Right;
- else if (align == "bottom-left")
- d->refPoint = BottomLeft;
- else if (align == "bottom")
- d->refPoint = Bottom;
- else if (align == "bottom-right")
- d->refPoint = BottomRight;
- }
- if (styleStack.hasProperty(KoXmlNS::draw, "fill-image-ref-point-x")) {
- QString pointX = styleStack.property(KoXmlNS::draw, "fill-image-ref-point-x");
- d->refPointOffsetPercent.setX(pointX.remove('%').toDouble());
- }
- if (styleStack.hasProperty(KoXmlNS::draw, "fill-image-ref-point-y")) {
- QString pointY = styleStack.property(KoXmlNS::draw, "fill-image-ref-point-y");
- d->refPointOffsetPercent.setY(pointY.remove('%').toDouble());
- }
- if (styleStack.hasProperty(KoXmlNS::draw, "tile-repeat-offset")) {
- QString repeatOffset = styleStack.property(KoXmlNS::draw, "tile-repeat-offset");
- QStringList tokens = repeatOffset.split('%');
- if (tokens.count() == 2) {
- QString direction = tokens[1].simplified();
- if (direction == "horizontal")
- d->tileRepeatOffsetPercent.setX(tokens[0].toDouble());
- else if (direction == "vertical")
- d->tileRepeatOffsetPercent.setY(tokens[0].toDouble());
- }
- }
- }
-
- return true;
-}
QRectF KoPatternBackground::patternRectFromFillSize(const QSizeF &size)
{
QRectF rect;
switch (d->repeat) {
case Tiled:
rect.setTopLeft(d->offsetFromRect(QRectF(QPointF(), size), d->targetSize()));
rect.setSize(d->targetSize());
break;
case Original:
rect.setLeft(0.5 * (size.width() - d->targetSize().width()));
rect.setTop(0.5 * (size.height() - d->targetSize().height()));
rect.setSize(d->targetSize());
break;
case Stretched:
rect.setTopLeft(QPointF(0.0, 0.0));
rect.setSize(size);
break;
}
return rect;
}
diff --git a/libs/flake/KoPatternBackground.h b/libs/flake/KoPatternBackground.h
index 5500f51d59..9ef7138cd9 100644
--- a/libs/flake/KoPatternBackground.h
+++ b/libs/flake/KoPatternBackground.h
@@ -1,130 +1,125 @@
/* This file is part of the KDE project
* Copyright (C) 2008 Jan Hambrecht <jaham@gmx.net>
*
* 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 KOPATTERNBACKGROUND_H
#define KOPATTERNBACKGROUND_H
#include "KoShapeBackground.h"
#include "kritaflake_export.h"
#include <QSharedDataPointer>
class KoImageCollection;
-class KoOdfLoadingContext;
class KoPatternBackgroundPrivate;
class KoImageData;
class QTransform;
class QImage;
class QPointF;
class QRectF;
/// A pattern shape background
class KRITAFLAKE_EXPORT KoPatternBackground : public KoShapeBackground
{
public:
/// Pattern rendering style
enum PatternRepeat {
Original,
Tiled,
Stretched
};
/// Pattern reference point
enum ReferencePoint {
TopLeft,
Top,
TopRight,
Left,
Center,
Right,
BottomLeft,
Bottom,
BottomRight
};
/// Constructs a new pattern background utilizing the given image collection
explicit KoPatternBackground(KoImageCollection *collection);
~KoPatternBackground() override;
bool compareTo(const KoShapeBackground *other) const override;
/// Sets the transform matrix
void setTransform(const QTransform &matrix);
/// Returns the transform matrix
QTransform transform() const;
/// Sets a new pattern
void setPattern(const QImage &pattern);
/// Sets a new pattern. imageData memory is deleted inside this class
void setPattern(KoImageData *imageData);
/// Returns the pattern
QImage pattern() const;
/// Sets the pattern repeatgfl
void setRepeat(PatternRepeat repeat);
/// Returns the pattern repeat
PatternRepeat repeat() const;
/// Returns the pattern reference point identifier
ReferencePoint referencePoint() const;
/// Sets the pattern reference point
void setReferencePoint(ReferencePoint referencePoint);
/// Returns reference point offset in percent of the pattern display size
QPointF referencePointOffset() const;
/// Sets the reference point offset in percent of the pattern display size
void setReferencePointOffset(const QPointF &offset);
/// Returns tile repeat offset in percent of the pattern display size
QPointF tileRepeatOffset() const;
/// Sets the tile repeat offset in percent of the pattern display size
void setTileRepeatOffset(const QPointF &offset);
/// Returns the pattern display size
QSizeF patternDisplaySize() const;
/// Sets pattern display size
void setPatternDisplaySize(const QSizeF &size);
/// Returns the original image size
QSizeF patternOriginalSize() const;
/// reimplemented from KoShapeBackground
void paint(QPainter &painter, KoShapePaintingContext &context, const QPainterPath &fillPath) const override;
- /// reimplemented from KoShapeBackground
- void fillStyle(KoGenStyle &style, KoShapeSavingContext &context) override;
- /// reimplemented from KoShapeBackground
- bool loadStyle(KoOdfLoadingContext &context, const QSizeF &shapeSize) override;
/// Returns the bounding rect of the pattern image based on the given fill size
QRectF patternRectFromFillSize(const QSizeF &size);
private:
class Private;
QSharedDataPointer<Private> d;
};
#endif // KOPATTERNBACKGROUND_H
diff --git a/libs/flake/KoSelection.cpp b/libs/flake/KoSelection.cpp
index 09cde55b91..46a66ceb8d 100644
--- a/libs/flake/KoSelection.cpp
+++ b/libs/flake/KoSelection.cpp
@@ -1,264 +1,255 @@
/* This file is part of the KDE project
Copyright (C) 2006 Boudewijn Rempt <boud@valdyas.org>
Copyright (C) 2006 Thorsten Zachmann <zachmann@kde.org>
Copyright (C) 2006 Jan Hambrecht <jaham@gmx.net>
Copyright (C) 2006-2007,2009 Thomas Zander <zander@kde.org>
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 "KoSelection.h"
#include "KoSelection_p.h"
#include "KoShapeContainer.h"
#include "KoShapeGroup.h"
#include "KoPointerEvent.h"
#include "KoShapePaintingContext.h"
#include "kis_algebra_2d.h"
#include "krita_container_utils.h"
#include <QPainter>
#include "kis_debug.h"
KoSelection::KoSelection(QObject *parent)
: QObject(parent)
, KoShape()
, d(new Private)
{
connect(&d->selectionChangedCompressor, SIGNAL(timeout()), SIGNAL(selectionChanged()));
}
KoSelection::KoSelection(const KoSelection &rhs)
: QObject()
, KoShape(rhs)
, d(rhs.d)
{
}
KoSelection::~KoSelection()
{
}
void KoSelection::paint(QPainter &painter, KoShapePaintingContext &paintcontext) const
{
Q_UNUSED(painter);
Q_UNUSED(paintcontext);
}
void KoSelection::setSize(const QSizeF &size)
{
Q_UNUSED(size);
qWarning() << "WARNING: KoSelection::setSize() should never be used!";
}
QSizeF KoSelection::size() const
{
return outlineRect().size();
}
QRectF KoSelection::outlineRect() const
{
const QTransform invertedTransform = transformation().inverted();
QRectF boundingRect;
Q_FOREACH (KoShape *shape, selectedVisibleShapes()) {
// it is cheaper to invert-transform each outline, than
// to group 300+ rotated rectangles into a polygon
boundingRect |=
invertedTransform.map(
shape->absoluteTransformation().map(
QPolygonF(shape->outlineRect()))).boundingRect();
}
return boundingRect;
}
QRectF KoSelection::boundingRect() const
{
return KoShape::boundingRect(selectedVisibleShapes());
}
void KoSelection::select(KoShape *shape)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(shape != this);
KIS_SAFE_ASSERT_RECOVER_RETURN(shape);
if (!shape->isSelectable() || !shape->isVisible()) {
return;
}
// check recursively
if (isSelected(shape)) {
return;
}
// find the topmost parent to select
while (KoShapeGroup *parentGroup = dynamic_cast<KoShapeGroup*>(shape->parent())) {
shape = parentGroup;
}
d->selectedShapes << shape;
shape->addShapeChangeListener(this);
if (d->selectedShapes.size() == 1) {
setTransformation(shape->absoluteTransformation());
} else {
setTransformation(QTransform());
}
d->selectionChangedCompressor.start();
}
void KoSelection::deselect(KoShape *shape)
{
if (!d->selectedShapes.contains(shape))
return;
d->selectedShapes.removeAll(shape);
shape->removeShapeChangeListener(this);
if (d->selectedShapes.size() == 1) {
setTransformation(d->selectedShapes.first()->absoluteTransformation());
}
d->selectionChangedCompressor.start();
}
void KoSelection::deselectAll()
{
if (d->selectedShapes.isEmpty())
return;
Q_FOREACH (KoShape *shape, d->selectedShapes) {
shape->removeShapeChangeListener(this);
}
// reset the transformation matrix of the selection
setTransformation(QTransform());
d->selectedShapes.clear();
d->selectionChangedCompressor.start();
}
int KoSelection::count() const
{
return d->selectedShapes.size();
}
bool KoSelection::hitTest(const QPointF &position) const
{
Q_FOREACH (KoShape *shape, d->selectedShapes) {
if (shape->isVisible()) continue;
if (shape->hitTest(position)) return true;
}
return false;
}
const QList<KoShape*> KoSelection::selectedShapes() const
{
return d->selectedShapes;
}
const QList<KoShape *> KoSelection::selectedVisibleShapes() const
{
QList<KoShape*> shapes = selectedShapes();
KritaUtils::filterContainer (shapes, [](KoShape *shape) {
return shape->isVisible();
});
return shapes;
}
const QList<KoShape *> KoSelection::selectedEditableShapes() const
{
QList<KoShape*> shapes = selectedShapes();
KritaUtils::filterContainer (shapes, [](KoShape *shape) {
return shape->isShapeEditable();
});
return shapes;
}
const QList<KoShape *> KoSelection::selectedEditableShapesAndDelegates() const
{
QList<KoShape*> shapes;
Q_FOREACH (KoShape *shape, selectedShapes()) {
QSet<KoShape *> delegates = shape->toolDelegates();
if (delegates.isEmpty()) {
shapes.append(shape);
} else {
Q_FOREACH (KoShape *delegatedShape, delegates) {
shapes.append(delegatedShape);
}
}
}
return shapes;
}
bool KoSelection::isSelected(const KoShape *shape) const
{
if (shape == this)
return true;
const KoShape *tmpShape = shape;
while (tmpShape && std::find(d->selectedShapes.begin(), d->selectedShapes.end(), tmpShape) == d->selectedShapes.end()) {
tmpShape = tmpShape->parent();
}
return tmpShape;
}
KoShape *KoSelection::firstSelectedShape() const
{
return !d->selectedShapes.isEmpty() ? d->selectedShapes.first() : 0;
}
void KoSelection::setActiveLayer(KoShapeLayer *layer)
{
d->activeLayer = layer;
emit currentLayerChanged(layer);
}
KoShapeLayer* KoSelection::activeLayer() const
{
return d->activeLayer;
}
void KoSelection::notifyShapeChanged(KoShape::ChangeType type, KoShape *shape)
{
Q_UNUSED(shape);
if (type == KoShape::Deleted) {
deselect(shape);
// HACK ALERT: the caller will also remove the listener, which was
// removed in deselect(), so re-add it here
shape->addShapeChangeListener(this);
}
}
-
-void KoSelection::saveOdf(KoShapeSavingContext &) const
-{
-}
-
-bool KoSelection::loadOdf(const KoXmlElement &, KoShapeLoadingContext &)
-{
- return true;
-}
diff --git a/libs/flake/KoSelection.h b/libs/flake/KoSelection.h
index a372e331dd..4e80601dfe 100644
--- a/libs/flake/KoSelection.h
+++ b/libs/flake/KoSelection.h
@@ -1,169 +1,165 @@
/* This file is part of the KDE project
Copyright (C) 2006 Boudewijn Rempt <boud@valdyas.org>
Copyright (C) 2006 Thorsten Zachmann <zachmann@kde.org>
Copyright (C) 2007,2009 Thomas Zander <zander@kde.org>
Copyright (C) 2006,2007 Jan Hambrecht <jaham@gmx.net>
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 KOSELECTION_H
#define KOSELECTION_H
#include <QObject>
#include "KoShape.h"
#include "KoFlake.h"
#include "kritaflake_export.h"
class KoShapeLayer;
class KoSelectionPrivate;
/**
* A selection is a shape that contains a number of references
* to shapes. That means that a selection can be manipulated in
* the same way as a single shape.
*
* Note that a single shape can be selected in one view, and not in
* another, and that in a single view, more than one selection can be
* present. So selections should not be seen as singletons, or as
* something completely transient.
*
* A selection, however, should not be selectable. We need to think
* a little about the interaction here.
*/
class KRITAFLAKE_EXPORT KoSelection : public QObject, public KoShape, public KoShape::ShapeChangeListener
{
Q_OBJECT
public:
KoSelection(QObject *parent = 0);
~KoSelection() override;
void paint(QPainter &painter, KoShapePaintingContext &paintcontext) const override;
void setSize(const QSizeF &size) override;
QSizeF size() const override;
QRectF outlineRect() const override;
QRectF boundingRect() const override;
/**
* Adds a shape to the selection.
*
* If the shape is a KoShapeGroup all of its child shapes are automatically added
* to the selection.
* If the shape has no parent or is not a KoShapeGroup, only the given shape is
* added to the selection.
* If the given shape is a child of a KoShapeGroup and recursive selection is enabled
* the all parents and their child shapes up to the toplevel KoShapeGroup are added to
* the selection.
*
* @param shape the shape to add to the selection
*/
void select(KoShape *shape);
/**
* Removes a selected shape.
*
* If the shape is a KoShapeGroup all of its child shapes are automatically removed
* from the selection.
* If the shape has no parent or is not a KoShapeGroup, only the given shape is
* removed from the selection.
* If the given shape is a child of a KoShapeGroup and recursive selection is enabled
* the all parents and their child shape up to the toplevel KoShapeGroup are removed
* from the selection.
*
* @param shape the shape to remove from the selection
*/
void deselect(KoShape *shape);
/// clear the selections list
void deselectAll();
/**
* Return the list of selected shapes
* @return the list of selected shapes
*/
const QList<KoShape*> selectedShapes() const;
/**
* Same as selectedShapes() but only for shapes in visible state. Used by
* the algorithms that draw shapes on the image
*/
const QList<KoShape*> selectedVisibleShapes() const;
/**
* Same as selectedShapes() but only for editable shapes. Used by
* the algorithms that modify the image
*/
const QList<KoShape*> selectedEditableShapes() const;
/**
* Same as selectedEditableShapes() but also includes shapes delegates.
* Used for
*/
const QList<KoShape*> selectedEditableShapesAndDelegates() const;
/**
* Return the first selected shape, or 0 if there is nothing selected.
*/
KoShape *firstSelectedShape() const;
/// return true if the shape is selected
bool isSelected(const KoShape *shape) const;
/// return the selection count, i.e. the number of all selected shapes
int count() const;
bool hitTest(const QPointF &position) const override;
/**
* Sets the currently active layer.
* @param layer the new active layer
*/
void setActiveLayer(KoShapeLayer *layer);
/**
* Returns a currently active layer.
*
* @return the currently active layer, or zero if there is none
*/
KoShapeLayer *activeLayer() const;
void notifyShapeChanged(ChangeType type, KoShape *shape) override;
Q_SIGNALS:
/// emitted when the selection is changed
void selectionChanged();
/// emitted when the current layer is changed
void currentLayerChanged(const KoShapeLayer *layer);
-private:
- void saveOdf(KoShapeSavingContext &) const override;
- bool loadOdf(const KoXmlElement &, KoShapeLoadingContext &) override;
-
protected:
KoSelection(const KoSelection &rhs);
private:
class Private;
QSharedDataPointer<Private> d;
};
#endif
diff --git a/libs/flake/KoShape.cpp b/libs/flake/KoShape.cpp
index 8e8feb652a..91164813f9 100644
--- a/libs/flake/KoShape.cpp
+++ b/libs/flake/KoShape.cpp
@@ -1,2411 +1,1353 @@
/* This file is part of the KDE project
Copyright (C) 2006 C. Boemann Rasmussen <cbo@boemann.dk>
Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
Copyright (C) 2006-2010 Thorsten Zachmann <zachmann@kde.org>
Copyright (C) 2007-2009,2011 Jan Hambrecht <jaham@gmx.net>
CopyRight (C) 2010 Boudewijn Rempt <boud@valdyas.org>
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 <limits>
#include "KoShape.h"
#include "KoShape_p.h"
#include "KoShapeContainer.h"
#include "KoShapeLayer.h"
#include "KoShapeContainerModel.h"
#include "KoSelection.h"
#include "KoPointerEvent.h"
#include "KoInsets.h"
#include "KoShapeStrokeModel.h"
#include "KoShapeBackground.h"
#include "KoColorBackground.h"
#include "KoHatchBackground.h"
#include "KoGradientBackground.h"
#include "KoPatternBackground.h"
#include "KoShapeManager.h"
#include "KoShapeUserData.h"
#include "KoShapeApplicationData.h"
#include "KoShapeSavingContext.h"
#include "KoShapeLoadingContext.h"
#include "KoViewConverter.h"
#include "KoShapeStroke.h"
#include "KoShapeShadow.h"
#include "KoClipPath.h"
#include "KoPathShape.h"
-#include "KoOdfWorkaround.h"
#include "KoFilterEffectStack.h"
#include <KoSnapData.h>
-#include <KoElementReference.h>
#include <KoXmlReader.h>
#include <KoXmlWriter.h>
#include <KoXmlNS.h>
-#include <KoGenStyle.h>
-#include <KoGenStyles.h>
#include <KoUnit.h>
-#include <KoOdfStylesReader.h>
-#include <KoOdfGraphicStyles.h>
-#include <KoOdfLoadingContext.h>
-#include <KoStyleStack.h>
-#include <KoBorder.h>
#include <QPainter>
#include <QVariant>
#include <QPainterPath>
#include <QList>
#include <QMap>
#include <QByteArray>
#include <FlakeDebug.h>
#include "kis_assert.h"
-#include "KoOdfGradientBackground.h"
#include <KisHandlePainterHelper.h>
// KoShape::Private
KoShape::SharedData::SharedData()
: QSharedData()
, size(50, 50)
, shadow(0)
- , border(0)
, filterEffectStack(0)
, transparency(0.0)
, zIndex(0)
, runThrough(0)
, visible(true)
, printable(true)
, geometryProtected(false)
, keepAspect(false)
, selectable(true)
, protectContent(false)
, textRunAroundSide(KoShape::BiggestRunAroundSide)
, textRunAroundDistanceLeft(0.0)
, textRunAroundDistanceTop(0.0)
, textRunAroundDistanceRight(0.0)
, textRunAroundDistanceBottom(0.0)
, textRunAroundThreshold(0.0)
, textRunAroundContour(KoShape::ContourFull)
-{
- connectors[KoConnectionPoint::TopConnectionPoint] = KoConnectionPoint::defaultConnectionPoint(KoConnectionPoint::TopConnectionPoint);
- connectors[KoConnectionPoint::RightConnectionPoint] = KoConnectionPoint::defaultConnectionPoint(KoConnectionPoint::RightConnectionPoint);
- connectors[KoConnectionPoint::BottomConnectionPoint] = KoConnectionPoint::defaultConnectionPoint(KoConnectionPoint::BottomConnectionPoint);
- connectors[KoConnectionPoint::LeftConnectionPoint] = KoConnectionPoint::defaultConnectionPoint(KoConnectionPoint::LeftConnectionPoint);
- connectors[KoConnectionPoint::FirstCustomConnectionPoint] = KoConnectionPoint(QPointF(0.5, 0.5), KoConnectionPoint::AllDirections, KoConnectionPoint::AlignCenter);
-}
+{ }
KoShape::SharedData::SharedData(const SharedData &rhs)
: QSharedData()
, size(rhs.size)
, shapeId(rhs.shapeId)
, name(rhs.name)
, localMatrix(rhs.localMatrix)
- , connectors(rhs.connectors)
, userData(rhs.userData ? rhs.userData->clone() : 0)
, stroke(rhs.stroke)
, fill(rhs.fill)
, inheritBackground(rhs.inheritBackground)
, inheritStroke(rhs.inheritStroke)
, shadow(0) // WARNING: not implemented in Krita
- , border(0) // WARNING: not implemented in Krita
, clipPath(rhs.clipPath ? rhs.clipPath->clone() : 0)
, clipMask(rhs.clipMask ? rhs.clipMask->clone() : 0)
, additionalAttributes(rhs.additionalAttributes)
, additionalStyleAttributes(rhs.additionalStyleAttributes)
, filterEffectStack(0) // WARNING: not implemented in Krita
, transparency(rhs.transparency)
, hyperLink(rhs.hyperLink)
, zIndex(rhs.zIndex)
, runThrough(rhs.runThrough)
, visible(rhs.visible)
, printable(rhs.visible)
, geometryProtected(rhs.geometryProtected)
, keepAspect(rhs.keepAspect)
, selectable(rhs.selectable)
, protectContent(rhs.protectContent)
, textRunAroundSide(rhs.textRunAroundSide)
, textRunAroundDistanceLeft(rhs.textRunAroundDistanceLeft)
, textRunAroundDistanceTop(rhs.textRunAroundDistanceTop)
, textRunAroundDistanceRight(rhs.textRunAroundDistanceRight)
, textRunAroundDistanceBottom(rhs.textRunAroundDistanceBottom)
, textRunAroundThreshold(rhs.textRunAroundThreshold)
, textRunAroundContour(rhs.textRunAroundContour)
{
}
KoShape::SharedData::~SharedData()
{
if (shadow && !shadow->deref())
delete shadow;
if (filterEffectStack && !filterEffectStack->deref())
delete filterEffectStack;
}
void KoShape::shapeChangedPriv(KoShape::ChangeType type)
{
if (d->parent)
d->parent->model()->childChanged(this, type);
this->shapeChanged(type);
Q_FOREACH (KoShape * shape, d->dependees) {
shape->shapeChanged(type, this);
}
Q_FOREACH (KoShape::ShapeChangeListener *listener, d->listeners) {
listener->notifyShapeChangedImpl(type, this);
}
}
void KoShape::addShapeManager(KoShapeManager *manager)
{
d->shapeManagers.insert(manager);
}
void KoShape::removeShapeManager(KoShapeManager *manager)
{
d->shapeManagers.remove(manager);
}
-void KoShape::SharedData::convertFromShapeCoordinates(KoConnectionPoint &point, const QSizeF &shapeSize) const
-{
- switch(point.alignment) {
- case KoConnectionPoint::AlignNone:
- point.position = KoFlake::toRelative(point.position, shapeSize);
- point.position.rx() = qBound<qreal>(0.0, point.position.x(), 1.0);
- point.position.ry() = qBound<qreal>(0.0, point.position.y(), 1.0);
- break;
- case KoConnectionPoint::AlignRight:
- point.position.rx() -= shapeSize.width();
- break;
- case KoConnectionPoint::AlignLeft:
- point.position.ry() = 0.5*shapeSize.height();
- break;
- case KoConnectionPoint::AlignBottom:
- point.position.ry() -= shapeSize.height();
- break;
- case KoConnectionPoint::AlignTop:
- point.position.rx() = 0.5*shapeSize.width();
- break;
- case KoConnectionPoint::AlignTopLeft:
- // nothing to do here
- break;
- case KoConnectionPoint::AlignTopRight:
- point.position.rx() -= shapeSize.width();
- break;
- case KoConnectionPoint::AlignBottomLeft:
- point.position.ry() -= shapeSize.height();
- break;
- case KoConnectionPoint::AlignBottomRight:
- point.position.rx() -= shapeSize.width();
- point.position.ry() -= shapeSize.height();
- break;
- case KoConnectionPoint::AlignCenter:
- point.position.rx() -= 0.5 * shapeSize.width();
- point.position.ry() -= 0.5 * shapeSize.height();
- break;
- }
-}
-
-void KoShape::SharedData::convertToShapeCoordinates(KoConnectionPoint &point, const QSizeF &shapeSize) const
-{
- switch(point.alignment) {
- case KoConnectionPoint::AlignNone:
- point.position = KoFlake::toAbsolute(point.position, shapeSize);
- break;
- case KoConnectionPoint::AlignRight:
- point.position.rx() += shapeSize.width();
- break;
- case KoConnectionPoint::AlignLeft:
- point.position.ry() = 0.5*shapeSize.height();
- break;
- case KoConnectionPoint::AlignBottom:
- point.position.ry() += shapeSize.height();
- break;
- case KoConnectionPoint::AlignTop:
- point.position.rx() = 0.5*shapeSize.width();
- break;
- case KoConnectionPoint::AlignTopLeft:
- // nothing to do here
- break;
- case KoConnectionPoint::AlignTopRight:
- point.position.rx() += shapeSize.width();
- break;
- case KoConnectionPoint::AlignBottomLeft:
- point.position.ry() += shapeSize.height();
- break;
- case KoConnectionPoint::AlignBottomRight:
- point.position.rx() += shapeSize.width();
- point.position.ry() += shapeSize.height();
- break;
- case KoConnectionPoint::AlignCenter:
- point.position.rx() += 0.5 * shapeSize.width();
- point.position.ry() += 0.5 * shapeSize.height();
- break;
- }
-}
-
-// static
-QString KoShape::SharedData::getStyleProperty(const char *property, KoShapeLoadingContext &context)
-{
- KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
- QString value;
-
- if (styleStack.hasProperty(KoXmlNS::draw, property)) {
- value = styleStack.property(KoXmlNS::draw, property);
- }
-
- return value;
-}
-
-
-
// ======== KoShape
const qint16 KoShape::maxZIndex = std::numeric_limits<qint16>::max();
const qint16 KoShape::minZIndex = std::numeric_limits<qint16>::min();
KoShape::KoShape()
: d(new Private()),
s(new SharedData)
{
notifyChanged();
}
KoShape::KoShape(const KoShape &rhs)
: d(new Private()),
s(rhs.s)
{
}
KoShape::~KoShape()
{
shapeChangedPriv(Deleted);
d->listeners.clear();
/**
* The shape must have already been detached from all the parents and
* shape managers. Otherwise we migh accidentally request some RTTI
* information, which is not available anymore (we are in d-tor).
*
* TL;DR: fix the code that caused this destruction without unparenting
* instead of trying to remove these assert!
*/
KIS_SAFE_ASSERT_RECOVER (!d->parent) {
d->parent->removeShape(this);
}
KIS_SAFE_ASSERT_RECOVER (d->shapeManagers.isEmpty()) {
Q_FOREACH (KoShapeManager *manager, d->shapeManagers) {
manager->shapeInterface()->notifyShapeDestructed(this);
}
d->shapeManagers.clear();
}
}
KoShape *KoShape::cloneShape() const
{
KIS_SAFE_ASSERT_RECOVER_NOOP(0 && "not implemented!");
qWarning() << shapeId() << "cannot be cloned";
return 0;
}
void KoShape::paintStroke(QPainter &painter, KoShapePaintingContext &paintcontext) const
{
Q_UNUSED(paintcontext);
if (stroke()) {
stroke()->paint(this, painter);
}
}
void KoShape::scale(qreal sx, qreal sy)
{
QPointF pos = position();
QTransform scaleMatrix;
scaleMatrix.translate(pos.x(), pos.y());
scaleMatrix.scale(sx, sy);
scaleMatrix.translate(-pos.x(), -pos.y());
s->localMatrix = s->localMatrix * scaleMatrix;
notifyChanged();
shapeChangedPriv(ScaleChanged);
}
void KoShape::rotate(qreal angle)
{
QPointF center = s->localMatrix.map(QPointF(0.5 * size().width(), 0.5 * size().height()));
QTransform rotateMatrix;
rotateMatrix.translate(center.x(), center.y());
rotateMatrix.rotate(angle);
rotateMatrix.translate(-center.x(), -center.y());
s->localMatrix = s->localMatrix * rotateMatrix;
notifyChanged();
shapeChangedPriv(RotationChanged);
}
void KoShape::shear(qreal sx, qreal sy)
{
QPointF pos = position();
QTransform shearMatrix;
shearMatrix.translate(pos.x(), pos.y());
shearMatrix.shear(sx, sy);
shearMatrix.translate(-pos.x(), -pos.y());
s->localMatrix = s->localMatrix * shearMatrix;
notifyChanged();
shapeChangedPriv(ShearChanged);
}
void KoShape::setSize(const QSizeF &newSize)
{
QSizeF oldSize(size());
// always set size, as d->size and size() may vary
setSizeImpl(newSize);
if (oldSize == newSize)
return;
notifyChanged();
shapeChangedPriv(SizeChanged);
}
void KoShape::setSizeImpl(const QSizeF &size) const
{
s->size = size;
}
void KoShape::setPosition(const QPointF &newPosition)
{
QPointF currentPos = position();
if (newPosition == currentPos)
return;
QTransform translateMatrix;
translateMatrix.translate(newPosition.x() - currentPos.x(), newPosition.y() - currentPos.y());
s->localMatrix = s->localMatrix * translateMatrix;
notifyChanged();
shapeChangedPriv(PositionChanged);
}
bool KoShape::hitTest(const QPointF &position) const
{
if (d->parent && d->parent->isClipped(this) && !d->parent->hitTest(position))
return false;
QPointF point = absoluteTransformation().inverted().map(position);
QRectF bb = outlineRect();
if (s->stroke) {
KoInsets insets;
s->stroke->strokeInsets(this, insets);
bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
}
if (bb.contains(point))
return true;
// if there is no shadow we can as well just leave
if (! s->shadow)
return false;
// the shadow has an offset to the shape, so we simply
// check if the position minus the shadow offset hits the shape
point = absoluteTransformation().inverted().map(position - s->shadow->offset());
return bb.contains(point);
}
QRectF KoShape::boundingRect() const
{
QTransform transform = absoluteTransformation();
QRectF bb = outlineRect();
if (s->stroke) {
KoInsets insets;
s->stroke->strokeInsets(this, insets);
bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
}
bb = transform.mapRect(bb);
if (s->shadow) {
KoInsets insets;
s->shadow->insets(insets);
bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
}
if (s->filterEffectStack) {
QRectF clipRect = s->filterEffectStack->clipRectForBoundingRect(outlineRect());
bb |= transform.mapRect(clipRect);
}
return bb;
}
QRectF KoShape::boundingRect(const QList<KoShape *> &shapes)
{
QRectF boundingRect;
Q_FOREACH (KoShape *shape, shapes) {
boundingRect |= shape->boundingRect();
}
return boundingRect;
}
QRectF KoShape::absoluteOutlineRect() const
{
return absoluteTransformation().map(outline()).boundingRect();
}
QRectF KoShape::absoluteOutlineRect(const QList<KoShape *> &shapes)
{
QRectF absoluteOutlineRect;
Q_FOREACH (KoShape *shape, shapes) {
absoluteOutlineRect |= shape->absoluteOutlineRect();
}
return absoluteOutlineRect;
}
QTransform KoShape::absoluteTransformation() const
{
QTransform matrix;
// apply parents matrix to inherit any transformations done there.
KoShapeContainer * container = d->parent;
if (container) {
if (container->inheritsTransform(this)) {
matrix = container->absoluteTransformation();
} else {
QSizeF containerSize = container->size();
QPointF containerPos = container->absolutePosition() - QPointF(0.5 * containerSize.width(), 0.5 * containerSize.height());
matrix.translate(containerPos.x(), containerPos.y());
}
}
return s->localMatrix * matrix;
}
void KoShape::applyAbsoluteTransformation(const QTransform &matrix)
{
QTransform globalMatrix = absoluteTransformation();
// the transformation is relative to the global coordinate system
// but we want to change the local matrix, so convert the matrix
// to be relative to the local coordinate system
QTransform transformMatrix = globalMatrix * matrix * globalMatrix.inverted();
applyTransformation(transformMatrix);
}
void KoShape::applyTransformation(const QTransform &matrix)
{
s->localMatrix = matrix * s->localMatrix;
notifyChanged();
shapeChangedPriv(GenericMatrixChange);
}
void KoShape::setTransformation(const QTransform &matrix)
{
s->localMatrix = matrix;
notifyChanged();
shapeChangedPriv(GenericMatrixChange);
}
QTransform KoShape::transformation() const
{
return s->localMatrix;
}
KoShape::ChildZOrderPolicy KoShape::childZOrderPolicy()
{
return ChildZDefault;
}
bool KoShape::compareShapeZIndex(KoShape *s1, KoShape *s2)
{
/**
* WARNING: Our definition of zIndex is not yet compatible with SVG2's
* definition. In SVG stacking context of groups with the same
* zIndex are **merged**, while in Krita the contents of groups
* is never merged. One group will always below than the other.
* Therefore, when zIndex of two groups inside the same parent
* coincide, the resulting painting order in Krita is
* **UNDEFINED**.
*
* To avoid this trouble we use KoShapeReorderCommand::mergeInShape()
* inside KoShapeCreateCommand.
*/
/**
* The algorithm below doesn't correctly handle the case when the two pointers actually
* point to the same shape. So just check it in advance to guarantee strict weak ordering
* relation requirement
*/
if (s1 == s2) return false;
// First sort according to runThrough which is sort of a master level
KoShape *parentShapeS1 = s1->parent();
KoShape *parentShapeS2 = s2->parent();
int runThrough1 = s1->runThrough();
int runThrough2 = s2->runThrough();
while (parentShapeS1) {
if (parentShapeS1->childZOrderPolicy() == KoShape::ChildZParentChild) {
runThrough1 = parentShapeS1->runThrough();
} else {
runThrough1 = runThrough1 + parentShapeS1->runThrough();
}
parentShapeS1 = parentShapeS1->parent();
}
while (parentShapeS2) {
if (parentShapeS2->childZOrderPolicy() == KoShape::ChildZParentChild) {
runThrough2 = parentShapeS2->runThrough();
} else {
runThrough2 = runThrough2 + parentShapeS2->runThrough();
}
parentShapeS2 = parentShapeS2->parent();
}
if (runThrough1 > runThrough2) {
return false;
}
if (runThrough1 < runThrough2) {
return true;
}
// If on the same runThrough level then the zIndex is all that matters.
//
// We basically walk up through the parents until we find a common base parent
// To do that we need two loops where the inner loop walks up through the parents
// of s2 every time we step up one parent level on s1
//
// We don't update the index value until after we have seen that it's not a common base
// That way we ensure that two children of a common base are sorted according to their respective
// z value
bool foundCommonParent = false;
int index1 = s1->zIndex();
int index2 = s2->zIndex();
parentShapeS1 = s1;
parentShapeS2 = s2;
while (parentShapeS1 && !foundCommonParent) {
parentShapeS2 = s2;
index2 = parentShapeS2->zIndex();
while (parentShapeS2) {
if (parentShapeS2 == parentShapeS1) {
foundCommonParent = true;
break;
}
if (parentShapeS2->childZOrderPolicy() == KoShape::ChildZParentChild) {
index2 = parentShapeS2->zIndex();
}
parentShapeS2 = parentShapeS2->parent();
}
if (!foundCommonParent) {
if (parentShapeS1->childZOrderPolicy() == KoShape::ChildZParentChild) {
index1 = parentShapeS1->zIndex();
}
parentShapeS1 = parentShapeS1->parent();
}
}
// If the one shape is a parent/child of the other then sort so.
if (s1 == parentShapeS2) {
return true;
}
if (s2 == parentShapeS1) {
return false;
}
// If we went that far then the z-Index is used for sorting.
return index1 < index2;
}
void KoShape::setParent(KoShapeContainer *parent)
{
if (d->parent == parent) {
return;
}
KoShapeContainer *oldParent = d->parent;
d->parent = 0; // avoids recursive removing
if (oldParent) {
oldParent->shapeInterface()->removeShape(this);
}
KIS_SAFE_ASSERT_RECOVER_NOOP(parent != this);
if (parent && parent != this) {
d->parent = parent;
parent->shapeInterface()->addShape(this);
}
notifyChanged();
shapeChangedPriv(ParentChanged);
}
bool KoShape::inheritsTransformFromAny(const QList<KoShape *> ancestorsInQuestion) const
{
bool result = false;
KoShape *shape = const_cast<KoShape*>(this);
while (shape) {
KoShapeContainer *parent = shape->parent();
if (parent && !parent->inheritsTransform(shape)) {
break;
}
if (ancestorsInQuestion.contains(shape)) {
result = true;
break;
}
shape = parent;
}
return result;
}
bool KoShape::hasCommonParent(const KoShape *shape) const
{
const KoShape *thisShape = this;
while (thisShape) {
const KoShape *otherShape = shape;
while (otherShape) {
if (thisShape == otherShape) {
return true;
}
otherShape = otherShape->parent();
}
thisShape = thisShape->parent();
}
return false;
}
qint16 KoShape::zIndex() const
{
return s->zIndex;
}
void KoShape::update() const
{
if (!d->shapeManagers.empty()) {
- QRectF rect(boundingRect());
+ const QRectF rect(boundingRect());
Q_FOREACH (KoShapeManager * manager, d->shapeManagers) {
manager->update(rect, this, true);
}
}
}
void KoShape::updateAbsolute(const QRectF &rect) const
{
if (rect.isEmpty() && !rect.isNull()) {
return;
}
if (!d->shapeManagers.empty() && isVisible()) {
Q_FOREACH (KoShapeManager *manager, d->shapeManagers) {
manager->update(rect);
}
}
}
QPainterPath KoShape::outline() const
{
QPainterPath path;
path.addRect(outlineRect());
return path;
}
QRectF KoShape::outlineRect() const
{
const QSizeF s = size();
return QRectF(QPointF(0, 0), QSizeF(qMax(s.width(), qreal(0.0001)),
qMax(s.height(), qreal(0.0001))));
}
QPainterPath KoShape::shadowOutline() const
{
if (background()) {
return outline();
}
return QPainterPath();
}
QPointF KoShape::absolutePosition(KoFlake::AnchorPosition anchor) const
{
const QRectF rc = outlineRect();
QPointF point = rc.topLeft();
bool valid = false;
QPointF anchoredPoint = KoFlake::anchorToPoint(anchor, rc, &valid);
if (valid) {
point = anchoredPoint;
}
return absoluteTransformation().map(point);
}
void KoShape::setAbsolutePosition(const QPointF &newPosition, KoFlake::AnchorPosition anchor)
{
QPointF currentAbsPosition = absolutePosition(anchor);
QPointF translate = newPosition - currentAbsPosition;
QTransform translateMatrix;
translateMatrix.translate(translate.x(), translate.y());
applyAbsoluteTransformation(translateMatrix);
notifyChanged();
shapeChangedPriv(PositionChanged);
}
void KoShape::copySettings(const KoShape *shape)
{
s->size = shape->size();
- s->connectors.clear();
- Q_FOREACH (const KoConnectionPoint &point, shape->connectionPoints())
- addConnectionPoint(point);
s->zIndex = shape->zIndex();
s->visible = shape->isVisible(false);
// Ensure printable is true by default
if (!s->visible)
s->printable = true;
else
s->printable = shape->isPrintable();
s->geometryProtected = shape->isGeometryProtected();
s->protectContent = shape->isContentProtected();
s->selectable = shape->isSelectable();
s->keepAspect = shape->keepAspectRatio();
s->localMatrix = shape->s->localMatrix;
}
void KoShape::notifyChanged()
{
Q_FOREACH (KoShapeManager * manager, d->shapeManagers) {
manager->notifyShapeChanged(this);
}
}
void KoShape::setUserData(KoShapeUserData *userData)
{
s->userData.reset(userData);
}
KoShapeUserData *KoShape::userData() const
{
return s->userData.data();
}
bool KoShape::hasTransparency() const
{
QSharedPointer<KoShapeBackground> bg = background();
return !bg || bg->hasTransparency() || s->transparency > 0.0;
}
void KoShape::setTransparency(qreal transparency)
{
s->transparency = qBound<qreal>(0.0, transparency, 1.0);
shapeChangedPriv(TransparencyChanged);
notifyChanged();
}
qreal KoShape::transparency(bool recursive) const
{
if (!recursive || !parent()) {
return s->transparency;
} else {
const qreal parentOpacity = 1.0-parent()->transparency(recursive);
const qreal childOpacity = 1.0-s->transparency;
return 1.0-(parentOpacity*childOpacity);
}
}
KoInsets KoShape::strokeInsets() const
{
KoInsets answer;
if (s->stroke)
s->stroke->strokeInsets(this, answer);
return answer;
}
qreal KoShape::rotation() const
{
// try to extract the rotation angle out of the local matrix
// if it is a pure rotation matrix
// check if the matrix has shearing mixed in
if (fabs(fabs(s->localMatrix.m12()) - fabs(s->localMatrix.m21())) > 1e-10)
return std::numeric_limits<qreal>::quiet_NaN();
// check if the matrix has scaling mixed in
if (fabs(s->localMatrix.m11() - s->localMatrix.m22()) > 1e-10)
return std::numeric_limits<qreal>::quiet_NaN();
// calculate the angle from the matrix elements
qreal angle = atan2(-s->localMatrix.m21(), s->localMatrix.m11()) * 180.0 / M_PI;
if (angle < 0.0)
angle += 360.0;
return angle;
}
QSizeF KoShape::size() const
{
return s->size;
}
QPointF KoShape::position() const
{
QPointF center = outlineRect().center();
return s->localMatrix.map(center) - center;
}
-int KoShape::addConnectionPoint(const KoConnectionPoint &point)
-{
-
- // get next glue point id
- int nextConnectionPointId = KoConnectionPoint::FirstCustomConnectionPoint;
- if (s->connectors.size())
- nextConnectionPointId = qMax(nextConnectionPointId, (--s->connectors.end()).key()+1);
-
- KoConnectionPoint p = point;
- s->convertFromShapeCoordinates(p, size());
- s->connectors[nextConnectionPointId] = p;
-
- return nextConnectionPointId;
-}
-
-bool KoShape::setConnectionPoint(int connectionPointId, const KoConnectionPoint &point)
-{
- if (connectionPointId < 0)
- return false;
-
- const bool insertPoint = !hasConnectionPoint(connectionPointId);
-
- switch(connectionPointId) {
- case KoConnectionPoint::TopConnectionPoint:
- case KoConnectionPoint::RightConnectionPoint:
- case KoConnectionPoint::BottomConnectionPoint:
- case KoConnectionPoint::LeftConnectionPoint:
- {
- KoConnectionPoint::PointId id = static_cast<KoConnectionPoint::PointId>(connectionPointId);
- s->connectors[id] = KoConnectionPoint::defaultConnectionPoint(id);
- break;
- }
- default:
- {
- KoConnectionPoint p = point;
- s->convertFromShapeCoordinates(p, size());
- s->connectors[connectionPointId] = p;
- break;
- }
- }
-
- if(!insertPoint)
- shapeChangedPriv(ConnectionPointChanged);
-
- return true;
-}
-
-bool KoShape::hasConnectionPoint(int connectionPointId) const
-{
- return s->connectors.contains(connectionPointId);
-}
-
-KoConnectionPoint KoShape::connectionPoint(int connectionPointId) const
-{
- KoConnectionPoint p = s->connectors.value(connectionPointId, KoConnectionPoint());
- // convert glue point to shape coordinates
- s->convertToShapeCoordinates(p, size());
- return p;
-}
-
-KoConnectionPoints KoShape::connectionPoints() const
-{
- QSizeF size = this->size();
- KoConnectionPoints points = s->connectors;
- KoConnectionPoints::iterator point = points.begin();
- KoConnectionPoints::iterator lastPoint = points.end();
- // convert glue points to shape coordinates
- for(; point != lastPoint; ++point) {
- s->convertToShapeCoordinates(point.value(), size);
- }
-
- return points;
-}
-
-void KoShape::removeConnectionPoint(int connectionPointId)
-{
- s->connectors.remove(connectionPointId);
- shapeChangedPriv(ConnectionPointChanged);
-}
-
-void KoShape::clearConnectionPoints()
-{
- s->connectors.clear();
-}
-
KoShape::TextRunAroundSide KoShape::textRunAroundSide() const
{
return s->textRunAroundSide;
}
void KoShape::setTextRunAroundSide(TextRunAroundSide side, RunThroughLevel runThrought)
{
if (side == RunThrough) {
if (runThrought == Background) {
setRunThrough(-1);
} else {
setRunThrough(1);
}
} else {
setRunThrough(0);
}
if ( s->textRunAroundSide == side) {
return;
}
s->textRunAroundSide = side;
notifyChanged();
shapeChangedPriv(TextRunAroundChanged);
}
qreal KoShape::textRunAroundDistanceTop() const
{
return s->textRunAroundDistanceTop;
}
void KoShape::setTextRunAroundDistanceTop(qreal distance)
{
s->textRunAroundDistanceTop = distance;
}
qreal KoShape::textRunAroundDistanceLeft() const
{
return s->textRunAroundDistanceLeft;
}
void KoShape::setTextRunAroundDistanceLeft(qreal distance)
{
s->textRunAroundDistanceLeft = distance;
}
qreal KoShape::textRunAroundDistanceRight() const
{
return s->textRunAroundDistanceRight;
}
void KoShape::setTextRunAroundDistanceRight(qreal distance)
{
s->textRunAroundDistanceRight = distance;
}
qreal KoShape::textRunAroundDistanceBottom() const
{
return s->textRunAroundDistanceBottom;
}
void KoShape::setTextRunAroundDistanceBottom(qreal distance)
{
s->textRunAroundDistanceBottom = distance;
}
qreal KoShape::textRunAroundThreshold() const
{
return s->textRunAroundThreshold;
}
void KoShape::setTextRunAroundThreshold(qreal threshold)
{
s->textRunAroundThreshold = threshold;
}
KoShape::TextRunAroundContour KoShape::textRunAroundContour() const
{
return s->textRunAroundContour;
}
void KoShape::setTextRunAroundContour(KoShape::TextRunAroundContour contour)
{
s->textRunAroundContour = contour;
}
void KoShape::setBackground(QSharedPointer<KoShapeBackground> fill)
{
s->inheritBackground = false;
s->fill = fill;
shapeChangedPriv(BackgroundChanged);
notifyChanged();
}
QSharedPointer<KoShapeBackground> KoShape::background() const
{
QSharedPointer<KoShapeBackground> bg;
if (!s->inheritBackground) {
bg = s->fill;
} else if (parent()) {
bg = parent()->background();
}
return bg;
}
void KoShape::setInheritBackground(bool value)
{
s->inheritBackground = value;
if (s->inheritBackground) {
s->fill.clear();
}
}
bool KoShape::inheritBackground() const
{
return s->inheritBackground;
}
void KoShape::setZIndex(qint16 zIndex)
{
if (s->zIndex == zIndex)
return;
s->zIndex = zIndex;
notifyChanged();
}
int KoShape::runThrough() const
{
return s->runThrough;
}
void KoShape::setRunThrough(short int runThrough)
{
s->runThrough = runThrough;
}
void KoShape::setVisible(bool on)
{
int _on = (on ? 1 : 0);
if (s->visible == _on) return;
s->visible = _on;
}
bool KoShape::isVisible(bool recursive) const
{
if (!recursive)
return s->visible;
if (!s->visible)
return false;
KoShapeContainer * parentShape = parent();
if (parentShape) {
return parentShape->isVisible(true);
}
return true;
}
void KoShape::setPrintable(bool on)
{
s->printable = on;
}
bool KoShape::isPrintable() const
{
if (s->visible)
return s->printable;
else
return false;
}
void KoShape::setSelectable(bool selectable)
{
s->selectable = selectable;
}
bool KoShape::isSelectable() const
{
return s->selectable;
}
void KoShape::setGeometryProtected(bool on)
{
s->geometryProtected = on;
}
bool KoShape::isGeometryProtected() const
{
return s->geometryProtected;
}
void KoShape::setContentProtected(bool protect)
{
s->protectContent = protect;
}
bool KoShape::isContentProtected() const
{
return s->protectContent;
}
KoShapeContainer *KoShape::parent() const
{
return d->parent;
}
void KoShape::setKeepAspectRatio(bool keepAspect)
{
s->keepAspect = keepAspect;
shapeChangedPriv(KeepAspectRatioChange);
notifyChanged();
}
bool KoShape::keepAspectRatio() const
{
return s->keepAspect;
}
QString KoShape::shapeId() const
{
return s->shapeId;
}
void KoShape::setShapeId(const QString &id)
{
s->shapeId = id;
}
KoShapeStrokeModelSP KoShape::stroke() const
{
KoShapeStrokeModelSP stroke;
if (!s->inheritStroke) {
stroke = s->stroke;
} else if (parent()) {
stroke = parent()->stroke();
}
return stroke;
}
void KoShape::setStroke(KoShapeStrokeModelSP stroke)
{
s->inheritStroke = false;
s->stroke = stroke;
shapeChangedPriv(StrokeChanged);
notifyChanged();
}
void KoShape::setInheritStroke(bool value)
{
s->inheritStroke = value;
if (s->inheritStroke) {
s->stroke.clear();
}
}
bool KoShape::inheritStroke() const
{
return s->inheritStroke;
}
void KoShape::setShadow(KoShapeShadow *shadow)
{
if (s->shadow)
s->shadow->deref();
s->shadow = shadow;
if (s->shadow) {
s->shadow->ref();
// TODO update changed area
}
shapeChangedPriv(ShadowChanged);
notifyChanged();
}
KoShapeShadow *KoShape::shadow() const
{
return s->shadow;
}
-void KoShape::setBorder(KoBorder *border)
-{
- if (s->border) {
- // The shape owns the border.
- delete s->border;
- }
- s->border = border;
- shapeChangedPriv(BorderChanged);
- notifyChanged();
-}
-
-KoBorder *KoShape::border() const
-{
- return s->border;
-}
-
void KoShape::setClipPath(KoClipPath *clipPath)
{
s->clipPath.reset(clipPath);
shapeChangedPriv(ClipPathChanged);
notifyChanged();
}
KoClipPath * KoShape::clipPath() const
{
return s->clipPath.data();
}
void KoShape::setClipMask(KoClipMask *clipMask)
{
s->clipMask.reset(clipMask);
shapeChangedPriv(ClipMaskChanged);
notifyChanged();
}
KoClipMask* KoShape::clipMask() const
{
return s->clipMask.data();
}
QTransform KoShape::transform() const
{
return s->localMatrix;
}
QString KoShape::name() const
{
return s->name;
}
void KoShape::setName(const QString &name)
{
s->name = name;
}
void KoShape::waitUntilReady(bool asynchronous) const
{
Q_UNUSED(asynchronous);
}
bool KoShape::isShapeEditable(bool recursive) const
{
if (!s->visible || s->geometryProtected)
return false;
if (recursive && d->parent) {
return d->parent->isShapeEditable(true);
}
return true;
}
-// loading & saving methods
-QString KoShape::saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const
-{
- // and fill the style
- KoShapeStrokeModelSP sm = stroke();
- if (sm) {
- sm->fillStyle(style, context);
- }
- else {
- style.addProperty("draw:stroke", "none", KoGenStyle::GraphicType);
- }
- KoShapeShadow *shadow = this->shadow();
- if (shadow)
- shadow->fillStyle(style, context);
-
- QSharedPointer<KoShapeBackground> bg = background();
- if (bg) {
- bg->fillStyle(style, context);
- }
- else {
- style.addProperty("draw:fill", "none", KoGenStyle::GraphicType);
- }
-
- KoBorder *b = border();
- if (b) {
- b->saveOdf(style);
- }
-
- if (context.isSet(KoShapeSavingContext::AutoStyleInStyleXml)) {
- style.setAutoStyleInStylesDotXml(true);
- }
-
- QString value;
- if (isGeometryProtected()) {
- value = "position size";
- }
- if (isContentProtected()) {
- if (! value.isEmpty())
- value += ' ';
- value += "content";
- }
- if (!value.isEmpty()) {
- style.addProperty("style:protect", value, KoGenStyle::GraphicType);
- }
-
- QMap<QByteArray, QString>::const_iterator it(s->additionalStyleAttributes.constBegin());
- for (; it != s->additionalStyleAttributes.constEnd(); ++it) {
- style.addProperty(it.key(), it.value());
- }
-
- if (parent() && parent()->isClipped(this)) {
- /*
- * In Calligra clipping is done using a parent shape which can be rotated, sheared etc
- * and even non-square. So the ODF interoperability version we write here is really
- * just a very simple version of that...
- */
- qreal top = -position().y();
- qreal left = -position().x();
- qreal right = parent()->size().width() - size().width() - left;
- qreal bottom = parent()->size().height() - size().height() - top;
-
- style.addProperty("fo:clip", QString("rect(%1pt, %2pt, %3pt, %4pt)")
- .arg(top, 10, 'f').arg(right, 10, 'f')
- .arg(bottom, 10, 'f').arg(left, 10, 'f'), KoGenStyle::GraphicType);
-
- }
-
- QString wrap;
- switch (textRunAroundSide()) {
- case BiggestRunAroundSide:
- wrap = "biggest";
- break;
- case LeftRunAroundSide:
- wrap = "left";
- break;
- case RightRunAroundSide:
- wrap = "right";
- break;
- case EnoughRunAroundSide:
- wrap = "dynamic";
- break;
- case BothRunAroundSide:
- wrap = "parallel";
- break;
- case NoRunAround:
- wrap = "none";
- break;
- case RunThrough:
- wrap = "run-through";
- break;
- }
- style.addProperty("style:wrap", wrap, KoGenStyle::GraphicType);
- switch (textRunAroundContour()) {
- case ContourBox:
- style.addProperty("style:wrap-contour", "false", KoGenStyle::GraphicType);
- break;
- case ContourFull:
- style.addProperty("style:wrap-contour", "true", KoGenStyle::GraphicType);
- style.addProperty("style:wrap-contour-mode", "full", KoGenStyle::GraphicType);
- break;
- case ContourOutside:
- style.addProperty("style:wrap-contour", "true", KoGenStyle::GraphicType);
- style.addProperty("style:wrap-contour-mode", "outside", KoGenStyle::GraphicType);
- break;
- }
- style.addPropertyPt("style:wrap-dynamic-threshold", textRunAroundThreshold(), KoGenStyle::GraphicType);
- if ((textRunAroundDistanceLeft() == textRunAroundDistanceRight())
- && (textRunAroundDistanceTop() == textRunAroundDistanceBottom())
- && (textRunAroundDistanceLeft() == textRunAroundDistanceTop())) {
- style.addPropertyPt("fo:margin", textRunAroundDistanceLeft(), KoGenStyle::GraphicType);
- } else {
- style.addPropertyPt("fo:margin-left", textRunAroundDistanceLeft(), KoGenStyle::GraphicType);
- style.addPropertyPt("fo:margin-top", textRunAroundDistanceTop(), KoGenStyle::GraphicType);
- style.addPropertyPt("fo:margin-right", textRunAroundDistanceRight(), KoGenStyle::GraphicType);
- style.addPropertyPt("fo:margin-bottom", textRunAroundDistanceBottom(), KoGenStyle::GraphicType);
- }
-
- return context.mainStyles().insert(style, context.isSet(KoShapeSavingContext::PresentationShape) ? "pr" : "gr");
-}
-
-void KoShape::loadStyle(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
-
- KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
- styleStack.setTypeProperties("graphic");
-
- s->fill.clear();
- s->stroke.clear();
-
- if (s->shadow && !s->shadow->deref()) {
- delete s->shadow;
- s->shadow = 0;
- }
- setBackground(loadOdfFill(context));
- setStroke(loadOdfStroke(element, context));
- setShadow(s->loadOdfShadow(context));
- setBorder(s->loadOdfBorder(context));
-
- QString protect(styleStack.property(KoXmlNS::style, "protect"));
- setGeometryProtected(protect.contains("position") || protect.contains("size"));
- setContentProtected(protect.contains("content"));
-
- QString margin = styleStack.property(KoXmlNS::fo, "margin");
- if (!margin.isEmpty()) {
- setTextRunAroundDistanceLeft(KoUnit::parseValue(margin));
- setTextRunAroundDistanceTop(KoUnit::parseValue(margin));
- setTextRunAroundDistanceRight(KoUnit::parseValue(margin));
- setTextRunAroundDistanceBottom(KoUnit::parseValue(margin));
- }
- margin = styleStack.property(KoXmlNS::fo, "margin-left");
- if (!margin.isEmpty()) {
- setTextRunAroundDistanceLeft(KoUnit::parseValue(margin));
- }
-
- margin = styleStack.property(KoXmlNS::fo, "margin-top");
- if (!margin.isEmpty()) {
- setTextRunAroundDistanceTop(KoUnit::parseValue(margin));
- }
- margin = styleStack.property(KoXmlNS::fo, "margin-right");
- if (!margin.isEmpty()) {
- setTextRunAroundDistanceRight(KoUnit::parseValue(margin));
- }
- margin = styleStack.property(KoXmlNS::fo, "margin-bottom");
- if (!margin.isEmpty()) {
- setTextRunAroundDistanceBottom(KoUnit::parseValue(margin));
- }
-
- QString wrap;
- if (styleStack.hasProperty(KoXmlNS::style, "wrap")) {
- wrap = styleStack.property(KoXmlNS::style, "wrap");
- } else {
- // no value given in the file, but guess biggest
- wrap = "biggest";
- }
- if (wrap == "none") {
- setTextRunAroundSide(KoShape::NoRunAround);
- } else if (wrap == "run-through") {
- QString runTrought = styleStack.property(KoXmlNS::style, "run-through", "background");
- if (runTrought == "background") {
- setTextRunAroundSide(KoShape::RunThrough, KoShape::Background);
- } else {
- setTextRunAroundSide(KoShape::RunThrough, KoShape::Foreground);
- }
- } else {
- if (wrap == "biggest")
- setTextRunAroundSide(KoShape::BiggestRunAroundSide);
- else if (wrap == "left")
- setTextRunAroundSide(KoShape::LeftRunAroundSide);
- else if (wrap == "right")
- setTextRunAroundSide(KoShape::RightRunAroundSide);
- else if (wrap == "dynamic")
- setTextRunAroundSide(KoShape::EnoughRunAroundSide);
- else if (wrap == "parallel")
- setTextRunAroundSide(KoShape::BothRunAroundSide);
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "wrap-dynamic-threshold")) {
- QString wrapThreshold = styleStack.property(KoXmlNS::style, "wrap-dynamic-threshold");
- if (!wrapThreshold.isEmpty()) {
- setTextRunAroundThreshold(KoUnit::parseValue(wrapThreshold));
- }
- }
- if (styleStack.property(KoXmlNS::style, "wrap-contour", "false") == "true") {
- if (styleStack.property(KoXmlNS::style, "wrap-contour-mode", "full") == "full") {
- setTextRunAroundContour(KoShape::ContourFull);
- } else {
- setTextRunAroundContour(KoShape::ContourOutside);
- }
- } else {
- setTextRunAroundContour(KoShape::ContourBox);
- }
-}
-
-bool KoShape::loadOdfAttributes(const KoXmlElement &element, KoShapeLoadingContext &context, int attributes)
-{
- if (attributes & OdfPosition) {
- QPointF pos(position());
- if (element.hasAttributeNS(KoXmlNS::svg, "x"))
- pos.setX(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "x", QString())));
- if (element.hasAttributeNS(KoXmlNS::svg, "y"))
- pos.setY(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "y", QString())));
- setPosition(pos);
- }
-
- if (attributes & OdfSize) {
- QSizeF s(size());
- if (element.hasAttributeNS(KoXmlNS::svg, "width"))
- s.setWidth(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "width", QString())));
- if (element.hasAttributeNS(KoXmlNS::svg, "height"))
- s.setHeight(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "height", QString())));
- setSize(s);
- }
-
- if (attributes & OdfLayer) {
- if (element.hasAttributeNS(KoXmlNS::draw, "layer")) {
- KoShapeLayer *layer = context.layer(element.attributeNS(KoXmlNS::draw, "layer"));
- if (layer) {
- setParent(layer);
- }
- }
- }
-
- if (attributes & OdfId) {
- KoElementReference ref;
- ref.loadOdf(element);
- if (ref.isValid()) {
- context.addShapeId(this, ref.toString());
- }
- }
-
- if (attributes & OdfZIndex) {
- if (element.hasAttributeNS(KoXmlNS::draw, "z-index")) {
- setZIndex(element.attributeNS(KoXmlNS::draw, "z-index").toInt());
- } else {
- setZIndex(context.zIndex());
- }
- }
-
- if (attributes & OdfName) {
- if (element.hasAttributeNS(KoXmlNS::draw, "name")) {
- setName(element.attributeNS(KoXmlNS::draw, "name"));
- }
- }
-
- if (attributes & OdfStyle) {
- KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
- styleStack.save();
- if (element.hasAttributeNS(KoXmlNS::draw, "style-name")) {
- context.odfLoadingContext().fillStyleStack(element, KoXmlNS::draw, "style-name", "graphic");
- }
- if (element.hasAttributeNS(KoXmlNS::presentation, "style-name")) {
- context.odfLoadingContext().fillStyleStack(element, KoXmlNS::presentation, "style-name", "presentation");
- }
- loadStyle(element, context);
-
- styleStack.restore();
- }
-
- if (attributes & OdfTransformation) {
- QString transform = element.attributeNS(KoXmlNS::draw, "transform", QString());
- if (! transform.isEmpty())
- applyAbsoluteTransformation(parseOdfTransform(transform));
- }
-
- if (attributes & OdfAdditionalAttributes) {
- QSet<KoShapeLoadingContext::AdditionalAttributeData> additionalAttributeData = KoShapeLoadingContext::additionalAttributeData();
- Q_FOREACH (const KoShapeLoadingContext::AdditionalAttributeData &attributeData, additionalAttributeData) {
- if (element.hasAttributeNS(attributeData.ns, attributeData.tag)) {
- QString value = element.attributeNS(attributeData.ns, attributeData.tag);
- //debugFlake << "load additional attribute" << attributeData.tag << value;
- setAdditionalAttribute(attributeData.name, value);
- }
- }
- }
-
- if (attributes & OdfCommonChildElements) {
- // load glue points (connection points)
- loadOdfGluePoints(element, context);
- }
-
- return true;
-}
-
-QSharedPointer<KoShapeBackground> KoShape::loadOdfFill(KoShapeLoadingContext &context) const
-{
- QString fill = KoShape::SharedData::getStyleProperty("fill", context);
- QSharedPointer<KoShapeBackground> bg;
- if (fill == "solid") {
- bg = QSharedPointer<KoShapeBackground>(new KoColorBackground());
- }
- else if (fill == "hatch") {
- bg = QSharedPointer<KoShapeBackground>(new KoHatchBackground());
- }
- else if (fill == "gradient") {
- QString styleName = KoShape::SharedData::getStyleProperty("fill-gradient-name", context);
- KoXmlElement *e = context.odfLoadingContext().stylesReader().drawStyles("gradient")[styleName];
- QString style;
- if (e) {
- style = e->attributeNS(KoXmlNS::draw, "style", QString());
- }
- if ((style == "rectangular") || (style == "square")) {
- bg = QSharedPointer<KoShapeBackground>(new KoOdfGradientBackground());
- } else {
- QGradient *gradient = new QLinearGradient();
- gradient->setCoordinateMode(QGradient::ObjectBoundingMode);
- bg = QSharedPointer<KoShapeBackground>(new KoGradientBackground(gradient));
- }
- } else if (fill == "bitmap") {
- bg = QSharedPointer<KoShapeBackground>(new KoPatternBackground(context.imageCollection()));
-#ifndef NWORKAROUND_ODF_BUGS
- } else if (fill.isEmpty()) {
- bg = QSharedPointer<KoShapeBackground>(KoOdfWorkaround::fixBackgroundColor(this, context));
- return bg;
-#endif
- } else {
- return QSharedPointer<KoShapeBackground>(0);
- }
-
- if (!bg->loadStyle(context.odfLoadingContext(), size())) {
- return QSharedPointer<KoShapeBackground>(0);
- }
-
- return bg;
-}
-
-KoShapeStrokeModelSP KoShape::loadOdfStroke(const KoXmlElement &element, KoShapeLoadingContext &context) const
-{
- KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
- KoOdfStylesReader &stylesReader = context.odfLoadingContext().stylesReader();
-
- QString stroke = KoShape::SharedData::getStyleProperty("stroke", context);
- if (stroke == "solid" || stroke == "dash") {
- QPen pen = KoOdfGraphicStyles::loadOdfStrokeStyle(styleStack, stroke, stylesReader);
-
- QSharedPointer<KoShapeStroke> stroke(new KoShapeStroke());
-
- if (styleStack.hasProperty(KoXmlNS::calligra, "stroke-gradient")) {
- QString gradientName = styleStack.property(KoXmlNS::calligra, "stroke-gradient");
- QBrush brush = KoOdfGraphicStyles::loadOdfGradientStyleByName(stylesReader, gradientName, size());
- stroke->setLineBrush(brush);
- } else {
- stroke->setColor(pen.color());
- }
-
-#ifndef NWORKAROUND_ODF_BUGS
- KoOdfWorkaround::fixPenWidth(pen, context);
-#endif
- stroke->setLineWidth(pen.widthF());
- stroke->setJoinStyle(pen.joinStyle());
- stroke->setLineStyle(pen.style(), pen.dashPattern());
- stroke->setCapStyle(pen.capStyle());
-
- return stroke;
-#ifndef NWORKAROUND_ODF_BUGS
- } else if (stroke.isEmpty()) {
- QPen pen = KoOdfGraphicStyles::loadOdfStrokeStyle(styleStack, "solid", stylesReader);
- if (KoOdfWorkaround::fixMissingStroke(pen, element, context, this)) {
- QSharedPointer<KoShapeStroke> stroke(new KoShapeStroke());
-
-#ifndef NWORKAROUND_ODF_BUGS
- KoOdfWorkaround::fixPenWidth(pen, context);
-#endif
- stroke->setLineWidth(pen.widthF());
- stroke->setJoinStyle(pen.joinStyle());
- stroke->setLineStyle(pen.style(), pen.dashPattern());
- stroke->setCapStyle(pen.capStyle());
- stroke->setColor(pen.color());
-
- return stroke;
- }
-#endif
- }
-
- return KoShapeStrokeModelSP();
-}
-
-KoShapeShadow *KoShape::SharedData::loadOdfShadow(KoShapeLoadingContext &context) const
-{
- KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
- QString shadowStyle = KoShape::SharedData::getStyleProperty("shadow", context);
- if (shadowStyle == "visible" || shadowStyle == "hidden") {
- KoShapeShadow *shadow = new KoShapeShadow();
- QColor shadowColor(styleStack.property(KoXmlNS::draw, "shadow-color"));
- qreal offsetX = KoUnit::parseValue(styleStack.property(KoXmlNS::draw, "shadow-offset-x"));
- qreal offsetY = KoUnit::parseValue(styleStack.property(KoXmlNS::draw, "shadow-offset-y"));
- shadow->setOffset(QPointF(offsetX, offsetY));
- qreal blur = KoUnit::parseValue(styleStack.property(KoXmlNS::calligra, "shadow-blur-radius"));
- shadow->setBlur(blur);
-
- QString opacity = styleStack.property(KoXmlNS::draw, "shadow-opacity");
- if (! opacity.isEmpty() && opacity.right(1) == "%")
- shadowColor.setAlphaF(opacity.left(opacity.length() - 1).toFloat() / 100.0);
- shadow->setColor(shadowColor);
- shadow->setVisible(shadowStyle == "visible");
-
- return shadow;
- }
- return 0;
-}
-
-KoBorder *KoShape::SharedData::loadOdfBorder(KoShapeLoadingContext &context) const
-{
- KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
-
- KoBorder *border = new KoBorder();
- if (border->loadOdf(styleStack)) {
- return border;
- }
- delete border;
- return 0;
-}
-
-
-void KoShape::loadOdfGluePoints(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
-
- KoXmlElement child;
- bool hasCenterGluePoint = false;
- forEachElement(child, element) {
- if (child.namespaceURI() != KoXmlNS::draw)
- continue;
- if (child.localName() != "glue-point")
- continue;
-
- // NOTE: this uses draw:id, but apparently while ODF 1.2 has deprecated
- // all use of draw:id for xml:id, it didn't specify that here, so it
- // doesn't support xml:id (and so, maybe, shouldn't use KoElementReference.
- const QString id = child.attributeNS(KoXmlNS::draw, "id", QString());
- const int index = id.toInt();
- // connection point in center should be default but odf doesn't support,
- // in new shape, first custom point is in center, it's okay to replace that point
- // with point from xml now, we'll add it back later
- if(id.isEmpty() || index < KoConnectionPoint::FirstCustomConnectionPoint ||
- (index != KoConnectionPoint::FirstCustomConnectionPoint && s->connectors.contains(index))) {
- warnFlake << "glue-point with no or invalid id";
- continue;
- }
- QString xStr = child.attributeNS(KoXmlNS::svg, "x", QString()).simplified();
- QString yStr = child.attributeNS(KoXmlNS::svg, "y", QString()).simplified();
- if(xStr.isEmpty() || yStr.isEmpty()) {
- warnFlake << "glue-point with invald position";
- continue;
- }
-
- KoConnectionPoint connector;
-
- const QString align = child.attributeNS(KoXmlNS::draw, "align", QString());
- if (align.isEmpty()) {
-#ifndef NWORKAROUND_ODF_BUGS
- KoOdfWorkaround::fixGluePointPosition(xStr, context);
- KoOdfWorkaround::fixGluePointPosition(yStr, context);
-#endif
- if(!xStr.endsWith('%') || !yStr.endsWith('%')) {
- warnFlake << "glue-point with invald position";
- continue;
- }
- // x and y are relative to drawing object center
- connector.position.setX(xStr.remove('%').toDouble()/100.0);
- connector.position.setY(yStr.remove('%').toDouble()/100.0);
- // convert position to be relative to top-left corner
- connector.position += QPointF(0.5, 0.5);
- connector.position.rx() = qBound<qreal>(0.0, connector.position.x(), 1.0);
- connector.position.ry() = qBound<qreal>(0.0, connector.position.y(), 1.0);
- } else {
- // absolute distances to the edge specified by align
- connector.position.setX(KoUnit::parseValue(xStr));
- connector.position.setY(KoUnit::parseValue(yStr));
- if (align == "top-left") {
- connector.alignment = KoConnectionPoint::AlignTopLeft;
- } else if (align == "top") {
- connector.alignment = KoConnectionPoint::AlignTop;
- } else if (align == "top-right") {
- connector.alignment = KoConnectionPoint::AlignTopRight;
- } else if (align == "left") {
- connector.alignment = KoConnectionPoint::AlignLeft;
- } else if (align == "center") {
- connector.alignment = KoConnectionPoint::AlignCenter;
- } else if (align == "right") {
- connector.alignment = KoConnectionPoint::AlignRight;
- } else if (align == "bottom-left") {
- connector.alignment = KoConnectionPoint::AlignBottomLeft;
- } else if (align == "bottom") {
- connector.alignment = KoConnectionPoint::AlignBottom;
- } else if (align == "bottom-right") {
- connector.alignment = KoConnectionPoint::AlignBottomRight;
- }
- debugFlake << "using alignment" << align;
- }
- const QString escape = child.attributeNS(KoXmlNS::draw, "escape-direction", QString());
- if (!escape.isEmpty()) {
- if (escape == "horizontal") {
- connector.escapeDirection = KoConnectionPoint::HorizontalDirections;
- } else if (escape == "vertical") {
- connector.escapeDirection = KoConnectionPoint::VerticalDirections;
- } else if (escape == "left") {
- connector.escapeDirection = KoConnectionPoint::LeftDirection;
- } else if (escape == "right") {
- connector.escapeDirection = KoConnectionPoint::RightDirection;
- } else if (escape == "up") {
- connector.escapeDirection = KoConnectionPoint::UpDirection;
- } else if (escape == "down") {
- connector.escapeDirection = KoConnectionPoint::DownDirection;
- }
- debugFlake << "using escape direction" << escape;
- }
- s->connectors[index] = connector;
- debugFlake << "loaded glue-point" << index << "at position" << connector.position;
- if (s->connectors[index].position == QPointF(0.5, 0.5)) {
- hasCenterGluePoint = true;
- debugFlake << "center glue-point found at id " << index;
- }
- }
- if (!hasCenterGluePoint) {
- s->connectors[s->connectors.count()] = KoConnectionPoint(QPointF(0.5, 0.5),
- KoConnectionPoint::AllDirections, KoConnectionPoint::AlignCenter);
- }
- debugFlake << "shape has now" << s->connectors.count() << "glue-points";
-}
-
-void KoShape::loadOdfClipContour(const KoXmlElement &element, KoShapeLoadingContext &context, const QSizeF &scaleFactor)
-{
-
- KoXmlElement child;
- forEachElement(child, element) {
- if (child.namespaceURI() != KoXmlNS::draw)
- continue;
- if (child.localName() != "contour-polygon")
- continue;
-
- debugFlake << "shape loads contour-polygon";
- KoPathShape *ps = new KoPathShape();
- ps->loadContourOdf(child, context, scaleFactor);
- ps->setTransformation(transformation());
-
- KoClipPath *clipPath = new KoClipPath({ps}, KoFlake::UserSpaceOnUse);
- s->clipPath.reset(clipPath);
- }
-}
-
-QTransform KoShape::parseOdfTransform(const QString &transform)
-{
- QTransform matrix;
-
- // Split string for handling 1 transform statement at a time
- QStringList subtransforms = transform.split(')', QString::SkipEmptyParts);
- QStringList::ConstIterator it = subtransforms.constBegin();
- QStringList::ConstIterator end = subtransforms.constEnd();
- for (; it != end; ++it) {
- QStringList subtransform = (*it).split('(', QString::SkipEmptyParts);
-
- subtransform[0] = subtransform[0].trimmed().toLower();
- subtransform[1] = subtransform[1].simplified();
- QRegExp reg("[,( ]");
- QStringList params = subtransform[1].split(reg, QString::SkipEmptyParts);
-
- if (subtransform[0].startsWith(';') || subtransform[0].startsWith(','))
- subtransform[0] = subtransform[0].right(subtransform[0].length() - 1);
-
- QString cmd = subtransform[0].toLower();
-
- if (cmd == "rotate") {
- QTransform rotMatrix;
- if (params.count() == 3) {
- qreal x = KoUnit::parseValue(params[1]);
- qreal y = KoUnit::parseValue(params[2]);
-
- rotMatrix.translate(x, y);
- // oo2 rotates by radians
- rotMatrix.rotate(-params[0].toDouble()*180.0 / M_PI);
- rotMatrix.translate(-x, -y);
- } else {
- // oo2 rotates by radians
- rotMatrix.rotate(-params[0].toDouble()*180.0 / M_PI);
- }
- matrix = matrix * rotMatrix;
- } else if (cmd == "translate") {
- QTransform moveMatrix;
- if (params.count() == 2) {
- qreal x = KoUnit::parseValue(params[0]);
- qreal y = KoUnit::parseValue(params[1]);
- moveMatrix.translate(x, y);
- } else // Spec : if only one param given, assume 2nd param to be 0
- moveMatrix.translate(KoUnit::parseValue(params[0]) , 0);
- matrix = matrix * moveMatrix;
- } else if (cmd == "scale") {
- QTransform scaleMatrix;
- if (params.count() == 2)
- scaleMatrix.scale(params[0].toDouble(), params[1].toDouble());
- else // Spec : if only one param given, assume uniform scaling
- scaleMatrix.scale(params[0].toDouble(), params[0].toDouble());
- matrix = matrix * scaleMatrix;
- } else if (cmd == "skewx") {
- QPointF p = absolutePosition(KoFlake::TopLeft);
- QTransform shearMatrix;
- shearMatrix.translate(p.x(), p.y());
- shearMatrix.shear(tan(-params[0].toDouble()), 0.0F);
- shearMatrix.translate(-p.x(), -p.y());
- matrix = matrix * shearMatrix;
- } else if (cmd == "skewy") {
- QPointF p = absolutePosition(KoFlake::TopLeft);
- QTransform shearMatrix;
- shearMatrix.translate(p.x(), p.y());
- shearMatrix.shear(0.0F, tan(-params[0].toDouble()));
- shearMatrix.translate(-p.x(), -p.y());
- matrix = matrix * shearMatrix;
- } else if (cmd == "matrix") {
- QTransform m;
- if (params.count() >= 6) {
- m.setMatrix(params[0].toDouble(), params[1].toDouble(), 0,
- params[2].toDouble(), params[3].toDouble(), 0,
- KoUnit::parseValue(params[4]), KoUnit::parseValue(params[5]), 1);
- }
- matrix = matrix * m;
- }
- }
-
- return matrix;
-}
-
-void KoShape::saveOdfAttributes(KoShapeSavingContext &context, int attributes) const
-{
- if (attributes & OdfStyle) {
- KoGenStyle style;
- // all items that should be written to 'draw:frame' and any other 'draw:' object that inherits this shape
- if (context.isSet(KoShapeSavingContext::PresentationShape)) {
- style = KoGenStyle(KoGenStyle::PresentationAutoStyle, "presentation");
- context.xmlWriter().addAttribute("presentation:style-name", saveStyle(style, context));
- } else {
- style = KoGenStyle(KoGenStyle::GraphicAutoStyle, "graphic");
- context.xmlWriter().addAttribute("draw:style-name", saveStyle(style, context));
- }
- }
-
- if (attributes & OdfId) {
- if (context.isSet(KoShapeSavingContext::DrawId)) {
- KoElementReference ref = context.xmlid(this, "shape", KoElementReference::Counter);
- ref.saveOdf(&context.xmlWriter(), KoElementReference::DrawId);
- }
- }
-
- if (attributes & OdfName) {
- if (! name().isEmpty())
- context.xmlWriter().addAttribute("draw:name", name());
- }
-
- if (attributes & OdfLayer) {
- KoShape *parent = d->parent;
- while (parent) {
- if (dynamic_cast<KoShapeLayer*>(parent)) {
- context.xmlWriter().addAttribute("draw:layer", parent->name());
- break;
- }
- parent = parent->parent();
- }
- }
-
- if (attributes & OdfZIndex && context.isSet(KoShapeSavingContext::ZIndex)) {
- context.xmlWriter().addAttribute("draw:z-index", zIndex());
- }
-
- if (attributes & OdfSize) {
- QSizeF s(size());
- if (parent() && parent()->isClipped(this)) { // being clipped shrinks our visible size
- // clipping in ODF is done using a combination of visual size and content cliprect.
- // A picture of 10cm x 10cm displayed in a box of 2cm x 4cm will be scaled (out
- // of proportion in this case). If we then add a fo:clip like;
- // fo:clip="rect(2cm, 3cm, 4cm, 5cm)" (top, right, bottom, left)
- // our original 10x10 is clipped to 2cm x 4cm and *then* fitted in that box.
-
- // TODO do this properly by subtracting rects
- s = parent()->size();
- }
- context.xmlWriter().addAttribute("svg:width", s.width());
- context.xmlWriter().addAttribute("svg:height", s.height());
- }
-
- // The position is implicitly stored in the transformation matrix
- // if the transformation is saved as well
- if ((attributes & OdfPosition) && !(attributes & OdfTransformation)) {
- const QPointF p(position() * context.shapeOffset(this));
- context.xmlWriter().addAttribute("svg:x", p.x());
- context.xmlWriter().addAttribute("svg:y", p.y());
- }
-
- if (attributes & OdfTransformation) {
- QTransform matrix = absoluteTransformation() * context.shapeOffset(this);
- if (! matrix.isIdentity()) {
- if (qAbs(matrix.m11() - 1) < 1E-5 // 1
- && qAbs(matrix.m12()) < 1E-5 // 0
- && qAbs(matrix.m21()) < 1E-5 // 0
- && qAbs(matrix.m22() - 1) < 1E-5) { // 1
- context.xmlWriter().addAttribute("svg:x", matrix.dx());
- context.xmlWriter().addAttribute("svg:y", matrix.dy());
- } else {
- QString m = QString("matrix(%1 %2 %3 %4 %5pt %6pt)")
- .arg(matrix.m11(), 0, 'f', 11)
- .arg(matrix.m12(), 0, 'f', 11)
- .arg(matrix.m21(), 0, 'f', 11)
- .arg(matrix.m22(), 0, 'f', 11)
- .arg(matrix.dx(), 0, 'f', 11)
- .arg(matrix.dy(), 0, 'f', 11);
- context.xmlWriter().addAttribute("draw:transform", m);
- }
- }
- }
-
- if (attributes & OdfViewbox) {
- const QSizeF s(size());
- QString viewBox = QString("0 0 %1 %2").arg(qRound(s.width())).arg(qRound(s.height()));
- context.xmlWriter().addAttribute("svg:viewBox", viewBox);
- }
-
- if (attributes & OdfAdditionalAttributes) {
- QMap<QString, QString>::const_iterator it(s->additionalAttributes.constBegin());
- for (; it != s->additionalAttributes.constEnd(); ++it) {
- context.xmlWriter().addAttribute(it.key().toUtf8(), it.value());
- }
- }
-}
-
-void KoShape::saveOdfCommonChildElements(KoShapeSavingContext &context) const
-{
- // save glue points see ODF 9.2.19 Glue Points
- if(s->connectors.count()) {
- KoConnectionPoints::const_iterator cp = s->connectors.constBegin();
- KoConnectionPoints::const_iterator lastCp = s->connectors.constEnd();
- for(; cp != lastCp; ++cp) {
- // do not save default glue points
- if(cp.key() < 4)
- continue;
- context.xmlWriter().startElement("draw:glue-point");
- context.xmlWriter().addAttribute("draw:id", QString("%1").arg(cp.key()));
- if (cp.value().alignment == KoConnectionPoint::AlignNone) {
- // convert to percent from center
- const qreal x = cp.value().position.x() * 100.0 - 50.0;
- const qreal y = cp.value().position.y() * 100.0 - 50.0;
- context.xmlWriter().addAttribute("svg:x", QString("%1%").arg(x));
- context.xmlWriter().addAttribute("svg:y", QString("%1%").arg(y));
- } else {
- context.xmlWriter().addAttribute("svg:x", cp.value().position.x());
- context.xmlWriter().addAttribute("svg:y", cp.value().position.y());
- }
- QString escapeDirection;
- switch(cp.value().escapeDirection) {
- case KoConnectionPoint::HorizontalDirections:
- escapeDirection = "horizontal";
- break;
- case KoConnectionPoint::VerticalDirections:
- escapeDirection = "vertical";
- break;
- case KoConnectionPoint::LeftDirection:
- escapeDirection = "left";
- break;
- case KoConnectionPoint::RightDirection:
- escapeDirection = "right";
- break;
- case KoConnectionPoint::UpDirection:
- escapeDirection = "up";
- break;
- case KoConnectionPoint::DownDirection:
- escapeDirection = "down";
- break;
- default:
- break;
- }
- if(!escapeDirection.isEmpty()) {
- context.xmlWriter().addAttribute("draw:escape-direction", escapeDirection);
- }
- QString alignment;
- switch(cp.value().alignment) {
- case KoConnectionPoint::AlignTopLeft:
- alignment = "top-left";
- break;
- case KoConnectionPoint::AlignTop:
- alignment = "top";
- break;
- case KoConnectionPoint::AlignTopRight:
- alignment = "top-right";
- break;
- case KoConnectionPoint::AlignLeft:
- alignment = "left";
- break;
- case KoConnectionPoint::AlignCenter:
- alignment = "center";
- break;
- case KoConnectionPoint::AlignRight:
- alignment = "right";
- break;
- case KoConnectionPoint::AlignBottomLeft:
- alignment = "bottom-left";
- break;
- case KoConnectionPoint::AlignBottom:
- alignment = "bottom";
- break;
- case KoConnectionPoint::AlignBottomRight:
- alignment = "bottom-right";
- break;
- default:
- break;
- }
- if(!alignment.isEmpty()) {
- context.xmlWriter().addAttribute("draw:align", alignment);
- }
- context.xmlWriter().endElement();
- }
- }
-}
-
-void KoShape::saveOdfClipContour(KoShapeSavingContext &context, const QSizeF &originalSize) const
-{
-
- debugFlake << "shape saves contour-polygon";
- if (s->clipPath && !s->clipPath->clipPathShapes().isEmpty()) {
- // This will loose data as odf can only save one set of contour whereas
- // svg loading and at least karbon editing can produce more than one
- // TODO, FIXME see if we can save more than one clipshape to odf
- s->clipPath->clipPathShapes().first()->saveContourOdf(context, originalSize);
- }
-}
-
-// end loading & saving methods
-
KisHandlePainterHelper KoShape::createHandlePainterHelperView(QPainter *painter, KoShape *shape, const KoViewConverter &converter, qreal handleRadius)
{
const QTransform originalPainterTransform = painter->transform();
painter->setTransform(shape->absoluteTransformation() *
converter.documentToView() *
painter->transform());
// move c-tor
return KisHandlePainterHelper(painter, originalPainterTransform, handleRadius);
}
KisHandlePainterHelper KoShape::createHandlePainterHelperDocument(QPainter *painter, KoShape *shape, qreal handleRadius)
{
const QTransform originalPainterTransform = painter->transform();
painter->setTransform(shape->absoluteTransformation() *
painter->transform());
// move c-tor
return KisHandlePainterHelper(painter, originalPainterTransform, handleRadius);
}
QPointF KoShape::shapeToDocument(const QPointF &point) const
{
return absoluteTransformation().map(point);
}
QRectF KoShape::shapeToDocument(const QRectF &rect) const
{
return absoluteTransformation().mapRect(rect);
}
QPointF KoShape::documentToShape(const QPointF &point) const
{
return absoluteTransformation().inverted().map(point);
}
QRectF KoShape::documentToShape(const QRectF &rect) const
{
return absoluteTransformation().inverted().mapRect(rect);
}
bool KoShape::addDependee(KoShape *shape)
{
if (! shape)
return false;
// refuse to establish a circular dependency
if (shape->hasDependee(this))
return false;
if (! d->dependees.contains(shape))
d->dependees.append(shape);
return true;
}
void KoShape::removeDependee(KoShape *shape)
{
int index = d->dependees.indexOf(shape);
if (index >= 0)
d->dependees.removeAt(index);
}
bool KoShape::hasDependee(KoShape *shape) const
{
return d->dependees.contains(shape);
}
QList<KoShape*> KoShape::dependees() const
{
return d->dependees;
}
void KoShape::shapeChanged(ChangeType type, KoShape *shape)
{
Q_UNUSED(type);
Q_UNUSED(shape);
}
KoSnapData KoShape::snapData() const
{
return KoSnapData();
}
void KoShape::setAdditionalAttribute(const QString &name, const QString &value)
{
s->additionalAttributes.insert(name, value);
}
void KoShape::removeAdditionalAttribute(const QString &name)
{
s->additionalAttributes.remove(name);
}
bool KoShape::hasAdditionalAttribute(const QString &name) const
{
return s->additionalAttributes.contains(name);
}
QString KoShape::additionalAttribute(const QString &name) const
{
return s->additionalAttributes.value(name);
}
void KoShape::setAdditionalStyleAttribute(const char *name, const QString &value)
{
s->additionalStyleAttributes.insert(name, value);
}
void KoShape::removeAdditionalStyleAttribute(const char *name)
{
s->additionalStyleAttributes.remove(name);
}
KoFilterEffectStack *KoShape::filterEffectStack() const
{
return s->filterEffectStack;
}
void KoShape::setFilterEffectStack(KoFilterEffectStack *filterEffectStack)
{
if (s->filterEffectStack)
s->filterEffectStack->deref();
s->filterEffectStack = filterEffectStack;
if (s->filterEffectStack) {
s->filterEffectStack->ref();
}
notifyChanged();
}
QSet<KoShape*> KoShape::toolDelegates() const
{
return d->toolDelegates;
}
void KoShape::setToolDelegates(const QSet<KoShape*> &delegates)
{
d->toolDelegates = delegates;
}
QString KoShape::hyperLink () const
{
return s->hyperLink;
}
void KoShape::setHyperLink(const QString &hyperLink)
{
s->hyperLink = hyperLink;
}
KoShape::ShapeChangeListener::~ShapeChangeListener()
{
Q_FOREACH(KoShape *shape, m_registeredShapes) {
shape->removeShapeChangeListener(this);
}
}
void KoShape::ShapeChangeListener::registerShape(KoShape *shape)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(!m_registeredShapes.contains(shape));
m_registeredShapes.append(shape);
}
void KoShape::ShapeChangeListener::unregisterShape(KoShape *shape)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(m_registeredShapes.contains(shape));
m_registeredShapes.removeAll(shape);
}
void KoShape::ShapeChangeListener::notifyShapeChangedImpl(KoShape::ChangeType type, KoShape *shape)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(m_registeredShapes.contains(shape));
notifyShapeChanged(type, shape);
if (type == KoShape::Deleted) {
unregisterShape(shape);
}
}
void KoShape::addShapeChangeListener(KoShape::ShapeChangeListener *listener)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(!d->listeners.contains(listener));
listener->registerShape(this);
d->listeners.append(listener);
}
void KoShape::removeShapeChangeListener(KoShape::ShapeChangeListener *listener)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(d->listeners.contains(listener));
d->listeners.removeAll(listener);
listener->unregisterShape(this);
}
QList<KoShape::ShapeChangeListener *> KoShape::listeners() const
{
return d->listeners;
}
QList<KoShape *> KoShape::linearizeSubtree(const QList<KoShape *> &shapes)
{
QList<KoShape *> result;
Q_FOREACH (KoShape *shape, shapes) {
result << shape;
KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape);
if (container) {
result << linearizeSubtree(container->shapes());
}
}
return result;
}
QList<KoShape *> KoShape::linearizeSubtreeSorted(const QList<KoShape *> &shapes)
{
QList<KoShape*> sortedShapes = shapes;
std::sort(sortedShapes.begin(), sortedShapes.end(), KoShape::compareShapeZIndex);
QList<KoShape *> result;
Q_FOREACH (KoShape *shape, sortedShapes) {
result << shape;
KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape);
if (container) {
result << linearizeSubtreeSorted(container->shapes());
}
}
return result;
}
diff --git a/libs/flake/KoShape.h b/libs/flake/KoShape.h
index e9fefbdf97..15297ba86d 100644
--- a/libs/flake/KoShape.h
+++ b/libs/flake/KoShape.h
@@ -1,1273 +1,1101 @@
/* This file is part of the KDE project
Copyright (C) 2006-2008 Thorsten Zachmann <zachmann@kde.org>
Copyright (C) 2006, 2008 C. Boemann <cbo@boemann.dk>
Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
Copyright (C) 2007-2009,2011 Jan Hambrecht <jaham@gmx.net>
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 KOSHAPE_H
#define KOSHAPE_H
#include "KoFlake.h"
#include "KoFlakeTypes.h"
-#include "KoConnectionPoint.h"
#include <QSharedPointer>
#include <QSet>
+#include <QMap>
#include <QMetaType>
#include <QSharedDataPointer>
#include <KoXmlReaderForward.h>
#include "kritaflake_export.h"
class QPainter;
class QRectF;
class QPainterPath;
class QTransform;
class KoShapeContainer;
class KoShapeStrokeModel;
class KoShapeUserData;
class KoViewConverter;
class KoShapeApplicationData;
class KoShapeSavingContext;
class KoShapeLoadingContext;
-class KoGenStyle;
class KoShapeShadow;
class KoFilterEffectStack;
class KoSnapData;
class KoClipPath;
class KoClipMask;
class KoShapePaintingContext;
class KoShapeAnchor;
-class KoBorder;
struct KoInsets;
class KoShapeBackground;
class KisHandlePainterHelper;
class KoShapeManager;
/**
* Base class for all flake shapes. Shapes extend this class
* to allow themselves to be manipulated. This class just represents
* a graphical shape in the document and can be manipulated by some default
* tools in this library.
*
* Due to the limited responsibility of this class, the extending object
* can have any data backend and is responsible for painting itself.
*
* We strongly suggest that any extending class will use a Model View
* Controller (MVC) design where the View part is all in this class, as well
* as the one that inherits from this one. This allows the data that rests
* in the model to be reused in different parts of the document. For example
* by having two flake objects that show that same data. Or each showing a section of it.
*
* The KoShape data is completely in postscript-points (pt) (see KoUnit
* for conversion methods to and from points).
* This image will explain the real-world use of the shape and its options.
* <img src="../flake_shape_coords.png" align=center><br>
* The Rotation center can be returned with absolutePosition()
*
* <p>Flake objects can be created in three ways:
* <ul>
* <li>a simple new KoDerivedFlake(),
* <li>through an associated tool,
* <li>through a factory
* </ul>
*
* <h1>Shape interaction notifications</h1>
* We had several notification methods that allow your shape to be notified of changes in other
* shapes positions or rotation etc.
* <ol><li>The most general is KoShape::shapeChanged().<br>
* a virtual method that you can use to check various changed to your shape made by tools or otherwise.</li>
* <li>for shape hierarchies the parent may receive a notification when a child was modified.
* This is done though KoShapeContainerModel::childChanged()</li>
* <li>any shape that is at a similar position as another shape there is collision detection.
* You can register your shape to be sensitive to any changes like moving or whatever to
* <b>other</b> shapes that intersect yours.
* Such changes will then be notified to your shape using the method from (1) You should call
* KoShape::setCollisionDetection(bool) to enable this.
* </ol>
*/
class KRITAFLAKE_EXPORT KoShape
{
public:
/// Used by shapeChanged() to select which change was made
enum ChangeType {
PositionChanged, ///< used after a setPosition()
RotationChanged, ///< used after a setRotation()
ScaleChanged, ///< used after a scale()
ShearChanged, ///< used after a shear()
SizeChanged, ///< used after a setSize()
GenericMatrixChange, ///< used after the matrix was changed without knowing which property explicitly changed
KeepAspectRatioChange, ///< used after setKeepAspectRatio()
ParentChanged, ///< used after a setParent()
Deleted, ///< the shape was deleted
StrokeChanged, ///< the shapes stroke has changed
BackgroundChanged, ///< the shapes background has changed
ShadowChanged, ///< the shapes shadow has changed
BorderChanged, ///< the shapes border has changed
ParameterChanged, ///< the shapes parameter has changed (KoParameterShape only)
ContentChanged, ///< the content of the shape changed e.g. a new image inside a pixmap/text change inside a textshape
TextRunAroundChanged, ///< used after a setTextRunAroundSide()
ChildChanged, ///< a child of a container was changed/removed. This is propagated to all parents
ConnectionPointChanged, ///< a connection point has changed
ClipPathChanged, ///< the shapes clip path has changed
ClipMaskChanged, ///< the shapes clip path has changed
TransparencyChanged ///< the shapetransparency value has changed
};
/// The behavior text should do when intersecting this shape.
enum TextRunAroundSide {
BiggestRunAroundSide, ///< Run other text around the side that has the most space
LeftRunAroundSide, ///< Run other text around the left side of the frame
RightRunAroundSide, ///< Run other text around the right side of the frame
EnoughRunAroundSide, ///< Run other text dynamically around both sides of the shape, provided there is sufficient space left
BothRunAroundSide, ///< Run other text around both sides of the shape
NoRunAround, ///< The text will be completely avoiding the frame by keeping the horizontal space that this frame occupies blank.
RunThrough ///< The text will completely ignore the frame and layout as if it was not there
};
/// The behavior text should do when intersecting this shape.
enum TextRunAroundContour {
ContourBox, /// Run other text around a bounding rect of the outline
ContourFull, ///< Run other text around also on the inside
ContourOutside ///< Run other text around only on the outside
};
/**
* TODO
*/
enum RunThroughLevel {
Background,
Foreground
};
/**
* @brief Constructor
*/
KoShape();
/**
* @brief Destructor
*/
virtual ~KoShape();
/**
- * @brief creates a deep copy of the shape or shape's subtree
+ * @brief creates a deep copy of the shape or shape's subtree
* @return a cloned shape
*/
virtual KoShape* cloneShape() const;
/**
* @brief Paint the shape fill
* The class extending this one is responsible for painting itself. \p painter is expected
* to be preconfigured to work in "document" pixels.
*
* @param painter used for painting the shape
* @param paintcontext the painting context.
*/
virtual void paint(QPainter &painter, KoShapePaintingContext &paintcontext) const = 0;
/**
* @brief paintStroke paints the shape's stroked outline
* @param painter used for painting the shape
* @see applyConversion()
* @param paintcontext the painting context.
*/
virtual void paintStroke(QPainter &painter, KoShapePaintingContext &paintcontext) const;
- /**
- * Load a shape from odf
- *
- * @param context the KoShapeLoadingContext used for loading
- * @param element element which represents the shape in odf
- *
- * @return false if loading failed
- */
- virtual bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) = 0;
-
- /**
- * @brief store the shape data as ODF XML.
- * This is the method that will be called when saving a shape as a described in
- * OpenDocument 9.2 Drawing Shapes.
- * @see saveOdfAttributes
- */
- virtual void saveOdf(KoShapeSavingContext &context) const = 0;
-
- /**
- * This method can be used while saving the shape as ODF to add the data
- * stored on this shape to the current element.
- *
- * @param context the context for the current save.
- * @param attributes a number of OdfAttribute items to state which attributes to save.
- * @see saveOdf
- */
- void saveOdfAttributes(KoShapeSavingContext &context, int attributes) const;
-
- /**
- * This method can be used while saving the shape as Odf to add common child elements
- *
- * The office:event-listeners and draw:glue-point are saved.
- * @param context the context for the current save.
- */
- void saveOdfCommonChildElements(KoShapeSavingContext &context) const;
-
- /**
- * This method can be used to save contour data from the clipPath()
- *
- * The draw:contour-polygon or draw:contour-path elements are saved.
- * @param context the context for the current save.
- * @param originalSize the original size of the unscaled image.
- */
- void saveOdfClipContour(KoShapeSavingContext &context, const QSizeF &originalSize) const;
-
/**
* @brief Scale the shape using the zero-point which is the top-left corner.
* @see position()
*
* @param sx scale in x direction
* @param sy scale in y direction
*/
void scale(qreal sx, qreal sy);
/**
* @brief Rotate the shape (relative)
*
* The shape will be rotated from the current rotation using the center of the shape using the size()
*
* @param angle change the angle of rotation increasing it with 'angle' degrees
*/
void rotate(qreal angle);
/**
* Return the current rotation in degrees.
* It returns NaN if the shape has a shearing or scaling transformation applied.
*/
qreal rotation() const;
/**
* @brief Shear the shape
* The shape will be sheared using the zero-point which is the top-left corner.
* @see position()
*
* @param sx shear in x direction
* @param sy shear in y direction
*/
void shear(qreal sx, qreal sy);
/**
* @brief Resize the shape
*
* @param size the new size of the shape. This is different from scaling as
* scaling is a so called secondary operation which is comparable to zooming in
* instead of changing the size of the basic shape.
* Easiest example of this difference is that using this method will not distort the
* size of pattern-fills and strokes.
*/
virtual void setSize(const QSizeF &size);
/**
* @brief Get the size of the shape in pt.
*
* The size is in shape coordinates.
*
* @return the size of the shape as set by setSize()
*/
virtual QSizeF size() const;
/**
* @brief Set the position of the shape in pt
*
* @param position the new position of the shape
*/
virtual void setPosition(const QPointF &position);
/**
* @brief Get the position of the shape in pt
*
* @return the position of the shape
*/
QPointF position() const;
/**
* @brief Check if the shape is hit on position
* @param position the position where the user clicked.
* @return true when it hits.
*/
virtual bool hitTest(const QPointF &position) const;
/**
* @brief Get the bounding box of the shape
*
* This includes the line width and the shadow of the shape
*
* @return the bounding box of the shape
*/
virtual QRectF boundingRect() const;
/**
* Get the united bounding box of a group of shapes. This is a utility
* function used in many places in Krita.
*/
static QRectF boundingRect(const QList<KoShape*> &shapes);
/**
* @return the bounding rect of the outline of the shape measured
* in absolute coordinate system. Please note that in contrast to
* boundingRect() this rect doesn't include the stroke and other
* insets.
*/
QRectF absoluteOutlineRect() const;
/**
* Same as a member function, but applies to a list of shapes and returns a
* united rect.
*/
static QRectF absoluteOutlineRect(const QList<KoShape*> &shapes);
- /**
- * @brief Add a connector point to the shape
- *
- * A connector is a place on the shape that allows a graphical connection to be made
- * using a line, for example.
- *
- * @param point the connection point to add
- * @return the id of the new connection point
- */
- int addConnectionPoint(const KoConnectionPoint &point);
-
- /**
- * Sets data of connection point with specified id.
- *
- * The position of the connector is restricted to the bounding rectangle of the shape.
- * When setting a default connection point, the new position is ignored, as these
- * are fixed at their default position.
- * The function will insert a new connection point if the specified id was not used
- * before.
- *
- * @param connectionPointId the id of the connection point to set
- * @param point the connection point data
- * @return false if specified connection point id is invalid, else true
- */
- bool setConnectionPoint(int connectionPointId, const KoConnectionPoint &point);
-
- /// Checks if a connection point with the specified id exists
- bool hasConnectionPoint(int connectionPointId) const;
-
- /// Returns connection point with specified connection point id
- KoConnectionPoint connectionPoint(int connectionPointId) const;
-
- /**
- * Return a list of the connection points that have been added to this shape.
- * All the points are relative to the shape position, see absolutePosition().
- * @return a list of the connectors that have been added to this shape.
- */
- KoConnectionPoints connectionPoints() const;
-
- /// Removes connection point with specified id
- void removeConnectionPoint(int connectionPointId);
-
- /// Removes all connection points
- void clearConnectionPoints();
-
/**
* Return the side text should flow around this shape. This implements the ODF style:wrap
* attribute that specifies how text is displayed around a frame or graphic object.
*/
TextRunAroundSide textRunAroundSide() const;
/**
* Set the side text should flow around this shape.
* @param side the requested side
* @param runThrough run through the foreground or background or...
*/
void setTextRunAroundSide(TextRunAroundSide side, RunThroughLevel runThrough = Background);
/**
* The space between this shape's left edge and text that runs around this shape.
* @return the space around this shape to keep free from text
*/
qreal textRunAroundDistanceLeft() const;
/**
* Set the space between this shape's left edge and the text that run around this shape.
* @param distance the space around this shape to keep free from text
*/
void setTextRunAroundDistanceLeft(qreal distance);
/**
* The space between this shape's top edge and text that runs around this shape.
* @return the space around this shape to keep free from text
*/
qreal textRunAroundDistanceTop() const;
/**
* Set the space between this shape's top edge and the text that run around this shape.
* @param distance the space around this shape to keep free from text
*/
void setTextRunAroundDistanceTop(qreal distance);
/**
* The space between this shape's right edge and text that runs around this shape.
* @return the space around this shape to keep free from text
*/
qreal textRunAroundDistanceRight() const;
/**
* Set the space between this shape's right edge and the text that run around this shape.
* @param distance the space around this shape to keep free from text
*/
void setTextRunAroundDistanceRight(qreal distance);
/**
* The space between this shape's bottom edge and text that runs around this shape.
* @return the space around this shape to keep free from text
*/
qreal textRunAroundDistanceBottom() const;
/**
* Set the space between this shape's bottom edge and the text that run around this shape.
* @param distance the space around this shape to keep free from text
*/
void setTextRunAroundDistanceBottom(qreal distance);
/**
* Return the threshold above which text should flow around this shape.
* The text will not flow around the shape on a side unless the space available on that side
* is above this threshold. Only used when the text run around side is EnoughRunAroundSide.
* @return threshold the threshold
*/
qreal textRunAroundThreshold() const;
/**
* Set the threshold above which text should flow around this shape.
* The text will not flow around the shape on a side unless the space available on that side
* is above this threshold. Only used when the text run around side is EnoughRunAroundSide.
* @param threshold the new threshold
*/
void setTextRunAroundThreshold(qreal threshold);
/**
* Return the how tight text run around is done around this shape.
* @return the contour
*/
TextRunAroundContour textRunAroundContour() const;
/**
* Set how tight text run around is done around this shape.
* @param contour the new contour
*/
void setTextRunAroundContour(TextRunAroundContour contour);
/**
* Set the KoShapeAnchor
*/
void setAnchor(KoShapeAnchor *anchor);
/**
* Return the KoShapeAnchor, or 0
*/
KoShapeAnchor *anchor() const;
/**
* Set the minimum height of the shape.
* Currently it's not respected but only for informational purpose
* @param height the minimum height of the frame.
*/
void setMinimumHeight(qreal height);
/**
* Return the minimum height of the shape.
* @return the minimum height of the shape. Default is 0.0.
*/
qreal minimumHeight() const;
/**
* Set the background of the shape.
* A shape background can be a plain color, a gradient, a pattern, be fully transparent
* or have a complex fill.
* Setting such a background will allow the shape to be filled and will be able to tell
* if it is transparent or not.
*
* If the shape inherited the background from its parent, its stops inheriting it, that
* is inheritBackground property resets to false.
*
* @param background the new shape background.
*/
void setBackground(QSharedPointer<KoShapeBackground> background);
/**
* return the brush used to paint te background of this shape with.
* A QBrush can have a plain color, be fully transparent or have a complex fill.
* setting such a brush will allow the shape to fill itself using that brush and
* will be able to tell if its transparent or not.
* @return the background-brush
*/
QSharedPointer<KoShapeBackground> background() const;
/**
* @brief setInheritBackground marks a shape as inhiriting the background
* from the parent shape. NOTE: The currently selected background is destroyed.
* @param value true if the shape should inherit the filling background
*/
void setInheritBackground(bool value);
/**
* @brief inheritBackground shows if the shape inherits background from its parent
* @return true if the shape inherits the fill
*/
bool inheritBackground() const;
/**
* Returns true if there is some transparency, false if the shape is fully opaque.
* The default implementation will just return if the background has some transparency,
* you should override it and always return true if your shape is not square.
* @return if the shape is (partly) transparent.
*/
virtual bool hasTransparency() const;
/**
* Sets shape level transparency.
* @param transparency the new shape level transparency
*/
void setTransparency(qreal transparency);
/**
* Returns the shape level transparency.
* @param recursive when true takes the parents transparency into account
*/
qreal transparency(bool recursive=false) const;
/**
* Retrieve the z-coordinate of this shape.
* The zIndex property is used to determine which shape lies on top of other objects.
* An shape with a higher z-order is on top, and can obscure another shape.
* @return the z-index of this shape.
* @see setZIndex()
*/
qint16 zIndex() const;
/**
* Set the z-coordinate of this shape.
* The zIndex property is used to determine which shape lies on top of other objects.
* An shape with a higher z-order is on top, and can obscure, another shape.
* <p>Just like two objects having the same x or y coordinate will make them 'touch',
* so will two objects with the same z-index touch on the z plane. In layering the
* shape this, however, can cause a little confusion as one always has to be on top.
* The layering if two overlapping objects have the same index is implementation dependent
* and probably depends on the order in which they are added to the shape manager.
* @param zIndex the new z-index;
*/
void setZIndex(qint16 zIndex);
/**
* Maximum value of z-index
*/
static const qint16 maxZIndex;
/**
* Minimum value of z-index
*/
static const qint16 minZIndex;
/**
* Retrieve the run through property of this shape.
* The run through property is used to determine if the shape is behind, inside or before text.
* @return the run through of this shape.
*/
int runThrough() const;
/**
* Set the run through property of this shape.
* The run through property is used to determine if the shape is behind, inside or before text.
* @param runThrough the new run through;
*/
virtual void setRunThrough(short int runThrough);
/**
* Changes the Shape to be visible or invisible.
* Being visible means being painted, as well as being used for
* things like guidelines or searches.
* @param on when true; set the shape to be visible.
* @see setGeometryProtected(), setContentProtected(), setSelectable()
*/
void setVisible(bool on);
/**
* Returns current visibility state of this shape.
* Being visible means being painted, as well as being used for
* things like guidelines or searches.
* @param recursive when true, checks visibility recursively
* @return current visibility state of this shape.
* @see isGeometryProtected(), isContentProtected(), isSelectable()
*/
bool isVisible(bool recursive = true) const;
/**
* Changes the shape to be printable or not. The default is true.
*
* If a Shape's print flag is true, the shape will be printed. If
* false, the shape will not be printed. If a shape is not visible (@see isVisible),
* it isPrinted will return false, too.
*/
void setPrintable(bool on);
/**
* Returns the current printable state of this shape.
*
* A shape can be visible but not printable, not printable and not visible
* or visible and printable, but not invisible and still printable.
*
* @return current printable state of this shape.
*/
bool isPrintable() const;
/**
* Makes it possible for the user to select this shape.
* This parameter defaults to true.
* @param selectable when true; set the shape to be selectable by the user.
* @see setGeometryProtected(), setContentProtected(), setVisible()
*/
void setSelectable(bool selectable);
/**
* Returns if this shape can be selected by the user.
* @return true only when the object is selectable.
* @see isGeometryProtected(), isContentProtected(), isVisible()
*/
bool isSelectable() const;
/**
* Tells the shape to have its position/rotation and size protected from user-changes.
* The geometry being protected means the user can not change shape or position of the
* shape. This includes any matrix operation such as rotation.
* @param on when true; set the shape to have its geometry protected.
* @see setContentProtected(), setSelectable(), setVisible()
*/
void setGeometryProtected(bool on);
/**
* Returns current geometry protection state of this shape.
* The geometry being protected means the user can not change shape or position of the
* shape. This includes any matrix operation such as rotation.
* @return current geometry protection state of this shape.
* @see isContentProtected(), isSelectable(), isVisible()
*/
bool isGeometryProtected() const;
/**
* Marks the shape to have its content protected against editing.
* Content protection is a hint for tools to disallow the user editing the content.
* @param protect when true set the shapes content to be protected from user modification.
* @see setGeometryProtected(), setSelectable(), setVisible()
*/
void setContentProtected(bool protect);
/**
* Returns current content protection state of this shape.
* Content protection is a hint for tools to disallow the user editing the content.
* @return current content protection state of this shape.
* @see isGeometryProtected(), isSelectable(), isVisible()
*/
bool isContentProtected() const;
/**
* Returns the parent, or 0 if there is no parent.
* @return the parent, or 0 if there is no parent.
*/
KoShapeContainer *parent() const;
/**
* Set the parent of this shape.
* @param parent the new parent of this shape. Can be 0 if the shape has no parent anymore.
*/
void setParent(KoShapeContainer *parent);
/**
* @brief inheritsTransformFromAny checks if the shape inherits transformation from
* any of the shapes listed in \p ancestorsInQuestion. The inheritance is checked
* in recursive way.
* @return true if there is a (transitive) transformation-wise parent found in \p ancestorsInQuestion
*/
bool inheritsTransformFromAny(const QList<KoShape*> ancestorsInQuestion) const;
/**
* @return true if this shape has a common parent with \p shape
*/
bool hasCommonParent(const KoShape *shape) const;
/**
* Request a repaint to be queued.
* The repaint will be of the entire Shape, including its selection handles should this
* shape be selected.
* <p>This method will return immediately and only request a repaint. Successive calls
* will be merged into an appropriate repaint action.
*/
virtual void update() const;
/**
* Request a repaint to be queued.
* The repaint will be restricted to the parameters rectangle, which is expected to be
* in absolute coordinates of the canvas and it is expected to be
* normalized.
* <p>This method will return immediately and only request a repaint. Successive calls
* will be merged into an appropriate repaint action.
* @param rect the rectangle (in pt) to queue for repaint.
*/
virtual void updateAbsolute(const QRectF &rect) const;
/// Used by compareShapeZIndex() to order shapes
enum ChildZOrderPolicy {
ChildZDefault,
ChildZParentChild = ChildZDefault, ///< normal parent/child ordering
ChildZPassThrough ///< children are considered equal to this shape
};
/**
* Returns if during compareShapeZIndex() how this shape portrays the values
* of its children. The default behaviour is to let this shape's z values take
* the place of its childrens values, so you get a parent/child relationship.
* The children are naturally still ordered relatively to their z values
*
* But for special cases (like Calligra's TextShape) it can be overloaded to return
* ChildZPassThrough which means the children keep their own z values
* @returns the z order policy of this shape
*/
virtual ChildZOrderPolicy childZOrderPolicy();
/**
* This is a method used to sort a list using the STL sorting methods.
* @param s1 the first shape
* @param s2 the second shape
*/
static bool compareShapeZIndex(KoShape *s1, KoShape *s2);
/**
* returns the outline of the shape in the form of a path.
* The outline returned will always be relative to the position() of the shape, so
* moving the shape will not alter the result. The outline is used to draw the stroke
* on, for example.
* @returns the outline of the shape in the form of a path.
*/
virtual QPainterPath outline() const;
/**
* returns the outline of the shape in the form of a rect.
* The outlineRect returned will always be relative to the position() of the shape, so
* moving the shape will not alter the result. The outline is used to calculate
* the boundingRect.
* @returns the outline of the shape in the form of a rect.
*/
virtual QRectF outlineRect() const;
/**
* returns the outline of the shape in the form of a path for the use of painting a shadow.
*
* Normally this would be the same as outline() if there is a fill (background) set on the
* shape and empty if not. However, a shape could reimplement this to return an outline
* even if no fill is defined. A typical example of this would be the picture shape
- * which has a picture but almost never a background.
+ * which has a picture but almost never a background.
*
* @returns the outline of the shape in the form of a path.
*/
virtual QPainterPath shadowOutline() const;
/**
* Returns the currently set stroke, or 0 if there is no stroke.
* @return the currently set stroke, or 0 if there is no stroke.
*/
KoShapeStrokeModelSP stroke() const;
/**
* Set a new stroke, removing the old one. The stroke inheritance becomes disabled.
* @param stroke the new stroke, or 0 if there should be no stroke.
*/
void setStroke(KoShapeStrokeModelSP stroke);
/**
* @brief setInheritStroke marks a shape as inhiriting the stroke
* from the parent shape. NOTE: The currently selected stroke is destroyed.
* @param value true if the shape should inherit the stroke style
*/
void setInheritStroke(bool value);
/**
* @brief inheritStroke shows if the shape inherits the stroke from its parent
* @return true if the shape inherits the stroke style
*/
bool inheritStroke() const;
/**
* Return the insets of the stroke.
* Convenience method for KoShapeStrokeModel::strokeInsets()
*/
KoInsets strokeInsets() const;
/// Sets the new shadow, removing the old one
void setShadow(KoShapeShadow *shadow);
/// Returns the currently set shadow or 0 if there is no shadow set
KoShapeShadow *shadow() const;
- /// Sets the new border, removing the old one.
- void setBorder(KoBorder *border);
-
- /// Returns the currently set border or 0 if there is no border set
- KoBorder *border() const;
-
/// Sets a new clip path, removing the old one
void setClipPath(KoClipPath *clipPath);
/// Returns the currently set clip path or 0 if there is no clip path set
KoClipPath * clipPath() const;
/// Sets a new clip mask, removing the old one. The mask is owned by the shape.
void setClipMask(KoClipMask *clipMask);
/// Returns the currently set clip mask or 0 if there is no clip mask set
KoClipMask* clipMask() const;
/**
* Setting the shape to keep its aspect-ratio has the effect that user-scaling will
* keep the width/height ratio intact so as not to distort shapes that rely on that
* ratio.
* @param keepAspect the new value
*/
void setKeepAspectRatio(bool keepAspect);
/**
* Setting the shape to keep its aspect-ratio has the effect that user-scaling will
* keep the width/height ratio intact so as not to distort shapes that rely on that
* ratio.
* @return whether to keep aspect ratio of this shape
*/
bool keepAspectRatio() const;
/**
* Return the position of this shape regardless of rotation/skew/scaling and regardless of
* this shape having a parent (being in a group) or not.<br>
* @param anchor The place on the (unaltered) shape that you want the position of.
* @return the point that is the absolute, centered position of this shape.
*/
QPointF absolutePosition(KoFlake::AnchorPosition anchor = KoFlake::Center) const;
/**
* Move this shape to an absolute position where the end location will be the same
* regardless of the shape's rotation/skew/scaling and regardless of this shape having
* a parent (being in a group) or not.<br>
* The newPosition is going to be the center of the shape.
* This has the convenient effect that: <pre>
shape-&gt;setAbsolutePosition(QPointF(0,0));
shape-&gt;rotate(45);</pre>
Will result in the same visual position of the shape as the opposite:<pre>
shape-&gt;rotate(45);
shape-&gt;setAbsolutePosition(QPointF(0,0));</pre>
* @param newPosition the new absolute center of the shape.
* @param anchor The place on the (unaltered) shape that you set the position of.
*/
void setAbsolutePosition(const QPointF &newPosition, KoFlake::AnchorPosition anchor = KoFlake::Center);
/**
* Set a data object on the shape to be used by an application.
* This is specifically useful when a shape is created in a plugin and that data from that
* shape should be accessible outside the plugin.
* @param userData the new user data, or 0 to delete the current one.
*/
void setUserData(KoShapeUserData *userData);
/**
* Return the current userData.
*/
KoShapeUserData *userData() const;
/**
* Return the Id of this shape, identifying the type of shape by the id of the factory.
* @see KoShapeFactoryBase::shapeId()
* @return the id of the shape-type
*/
QString shapeId() const;
/**
* Set the Id of this shape. A shapeFactory is expected to set the Id at creation
* so applications can find out what kind of shape this is.
* @see KoShapeFactoryBase::shapeId()
* @param id the ID from the factory that created this shape
*/
void setShapeId(const QString &id);
/**
* Create a matrix that describes all the transformations done on this shape.
*
* The absolute transformation is the combined transformation of this shape
* and all its parents and grandparents.
*/
QTransform absoluteTransformation() const;
/**
* Applies a transformation to this shape.
*
* The transformation given is relative to the global coordinate system, i.e. the document.
* This is a convenience function to apply a global transformation to this shape.
* @see applyTransformation
*
* @param matrix the transformation matrix to apply
*/
void applyAbsoluteTransformation(const QTransform &matrix);
/**
* Sets a new transformation matrix describing the local transformations on this shape.
* @param matrix the new transformation matrix
*/
void setTransformation(const QTransform &matrix);
/// Returns the shapes local transformation matrix
QTransform transformation() const;
/**
* Applies a transformation to this shape.
*
* The transformation given is relative to the shape coordinate system.
*
* @param matrix the transformation matrix to apply
*/
void applyTransformation(const QTransform &matrix);
/**
* Copy all the settings from the parameter shape and apply them to this shape.
* Settings like the position and rotation to visible and locked. The parent
* is a notable exclusion.
* @param shape the shape to use as original
*/
void copySettings(const KoShape *shape);
/**
* A convenience method that creates a handles helper with applying transformations at
* the same time. Please note that you shouldn't save/restore additionally. All the work
* on restoring original painter's transformations is done by the helper.
*/
static KisHandlePainterHelper createHandlePainterHelperView(QPainter *painter, KoShape *shape, const KoViewConverter &converter, qreal handleRadius = 0.0);
static KisHandlePainterHelper createHandlePainterHelperDocument(QPainter *painter, KoShape *shape, qreal handleRadius);
/**
* @brief Transforms point from shape coordinates to document coordinates
* @param point in shape coordinates
* @return point in document coordinates
*/
QPointF shapeToDocument(const QPointF &point) const;
/**
* @brief Transforms rect from shape coordinates to document coordinates
* @param rect in shape coordinates
* @return rect in document coordinates
*/
QRectF shapeToDocument(const QRectF &rect) const;
/**
* @brief Transforms point from document coordinates to shape coordinates
* @param point in document coordinates
* @return point in shape coordinates
*/
QPointF documentToShape(const QPointF &point) const;
/**
* @brief Transform rect from document coordinates to shape coordinates
* @param rect in document coordinates
* @return rect in shape coordinates
*/
QRectF documentToShape(const QRectF &rect) const;
/**
* Returns the name of the shape.
* @return the shapes name
*/
QString name() const;
/**
* Sets the name of the shape.
* @param name the new shape name
*/
void setName(const QString &name);
/**
* Update the position of the shape in the tree of the KoShapeManager.
*/
void notifyChanged();
/**
* A shape can be in a state that it is doing processing data like loading or text layout.
* In this case it can be shown on screen probably partially but it should really not be printed
* until it is fully done processing.
* Warning! This method can be blocking for a long time
* @param asynchronous If set to true the processing will can take place in a different thread and the
* function will not block until the shape is finished.
* In case of printing Flake will call this method from a non-main thread and only
* start printing it when the in case of printing method returned.
* If set to false the processing needs to be done synchronously and will
* block until the result is finished.
*/
virtual void waitUntilReady(bool asynchronous = true) const;
/// checks recursively if the shape or one of its parents is not visible or locked
virtual bool isShapeEditable(bool recursive = true) const;
/**
* Adds a shape which depends on this shape.
* Making a shape dependent on this one means it will get shapeChanged() called
* on each update of this shape.
*
* If this shape already depends on the given shape, establishing the
* dependency is refused to prevent circular dependencies.
*
* @param shape the shape which depends on this shape
* @return true if dependency could be established, otherwise false
* @see removeDependee(), hasDependee()
*/
bool addDependee(KoShape *shape);
/**
* Removes as shape depending on this shape.
* @see addDependee(), hasDependee()
*/
void removeDependee(KoShape *shape);
/// Returns if the given shape is dependent on this shape
bool hasDependee(KoShape *shape) const;
/// Returns list of shapes depending on this shape
QList<KoShape*> dependees() const;
/// Returns additional snap data the shape wants to have snapping to
virtual KoSnapData snapData() const;
/**
* Set additional attribute
*
* This can be used to attach additional attributes to a shape for attributes
* that are application specific like presentation:placeholder
*
* @param name The name of the attribute in the following form prefix:tag e.g. presentation:placeholder
* @param value The value of the attribute
*/
void setAdditionalAttribute(const QString &name, const QString &value);
/**
* Remove additional attribute
*
* @param name The name of the attribute in the following form prefix:tag e.g. presentation:placeholder
*/
void removeAdditionalAttribute(const QString &name);
/**
* Check if additional attribute is set
*
* @param name The name of the attribute in the following form prefix:tag e.g. presentation:placeholder
*
* @return true if there is a attribute with prefix:tag set, false otherwise
*/
bool hasAdditionalAttribute(const QString &name) const;
/**
* Get additional attribute
*
* @param name The name of the attribute in the following form prefix:tag e.g. presentation:placeholder
*
* @return The value of the attribute if it exists or a null string if not found.
*/
QString additionalAttribute(const QString &name) const;
void setAdditionalStyleAttribute(const char *name, const QString &value);
void removeAdditionalStyleAttribute(const char *name);
/**
* Returns the filter effect stack of the shape
*
* @return the list of filter effects applied on the shape when rendering.
*/
KoFilterEffectStack *filterEffectStack() const;
/// Sets the new filter effect stack, removing the old one
void setFilterEffectStack(KoFilterEffectStack *filterEffectStack);
/**
* Return the tool delegates for this shape.
* In Flake a shape being selected will cause the tool manager to make available all tools that
* can edit the selected shapes. In some cases selecting one shape should allow the tool to
* edit a related shape be available too. The tool delegates allows this to happen by taking
* all the shapes in the set into account on tool selection.
* Notice that if the set is non-empty 'this' shape is no longer looked at. You can choose
* to add itself to the set too.
*/
QSet<KoShape*> toolDelegates() const;
/**
* Set the tool delegates.
* @param delegates the new delegates.
* @see toolDelegates()
*/
void setToolDelegates(const QSet<KoShape*> &delegates);
/**
* Return the hyperlink for this shape.
*/
QString hyperLink () const;
/**
* Set hyperlink for this shape.
* @param hyperLink name.
*/
void setHyperLink(const QString &hyperLink);
public:
struct KRITAFLAKE_EXPORT ShapeChangeListener {
virtual ~ShapeChangeListener();
virtual void notifyShapeChanged(ChangeType type, KoShape *shape) = 0;
private:
friend class KoShape;
void registerShape(KoShape *shape);
void unregisterShape(KoShape *shape);
void notifyShapeChangedImpl(ChangeType type, KoShape *shape);
QList<KoShape*> m_registeredShapes;
};
void addShapeChangeListener(ShapeChangeListener *listener);
void removeShapeChangeListener(ShapeChangeListener *listener);
protected:
QList<ShapeChangeListener *> listeners() const;
void setSizeImpl(const QSizeF &size) const;
public:
static QList<KoShape*> linearizeSubtree(const QList<KoShape*> &shapes);
static QList<KoShape *> linearizeSubtreeSorted(const QList<KoShape *> &shapes);
protected:
KoShape(const KoShape &rhs);
- /* ** loading saving helper methods */
- /// attributes from ODF 1.1 chapter 9.2.15 Common Drawing Shape Attributes
- enum OdfAttribute {
- OdfTransformation = 1, ///< Store transformation information
- OdfSize = 2, ///< Store size information
- OdfPosition = 8, ///< Store position
- OdfAdditionalAttributes = 4, ///< Store additional attributes of the shape
- OdfCommonChildElements = 16, ///< Event actions and connection points
- OdfLayer = 64, ///< Store layer name
- OdfStyle = 128, ///< Store the style
- OdfId = 256, ///< Store the unique ID
- OdfName = 512, ///< Store the name of the shape
- OdfZIndex = 1024, ///< Store the z-index
- OdfViewbox = 2048, ///< Store the viewbox
-
- /// A mask for all mandatory attributes
- OdfMandatories = OdfLayer | OdfStyle | OdfId | OdfName | OdfZIndex,
- /// A mask for geometry attributes
- OdfGeometry = OdfPosition | OdfSize,
- /// A mask for all the attributes
- OdfAllAttributes = OdfTransformation | OdfGeometry | OdfAdditionalAttributes | OdfMandatories | OdfCommonChildElements
- };
-
- /**
- * This method is used during loading of the shape to load common attributes
- *
- * @param context the KoShapeLoadingContext used for loading
- * @param element element which represents the shape in odf
- * @param attributes a number of OdfAttribute items to state which attributes to load.
- */
- bool loadOdfAttributes(const KoXmlElement &element, KoShapeLoadingContext &context, int attributes);
-
- /**
- * Parses the transformation attribute from the given string
- * @param transform the transform attribute string
- * @return the resulting transformation matrix
- */
- QTransform parseOdfTransform(const QString &transform);
-
- /**
- * @brief Saves the style used for the shape
- *
- * This method fills the given style object with the stroke and
- * background properties and then adds the style to the context.
- *
- * @param style the style object to fill
- * @param context used for saving
- * @return the name of the style
- * @see saveOdf
- */
- virtual QString saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const;
-
- /**
- * Loads the stroke and fill style from the given element.
- *
- * @param element the xml element to load the style from
- * @param context the loading context used for loading
- */
- virtual void loadStyle(const KoXmlElement &element, KoShapeLoadingContext &context);
-
- /// Loads the stroke style
- KoShapeStrokeModelSP loadOdfStroke(const KoXmlElement &element, KoShapeLoadingContext &context) const;
-
- /// Loads the fill style
- QSharedPointer<KoShapeBackground> loadOdfFill(KoShapeLoadingContext &context) const;
-
- /// Loads the connection points
- void loadOdfGluePoints(const KoXmlElement &element, KoShapeLoadingContext &context);
-
- /// Loads the clip contour
- void loadOdfClipContour(const KoXmlElement &element, KoShapeLoadingContext &context, const QSizeF &scaleFactor);
-
- /* ** end loading saving */
-
- /**
+ /**
* A hook that allows inheriting classes to do something after a KoShape property changed
* This is called whenever the shape, position rotation or scale properties were altered.
* @param type an indicator which type was changed.
* @param shape the shape.
*/
virtual void shapeChanged(ChangeType type, KoShape *shape = 0);
/// return the current matrix that contains the rotation/scale/position of this shape
QTransform transform() const;
private:
class Private;
QScopedPointer<Private> d;
class SharedData;
QSharedDataPointer<SharedData> s;
protected:
/**
* Notify the shape that a change was done. To be used by inheriting shapes.
* @param type the change type
*/
void shapeChangedPriv(KoShape::ChangeType type);
private:
void addShapeManager(KoShapeManager *manager);
void removeShapeManager(KoShapeManager *manager);
friend class KoShapeManager;
};
Q_DECLARE_METATYPE(KoShape*)
#endif
diff --git a/libs/flake/KoShapeAnchor.cpp b/libs/flake/KoShapeAnchor.cpp
index a393e26235..f4049a2b0d 100644
--- a/libs/flake/KoShapeAnchor.cpp
+++ b/libs/flake/KoShapeAnchor.cpp
@@ -1,528 +1,197 @@
/* This file is part of the KDE project
* Copyright (C) 2007, 2009-2010 Thomas Zander <zander@kde.org>
* Copyright (C) 2010 Ko Gmbh <cbo@kogmbh.com>
* Copyright (C) 2011 Matus Hanzes <matus.hanzes@ixonos.com>
* Copyright (C) 2013 C. Boemann <cbo@boemann.dk>
*
* 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 "KoShapeAnchor.h"
-#include "KoStyleStack.h"
-#include "KoOdfLoadingContext.h"
#include <KoShapeContainer.h>
#include <KoXmlWriter.h>
#include <KoXmlReader.h>
#include <KoXmlNS.h>
#include <KoShapeSavingContext.h>
#include <KoShapeLoadingContext.h>
#include <QRectF>
#include <QTransform>
#include <FlakeDebug.h>
-#include <KoGenChanges.h>
-
class Q_DECL_HIDDEN KoShapeAnchor::Private
{
public:
Private(KoShape *s)
: shape(s)
, verticalPos(KoShapeAnchor::VTop)
, verticalRel(KoShapeAnchor::VLine)
, horizontalPos(KoShapeAnchor::HLeft)
, horizontalRel(KoShapeAnchor::HChar)
, flowWithText(true)
, anchorType(KoShapeAnchor::AnchorToCharacter)
, placementStrategy(0)
, pageNumber(-1)
, textLocation(0)
{
}
QDebug printDebug(QDebug dbg) const
{
#ifndef NDEBUG
dbg.space() << "KoShapeAnchor" << this;
dbg.space() << "offset:" << offset;
dbg.space() << "shape:" << shape->name();
#endif
return dbg.space();
}
KoShape * const shape;
QPointF offset;
KoShapeAnchor::VerticalPos verticalPos;
KoShapeAnchor::VerticalRel verticalRel;
KoShapeAnchor::HorizontalPos horizontalPos;
KoShapeAnchor::HorizontalRel horizontalRel;
QString wrapInfluenceOnPosition;
bool flowWithText;
KoShapeAnchor::AnchorType anchorType;
KoShapeAnchor::PlacementStrategy *placementStrategy;
int pageNumber;
KoShapeAnchor::TextLocation *textLocation;
};
KoShapeAnchor::KoShapeAnchor(KoShape *shape)
: d(new Private(shape))
{
}
KoShapeAnchor::~KoShapeAnchor()
{
if (d->placementStrategy != 0) {
delete d->placementStrategy;
}
delete d;
}
KoShape *KoShapeAnchor::shape() const
{
return d->shape;
}
KoShapeAnchor::AnchorType KoShapeAnchor::anchorType() const
{
return d->anchorType;
}
void KoShapeAnchor::setHorizontalPos(HorizontalPos hp)
{
d->horizontalPos = hp;
}
KoShapeAnchor::HorizontalPos KoShapeAnchor::horizontalPos() const
{
return d->horizontalPos;
}
void KoShapeAnchor::setHorizontalRel(HorizontalRel hr)
{
d->horizontalRel = hr;
}
KoShapeAnchor::HorizontalRel KoShapeAnchor::horizontalRel() const
{
return d->horizontalRel;
}
void KoShapeAnchor::setVerticalPos(VerticalPos vp)
{
d->verticalPos = vp;
}
KoShapeAnchor::VerticalPos KoShapeAnchor::verticalPos() const
{
return d->verticalPos;
}
void KoShapeAnchor::setVerticalRel(VerticalRel vr)
{
d->verticalRel = vr;
}
KoShapeAnchor::VerticalRel KoShapeAnchor::verticalRel() const
{
return d->verticalRel;
}
QString KoShapeAnchor::wrapInfluenceOnPosition() const
{
return d->wrapInfluenceOnPosition;
}
bool KoShapeAnchor::flowWithText() const
{
return d->flowWithText;
}
int KoShapeAnchor::pageNumber() const
{
return d->pageNumber;
}
const QPointF &KoShapeAnchor::offset() const
{
return d->offset;
}
void KoShapeAnchor::setOffset(const QPointF &offset)
{
d->offset = offset;
}
-void KoShapeAnchor::saveOdf(KoShapeSavingContext &context) const
-{
- // anchor-type
- switch (d->anchorType) {
- case AnchorToCharacter:
- shape()->setAdditionalAttribute("text:anchor-type", "char");
- break;
- case AnchorAsCharacter:
- shape()->setAdditionalAttribute("text:anchor-type", "as-char");
- break;
- case AnchorParagraph:
- shape()->setAdditionalAttribute("text:anchor-type", "paragraph");
- break;
- case AnchorPage:
- shape()->setAdditionalAttribute("text:anchor-type", "page");
- break;
- default:
- break;
- }
-
- // vertical-pos
- switch (d->verticalPos) {
- case VBelow:
- shape()->setAdditionalStyleAttribute("style:vertical-pos", "below");
- break;
- case VBottom:
- shape()->setAdditionalStyleAttribute("style:vertical-pos", "bottom");
- break;
- case VFromTop:
- shape()->setAdditionalStyleAttribute("style:vertical-pos", "from-top");
- break;
- case VMiddle:
- shape()->setAdditionalStyleAttribute("style:vertical-pos", "middle");
- break;
- case VTop:
- shape()->setAdditionalStyleAttribute("style:vertical-pos", "top");
- break;
- default:
- break;
- }
-
- // vertical-rel
- switch (d->verticalRel) {
- case VBaseline:
- shape()->setAdditionalStyleAttribute("style:vertical-rel", "baseline");
- break;
- case VChar:
- shape()->setAdditionalStyleAttribute("style:vertical-rel", "char");
- break;
- case VFrame:
- shape()->setAdditionalStyleAttribute("style:vertical-rel", "frame");
- break;
- case VFrameContent:
- shape()->setAdditionalStyleAttribute("style:vertical-rel", "frame-content");
- break;
- case VLine:
- shape()->setAdditionalStyleAttribute("style:vertical-rel", "line");
- break;
- case VPage:
- shape()->setAdditionalStyleAttribute("style:vertical-rel", "page");
- break;
- case VPageContent:
- shape()->setAdditionalStyleAttribute("style:vertical-rel", "page-content");
- break;
- case VParagraph:
- shape()->setAdditionalStyleAttribute("style:vertical-rel", "paragraph");
- break;
- case VParagraphContent:
- shape()->setAdditionalStyleAttribute("style:vertical-rel", "paragraph-content");
- break;
- case VText:
- shape()->setAdditionalStyleAttribute("style:vertical-rel", "text");
- break;
- default:
- break;
- }
-
- // horizontal-pos
- switch (d->horizontalPos) {
- case HCenter:
- shape()->setAdditionalStyleAttribute("style:horizontal-pos", "center");
- break;
- case HFromInside:
- shape()->setAdditionalStyleAttribute("style:horizontal-pos", "from-inside");
- break;
- case HFromLeft:
- shape()->setAdditionalStyleAttribute("style:horizontal-pos", "from-left");
- break;
- case HInside:
- shape()->setAdditionalStyleAttribute("style:horizontal-posl", "inside");
- break;
- case HLeft:
- shape()->setAdditionalStyleAttribute("style:horizontal-pos", "left");
- break;
- case HOutside:
- shape()->setAdditionalStyleAttribute("style:horizontal-pos", "outside");
- break;
- case HRight:
- shape()->setAdditionalStyleAttribute("style:horizontal-pos", "right");
- break;
- default:
- break;
- }
-
- // horizontal-rel
- switch (d->horizontalRel) {
- case HChar:
- shape()->setAdditionalStyleAttribute("style:horizontal-rel", "char");
- break;
- case HPage:
- shape()->setAdditionalStyleAttribute("style:horizontal-rel", "page");
- break;
- case HPageContent:
- shape()->setAdditionalStyleAttribute("style:horizontal-rel", "page-content");
- break;
- case HPageStartMargin:
- shape()->setAdditionalStyleAttribute("style:horizontal-rel", "page-start-margin");
- break;
- case HPageEndMargin:
- shape()->setAdditionalStyleAttribute("style:horizontal-rel", "page-end-margin");
- break;
- case HFrame:
- shape()->setAdditionalStyleAttribute("style:horizontal-rel", "frame");
- break;
- case HFrameContent:
- shape()->setAdditionalStyleAttribute("style:horizontal-rel", "frame-content");
- break;
- case HFrameEndMargin:
- shape()->setAdditionalStyleAttribute("style:horizontal-rel", "frame-end-margin");
- break;
- case HFrameStartMargin:
- shape()->setAdditionalStyleAttribute("style:horizontal-rel", "frame-start-margin");
- break;
- case HParagraph:
- shape()->setAdditionalStyleAttribute("style:horizontal-rel", "paragraph");
- break;
- case HParagraphContent:
- shape()->setAdditionalStyleAttribute("style:horizontal-rel", "paragraph-content");
- break;
- case HParagraphEndMargin:
- shape()->setAdditionalStyleAttribute("style:horizontal-rel", "paragraph-end-margin");
- break;
- case HParagraphStartMargin:
- shape()->setAdditionalStyleAttribute("style:horizontal-rel", "paragraph-start-margin");
- break;
- default:
- break;
- }
-
- if (!d->wrapInfluenceOnPosition.isEmpty()) {
- shape()->setAdditionalStyleAttribute("draw:wrap-influence-on-position", d->wrapInfluenceOnPosition);
- }
-
- if (d->flowWithText) {
- shape()->setAdditionalStyleAttribute("style:flow-with-text", "true");
- } else {
- shape()->setAdditionalStyleAttribute("style:flow-with-text", "false");
- }
-
- if (shape()->parent()) {// an anchor may not yet have been layout-ed
- QTransform parentMatrix = shape()->parent()->absoluteTransformation().inverted();
- QTransform shapeMatrix = shape()->absoluteTransformation();
-
- qreal dx = d->offset.x() - shapeMatrix.dx()*parentMatrix.m11()
- - shapeMatrix.dy()*parentMatrix.m21();
- qreal dy = d->offset.y() - shapeMatrix.dx()*parentMatrix.m12()
- - shapeMatrix.dy()*parentMatrix.m22();
- context.addShapeOffset(shape(), QTransform(parentMatrix.m11(),parentMatrix.m12(),
- parentMatrix.m21(),parentMatrix.m22(),
- dx,dy));
- }
-
- shape()->saveOdf(context);
-
- context.removeShapeOffset(shape());
-}
-
-bool KoShapeAnchor::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- d->offset = shape()->position();
-
- QString anchorType = shape()->additionalAttribute("text:anchor-type");
-
- if (anchorType == "char") {
- d->anchorType = AnchorToCharacter;
- } else if (anchorType == "as-char") {
- d->anchorType = AnchorAsCharacter;
- d->horizontalRel = HChar;
- d->horizontalPos = HLeft;
- } else if (anchorType == "paragraph") {
- d->anchorType = AnchorParagraph;
- } else {
- d->anchorType = AnchorPage;
- // it has different defaults at least LO thinks so - ODF doesn't define defaults for this
- d->horizontalPos = HFromLeft;
- d->verticalPos = VFromTop;
- d->horizontalRel = HPage;
- d->verticalRel = VPage;
- }
-
- if (anchorType == "page" && shape()->hasAdditionalAttribute("text:anchor-page-number")) {
- d->pageNumber = shape()->additionalAttribute("text:anchor-page-number").toInt();
- if (d->pageNumber <= 0) {
- // invalid if the page-number is invalid (OO.org does the same)
- // see https://bugs.kde.org/show_bug.cgi?id=281869
- d->pageNumber = -1;
- }
- } else {
- d->pageNumber = -1;
- }
- // always make it invisible or it will create empty rects on the first page
- // during initial layout. This is because only when we layout it's final page is
- // the shape moved away from page 1
- // in KWRootAreaProvider of textlayout it's set back to visible
- shape()->setVisible(false);
-
- // load settings from graphic style
- KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
- styleStack.save();
- if (element.hasAttributeNS(KoXmlNS::draw, "style-name")) {
- context.odfLoadingContext().fillStyleStack(element, KoXmlNS::draw, "style-name", "graphic");
- styleStack.setTypeProperties("graphic");
- }
- QString verticalPos = styleStack.property(KoXmlNS::style, "vertical-pos");
- QString verticalRel = styleStack.property(KoXmlNS::style, "vertical-rel");
- QString horizontalPos = styleStack.property(KoXmlNS::style, "horizontal-pos");
- QString horizontalRel = styleStack.property(KoXmlNS::style, "horizontal-rel");
- d->wrapInfluenceOnPosition = styleStack.property(KoXmlNS::draw, "wrap-influence-on-position");
- QString flowWithText = styleStack.property(KoXmlNS::style, "flow-with-text");
- d->flowWithText = flowWithText.isEmpty() ? false : flowWithText == "true";
- styleStack.restore();
-
- // vertical-pos
- if (verticalPos == "below") {//svg:y attribute is ignored
- d->verticalPos = VBelow;
- d->offset.setY(0);
- } else if (verticalPos == "bottom") {//svg:y attribute is ignored
- d->verticalPos = VBottom;
- d->offset.setY(-shape()->size().height());
- } else if (verticalPos == "from-top") {
- d->verticalPos = VFromTop;
- } else if (verticalPos == "middle") {//svg:y attribute is ignored
- d->verticalPos = VMiddle;
- d->offset.setY(-(shape()->size().height()/2));
- } else if (verticalPos == "top") {//svg:y attribute is ignored
- d->verticalPos = VTop;
- d->offset.setY(0);
- }
-
- // vertical-rel
- if (verticalRel == "baseline")
- d->verticalRel = VBaseline;
- else if (verticalRel == "char")
- d->verticalRel = VChar;
- else if (verticalRel == "frame")
- d->verticalRel = VFrame;
- else if (verticalRel == "frame-content")
- d->verticalRel = VFrameContent;
- else if (verticalRel == "line")
- d->verticalRel = VLine;
- else if (verticalRel == "page")
- d->verticalRel = VPage;
- else if (verticalRel == "page-content")
- d->verticalRel = VPageContent;
- else if (verticalRel == "paragraph")
- d->verticalRel = VParagraph;
- else if (verticalRel == "paragraph-content")
- d->verticalRel = VParagraphContent;
- else if (verticalRel == "text")
- d->verticalRel = VText;
-
- // horizontal-pos
- if (horizontalPos == "center") {//svg:x attribute is ignored
- d->horizontalPos = HCenter;
- d->offset.setX(-(shape()->size().width()/2));
- } else if (horizontalPos == "from-inside") {
- d->horizontalPos = HFromInside;
- } else if (horizontalPos == "from-left") {
- d->horizontalPos = HFromLeft;
- } else if (horizontalPos == "inside") {//svg:x attribute is ignored
- d->horizontalPos = HInside;
- d->offset.setX(0);
- } else if (horizontalPos == "left") {//svg:x attribute is ignored
- d->horizontalPos = HLeft;
- d->offset.setX(0);
- }else if (horizontalPos == "outside") {//svg:x attribute is ignored
- d->horizontalPos = HOutside;
- d->offset.setX(-shape()->size().width());
- }else if (horizontalPos == "right") {//svg:x attribute is ignored
- d->horizontalPos = HRight;
- d->offset.setX(-shape()->size().width());
- }
-
- // horizontal-rel
- if (horizontalRel == "char")
- d->horizontalRel = HChar;
- else if (horizontalRel == "page")
- d->horizontalRel = HPage;
- else if (horizontalRel == "page-content")
- d->horizontalRel = HPageContent;
- else if (horizontalRel == "page-start-margin")
- d->horizontalRel = HPageStartMargin;
- else if (horizontalRel == "page-end-margin")
- d->horizontalRel = HPageEndMargin;
- else if (horizontalRel == "frame")
- d->horizontalRel = HFrame;
- else if (horizontalRel == "frame-content")
- d->horizontalRel = HFrameContent;
- else if (horizontalRel == "frame-end-margin")
- d->horizontalRel = HFrameEndMargin;
- else if (horizontalRel == "frame-start-margin")
- d->horizontalRel = HFrameStartMargin;
- else if (horizontalRel == "paragraph")
- d->horizontalRel = HParagraph;
- else if (horizontalRel == "paragraph-content")
- d->horizontalRel = HParagraphContent;
- else if (horizontalRel == "paragraph-end-margin")
- d->horizontalRel = HParagraphEndMargin;
- else if (horizontalRel == "paragraph-start-margin")
- d->horizontalRel = HParagraphStartMargin;
-
- // if svg:x or svg:y should be ignored set new position
- shape()->setPosition(d->offset);
-
- return true;
-}
-
void KoShapeAnchor::setAnchorType(KoShapeAnchor::AnchorType type)
{
d->anchorType = type;
if (type == AnchorAsCharacter) {
d->horizontalRel = HChar;
d->horizontalPos = HLeft;
}
}
KoShapeAnchor::TextLocation *KoShapeAnchor::textLocation() const
{
return d->textLocation;
}
void KoShapeAnchor::setTextLocation(TextLocation *textLocation)
{
d->textLocation = textLocation;
}
KoShapeAnchor::PlacementStrategy *KoShapeAnchor::placementStrategy() const
{
return d->placementStrategy;
}
void KoShapeAnchor::setPlacementStrategy(PlacementStrategy *placementStrategy)
{
if (placementStrategy != d->placementStrategy) {
delete d->placementStrategy;
d->placementStrategy = placementStrategy;
}
}
diff --git a/libs/flake/KoShapeAnchor.h b/libs/flake/KoShapeAnchor.h
index 06b3465e7e..82f458c47d 100644
--- a/libs/flake/KoShapeAnchor.h
+++ b/libs/flake/KoShapeAnchor.h
@@ -1,262 +1,253 @@
/* This file is part of the KDE project
* Copyright (C) 2007, 2009 Thomas Zander <zander@kde.org>
* Copyright (C) 2011 Matus Hanzes <matus.hanzes@ixonos.com>
* Copyright (C) 2013 C. Boemann <cbo@boemann.dk>
*
* 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 KOSHAPEANCHOR_H
#define KOSHAPEANCHOR_H
#include "kritaflake_export.h"
class KoShape;
#include <KoXmlReaderForward.h>
class KoShapeLoadingContext;
class KoShapeSavingContext;
class KoShapeAnchorPrivate;
class QTextDocument;
class QPointF;
class QString;
/**
* This class is the object that explains how a shape is anchored to something.
*
* The anchored shape will be positioned (in supporting applications) based on the properties
* defined in this class.
*
* This class can be used in three different ways:
* -page anchor
* -as-char
* -char, paragraph anchor
*
* If it's a page anchor it just provide the info about how the shape relates to a page with a specific
* page number.
*
* For the other types of anchoring it has to have a TextLocation in a QTextDocument. This TextLocation
* can either be an inline character (type as-char) or a position (type char or paragraph) The
* KoShapeAnchor and TextLocation connects the anchored-shape to the text flow so the anchored shape
* can be repositioned on the canvas if new text is inserted or removed before the anchor character.
*
* For as-char, char and paragraph use cases:
* @see KoAnchorInlineObject
* @see KoAnchorTextRange
* which are both implemented as subclasses of TextLocation
*
- * The position of the shape relative to the anchor is called the offset. It's loaded by loadOdf().
+ * The position of the shape relative to the anchor is called the offset.
* @see PlacementStrategy for more information about the layout of anchors/shapes.
*/
class KRITAFLAKE_EXPORT KoShapeAnchor
{
public:
/**
* This class is an interface that positions the shape linked to text anchor
*/
class PlacementStrategy {
public:
PlacementStrategy(){};
virtual ~PlacementStrategy(){};
/**
* Reparent the anchored shape to not have a parent shape container (and model)
*
*/
virtual void detachFromModel() = 0;
/**
* Reparent the anchored shape under an appropriate shape container (and model)
*
* If needed, it changes the parent KoShapeContainerModel and KoShapeContainer of the anchored
* shape.
*/
virtual void updateContainerModel() = 0;
};
class TextLocation {
public:
TextLocation(){};
virtual ~TextLocation(){};
virtual const QTextDocument *document() const = 0;
virtual int position() const = 0;
};
enum HorizontalPos {
HCenter,
HFromInside,
HFromLeft,
HInside,
HLeft,
HOutside,
HRight
};
enum HorizontalRel { //NOTE: update KWAnchoringProperties if you change this
HChar,
HPage,
HPageContent,
HPageStartMargin,
HPageEndMargin,
HFrame,
HFrameContent,
HFrameEndMargin,
HFrameStartMargin,
HParagraph,
HParagraphContent,
HParagraphEndMargin,
HParagraphStartMargin
};
enum VerticalPos {
VBelow,
VBottom,
VFromTop,
VMiddle,
VTop
};
enum VerticalRel { //NOTE: update KWAnchoringProperties if you change this
VBaseline,
VChar,
VFrame,
VFrameContent,
VLine,
VPage,
VPageContent,
VParagraph,
VParagraphContent,
VText
};
enum AnchorType {
AnchorAsCharacter,
AnchorToCharacter,
AnchorParagraph,
AnchorPage
};
/**
* Constructor for an in-place anchor.
* @param shape the anchored shape that this anchor links to.
*/
explicit KoShapeAnchor(KoShape *shape);
virtual ~KoShapeAnchor();
/**
* Return the shape that is linked to from the text anchor.
*/
KoShape *shape() const;
/**
* Returns the type of the anchor.
*
* The text:anchor-type attribute specifies how a frame is bound to a
* text document. The anchor position is the point at which a frame is
* bound to a text document. The defined values for the text:anchor-type
* attribute are;
*
* - as-char
* There is no anchor position. The drawing shape behaves like a
* character.
* - char
* The character after the drawing shape element.
* - frame
* The parent text box that the current drawing shape element is
* contained in.
* FIXME we don't support type frame
* - page
* The page that has the same physical page number as the value of the
* text:anchor-page-number attribute that is attached to the drawing
* shape element.
* - paragraph
* The paragraph that the current drawing shape element is contained in.
*/
AnchorType anchorType() const;
/**
* Set how the anchor behaves
*/
void setAnchorType(AnchorType type);
/// set the current vertical-pos
void setHorizontalPos(HorizontalPos);
/// return the current vertical-pos
HorizontalPos horizontalPos() const;
/// set the current vertical-rel
void setHorizontalRel(HorizontalRel);
/// return the current vertical-rel
HorizontalRel horizontalRel() const;
/// set the current horizontal-pos
void setVerticalPos(VerticalPos);
/// return the current horizontal-pos
VerticalPos verticalPos() const;
/// set the current horizontal-rel
void setVerticalRel(VerticalRel);
/// return the current horizontal-rel
VerticalRel verticalRel() const;
/// return the wrap influence on position
QString wrapInfluenceOnPosition() const;
/// return if flow-with-text (odf attribute)
bool flowWithText() const;
/// return the page number of the shape (valid with page anchoring, -1 indicates auto).
int pageNumber() const;
/// return the offset of the shape from the anchor.
const QPointF &offset() const;
/// set the new offset of the shape. Causes a new layout soon.
void setOffset(const QPointF &offset);
- /// Load the additional attributes.
- /// This will also make the shape invisible so it doesn't mess up any layout
- /// before it's ready to be placed where it belongs
- /// The textlayout should make it visible again
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context);
-
- /// Save the additional attributes.
- void saveOdf(KoShapeSavingContext &context) const;
-
/// Get extra data structure that is what is actually inside a text document
TextLocation *textLocation() const;
/// Set extra data structure that is what is actually inside a text document
/// We do NOT take ownership (may change in the future)
void setTextLocation(TextLocation *textLocation);
/// Get placement strategy which is used to position shape linked to text anchor
PlacementStrategy *placementStrategy() const;
/// Set placement strategy which is used to position shape linked to text anchor
/// We take owner ship and will make sure the strategy is deleted
void setPlacementStrategy(PlacementStrategy *placementStrategy);
private:
class Private;
Private * const d;
};
#endif
diff --git a/libs/flake/KoShapeBackground.h b/libs/flake/KoShapeBackground.h
index 51f2d762c1..a7065219f2 100644
--- a/libs/flake/KoShapeBackground.h
+++ b/libs/flake/KoShapeBackground.h
@@ -1,68 +1,56 @@
/* This file is part of the KDE project
* Copyright (C) 2008 Jan Hambrecht <jaham@gmx.net>
*
* 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 KOSHAPEBACKGROUND_H
#define KOSHAPEBACKGROUND_H
#include "kritaflake_export.h"
#include <QtGlobal>
class QSizeF;
class QPainter;
class QPainterPath;
-class KoGenStyle;
class KoShapeSavingContext;
-class KoOdfLoadingContext;
class KoShapePaintingContext;
/**
* This is the base class for shape backgrounds.
* Derived classes are used to paint the background of
* a shape within a given painter path.
*/
class KRITAFLAKE_EXPORT KoShapeBackground
{
public:
KoShapeBackground();
virtual ~KoShapeBackground();
/// Paints the background using the given fill path
virtual void paint(QPainter &painter, KoShapePaintingContext &context, const QPainterPath &fillPath) const = 0;
/// Returns if the background has some transparency.
virtual bool hasTransparency() const;
virtual bool compareTo(const KoShapeBackground *other) const = 0;
- /**
- * Fills the style object
- * @param style object
- * @param context used for saving
- */
- virtual void fillStyle(KoGenStyle &style, KoShapeSavingContext &context) = 0;
-
- /// load background from odf styles
- virtual bool loadStyle(KoOdfLoadingContext &context, const QSizeF &shapeSize) = 0;
-
virtual explicit operator bool() const { return true; }
};
#endif // KOSHAPEBACKGROUND_H
diff --git a/libs/flake/KoShapeController.cpp b/libs/flake/KoShapeController.cpp
index cd16569232..23fb99c4e4 100644
--- a/libs/flake/KoShapeController.cpp
+++ b/libs/flake/KoShapeController.cpp
@@ -1,212 +1,196 @@
/* This file is part of the KDE project
*
* Copyright (C) 2006-2007, 2010 Thomas Zander <zander@kde.org>
* Copyright (C) 2006-2008 Thorsten Zachmann <zachmann@kde.org>
* Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
*
* 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 "KoShapeController.h"
#include "KoShapeControllerBase.h"
#include "KoShapeRegistry.h"
#include "KoDocumentResourceManager.h"
#include "KoShapeManager.h"
#include "KoShapeLayer.h"
#include "KoSelection.h"
#include "commands/KoShapeCreateCommand.h"
#include "commands/KoShapeDeleteCommand.h"
-#include "commands/KoShapeConnectionChangeCommand.h"
#include "KoCanvasBase.h"
#include "KoShapeConfigWidgetBase.h"
#include "KoShapeFactoryBase.h"
#include "KoShape.h"
-#include "KoConnectionShape.h"
#include <KoUnit.h>
#include <QObject>
#include <kpagedialog.h>
#include <klocalizedstring.h>
class KoShapeController::Private
{
public:
Private()
: canvas(0),
shapeController(0)
{
}
KoCanvasBase *canvas;
KoShapeControllerBase *shapeController;
KUndo2Command* addShape(KoShape *shape, bool showDialog, KoShapeContainer *parentShape, KUndo2Command *parent) {
if (canvas) {
if (showDialog && !shape->shapeId().isEmpty()) {
KoShapeFactoryBase *factory = KoShapeRegistry::instance()->value(shape->shapeId());
Q_ASSERT(factory);
qint16 z = 0;
Q_FOREACH (KoShape *sh, canvas->shapeManager()->shapes()) {
z = qMax(z, sh->zIndex());
}
shape->setZIndex(z + 1);
// show config dialog.
KPageDialog *dialog = new KPageDialog(canvas->canvasWidget());
dialog->setWindowTitle(i18n("%1 Options", factory->name()));
int pageCount = 0;
QList<KoShapeConfigWidgetBase*> widgets;
Q_FOREACH (KoShapeConfigWidgetBase* panel, factory->createShapeOptionPanels()) {
if (! panel->showOnShapeCreate())
continue;
panel->open(shape);
panel->connect(panel, SIGNAL(accept()), dialog, SLOT(accept()));
widgets.append(panel);
panel->setResourceManager(canvas->resourceManager());
panel->setUnit(canvas->unit());
QString title = panel->windowTitle().isEmpty() ? panel->objectName() : panel->windowTitle();
dialog->addPage(panel, title);
pageCount ++;
}
if (pageCount > 0) {
if (pageCount > 1)
dialog->setFaceType(KPageDialog::Tabbed);
if (dialog->exec() != KPageDialog::Accepted) {
delete dialog;
return 0;
}
Q_FOREACH (KoShapeConfigWidgetBase *widget, widgets)
widget->save();
}
delete dialog;
}
}
return addShapesDirect({shape}, parentShape, parent);
}
KUndo2Command* addShapesDirect(const QList<KoShape*> shapes, KoShapeContainer *parentShape, KUndo2Command *parent)
{
- return new KoShapeCreateCommand(shapeController, shapes, parentShape, parent);
- }
-
- void handleAttachedConnections(KoShape *shape, KUndo2Command *parentCmd) {
- foreach (KoShape *dependee, shape->dependees()) {
- KoConnectionShape *connection = dynamic_cast<KoConnectionShape*>(dependee);
- if (connection) {
- if (shape == connection->firstShape()) {
- new KoShapeConnectionChangeCommand(connection, KoConnectionShape::StartHandle,
- shape, connection->firstConnectionId(), 0, -1, parentCmd);
- } else if (shape == connection->secondShape()) {
- new KoShapeConnectionChangeCommand(connection, KoConnectionShape::EndHandle,
- shape, connection->secondConnectionId(), 0, -1, parentCmd);
- }
- }
+ KUndo2Command *resultCommand = 0;
+
+ if (!parentShape) {
+ resultCommand = new KUndo2Command(parent);
+ parentShape = shapeController->createParentForShapes(shapes, resultCommand);
+ KUndo2Command *addShapeCommand = new KoShapeCreateCommand(shapeController, shapes, parentShape, resultCommand);
+ resultCommand->setText(addShapeCommand->text());
+ } else {
+ resultCommand = new KoShapeCreateCommand(shapeController, shapes, parentShape, parent);
}
+
+ return resultCommand;
}
};
KoShapeController::KoShapeController(KoCanvasBase *canvas, KoShapeControllerBase *shapeController)
: d(new Private())
{
d->canvas = canvas;
d->shapeController = shapeController;
}
KoShapeController::~KoShapeController()
{
delete d;
}
void KoShapeController::reset()
{
d->canvas = 0;
d->shapeController = 0;
}
KUndo2Command* KoShapeController::addShape(KoShape *shape, KoShapeContainer *parentShape, KUndo2Command *parent)
{
return d->addShape(shape, true, parentShape, parent);
}
KUndo2Command* KoShapeController::addShapeDirect(KoShape *shape, KoShapeContainer *parentShape, KUndo2Command *parent)
{
return d->addShapesDirect({shape}, parentShape, parent);
}
KUndo2Command *KoShapeController::addShapesDirect(const QList<KoShape *> shapes, KoShapeContainer *parentShape, KUndo2Command *parent)
{
return d->addShapesDirect(shapes, parentShape, parent);
}
KUndo2Command* KoShapeController::removeShape(KoShape *shape, KUndo2Command *parent)
{
- KUndo2Command *cmd = new KoShapeDeleteCommand(d->shapeController, shape, parent);
- QList<KoShape*> shapes;
- shapes.append(shape);
- d->shapeController->shapesRemoved(shapes, cmd);
- // detach shape from any attached connection shapes
- d->handleAttachedConnections(shape, cmd);
- return cmd;
+ return removeShapes({shape}, parent);
}
KUndo2Command* KoShapeController::removeShapes(const QList<KoShape*> &shapes, KUndo2Command *parent)
{
KUndo2Command *cmd = new KoShapeDeleteCommand(d->shapeController, shapes, parent);
- d->shapeController->shapesRemoved(shapes, cmd);
- foreach (KoShape *shape, shapes) {
- d->handleAttachedConnections(shape, cmd);
- }
return cmd;
}
void KoShapeController::setShapeControllerBase(KoShapeControllerBase *shapeController)
{
d->shapeController = shapeController;
}
QRectF KoShapeController::documentRectInPixels() const
{
return d->shapeController ? d->shapeController->documentRectInPixels() : QRectF(0,0,1920,1080);
}
qreal KoShapeController::pixelsPerInch() const
{
return d->shapeController ? d->shapeController->pixelsPerInch() : 72.0;
}
QRectF KoShapeController::documentRect() const
{
return d->shapeController ? d->shapeController->documentRect() : documentRectInPixels();
}
KoDocumentResourceManager *KoShapeController::resourceManager() const
{
if (!d->shapeController) {
qWarning() << "THIS IS NOT GOOD!";
return 0;
}
return d->shapeController->resourceManager();
}
KoShapeControllerBase *KoShapeController::documentBase() const
{
return d->shapeController;
}
diff --git a/libs/flake/KoShapeControllerBase.cpp b/libs/flake/KoShapeControllerBase.cpp
index ce0e445d25..824bf8cd3c 100644
--- a/libs/flake/KoShapeControllerBase.cpp
+++ b/libs/flake/KoShapeControllerBase.cpp
@@ -1,92 +1,92 @@
/* This file is part of the KDE project
Copyright (C) 2006, 2010 Thomas Zander <zander@kde.org>
Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
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 <QTransform>
#include <QPointer>
#include "KoShapeControllerBase.h"
#include "KoDocumentResourceManager.h"
#include "KoShapeRegistry.h"
#include "KoShapeFactoryBase.h"
#include <kconfig.h>
#include <kconfiggroup.h>
#include <ksharedconfig.h>
+#include <kundo2command.h>
class KoshapeControllerBasePrivate
{
public:
KoshapeControllerBasePrivate()
: resourceManager(new KoDocumentResourceManager())
{
KoShapeRegistry *registry = KoShapeRegistry::instance();
foreach (const QString &id, registry->keys()) {
KoShapeFactoryBase *shapeFactory = registry->value(id);
shapeFactory->newDocumentResourceManager(resourceManager);
}
// read persistent application wide resources
KSharedConfigPtr config = KSharedConfig::openConfig();
KConfigGroup miscGroup = config->group("Misc");
const uint grabSensitivity = miscGroup.readEntry("GrabSensitivity", 10);
resourceManager->setGrabSensitivity(grabSensitivity);
const uint handleRadius = miscGroup.readEntry("HandleRadius", 5);
resourceManager->setHandleRadius(handleRadius);
}
~KoshapeControllerBasePrivate()
{
delete resourceManager;
}
QPointer<KoDocumentResourceManager> resourceManager;
};
KoShapeControllerBase::KoShapeControllerBase()
: d(new KoshapeControllerBasePrivate())
{
}
KoShapeControllerBase::~KoShapeControllerBase()
{
delete d;
}
-void KoShapeControllerBase::addShape(KoShape *shape)
+KoShapeContainer* KoShapeControllerBase::createParentForShapes(const QList<KoShape*> shapes, KUndo2Command *parentCommand)
{
- addShapes({shape});
-}
+ Q_UNUSED(parentCommand);
+ Q_UNUSED(shapes);
-void KoShapeControllerBase::shapesRemoved(const QList<KoShape*> & /*shapes*/, KUndo2Command * /*command*/)
-{
+ return 0;
}
KoDocumentResourceManager *KoShapeControllerBase::resourceManager() const
{
return d->resourceManager;
}
QRectF KoShapeControllerBase::documentRect() const
{
const qreal pxToPt = 72.0 / pixelsPerInch();
QTransform t = QTransform::fromScale(pxToPt, pxToPt);
return t.mapRect(documentRectInPixels());
}
diff --git a/libs/flake/KoShapeControllerBase.h b/libs/flake/KoShapeControllerBase.h
index f14eee34a5..6491dfa700 100644
--- a/libs/flake/KoShapeControllerBase.h
+++ b/libs/flake/KoShapeControllerBase.h
@@ -1,110 +1,88 @@
/* This file is part of the KDE project
Copyright (C) 2006 Jan Hambrecht <jaham@gmx.net>
Copyright (C) 2006, 2010 Thomas Zander <zander@kde.org>
Copyright (C) 2008 C. Boemann <cbo@boemann.dk>
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 KOshapeControllerBASE_H
#define KOshapeControllerBASE_H
#include "kritaflake_export.h"
#include <QList>
class QRectF;
class KoShape;
+class KoShapeContainer;
class KoshapeControllerBasePrivate;
class KoDocumentResourceManager;
class KUndo2Command;
/**
* The KoshapeControllerBase is an abstract interface that the application's class
* that owns the shapes should implement. This tends to be the document.
* @see KoShapeDeleteCommand, KoShapeCreateCommand
*/
class KRITAFLAKE_EXPORT KoShapeControllerBase
{
public:
KoShapeControllerBase();
virtual ~KoShapeControllerBase();
/**
- * Add a shape to the shape controller, allowing it to be seen and saved.
- * The controller should add the shape to the ShapeManager instance(s) manually
- * if the shape is one that should be currently shown on screen.
- * @param shape the new shape
- */
- void addShape(KoShape *shape);
-
- /**
- * Add shapes to the shape controller, allowing it to be seen and saved.
- * The controller should add the shape to the ShapeManager instance(s) manually
- * if the shape is one that should be currently shown on screen.
- * @param shapes the shapes to add
- */
- virtual void addShapes(const QList<KoShape*> shapes) = 0;
-
- /**
- * Remove a shape from the shape controllers control, allowing it to be deleted shortly after
- * The controller should remove the shape from all the ShapeManager instance(s) manually
- * @param shape the shape to remove
- */
- virtual void removeShape(KoShape *shape) = 0;
-
- /**
- * This method gets called after the KoShapeDeleteCommand is executed
+ * When shapes are dropped to the canvas, the document should decide, where to
+ * which parent to put them. In some cases the document should even create a
+ * special layer for the new \p shapes.
*
- * This passes the KoShapeDeleteCommand as the command parameter. This makes it possible
- * for applications that need to do something after the KoShapeDeleteCommand is done, e.g.
- * adding one commands that need to be executed when a shape was deleted.
- * The default implementation is empty.
- * @param shapes The list of shapes that got removed.
- * @param command The command that was used to remove the shapes from the document.
+ * \return the proposed parent for \p shapes
+ * \param parentCommand the command, which should be executed before the
+ * proposed parent will be added to the document (if
+ * new layer should be created)
*/
- virtual void shapesRemoved(const QList<KoShape*> &shapes, KUndo2Command *command);
+ virtual KoShapeContainer* createParentForShapes(const QList<KoShape*> shapes, KUndo2Command *parentCommand);
/**
* Return a pointer to the resource manager associated with the
* shape-set (typically a document). The resource manager contains
* document wide resources * such as variable managers, the image
* collection and others.
*/
virtual KoDocumentResourceManager *resourceManager() const;
/**
* The size of the document measured in rasterized pixels. This information is needed for loading
* SVG documents that use 'px' as the default unit.
*/
virtual QRectF documentRectInPixels() const = 0;
/**
* The size of the document measured in 'pt'
*/
QRectF documentRect() const;
/**
* Resolution of the rasterized representation of the document. Used to load SVG documents correctly.
*/
virtual qreal pixelsPerInch() const = 0;
private:
KoshapeControllerBasePrivate * const d;
};
#endif
diff --git a/libs/flake/KoShapeFactoryBase.cpp b/libs/flake/KoShapeFactoryBase.cpp
index 476817a5e5..8244cd0859 100644
--- a/libs/flake/KoShapeFactoryBase.cpp
+++ b/libs/flake/KoShapeFactoryBase.cpp
@@ -1,259 +1,248 @@
/* This file is part of the KDE project
* Copyright (c) 2006 Boudewijn Rempt (boud@valdyas.org)
* Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
* Copyright (C) 2008 C. Boemann <cbo@boemann.dk>
* Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
*
* 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 "KoShapeFactoryBase.h"
#include <QDebug>
#include "KoDocumentResourceManager.h"
#include "KoDeferredShapeFactoryBase.h"
#include "KoShape.h"
#include "KoShapeLoadingContext.h"
-#include <KoOdfLoadingContext.h>
#include <KoProperties.h>
-#include <KoStyleStack.h>
#include <KoJsonTrader.h>
#include <KPluginFactory>
#include <QPluginLoader>
#include <QMutexLocker>
#include <QMutex>
#include <QPointer>
#include <FlakeDebug.h>
class Q_DECL_HIDDEN KoShapeFactoryBase::Private
{
public:
Private(const QString &_id, const QString &_name, const QString &_deferredPluginName)
: deferredFactory(0),
deferredPluginName(_deferredPluginName),
id(_id),
name(_name),
loadingPriority(0),
hidden(false)
{
}
~Private() {
Q_FOREACH (const KoShapeTemplate & t, templates)
delete t.properties;
templates.clear();
}
KoDeferredShapeFactoryBase *deferredFactory;
QMutex pluginLoadingMutex;
QString deferredPluginName;
QList<KoShapeTemplate> templates;
const QString id;
const QString name;
QString family;
QString tooltip;
QString iconName;
int loadingPriority;
QList<QPair<QString, QStringList> > xmlElements; // xml name space -> xml element names
bool hidden;
QList<QPointer<KoDocumentResourceManager> > resourceManagers;
};
KoShapeFactoryBase::KoShapeFactoryBase(const QString &id, const QString &name, const QString &deferredPluginName)
: d(new Private(id, name, deferredPluginName))
{
}
KoShapeFactoryBase::~KoShapeFactoryBase()
{
delete d;
}
QString KoShapeFactoryBase::toolTip() const
{
return d->tooltip;
}
QString KoShapeFactoryBase::iconName() const
{
return d->iconName;
}
QString KoShapeFactoryBase::name() const
{
return d->name;
}
QString KoShapeFactoryBase::family() const
{
return d->family;
}
int KoShapeFactoryBase::loadingPriority() const
{
return d->loadingPriority;
}
QList<QPair<QString, QStringList> > KoShapeFactoryBase::odfElements() const
{
return d->xmlElements;
}
void KoShapeFactoryBase::addTemplate(const KoShapeTemplate &params)
{
KoShapeTemplate tmplate = params;
tmplate.id = d->id;
d->templates.append(tmplate);
}
void KoShapeFactoryBase::setToolTip(const QString & tooltip)
{
d->tooltip = tooltip;
}
void KoShapeFactoryBase::setIconName(const char *iconName)
{
d->iconName = QLatin1String(iconName);
}
void KoShapeFactoryBase::setFamily(const QString & family)
{
d->family = family;
}
QString KoShapeFactoryBase::id() const
{
return d->id;
}
QList<KoShapeTemplate> KoShapeFactoryBase::templates() const
{
return d->templates;
}
void KoShapeFactoryBase::setLoadingPriority(int priority)
{
d->loadingPriority = priority;
}
void KoShapeFactoryBase::setXmlElementNames(const QString & nameSpace, const QStringList & names)
{
d->xmlElements.clear();
d->xmlElements.append(QPair<QString, QStringList>(nameSpace, names));
}
void KoShapeFactoryBase::setXmlElements(const QList<QPair<QString, QStringList> > &elementNamesList)
{
d->xmlElements = elementNamesList;
}
bool KoShapeFactoryBase::hidden() const
{
return d->hidden;
}
void KoShapeFactoryBase::setHidden(bool hidden)
{
d->hidden = hidden;
}
void KoShapeFactoryBase::newDocumentResourceManager(KoDocumentResourceManager *manager) const
{
d->resourceManagers.append(manager);
connect(manager, SIGNAL(destroyed(QObject*)), this, SLOT(pruneDocumentResourceManager(QObject*)));
}
KoShape *KoShapeFactoryBase::createDefaultShape(KoDocumentResourceManager *documentResources) const
{
if (!d->deferredPluginName.isEmpty()) {
const_cast<KoShapeFactoryBase*>(this)->getDeferredPlugin();
Q_ASSERT(d->deferredFactory);
if (d->deferredFactory) {
return d->deferredFactory->createDefaultShape(documentResources);
}
}
return 0;
}
KoShape *KoShapeFactoryBase::createShape(const KoProperties* properties,
KoDocumentResourceManager *documentResources) const
{
if (!d->deferredPluginName.isEmpty()) {
const_cast<KoShapeFactoryBase*>(this)->getDeferredPlugin();
Q_ASSERT(d->deferredFactory);
if (d->deferredFactory) {
return d->deferredFactory->createShape(properties, documentResources);
}
}
return createDefaultShape(documentResources);
}
-KoShape *KoShapeFactoryBase::createShapeFromOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
+KoShape *KoShapeFactoryBase::createShapeFromXML(const KoXmlElement &element, KoShapeLoadingContext &context)
{
KoShape *shape = createDefaultShape(context.documentResourceManager());
if (!shape)
return 0;
if (shape->shapeId().isEmpty())
shape->setShapeId(id());
- context.odfLoadingContext().styleStack().save();
- bool loaded = shape->loadOdf(element, context);
- context.odfLoadingContext().styleStack().restore();
-
- if (!loaded) {
- delete shape;
- return 0;
- }
-
return shape;
}
void KoShapeFactoryBase::getDeferredPlugin()
{
QMutexLocker(&d->pluginLoadingMutex);
if (d->deferredFactory) return;
const QList<QPluginLoader *> offers = KoJsonTrader::instance()->query("Krita/Deferred", QString());
Q_ASSERT(offers.size() > 0);
Q_FOREACH (QPluginLoader *pluginLoader, offers) {
KPluginFactory *factory = qobject_cast<KPluginFactory *>(pluginLoader->instance());
KoDeferredShapeFactoryBase *plugin = factory->create<KoDeferredShapeFactoryBase>(this, QVariantList());
if (plugin && plugin->deferredPluginName() == d->deferredPluginName) {
d->deferredFactory = plugin;
}
}
qDeleteAll(offers);
}
void KoShapeFactoryBase::pruneDocumentResourceManager(QObject *)
{
QList<QPointer<KoDocumentResourceManager> > rms;
Q_FOREACH(QPointer<KoDocumentResourceManager> rm, d->resourceManagers) {
if (rm) {
rms << rm;
}
}
d->resourceManagers = rms;
}
diff --git a/libs/flake/KoShapeFactoryBase.h b/libs/flake/KoShapeFactoryBase.h
index 7744cefffa..221b43841d 100644
--- a/libs/flake/KoShapeFactoryBase.h
+++ b/libs/flake/KoShapeFactoryBase.h
@@ -1,304 +1,304 @@
/* This file is part of the KDE project
* Copyright (c) 2006 Boudewijn Rempt (boud@valdyas.org)
* Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
* Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
*
* 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 KOSHAPEFACTORYBASE_H
#define KOSHAPEFACTORYBASE_H
#include <QObject>
#include <QString>
#include <QList>
#include "kritaflake_export.h"
#include <KoXmlReader.h>
class KoShape;
class KoProperties;
class KoShapeConfigWidgetBase;
class KoShapeLoadingContext;
class KoDocumentResourceManager;
class QStringList;
#define SHAPETEMPLATE_MIMETYPE "application/x-flake-shapetemplate"
#define SHAPEID_MIMETYPE "application/x-flake-shapeId"
/**
* Contains a KoProperties object that describes the settings of a
* particular variant of a shape object, together with a name, a description
* and an icon for use in the user interface.
*/
struct KRITAFLAKE_EXPORT KoShapeTemplate {
KoShapeTemplate() {
properties = 0;
}
QString id; ///< The id of the shape
QString templateId; ///< The id of this particular template - only has to be unique with the shape
QString name; ///< The name to be shown for this template
QString family; ///< The family of the shape (possible values are: "funny","arrow")
QString toolTip; ///< The tooltip text for the template
QString iconName; ///< Icon name
/**
* The properties which, when passed to the KoShapeFactoryBase::createShape() method
* result in the shape this template represents.
*/
const KoProperties *properties;
};
/**
* A factory for KoShape objects.
* The baseclass for all shape plugins. Each plugin that ships a KoShape should also
* ship a factory. That factory will extend this class and set variable data like
* a toolTip and icon in the constructor of that extending class.
*
* An example usage would be:
@code
class MyShapeFactory : public KoShapeFactoryBase {
public:
MyShapeFactory()
: KoShapeFactoryBase("MyShape", i18n("My Shape")) {
setToolTip(i18n("A nice shape"));
}
~MyShapeFactory() {}
// more methods here
};
@endcode
* After you created the factory you should create a plugin that can announce the factory to the
* KoShapeRegistry. See the KoPluginLoader as well.
*/
class KRITAFLAKE_EXPORT KoShapeFactoryBase : public QObject
{
Q_OBJECT
public:
/**
* Create the new factory
* @param id a string that will be used internally for referencing the shape, for
* example for use by the KoToolBase::activateTemporary.
* @param name the user visible name of the shape this factory creates.
*/
KoShapeFactoryBase(const QString &id, const QString &name, const QString &deferredPluginName = QString());
~KoShapeFactoryBase() override;
/**
* Create a list of option panels to show on creating a new shape.
* The shape type this factory creates may have general or specific setting panels
* that will be shown after inserting a new shape.
* The first item in the list will be shown as the first tab in the list of panels,
* behind all app specific panels.
* This is a separate list as set by setOptionPanels() and fetched by panelFactories()
*/
virtual QList<KoShapeConfigWidgetBase*> createShapeOptionPanels() {
return QList<KoShapeConfigWidgetBase*>();
}
/**
* return the id for the shape this factory creates.
* @return the id for the shape this factory creates.
*/
QString id() const;
/**
* Return all the templates this factory knows about.
* Each template shows a different way to create a shape this factory is specialized in.
*/
QList<KoShapeTemplate> templates() const;
/**
* return a translated tooltip Text for a selector of shapes
* @return a translated tooltip Text
*/
QString toolTip() const;
/**
* return the basename of the icon for a selector of shapes
* @return the basename of the icon for a selector of shapes
*/
QString iconName() const;
/**
* return the user visible (and translated) name to be seen by the user.
* @return the user visible (and translated) name to be seen by the user.
*/
QString name() const;
/**
* return the non-visible name of the family the default shape belongs to.
* @return the family name.
*/
QString family() const;
/// lower prio means the shape is more generic and will be checked later
int loadingPriority() const;
/**
* The list of namespaces to the supported elements the factory supports.
*/
QList<QPair<QString, QStringList> > odfElements() const;
/// returns true if this shapeFactory is able to load the ODF type
/// started at argument element. ('draw:line' / 'draw:frame' / etc)
virtual bool supports(const KoXmlElement &element, KoShapeLoadingContext &context) const = 0;
/**
* The hidden boolean requests if the shape should be hidden in the
* shape selector or shown with all its templates.
* The default is false
* @see setHidden()
*/
bool hidden() const;
/**
* This method is called whenever there is a new document resource
* manager that is created. The factory may reimplement this in
* order to get existing resources or put factory specific resources in.
* In case the factory creates new resources it is advised to parent
* them to the manager (which is a QObject) for memory management
* purposes.
*
* FIXME: this method is only used by Tables. We should refactor so
* it is no longer necessary.
*
* NOTE: this actually is also used somehow to create the imagecollection
* for the picture shape?
*
* NOTE: we store the documentmanagers in a list, and remove them
* from the list on delete.
*
* @param manager the new manager
*/
virtual void newDocumentResourceManager(KoDocumentResourceManager *manager) const;
/**
* This method should be implemented by factories to create a shape that the user
* gets when doing a base insert. For example from a script. The created shape
* should have its values set to good defaults that the user can then adjust further if
* needed. Including the KoShape:setShapeId(), with the Id from this factory
* The default shape position is not relevant, it will be moved by the caller.
* @param documentResources the resources manager that has all the document wide
* resources which can be used to create the object.
* @return a new shape
* @see createShape() newDocumentResourceManager()
*/
virtual KoShape *createDefaultShape(KoDocumentResourceManager *documentResources = 0) const;
/**
* This method should be implemented by factories to create a shape based on a set of
* properties that are specifically made for this shape-type.
* This method should also set this factories shapeId on the shape using KoShape::setShapeId()
* The default implementation just ignores 'params' and calls createDefaultShape()
* @return a new shape
* @param params the parameters to use when creating the shape
* @param documentResources the resources manager that has all the document wide
* resources which can be used to create the object.
* @see createDefaultShape() newDocumentResourceManager() addTemplate()
* @see KoShapeTemplate::properties
*/
virtual KoShape *createShape(const KoProperties *params, KoDocumentResourceManager *documentResources = 0) const;
/**
* This method provides the default implementation for creating a shape
* from a specified xml element of an odf document.
* Most derived factories do not need to reimplement this method, however if a factory
* has some special requirements or does something special it is still possible.
* One example is creating different shapes depending on the content of the passed
* xml element.
*/
- virtual KoShape *createShapeFromOdf(const KoXmlElement &element, KoShapeLoadingContext &context);
+ virtual KoShape *createShapeFromXML(const KoXmlElement &element, KoShapeLoadingContext &context);
protected:
/**
* Add a template with the properties of a specific type of shape this factory can generate
* using the createShape() method. The factory will take ownership of the properties object
* to which the member @p properties of @p params points to and destroy it only in its own destructor.
* @param params the new template this factory knows to produce
*/
void addTemplate(const KoShapeTemplate &params);
/**
* Set the tooltip to be used for a selector of shapes
* @param tooltip the tooltip
*/
void setToolTip(const QString &tooltip);
/**
* Set an icon to be used in a selector of shapes
* @param iconName the basename (without extension) of the icon
*/
void setIconName(const char *iconName);
/**
* Set the family name of the default shape
* @param family the family name of the default shape this factory creates.
* for example "funny", "arrows", "geometrics". Use "" for default
*/
void setFamily(const QString &family);
/**
* Set the loading priority for this icon; higher priority means
* the shape is more specific which means it will be earlier in
* the queue to try loading a particular odf element.
*/
void setLoadingPriority(int priority);
/**
* Set the namespace and element tags used for quick checking whether this shapefactory
* is able to create a shape from xml identified by this element
* name.
*
* @param nameSpace the ODF name space (like
* urn:oasis:names:tc:opendocument:xmlns:text:1.0,
* take it from KoXmlNS.h)
* @param elementNames the name of the element itself, like "path"
*
*/
void setXmlElementNames(const QString &nameSpace, const QStringList &elementNames);
/**
* Set the namespaces and according element tags used for quick checking whether this shapefactory
* is able to create a shape from xml identified by this element
* name.
*
* @param elementNamesList containing a list of namespace (like
* urn:oasis:names:tc:opendocument:xmlns:text:1.0,
* take it from KoXmlNS.h) to a list of elementName of the element itself, like "path"
*/
void setXmlElements(const QList<QPair<QString, QStringList> > &elementNamesList);
/**
* The hidden boolean requests if the shape should be hidden in the
* shape selector or shown with all its templates.
* The default is false
* @see hidden()
*/
void setHidden(bool hidden);
private:
void getDeferredPlugin();
private Q_SLOTS:
/// called whenever a document KoDocumentResourceManager is deleted
void pruneDocumentResourceManager(QObject *);
private:
class Private;
Private * const d;
};
#endif
diff --git a/libs/flake/KoShapeGroup.cpp b/libs/flake/KoShapeGroup.cpp
index 28ee45da2a..34403b4c25 100644
--- a/libs/flake/KoShapeGroup.cpp
+++ b/libs/flake/KoShapeGroup.cpp
@@ -1,276 +1,212 @@
/* This file is part of the KDE project
* Copyright (C) 2006 Thomas Zander <zander@kde.org>
* Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
*
* 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 "KoShapeGroup.h"
#include "KoShapeContainerModel.h"
#include "KoShapeContainer_p.h"
#include "KoShapeLayer.h"
#include "SimpleShapeContainerModel.h"
#include "KoShapeSavingContext.h"
#include "KoShapeLoadingContext.h"
#include "KoXmlWriter.h"
#include "KoXmlReader.h"
#include "KoShapeRegistry.h"
#include "KoShapeStrokeModel.h"
#include "KoShapeShadow.h"
#include "KoInsets.h"
#include <FlakeDebug.h>
#include <QPainter>
class ShapeGroupContainerModel : public SimpleShapeContainerModel
{
public:
ShapeGroupContainerModel(KoShapeGroup *group) : m_group(group) {}
~ShapeGroupContainerModel() override {}
ShapeGroupContainerModel(const ShapeGroupContainerModel &rhs, KoShapeGroup *group)
: SimpleShapeContainerModel(rhs),
m_group(group)
{
}
void add(KoShape *child) override
{
SimpleShapeContainerModel::add(child);
m_group->invalidateSizeCache();
}
void remove(KoShape *child) override
{
SimpleShapeContainerModel::remove(child);
m_group->invalidateSizeCache();
}
void childChanged(KoShape *shape, KoShape::ChangeType type) override
{
SimpleShapeContainerModel::childChanged(shape, type);
//debugFlake << type;
switch (type) {
case KoShape::PositionChanged:
case KoShape::RotationChanged:
case KoShape::ScaleChanged:
case KoShape::ShearChanged:
case KoShape::SizeChanged:
case KoShape::GenericMatrixChange:
case KoShape::ParameterChanged:
case KoShape::ClipPathChanged :
case KoShape::ClipMaskChanged :
m_group->invalidateSizeCache();
break;
default:
break;
}
}
private: // members
KoShapeGroup * m_group;
};
class KoShapeGroup::Private
{
public:
Private() {}
Private(const Private &) {}
virtual ~Private() = default;
mutable QRectF savedOutlineRect;
mutable bool sizeCached = false;
};
KoShapeGroup::KoShapeGroup()
: KoShapeContainer()
, d(new Private)
{
setModelInit(new ShapeGroupContainerModel(this));
}
KoShapeGroup::KoShapeGroup(const KoShapeGroup &rhs)
: KoShapeContainer(rhs)
, d(new Private(*rhs.d))
{
ShapeGroupContainerModel *otherModel = dynamic_cast<ShapeGroupContainerModel*>(rhs.model());
KIS_ASSERT_RECOVER_RETURN(otherModel);
setModelInit(new ShapeGroupContainerModel(*otherModel, this));
}
KoShapeGroup::~KoShapeGroup()
{
/**
* HACK alert: model will use KoShapeGroup::invalidateSizeCache(), which uses
* KoShapeGroup's d-pointer. We have to manually remove child shapes from the
* model in the destructor of KoShapeGroup as the instance d is no longer accessible
* since ~KoShapeGroup() is executed
*/
model()->deleteOwnedShapes();
}
KoShape *KoShapeGroup::cloneShape() const
{
return new KoShapeGroup(*this);
}
void KoShapeGroup::paintComponent(QPainter &painter, KoShapePaintingContext &) const
{
Q_UNUSED(painter);
}
bool KoShapeGroup::hitTest(const QPointF &position) const
{
Q_UNUSED(position);
return false;
}
void KoShapeGroup::tryUpdateCachedSize() const
{
if (!d->sizeCached) {
QRectF bound;
Q_FOREACH (KoShape *shape, shapes()) {
bound |= shape->transformation().mapRect(shape->outlineRect());
}
d->savedOutlineRect = bound;
KoShape::setSizeImpl(bound.size());
d->sizeCached = true;
}
}
QSizeF KoShapeGroup::size() const
{
tryUpdateCachedSize();
return KoShape::size();
}
void KoShapeGroup::setSize(const QSizeF &size)
{
QSizeF oldSize = this->size();
if (!shapeCount() || oldSize.isNull()) return;
const QTransform scale =
QTransform::fromScale(size.width() / oldSize.width(), size.height() / oldSize.height());
setTransformation(scale * transformation());
KoShapeContainer::setSize(size);
}
QRectF KoShapeGroup::outlineRect() const
{
tryUpdateCachedSize();
return d->savedOutlineRect;
}
QRectF KoShapeGroup::boundingRect() const
{
QRectF groupBound = KoShape::boundingRect(shapes());
if (shadow()) {
KoInsets insets;
shadow()->insets(insets);
groupBound.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
}
return groupBound;
}
-void KoShapeGroup::saveOdf(KoShapeSavingContext & context) const
-{
- context.xmlWriter().startElement("draw:g");
- saveOdfAttributes(context, (OdfMandatories ^ (OdfLayer | OdfZIndex)) | OdfAdditionalAttributes);
- context.xmlWriter().addAttribute("svg:y", position().y());
-
- QList<KoShape*> shapes = this->shapes();
- std::sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
-
- Q_FOREACH (KoShape* shape, shapes) {
- shape->saveOdf(context);
- }
-
- saveOdfCommonChildElements(context);
- context.xmlWriter().endElement();
-}
-
-bool KoShapeGroup::loadOdf(const KoXmlElement & element, KoShapeLoadingContext &context)
-{
- loadOdfAttributes(element, context, OdfMandatories | OdfStyle | OdfAdditionalAttributes | OdfCommonChildElements);
-
- KoXmlElement child;
- QMap<KoShapeLayer*, int> usedLayers;
- forEachElement(child, element) {
- KoShape * shape = KoShapeRegistry::instance()->createShapeFromOdf(child, context);
- if (shape) {
- KoShapeLayer *layer = dynamic_cast<KoShapeLayer*>(shape->parent());
- if (layer) {
- usedLayers[layer]++;
- }
- addShape(shape);
- }
- }
- KoShapeLayer *parent = 0;
- int maxUseCount = 0;
- // find most used layer and use this as parent for the group
- for (QMap<KoShapeLayer*, int>::const_iterator it(usedLayers.constBegin()); it != usedLayers.constEnd(); ++it) {
- if (it.value() > maxUseCount) {
- maxUseCount = it.value();
- parent = it.key();
- }
- }
- setParent(parent);
-
- QRectF bound;
- bool boundInitialized = false;
- Q_FOREACH (KoShape * shape, shapes()) {
- if (! boundInitialized) {
- bound = shape->boundingRect();
- boundInitialized = true;
- } else
- bound = bound.united(shape->boundingRect());
- }
-
- setSize(bound.size());
- d->sizeCached = true;
- setPosition(bound.topLeft());
-
- Q_FOREACH (KoShape * shape, shapes())
- shape->setAbsolutePosition(shape->absolutePosition() - bound.topLeft());
-
- return true;
-}
-
void KoShapeGroup::shapeChanged(ChangeType type, KoShape *shape)
{
Q_UNUSED(shape);
KoShapeContainer::shapeChanged(type, shape);
switch (type) {
case KoShape::StrokeChanged:
break;
default:
break;
}
invalidateSizeCache();
}
void KoShapeGroup::invalidateSizeCache()
{
d->sizeCached = false;
}
diff --git a/libs/flake/KoShapeGroup.h b/libs/flake/KoShapeGroup.h
index 3da60e2e43..cb4253036e 100644
--- a/libs/flake/KoShapeGroup.h
+++ b/libs/flake/KoShapeGroup.h
@@ -1,96 +1,92 @@
/* This file is part of the KDE project
* Copyright (C) 2006 Thomas Zander <zander@kde.org>
*
* 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 KOSHAPEGROUP_H
#define KOSHAPEGROUP_H
#include "KoShapeContainer.h"
#include <QList>
#include "kritaflake_export.h"
class KoShapeSavingContext;
class KoShapeLoadingContext;
class KoShapeGroupPrivate;
/**
* Provide grouping for shapes.
* The group shape allows you to add children which will then be grouped in selections
* and actions.
* <p>If you have a set of shapes that together make up a bigger shape it is often
* useful to group them together so the user will perceive the different shapes as
* actually being one. This means that if the user clicks on one shape, all shapes
* in the group will be selected at once, making the tools that works on
* selections alter all of them at the same time.
*
* <p>Note that while this object is also a shape, it is not actually visible and the user
* can't interact with it.
*
* <p>WARNING: this class is NOT threadsafe, it caches the size in an unsafe way
*/
class KRITAFLAKE_EXPORT KoShapeGroup : public KoShapeContainer
{
public:
/// Constructor
KoShapeGroup();
/// destructor
~KoShapeGroup() override;
KoShape* cloneShape() const override;
/// This implementation is empty since a group is itself not visible.
void paintComponent(QPainter &painter, KoShapePaintingContext &paintcontext) const override;
/// always returns false since the group itself can't be selected or hit
bool hitTest(const QPointF &position) const override;
QSizeF size() const override;
void setSize(const QSizeF &size) override;
QRectF outlineRect() const override;
/// a group's boundingRect
QRectF boundingRect() const override;
- /// reimplemented from KoShape
- void saveOdf(KoShapeSavingContext &context) const override;
- // reimplemented
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
private:
friend class ShapeGroupContainerModel;
/**
* @brief Invalidate the size cache of the group
*
* The group shape caches the size of itself as it can be quite expensive to recalculate
* the size if there are a lot of subshapes. This function is called when the cache needs
* to be invalidated.
*/
void invalidateSizeCache();
private:
KoShapeGroup(const KoShapeGroup &rhs);
private:
void tryUpdateCachedSize() const;
void shapeChanged(ChangeType type, KoShape *shape = 0) override;
class Private;
QScopedPointer<Private> d;
};
#endif
diff --git a/libs/flake/KoShapeLayer.cpp b/libs/flake/KoShapeLayer.cpp
index 1a11b5f6f4..d511c0c256 100644
--- a/libs/flake/KoShapeLayer.cpp
+++ b/libs/flake/KoShapeLayer.cpp
@@ -1,81 +1,56 @@
/* This file is part of the KDE project
Copyright (C) 2006-2007 Jan Hambrecht <jaham@gmx.net>
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 "KoShapeLayer.h"
#include <QRectF>
#include "SimpleShapeContainerModel.h"
#include "KoShapeSavingContext.h"
#include "KoShapeLoadingContext.h"
#include <KoXmlReader.h>
#include <KoXmlWriter.h>
#include <KoXmlNS.h>
KoShapeLayer::KoShapeLayer()
: KoShapeContainer(new SimpleShapeContainerModel())
{
setSelectable(false);
}
KoShapeLayer::KoShapeLayer(KoShapeContainerModel *model)
: KoShapeContainer(model)
{
setSelectable(false);
}
bool KoShapeLayer::hitTest(const QPointF &position) const
{
Q_UNUSED(position);
return false;
}
QRectF KoShapeLayer::boundingRect() const
{
return KoShape::boundingRect(shapes());
}
-void KoShapeLayer::saveOdf(KoShapeSavingContext & context) const
-{
- QList<KoShape*> shapes = this->shapes();
- std::sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
-
- Q_FOREACH (KoShape* shape, shapes) {
- shape->saveOdf(context);
- }
-}
-
-bool KoShapeLayer::loadOdf(const KoXmlElement & element, KoShapeLoadingContext &context)
-{
- // set layer name
- setName(element.attributeNS(KoXmlNS::draw, "name"));
- // layer locking
- setGeometryProtected(element.attributeNS(KoXmlNS::draw, "protected", "false") == "true");
- // layer visibility
- setVisible(element.attributeNS(KoXmlNS::draw, "display", "false") != "none");
-
- // add layer by name into shape context
- context.addLayer(this, name());
-
- return true;
-}
-
void KoShapeLayer::paintComponent(QPainter &, KoShapePaintingContext &) const
{
}
diff --git a/libs/flake/KoShapeLayer.h b/libs/flake/KoShapeLayer.h
index a9208a6143..63ec15f917 100644
--- a/libs/flake/KoShapeLayer.h
+++ b/libs/flake/KoShapeLayer.h
@@ -1,54 +1,52 @@
/* This file is part of the KDE project
Copyright (C) 2006-2007 Jan Hambrecht <jaham@gmx.net>
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 __KOSHAPELAYER_H__
#define __KOSHAPELAYER_H__
#include "KoShapeContainer.h"
#include "kritaflake_export.h"
/**
* Provides arranging shapes into layers.
* This makes it possible to have a higher key of a number of objects
* in a document.
* A layer is always invisible and unselectable.
*/
class KRITAFLAKE_EXPORT KoShapeLayer : public KoShapeContainer
{
public:
/// The default constructor
KoShapeLayer();
/**
* Constructor with custom model
* @param model the custom modem
*/
explicit KoShapeLayer(KoShapeContainerModel *model);
/**
* Empty implementation, as the layer itself is not visible
*/
void paintComponent(QPainter &painter, KoShapePaintingContext &paintcontext) const override;
bool hitTest(const QPointF &position) const override;
QRectF boundingRect() const override;
- void saveOdf(KoShapeSavingContext & context) const override;
- bool loadOdf(const KoXmlElement & element, KoShapeLoadingContext &context) override;
};
#endif // __KOSHAPELAYER_H__
diff --git a/libs/flake/KoShapeLoadingContext.cpp b/libs/flake/KoShapeLoadingContext.cpp
index 6d6d45ff5e..7e18c6635d 100644
--- a/libs/flake/KoShapeLoadingContext.cpp
+++ b/libs/flake/KoShapeLoadingContext.cpp
@@ -1,221 +1,207 @@
/* This file is part of the KDE project
Copyright (C) 2007-2009, 2011 Thorsten Zachmann <zachmann@kde.org>
Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
Copyright (C) 2014-2015 Denis Kuplyakov <dener.kup@gmail.com>
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 "KoShapeLoadingContext.h"
#include "KoShape.h"
#include "KoShapeContainer.h"
#include "KoSharedLoadingData.h"
#include "KoShapeControllerBase.h"
#include "KoImageCollection.h"
#include "KoMarkerCollection.h"
#include "KoDocumentResourceManager.h"
#include "KoLoadingShapeUpdater.h"
#include <FlakeDebug.h>
uint qHash(const KoShapeLoadingContext::AdditionalAttributeData & attributeData)
{
return qHash(attributeData.name);
}
static QSet<KoShapeLoadingContext::AdditionalAttributeData> s_additionlAttributes;
class Q_DECL_HIDDEN KoShapeLoadingContext::Private
{
public:
- Private(KoOdfLoadingContext &c, KoDocumentResourceManager *resourceManager)
- : context(c)
+ Private(KoStore *store, KoDocumentResourceManager *resourceManager)
+ : store(store)
, zIndex(0)
, documentResources(resourceManager)
- , documentRdf(0)
, sectionModel(0)
{
}
~Private() {
Q_FOREACH (KoSharedLoadingData * data, sharedData) {
delete data;
}
}
- KoOdfLoadingContext &context;
+ KoStore *store;
+
QMap<QString, KoShapeLayer*> layers;
QMap<QString, KoShape*> drawIds;
QMap<QString, QPair<KoShape *, QVariant> > subIds;
QMap<QString, KoSharedLoadingData *> sharedData; //FIXME: use QScopedPointer here to auto delete in destructor
int zIndex;
QMap<QString, KoLoadingShapeUpdater*> updaterById;
QMap<KoShape *, KoLoadingShapeUpdater*> updaterByShape;
KoDocumentResourceManager *documentResources;
- QObject *documentRdf;
- KoSectionModel *sectionModel;
-};
+ KoSectionModel *sectionModel; };
-KoShapeLoadingContext::KoShapeLoadingContext(KoOdfLoadingContext & context, KoDocumentResourceManager *documentResources)
- : d(new Private(context, documentResources))
+KoShapeLoadingContext::KoShapeLoadingContext(KoStore *store, KoDocumentResourceManager *documentResources)
+ : d(new Private(store, documentResources))
{
- if (d->documentResources) {
- KoMarkerCollection *markerCollection = d->documentResources->resource(KoDocumentResourceManager::MarkerCollection).value<KoMarkerCollection*>();
- if (markerCollection) {
- //markerCollection->loadOdf(*this);
- }
- }
}
KoShapeLoadingContext::~KoShapeLoadingContext()
{
delete d;
}
-KoOdfLoadingContext & KoShapeLoadingContext::odfLoadingContext()
+KoStore *KoShapeLoadingContext::store() const
{
- return d->context;
+ return d->store;
+}
+
+QString KoShapeLoadingContext::mimeTypeForPath(const QString &href, bool b)
+{
+ return "image/svg+xml";
}
KoShapeLayer * KoShapeLoadingContext::layer(const QString & layerName)
{
return d->layers.value(layerName, 0);
}
void KoShapeLoadingContext::addLayer(KoShapeLayer * layer, const QString & layerName)
{
d->layers[ layerName ] = layer;
}
void KoShapeLoadingContext::clearLayers()
{
d->layers.clear();
}
void KoShapeLoadingContext::addShapeId(KoShape * shape, const QString & id)
{
d->drawIds.insert(id, shape);
QMap<QString, KoLoadingShapeUpdater*>::iterator it(d->updaterById.find(id));
while (it != d->updaterById.end() && it.key() == id) {
d->updaterByShape.insertMulti(shape, it.value());
it = d->updaterById.erase(it);
}
}
KoShape * KoShapeLoadingContext::shapeById(const QString &id)
{
return d->drawIds.value(id, 0);
}
void KoShapeLoadingContext::addShapeSubItemId(KoShape *shape, const QVariant &subItem, const QString &id)
{
d->subIds.insert(id, QPair<KoShape *, QVariant>(shape, subItem));
}
QPair<KoShape *, QVariant> KoShapeLoadingContext::shapeSubItemById(const QString &id)
{
return d->subIds.value(id);
}
// TODO make sure to remove the shape from the loading context when loading for it failed and it was deleted. This can also happen when the parent is deleted
void KoShapeLoadingContext::updateShape(const QString & id, KoLoadingShapeUpdater * shapeUpdater)
{
d->updaterById.insertMulti(id, shapeUpdater);
}
void KoShapeLoadingContext::shapeLoaded(KoShape * shape)
{
QMap<KoShape*, KoLoadingShapeUpdater*>::iterator it(d->updaterByShape.find(shape));
while (it != d->updaterByShape.end() && it.key() == shape) {
it.value()->update(shape);
delete it.value();
it = d->updaterByShape.erase(it);
}
}
KoImageCollection * KoShapeLoadingContext::imageCollection()
{
return d->documentResources ? d->documentResources->imageCollection() : 0;
}
int KoShapeLoadingContext::zIndex()
{
return d->zIndex++;
}
void KoShapeLoadingContext::setZIndex(int index)
{
d->zIndex = index;
}
void KoShapeLoadingContext::addSharedData(const QString & id, KoSharedLoadingData * data)
{
QMap<QString, KoSharedLoadingData*>::iterator it(d->sharedData.find(id));
// data will not be overwritten
if (it == d->sharedData.end()) {
d->sharedData.insert(id, data);
} else {
warnFlake << "The id" << id << "is already registered. Data not inserted";
Q_ASSERT(it == d->sharedData.end());
}
}
KoSharedLoadingData * KoShapeLoadingContext::sharedData(const QString & id) const
{
KoSharedLoadingData * data = 0;
QMap<QString, KoSharedLoadingData*>::const_iterator it(d->sharedData.find(id));
if (it != d->sharedData.constEnd()) {
data = it.value();
}
return data;
}
void KoShapeLoadingContext::addAdditionalAttributeData(const AdditionalAttributeData & attributeData)
{
s_additionlAttributes.insert(attributeData);
}
QSet<KoShapeLoadingContext::AdditionalAttributeData> KoShapeLoadingContext::additionalAttributeData()
{
return s_additionlAttributes;
}
KoDocumentResourceManager *KoShapeLoadingContext::documentResourceManager() const
{
return d->documentResources;
}
-QObject *KoShapeLoadingContext::documentRdf() const
-{
- return d->documentRdf;
-}
-
-
-void KoShapeLoadingContext::setDocumentRdf(QObject *documentRdf)
-{
- d->documentRdf = documentRdf;
-}
-
KoSectionModel *KoShapeLoadingContext::sectionModel()
{
return d->sectionModel;
}
void KoShapeLoadingContext::setSectionModel(KoSectionModel *sectionModel)
{
d->sectionModel = sectionModel;
}
diff --git a/libs/flake/KoShapeLoadingContext.h b/libs/flake/KoShapeLoadingContext.h
index 26d7007ee9..96c09f14cc 100644
--- a/libs/flake/KoShapeLoadingContext.h
+++ b/libs/flake/KoShapeLoadingContext.h
@@ -1,212 +1,200 @@
/* This file is part of the KDE project
Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
Copyright (C) 2014-2015 Denis Kuplyakov <dener.kup@gmail.com>
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 KOSHAPELOADINGCONTEXT_H
#define KOSHAPELOADINGCONTEXT_H
#include <QSet>
#include <QString>
#include <QPair>
#include "kritaflake_export.h"
-class KoOdfLoadingContext;
class KoShapeLayer;
class KoShape;
class KoShapeControllerBase;
class KoLoadingShapeUpdater;
class KoImageCollection;
class KoSharedLoadingData;
class KoDocumentResourceManager;
class KoSectionModel;
class QVariant;
class QObject;
+class KoStore;
/**
* Context passed to shapes during loading.
* This class holds various variables as well as a context full of variables which all together
* form the context of a loading operation.
*/
class KRITAFLAKE_EXPORT KoShapeLoadingContext
{
public:
/**
* Struct to store data about additional attributes that should be loaded during
* the shape loading.
*
* Make sure all parameters point to const char * that stay around. e.g. The a KoXmlNS or
* a "tag" defined string e.g.
* AdditionalAttributeData( KoXmlNS::presentation, "placeholder", presentation:placeholder" )
*/
struct AdditionalAttributeData {
AdditionalAttributeData(const QString &ns, const QString &tag, const QString &name)
: ns(ns)
, tag(tag)
, name(name) {
}
const QString ns;
const QString tag;
const QString name;
bool operator==(const AdditionalAttributeData &other) const {
return name == other.name;
}
};
/**
* constructor
* @param context the context created for generic ODF loading.
* @param documentResources the data of the shape controller.
*/
- KoShapeLoadingContext(KoOdfLoadingContext &context, KoDocumentResourceManager *documentResources);
+ KoShapeLoadingContext(KoStore *store, KoDocumentResourceManager *documentResources);
/// destructor
~KoShapeLoadingContext();
- /// return the embedded loading context
- KoOdfLoadingContext &odfLoadingContext();
+ KoStore *store() const;
+ QString mimeTypeForPath(const QString &href, bool b = true);
/// Returns layer referenced by given name
KoShapeLayer *layer(const QString &layerName);
/// Adds a new layer to be referenced by the given name later
void addLayer(KoShapeLayer *layer, const QString &layerName);
/**
* remove all layers
*
* This can be used for loading different layer sets per page.
*/
void clearLayers();
/// register the id for a specific shape
void addShapeId(KoShape *shape, const QString &id);
+
/// return the shape formerly registered using addShapeId()
KoShape *shapeById(const QString &id);
/// register the id for a specific shape sub item
void addShapeSubItemId(KoShape *shape, const QVariant &subItem, const QString &id);
/// return the shape and subitem formerly registered using addShapeSubItemId()
QPair<KoShape *, QVariant> shapeSubItemById(const QString &id);
/**
* call function on the shapeUpdater when the shape with the id shapeid is inserted
* After that destroy the updater.
*/
void updateShape(const QString &id, KoLoadingShapeUpdater *shapeUpdater);
/**
* this checks if there is an updater for this shape if yes it calls it
* this needs to be done via the shape id and
*/
void shapeLoaded(KoShape *shape);
/// Returns the image collection for loading images
KoImageCollection *imageCollection();
/// Get current z-index
int zIndex();
/// Set z-index
void setZIndex(int index);
/**
* Add shared data
*
* This can be use to pass data between shapes on loading. E.g. The decoded text styles
* of the TextShape. With that the styles only have to be read once and can be used in
* all shapes that also need them.
*
* The ownership of the added data is passed to the context. The KoShapeLoadingContext will
* delete the added data when it is destroyed.
*
* Data inserted for a specific id will not be overwritten by calling addSharedData with
* the same id again.
*
* You get an assertion when the id is already existing.
*
* @see KoSharedLoadingData
*/
void addSharedData(const QString &id, KoSharedLoadingData *data);
/**
* Get the shared data.
*
* @see KoSharedLoadingData
*
* @param id The id used to identify the shared data.
* @return The shared data for the id or 0 if there is no shared data for the id.
*/
KoSharedLoadingData *sharedData(const QString &id) const;
/**
* @brief Add an additional attribute that should be loaded during shape loading
*
* An application can use that to set the data for additional attributes that should be
* loaded during shape loading.
* If attribute is set it will not change if set again. The tag is used to differentiate
* the attributes
*
* @param attributeData The data describing the additional attribute data
*/
static void addAdditionalAttributeData(const AdditionalAttributeData &attributeData);
/**
* @brief Get the additional attribute data for loading of a shape
*
* This is used by KoShape::loadOdfAttributes to load all additional attributes defined
* in the returned set.
*/
static QSet<AdditionalAttributeData> additionalAttributeData();
KoDocumentResourceManager *documentResourceManager() const;
-
- /**
- * @brief get the rdf document
- * @return the rdf document, or 0 if there is none set/
- */
- QObject *documentRdf() const;
-
- /**
- * @brief setDocumentRdf sets the rdf document for the loading context
- * @param documentRdf the rdf document -- it needs to have been loaded already
- */
- void setDocumentRdf(QObject *documentRdf);
-
/**
* @brief returns the current section model
* @return the pointer to KoSectionModel
*/
KoSectionModel *sectionModel();
/**
* @brief sets the section model for the loading context
* @param sectionModel the section model to set
*/
void setSectionModel(KoSectionModel *sectionModel);
private:
// to allow only the KoShapeRegistry access to the KoShapeControllerBase
class Private;
Private * const d;
};
#endif /* KOSHAPELOADINGCONTEXT_H */
diff --git a/libs/flake/KoShapeManager.cpp b/libs/flake/KoShapeManager.cpp
index b4eb4cceec..68890c9f67 100644
--- a/libs/flake/KoShapeManager.cpp
+++ b/libs/flake/KoShapeManager.cpp
@@ -1,784 +1,784 @@
/* This file is part of the KDE project
Copyright (C) 2006-2008 Thorsten Zachmann <zachmann@kde.org>
Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
Copyright (C) 2009-2010 Jan Hambrecht <jaham@gmx.net>
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 "KoShapeManager.h"
#include "KoShapeManager_p.h"
#include "KoSelection.h"
#include "KoToolManager.h"
#include "KoPointerEvent.h"
#include "KoShape.h"
#include "KoShape_p.h"
#include "KoCanvasBase.h"
#include "KoShapeContainer.h"
#include "KoShapeStrokeModel.h"
#include "KoShapeGroup.h"
#include "KoToolProxy.h"
#include "KoShapeShadow.h"
#include "KoShapeLayer.h"
#include "KoFilterEffect.h"
#include "KoFilterEffectStack.h"
#include "KoFilterEffectRenderContext.h"
#include "KoShapeBackground.h"
#include <KoRTree.h>
#include "KoClipPath.h"
#include "KoClipMaskPainter.h"
#include "KoShapePaintingContext.h"
#include "KoViewConverter.h"
#include "KisQPainterStateSaver.h"
#include "KoSvgTextChunkShape.h"
#include "KoSvgTextShape.h"
#include <QApplication>
#include <QPainter>
#include <QPainterPath>
#include <QTimer>
#include <FlakeDebug.h>
#include "kis_painting_tweaks.h"
#include "kis_debug.h"
#include "KisForest.h"
#include <unordered_set>
namespace {
/**
* Returns whether the shape should be added to the RTree for collision and ROI
* detection.
*/
inline bool shapeUsedInRenderingTree(KoShape *shape)
{
// FIXME: make more general!
return !dynamic_cast<KoShapeGroup*>(shape) &&
!dynamic_cast<KoShapeLayer*>(shape) &&
!(dynamic_cast<KoSvgTextChunkShape*>(shape) && !dynamic_cast<KoSvgTextShape*>(shape));
}
/**
* Returns whether a shape should be added to the rendering tree because of
* its clip mask/path or effects.
*/
inline bool shapeHasGroupEffects(KoShape *shape) {
return shape->clipPath() ||
(shape->filterEffectStack() && !shape->filterEffectStack()->isEmpty()) ||
shape->clipMask();
}
/**
* Returns true if the shape is not fully transparent
*/
inline bool shapeIsVisible(KoShape *shape) {
return shape->isVisible(false) && shape->transparency() < 1.0;
}
/**
* Populate \p tree with the subtree of shapes pointed by a shape \p parentShape.
* All new shapes are added as children of \p parentIt. Please take it into account
* that \c *parentIt might be not the same as \c parentShape, because \c parentShape
* may be hidden from rendering.
*/
void populateRenderSubtree(KoShape *parentShape,
KisForest<KoShape*>::child_iterator parentIt,
KisForest<KoShape*> &tree,
std::function<bool(KoShape*)> shouldIncludeNode,
std::function<bool(KoShape*)> shouldEnterSubtree)
{
KoShapeContainer *parentContainer = dynamic_cast<KoShapeContainer*>(parentShape);
if (!parentContainer) return;
QList<KoShape*> children = parentContainer->shapes();
std::sort(children.begin(), children.end(), KoShape::compareShapeZIndex);
for (auto it = children.constBegin(); it != children.constEnd(); ++it) {
auto newParentIt = parentIt;
if (shouldIncludeNode(*it)) {
newParentIt = tree.insert(childEnd(parentIt), *it);
}
if (shouldEnterSubtree(*it)) {
populateRenderSubtree(*it, newParentIt, tree, shouldIncludeNode, shouldEnterSubtree);
}
}
}
/**
* Build a rendering tree for **leaf** nodes defined by \p leafNodes
*
* Sometimes we should render only a part of the layer (e.g. when we render
* in patches). So we shouldn't render the whole graph. The problem is that
* some of the shapes may have parents with clip paths/masks and/or effects.
* In such a case, these parents should be also included into the rendering
* process.
*
* \c buildRenderTree() builds a graph for such rendering. It includes the
* leaf shapes themselves, and all parent shapes that have some effects affecting
* these shapes.
*/
void buildRenderTree(QList<KoShape*> leafShapes,
KisForest<KoShape*> &tree)
{
QList<KoShape*> sortedShapes = leafShapes;
std::sort(sortedShapes.begin(), sortedShapes.end(), KoShape::compareShapeZIndex);
std::unordered_set<KoShape*> includedShapes;
Q_FOREACH (KoShape *shape, sortedShapes) {
bool shouldSkipShape = !shapeIsVisible(shape);
if (shouldSkipShape) continue;
bool shapeIsPartOfIncludedSubtree = false;
QVector<KoShape*> hierarchy = {shape};
while ((shape = shape->parent())) {
if (!shapeIsVisible(shape)) {
shouldSkipShape = true;
break;
}
if (includedShapes.find(shape) != end(includedShapes)) {
shapeIsPartOfIncludedSubtree = true;
break;
}
if (shapeHasGroupEffects(shape)) {
hierarchy << shape;
}
}
if (shouldSkipShape) continue;
if (!shapeIsPartOfIncludedSubtree &&
includedShapes.find(hierarchy.last()) == end(includedShapes)) {
tree.insert(childEnd(tree), hierarchy.last());
}
std::copy(hierarchy.begin(), hierarchy.end(),
std::inserter(includedShapes, end(includedShapes)));
}
auto shouldIncludeShape =
[includedShapes] (KoShape *shape) {
// included shapes are guaranteed to be visible
return includedShapes.find(shape) != end(includedShapes);
};
for (auto it = childBegin(tree); it != childEnd(tree); ++it) {
populateRenderSubtree(*it, it, tree, shouldIncludeShape, &shapeIsVisible);
}
}
/**
* Render the prebuilt rendering tree on \p painter
*/
void renderShapes(typename KisForest<KoShape*>::child_iterator beginIt,
typename KisForest<KoShape*>::child_iterator endIt,
QPainter &painter,
KoShapePaintingContext &paintContext)
{
for (auto it = beginIt; it != endIt; ++it) {
KoShape *shape = *it;
KisQPainterStateSaver saver(&painter);
if (!isEnd(parent(it))) {
painter.setTransform(shape->transformation() * painter.transform());
} else {
painter.setTransform(shape->absoluteTransformation() * painter.transform());
}
KoClipPath::applyClipping(shape, painter);
qreal transparency = shape->transparency(true);
if (transparency > 0.0) {
painter.setOpacity(1.0-transparency);
}
if (shape->shadow()) {
KisQPainterStateSaver saver(&painter);
shape->shadow()->paint(shape, painter);
}
QScopedPointer<KoClipMaskPainter> clipMaskPainter;
QPainter *shapePainter = &painter;
KoClipMask *clipMask = shape->clipMask();
if (clipMask) {
const QRectF bounds = painter.transform().mapRect(shape->outlineRect());
clipMaskPainter.reset(new KoClipMaskPainter(&painter, bounds/*shape->boundingRect())*/));
shapePainter = clipMaskPainter->shapePainter();
}
/**
* We expect the shape to save/restore the painter's state itself. Such design was not
* not always here, so we need a period of sanity checks to ensure all the shapes are
* ported correctly.
*/
const QTransform sanityCheckTransformSaved = shapePainter->transform();
renderShapes(childBegin(it), childEnd(it), *shapePainter, paintContext);
shape->paint(*shapePainter, paintContext);
shape->paintStroke(*shapePainter, paintContext);
KIS_SAFE_ASSERT_RECOVER(shapePainter->transform() == sanityCheckTransformSaved) {
shapePainter->setTransform(sanityCheckTransformSaved);
}
if (clipMask) {
clipMaskPainter->maskPainter()->save();
shape->clipMask()->drawMask(clipMaskPainter->maskPainter(), shape);
clipMaskPainter->renderOnGlobalPainter();
clipMaskPainter->maskPainter()->restore();
}
}
}
}
void KoShapeManager::Private::updateTree()
{
bool selectionModified = false;
bool anyModified = false;
{
QMutexLocker l(&this->treeMutex);
Q_FOREACH (KoShape *shape, aggregate4update) {
selectionModified = selectionModified || selection->isSelected(shape);
anyModified = true;
}
foreach (KoShape *shape, aggregate4update) {
if (!shapeUsedInRenderingTree(shape)) continue;
tree.remove(shape);
QRectF br(shape->boundingRect());
tree.insert(br, shape);
}
aggregate4update.clear();
shapeIndexesBeforeUpdate.clear();
}
if (selectionModified) {
emit q->selectionContentChanged();
}
if (anyModified) {
emit q->contentChanged();
}
}
void KoShapeManager::Private::forwardCompressedUdpate()
{
bool shouldUpdateDecorations = false;
QRectF scheduledUpdate;
{
QMutexLocker l(&shapesMutex);
if (!compressedUpdate.isEmpty()) {
scheduledUpdate = compressedUpdate;
compressedUpdate = QRect();
}
Q_FOREACH (const KoShape *shape, compressedUpdatedShapes) {
if (selection->isSelected(shape)) {
shouldUpdateDecorations = true;
break;
}
}
compressedUpdatedShapes.clear();
}
if (shouldUpdateDecorations && canvas->toolProxy()) {
canvas->toolProxy()->repaintDecorations();
}
canvas->updateCanvas(scheduledUpdate);
}
KoShapeManager::KoShapeManager(KoCanvasBase *canvas, const QList<KoShape *> &shapes)
: d(new Private(this, canvas))
{
Q_ASSERT(d->canvas); // not optional.
connect(d->selection, SIGNAL(selectionChanged()), this, SIGNAL(selectionChanged()));
setShapes(shapes);
/**
* Shape manager uses signal compressors with timers, therefore
* it might handle queued signals, therefore it should belong
* to the GUI thread.
*/
this->moveToThread(qApp->thread());
connect(&d->updateCompressor, SIGNAL(timeout()), this, SLOT(forwardCompressedUdpate()));
}
KoShapeManager::KoShapeManager(KoCanvasBase *canvas)
: d(new Private(this, canvas))
{
Q_ASSERT(d->canvas); // not optional.
connect(d->selection, SIGNAL(selectionChanged()), this, SIGNAL(selectionChanged()));
// see a comment in another constructor
this->moveToThread(qApp->thread());
connect(&d->updateCompressor, SIGNAL(timeout()), this, SLOT(forwardCompressedUdpate()));
}
void KoShapeManager::Private::unlinkFromShapesRecursively(const QList<KoShape*> &shapes)
{
Q_FOREACH (KoShape *shape, shapes) {
shape->removeShapeManager(q);
KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape);
if (container) {
unlinkFromShapesRecursively(container->shapes());
}
}
}
KoShapeManager::~KoShapeManager()
{
d->unlinkFromShapesRecursively(d->shapes);
d->shapes.clear();
delete d;
}
void KoShapeManager::setShapes(const QList<KoShape *> &shapes, Repaint repaint)
{
{
QMutexLocker l1(&d->shapesMutex);
QMutexLocker l2(&d->treeMutex);
//clear selection
d->selection->deselectAll();
d->unlinkFromShapesRecursively(d->shapes);
d->compressedUpdate = QRect();
d->compressedUpdatedShapes.clear();
d->aggregate4update.clear();
d->shapeIndexesBeforeUpdate.clear();
d->tree.clear();
d->shapes.clear();
}
Q_FOREACH (KoShape *shape, shapes) {
addShape(shape, repaint);
}
}
void KoShapeManager::addShape(KoShape *shape, Repaint repaint)
{
{
QMutexLocker l1(&d->shapesMutex);
if (d->shapes.contains(shape))
return;
shape->addShapeManager(this);
d->shapes.append(shape);
if (shapeUsedInRenderingTree(shape)) {
QMutexLocker l2(&d->treeMutex);
QRectF br(shape->boundingRect());
d->tree.insert(br, shape);
}
}
if (repaint == PaintShapeOnAdd) {
shape->update();
}
// add the children of a KoShapeContainer
KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape);
if (container) {
foreach (KoShape *containerShape, container->shapes()) {
addShape(containerShape, repaint);
}
}
}
void KoShapeManager::remove(KoShape *shape)
{
QRectF dirtyRect;
{
QMutexLocker l1(&d->shapesMutex);
QMutexLocker l2(&d->treeMutex);
- dirtyRect = shape->absoluteOutlineRect();
+ dirtyRect = shape->boundingRect();
shape->removeShapeManager(this);
d->selection->deselect(shape);
d->aggregate4update.remove(shape);
d->compressedUpdatedShapes.remove(shape);
if (shapeUsedInRenderingTree(shape)) {
d->tree.remove(shape);
}
d->shapes.removeAll(shape);
}
if (!dirtyRect.isEmpty()) {
d->canvas->updateCanvas(dirtyRect);
}
// remove the children of a KoShapeContainer
KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape);
if (container) {
foreach (KoShape *containerShape, container->shapes()) {
remove(containerShape);
}
}
}
KoShapeManager::ShapeInterface::ShapeInterface(KoShapeManager *_q)
: q(_q)
{
}
void KoShapeManager::ShapeInterface::notifyShapeDestructed(KoShape *shape)
{
QMutexLocker l1(&q->d->shapesMutex);
QMutexLocker l2(&q->d->treeMutex);
q->d->selection->deselect(shape);
q->d->aggregate4update.remove(shape);
q->d->compressedUpdatedShapes.remove(shape);
// we cannot access RTTI of the semi-destructed shape, so just
// unlink it lazily
if (q->d->tree.contains(shape)) {
q->d->tree.remove(shape);
}
q->d->shapes.removeAll(shape);
}
KoShapeManager::ShapeInterface *KoShapeManager::shapeInterface()
{
return &d->shapeInterface;
}
void KoShapeManager::preparePaintJobs(PaintJobsOrder &jobsOrder,
KoShape *excludeRoot)
{
d->updateTree();
QMutexLocker l1(&d->shapesMutex);
QSet<KoShape*> rootShapesSet;
Q_FOREACH (KoShape *shape, d->shapes) {
while (shape->parent() && shape->parent() != excludeRoot) {
shape = shape->parent();
}
if (!rootShapesSet.contains(shape) && shape != excludeRoot) {
rootShapesSet.insert(shape);
}
}
#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
const QList<KoShape*> rootShapes(rootShapesSet.begin(), rootShapesSet.end());
#else
const QList<KoShape*> rootShapes = QList<KoShape*>::fromSet(rootShapesSet);
#endif
QList<KoShape*> newRootShapes;
Q_FOREACH (KoShape *srcShape, rootShapes) {
KIS_SAFE_ASSERT_RECOVER(srcShape->parent() == excludeRoot) { continue; }
KoShape *clonedShape = srcShape->cloneShape();
KoShapeContainer *parentShape = srcShape->parent();
if (parentShape && !parentShape->transformation().isIdentity()) {
clonedShape->applyAbsoluteTransformation(parentShape->transformation());
}
newRootShapes << clonedShape;
}
PaintJobsOrder result;
PaintJob::SharedSafeStorage shapesStorage = std::make_shared<PaintJob::ShapesStorage>();
Q_FOREACH (KoShape *shape, newRootShapes) {
shapesStorage->emplace_back(std::unique_ptr<KoShape>(shape));
}
const QList<KoShape*> originalShapes = KoShape::linearizeSubtreeSorted(rootShapes);
const QList<KoShape*> clonedShapes = KoShape::linearizeSubtreeSorted(newRootShapes);
KIS_SAFE_ASSERT_RECOVER_RETURN(clonedShapes.size() == originalShapes.size());
QHash<KoShape*, KoShape*> clonedFromOriginal;
for (int i = 0; i < originalShapes.size(); i++) {
clonedFromOriginal[originalShapes[i]] = clonedShapes[i];
}
for (auto it = std::begin(jobsOrder.jobs); it != std::end(jobsOrder.jobs); ++it) {
QMutexLocker l(&d->treeMutex);
QList<KoShape*> unsortedOriginalShapes = d->tree.intersects(it->docUpdateRect);
it->allClonedShapes = shapesStorage;
Q_FOREACH (KoShape *shape, unsortedOriginalShapes) {
KIS_SAFE_ASSERT_RECOVER(shapeUsedInRenderingTree(shape)) { continue; }
it->shapes << clonedFromOriginal[shape];
}
}
}
void KoShapeManager::paintJob(QPainter &painter, const KoShapeManager::PaintJob &job, bool forPrint)
{
painter.setPen(Qt::NoPen); // painters by default have a black stroke, lets turn that off.
painter.setBrush(Qt::NoBrush);
KisForest<KoShape*> renderTree;
buildRenderTree(job.shapes, renderTree);
KoShapePaintingContext paintContext(d->canvas, forPrint); //FIXME
renderShapes(childBegin(renderTree), childEnd(renderTree), painter, paintContext);
}
void KoShapeManager::paint(QPainter &painter, bool forPrint)
{
d->updateTree();
QMutexLocker l1(&d->shapesMutex);
painter.setPen(Qt::NoPen); // painters by default have a black stroke, lets turn that off.
painter.setBrush(Qt::NoBrush);
QList<KoShape*> unsortedShapes;
if (painter.hasClipping()) {
QMutexLocker l(&d->treeMutex);
QRectF rect = KisPaintingTweaks::safeClipBoundingRect(painter);
unsortedShapes = d->tree.intersects(rect);
} else {
unsortedShapes = d->shapes;
warnFlake << "KoShapeManager::paint Painting with a painter that has no clipping will lead to too much being painted!";
}
KoShapePaintingContext paintContext(d->canvas, forPrint); //FIXME
KisForest<KoShape*> renderTree;
buildRenderTree(unsortedShapes, renderTree);
renderShapes(childBegin(renderTree), childEnd(renderTree), painter, paintContext);
}
void KoShapeManager::renderSingleShape(KoShape *shape, QPainter &painter, KoShapePaintingContext &paintContext)
{
KisForest<KoShape*> renderTree;
KoViewConverter converter;
auto root = renderTree.insert(childBegin(renderTree), shape);
populateRenderSubtree(shape, root, renderTree, &shapeIsVisible, &shapeIsVisible);
renderShapes(childBegin(renderTree), childEnd(renderTree), painter, paintContext);
}
KoShape *KoShapeManager::shapeAt(const QPointF &position, KoFlake::ShapeSelection selection, bool omitHiddenShapes)
{
d->updateTree();
QMutexLocker l(&d->shapesMutex);
QList<KoShape*> sortedShapes;
{
QMutexLocker l(&d->treeMutex);
sortedShapes = d->tree.contains(position);
}
std::sort(sortedShapes.begin(), sortedShapes.end(), KoShape::compareShapeZIndex);
KoShape *firstUnselectedShape = 0;
for (int count = sortedShapes.count() - 1; count >= 0; count--) {
KoShape *shape = sortedShapes.at(count);
if (omitHiddenShapes && ! shape->isVisible())
continue;
if (! shape->hitTest(position))
continue;
switch (selection) {
case KoFlake::ShapeOnTop:
if (shape->isSelectable())
return shape;
break;
case KoFlake::Selected:
if (d->selection->isSelected(shape))
return shape;
break;
case KoFlake::Unselected:
if (! d->selection->isSelected(shape))
return shape;
break;
case KoFlake::NextUnselected:
// we want an unselected shape
if (d->selection->isSelected(shape))
continue;
// memorize the first unselected shape
if (! firstUnselectedShape)
firstUnselectedShape = shape;
// check if the shape above is selected
if (count + 1 < sortedShapes.count() && d->selection->isSelected(sortedShapes.at(count + 1)))
return shape;
break;
}
}
// if we want the next unselected below a selected but there was none selected,
// return the first found unselected shape
if (selection == KoFlake::NextUnselected && firstUnselectedShape)
return firstUnselectedShape;
if (d->selection->hitTest(position))
return d->selection;
return 0; // missed everything
}
QList<KoShape *> KoShapeManager::shapesAt(const QRectF &rect, bool omitHiddenShapes, bool containedMode)
{
QMutexLocker l(&d->shapesMutex);
d->updateTree();
QList<KoShape*> shapes;
{
QMutexLocker l(&d->treeMutex);
shapes = containedMode ? d->tree.contained(rect) : d->tree.intersects(rect);
}
for (int count = shapes.count() - 1; count >= 0; count--) {
KoShape *shape = shapes.at(count);
if (omitHiddenShapes && !shape->isVisible()) {
shapes.removeAt(count);
} else {
const QPainterPath outline = shape->absoluteTransformation().map(shape->outline());
if (!containedMode && !outline.intersects(rect) && !outline.contains(rect)) {
shapes.removeAt(count);
} else if (containedMode) {
QPainterPath containingPath;
containingPath.addRect(rect);
if (!containingPath.contains(outline)) {
shapes.removeAt(count);
}
}
}
}
return shapes;
}
void KoShapeManager::update(const QRectF &rect, const KoShape *shape, bool selectionHandles)
{
if (d->updatesBlocked) return;
{
QMutexLocker l(&d->shapesMutex);
d->compressedUpdate |= rect;
if (selectionHandles) {
d->compressedUpdatedShapes.insert(shape);
}
}
d->updateCompressor.start();
}
void KoShapeManager::setUpdatesBlocked(bool value)
{
d->updatesBlocked = value;
}
bool KoShapeManager::updatesBlocked() const
{
return d->updatesBlocked;
}
void KoShapeManager::notifyShapeChanged(KoShape *shape)
{
{
QMutexLocker l(&d->treeMutex);
Q_ASSERT(shape);
if (d->aggregate4update.contains(shape)) {
return;
}
d->aggregate4update.insert(shape);
d->shapeIndexesBeforeUpdate.insert(shape, shape->zIndex());
}
KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape);
if (container) {
Q_FOREACH (KoShape *child, container->shapes())
notifyShapeChanged(child);
}
}
QList<KoShape*> KoShapeManager::shapes() const
{
QMutexLocker l(&d->shapesMutex);
return d->shapes;
}
QList<KoShape*> KoShapeManager::topLevelShapes() const
{
QMutexLocker l(&d->shapesMutex);
QList<KoShape*> shapes;
// get all toplevel shapes
Q_FOREACH (KoShape *shape, d->shapes) {
if (!shape->parent() || dynamic_cast<KoShapeLayer*>(shape->parent())) {
shapes.append(shape);
}
}
return shapes;
}
KoSelection *KoShapeManager::selection() const
{
return d->selection;
}
KoCanvasBase *KoShapeManager::canvas()
{
return d->canvas;
}
//have to include this because of Q_PRIVATE_SLOT
#include "moc_KoShapeManager.cpp"
diff --git a/libs/flake/KoShapeOdfSaveHelper.cpp b/libs/flake/KoShapeOdfSaveHelper.cpp
deleted file mode 100644
index 6ce57c4b2d..0000000000
--- a/libs/flake/KoShapeOdfSaveHelper.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 "KoShapeOdfSaveHelper.h"
-#include "KoDragOdfSaveHelper_p.h"
-
-#include <KoXmlWriter.h>
-#include <KoOdf.h>
-#include <KoShape.h>
-
-class KoShapeOdfSaveHelperPrivate : public KoDragOdfSaveHelperPrivate
-{
-public:
- KoShapeOdfSaveHelperPrivate(const QList<KoShape *> &shapes)
- : shapes(shapes) {}
-
- QList<KoShape *> shapes;
-};
-
-KoShapeOdfSaveHelper::KoShapeOdfSaveHelper(const QList<KoShape *> &shapes)
- : KoDragOdfSaveHelper(*(new KoShapeOdfSaveHelperPrivate(shapes)))
-{
-}
-
-bool KoShapeOdfSaveHelper::writeBody()
-{
- Q_D(KoShapeOdfSaveHelper);
- d->context->addOption(KoShapeSavingContext::DrawId);
-
- KoXmlWriter &bodyWriter = d->context->xmlWriter();
- bodyWriter.startElement("office:body");
- bodyWriter.startElement(KoOdf::bodyContentElement(KoOdf::Text, true));
-
- std::sort(d->shapes.begin(), d->shapes.end(), KoShape::compareShapeZIndex);
- foreach (KoShape *shape, d->shapes) {
- shape->saveOdf(*d->context);
- }
-
- bodyWriter.endElement(); // office:element
- bodyWriter.endElement(); // office:body
-
- return true;
-}
diff --git a/libs/flake/KoShapeOdfSaveHelper.h b/libs/flake/KoShapeOdfSaveHelper.h
deleted file mode 100644
index f26f9afdcc..0000000000
--- a/libs/flake/KoShapeOdfSaveHelper.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 KOSHAPEODFSAVEHELPER_H
-#define KOSHAPEODFSAVEHELPER_H
-
-#include "KoDragOdfSaveHelper.h"
-#include "kritaflake_export.h"
-
-#include <QList>
-
-class KoShape;
-class KoShapeOdfSaveHelperPrivate;
-
-/**
- * Save helper for saving shapes to odf.
- *
- * The shapes are saved in an office:text document.
- */
-class KRITAFLAKE_EXPORT KoShapeOdfSaveHelper : public KoDragOdfSaveHelper
-{
-public:
- /**
- * Constructor
- *
- * @param shapes The list of shapes to save. If the shapes contain
- * children these are also saved.
- */
- explicit KoShapeOdfSaveHelper(const QList<KoShape *> &shapes);
-
- /// reimplemented
- bool writeBody() override;
-
-private:
- Q_DECLARE_PRIVATE(KoShapeOdfSaveHelper)
-};
-
-#endif /* KOSHAPEODFSAVEHELPER_H */
diff --git a/libs/flake/KoShapeRegistry.cpp b/libs/flake/KoShapeRegistry.cpp
index a6c09ba023..c34f041f0a 100644
--- a/libs/flake/KoShapeRegistry.cpp
+++ b/libs/flake/KoShapeRegistry.cpp
@@ -1,575 +1,395 @@
/* This file is part of the KDE project
* Copyright (c) 2006 Boudewijn Rempt (boud@valdyas.org)
* Copyright (C) 2006-2007, 2010 Thomas Zander <zander@kde.org>
* Copyright (C) 2006,2008-2010 Thorsten Zachmann <zachmann@kde.org>
* Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
* Copyright (C) 2010 Inge Wallin <inge@lysator.liu.se>
*
* 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.
*/
// Own
#include "KoShapeRegistry.h"
#include "KoSvgTextShape.h"
#include "KoPathShapeFactory.h"
-#include "KoConnectionShapeFactory.h"
#include "KoShapeLoadingContext.h"
#include "KoShapeSavingContext.h"
#include "KoShapeGroup.h"
#include "KoShapeLayer.h"
#include "SvgShapeFactory.h"
#include <KoPluginLoader.h>
#include <KoXmlReader.h>
#include <KoXmlNS.h>
-#include <KoOdfLoadingContext.h>
-#include <KoStyleStack.h>
#include <QString>
#include <QHash>
#include <QMultiMap>
#include <QPainter>
#include <QGlobalStatic>
#include <FlakeDebug.h>
Q_GLOBAL_STATIC(KoShapeRegistry, s_instance)
class Q_DECL_HIDDEN KoShapeRegistry::Private
{
public:
void insertFactory(KoShapeFactoryBase *factory);
void init(KoShapeRegistry *q);
KoShape *createShapeInternal(const KoXmlElement &fullElement, KoShapeLoadingContext &context, const KoXmlElement &element) const;
// Map namespace,tagname to priority:factory
QHash<QPair<QString, QString>, QMultiMap<int, KoShapeFactoryBase*> > factoryMap;
};
KoShapeRegistry::KoShapeRegistry()
: d(new Private())
{
}
KoShapeRegistry::~KoShapeRegistry()
{
qDeleteAll(doubleEntries());
qDeleteAll(values());
delete d;
}
void KoShapeRegistry::Private::init(KoShapeRegistry *q)
{
KoPluginLoader::PluginsConfig config;
config.whiteList = "FlakePlugins";
config.blacklist = "FlakePluginsDisabled";
config.group = "krita";
KoPluginLoader::instance()->load(QString::fromLatin1("Krita/Flake"),
QString::fromLatin1("[X-Flake-PluginVersion] == 28"),
config);
config.whiteList = "ShapePlugins";
config.blacklist = "ShapePluginsDisabled";
KoPluginLoader::instance()->load(QString::fromLatin1("Krita/Shape"),
QString::fromLatin1("[X-Flake-PluginVersion] == 28"),
config);
// Also add our hard-coded basic shapes
q->add(new KoSvgTextShapeFactory());
q->add(new KoPathShapeFactory(QStringList()));
- q->add(new KoConnectionShapeFactory());
// As long as there is no shape dealing with embedded svg images
// we add the svg shape factory here by default
q->add(new SvgShapeFactory);
// Now all shape factories are registered with us, determine their
// associated odf tagname & priority and prepare ourselves for
// loading ODF.
QList<KoShapeFactoryBase*> factories = q->values();
for (int i = 0; i < factories.size(); ++i) {
insertFactory(factories[i]);
}
}
KoShapeRegistry* KoShapeRegistry::instance()
{
if (!s_instance.exists()) {
s_instance->d->init(s_instance);
}
return s_instance;
}
void KoShapeRegistry::addFactory(KoShapeFactoryBase * factory)
{
add(factory);
d->insertFactory(factory);
}
void KoShapeRegistry::Private::insertFactory(KoShapeFactoryBase *factory)
{
const QList<QPair<QString, QStringList> > odfElements(factory->odfElements());
if (odfElements.isEmpty()) {
debugFlake << "Shape factory" << factory->id() << " does not have OdfNamespace defined, ignoring";
}
else {
int priority = factory->loadingPriority();
for (QList<QPair<QString, QStringList> >::const_iterator it(odfElements.begin()); it != odfElements.end(); ++it) {
foreach (const QString &elementName, (*it).second) {
QPair<QString, QString> p((*it).first, elementName);
QMultiMap<int, KoShapeFactoryBase*> & priorityMap = factoryMap[p];
priorityMap.insert(priority, factory);
debugFlake << "Inserting factory" << factory->id() << " for"
<< p << " with priority "
<< priority << " into factoryMap making "
<< priorityMap.size() << " entries. ";
}
}
}
}
#include <KoXmlWriter.h>
#include <QBuffer>
#include <KoStore.h>
#include <boost/optional.hpp>
namespace {
struct ObjectEntry {
ObjectEntry()
{
}
ObjectEntry(const ObjectEntry &rhs)
: objectXmlContents(rhs.objectXmlContents),
objectName(rhs.objectName),
isDir(rhs.isDir)
{
}
~ObjectEntry()
{
}
QByteArray objectXmlContents; // the XML tree in the object
QString objectName; // object name in the frame without "./"
// This is extracted from objectXmlContents.
bool isDir = false;
};
// A FileEntry is used to store information about embedded files
// inside (i.e. referred to by) an object.
struct FileEntry {
FileEntry() {}
FileEntry(const FileEntry &rhs)
: path(rhs.path),
mimeType(rhs.mimeType),
isDir(rhs.isDir),
contents(rhs.contents)
{
}
QString path; // Normalized filename, i.e. without "./".
QString mimeType;
bool isDir;
QByteArray contents;
};
QByteArray loadFile(const QString &fileName, KoShapeLoadingContext &context)
{
// Can't load a file which is a directory, return an invalid QByteArray
if (fileName.endsWith('/'))
return QByteArray();
- KoStore *store = context.odfLoadingContext().store();
+ KoStore *store = context.store();
QByteArray fileContent;
if (!store->open(fileName)) {
store->close();
return QByteArray();
}
int fileSize = store->size();
fileContent = store->read(fileSize);
store->close();
//debugFlake << "File content: " << fileContent;
return fileContent;
}
boost::optional<FileEntry> storeFile(const QString &fileName, KoShapeLoadingContext &context)
{
debugFlake << "Saving file: " << fileName;
boost::optional<FileEntry> result;
QByteArray fileContent = loadFile(fileName, context);
if (!fileContent.isNull()) {
// Actually store the file in the list.
FileEntry entry;
entry.path = fileName;
if (entry.path.startsWith(QLatin1String("./"))) {
entry.path.remove(0, 2);
}
- entry.mimeType = context.odfLoadingContext().mimeTypeForPath(entry.path);
+ entry.mimeType = context.mimeTypeForPath(entry.path);
entry.isDir = false;
entry.contents = fileContent;
result = entry;
}
return result;
}
void storeXmlRecursive(const KoXmlElement &el, KoXmlWriter &writer,
ObjectEntry *object, QHash<QString, QString> &unknownNamespaces)
{
// Start the element;
// keep the name in a QByteArray so that it stays valid until end element is called.
const QByteArray name(el.nodeName().toLatin1());
writer.startElement(name.constData());
// Child elements
// Loop through all the child elements of the draw:frame.
KoXmlNode n = el.firstChild();
for (; !n.isNull(); n = n.nextSibling()) {
if (n.isElement()) {
storeXmlRecursive(n.toElement(), writer, object, unknownNamespaces);
}
else if (n.isText()) {
writer.addTextNode(n.toText().data()/*.toUtf8()*/);
}
}
// End the element
writer.endElement();
}
QVector<ObjectEntry> storeObjects(const KoXmlElement &element)
{
QVector<ObjectEntry> result;
// Loop through all the child elements of the draw:frame and save them.
KoXmlNode n = element.firstChild();
for (; !n.isNull(); n = n.nextSibling()) {
debugFlake << "In draw:frame, node =" << n.nodeName();
// This disregards #text, but that's not in the spec anyway so
// it doesn't need to be saved.
if (!n.isElement())
continue;
KoXmlElement el = n.toElement();
ObjectEntry object;
QByteArray contentsTmp;
QBuffer buffer(&contentsTmp); // the member
KoXmlWriter writer(&buffer);
// 1. Find out the objectName
// Save the normalized filename, i.e. without a starting "./".
// An empty string is saved if no name is found.
QString name = el.attributeNS(KoXmlNS::xlink, "href", QString());
if (name.startsWith(QLatin1String("./")))
name.remove(0, 2);
object.objectName = name;
// 2. Copy the XML code.
QHash<QString, QString> unknownNamespaces;
storeXmlRecursive(el, writer, &object, unknownNamespaces);
object.objectXmlContents = contentsTmp;
// 3, 4: the isDir and manifestEntry members are not set here,
// but initialize them anyway. .
object.isDir = false; // Has to be initialized to something.
result.append(object);
}
return result;
}
}
#include <svg/SvgShapeFactory.h>
#include "kis_debug.h"
#include <QMimeDatabase>
#include <KoUnit.h>
#include <KoDocumentResourceManager.h>
#include <KoShapeController.h>
#include <KoShapeGroupCommand.h>
-KoShape * KoShapeRegistry::createShapeFromOdf(const KoXmlElement & e, KoShapeLoadingContext & context) const
+KoShape * KoShapeRegistry::createShapeFromXML(const KoXmlElement & e, KoShapeLoadingContext & context) const
{
- debugFlake << "Going to check for" << e.namespaceURI() << ":" << e.tagName();
-
- KoShape * shape = 0;
-
- // Handle the case where the element is a draw:frame differently from other cases.
- if (e.tagName() == "frame" && e.namespaceURI() == KoXmlNS::draw) {
- // If the element is in a frame, the frame is already added by the
- // application and we only want to create a shape from the
- // embedded element. The very first shape we create is accepted.
- //
- // FIXME: we might want to have some code to determine which is
- // the "best" of the creatable shapes.
-
- if (e.hasChildNodes()) {
- // if we don't ignore white spaces it can be that the first child is not a element so look for the first element
- KoXmlNode node = e.firstChild();
- KoXmlElement element;
- while (!node.isNull() && element.isNull()) {
- element = node.toElement();
- node = node.nextSibling();
- }
-
- if (!element.isNull()) {
- // Check for draw:object
- if (element.tagName() == "object" && element.namespaceURI() == KoXmlNS::draw && element.hasChildNodes()) {
- // Loop through the elements and find the first one
- // that is handled by any shape.
- KoXmlNode n = element.firstChild();
- for (; !n.isNull(); n = n.nextSibling()) {
- if (n.isElement()) {
- debugFlake << "trying for element " << n.toElement().tagName();
- shape = d->createShapeInternal(e, context, n.toElement());
- break;
- }
- }
- if (shape)
- debugFlake << "Found a shape for draw:object";
- else
- debugFlake << "Found NO shape shape for draw:object";
- }
- else {
- // If not draw:object, e.g draw:image or draw:plugin
- shape = d->createShapeInternal(e, context, element);
- }
- }
-
- if (shape) {
- debugFlake << "A shape supporting the requested type was found.";
- }
- else {
- // If none of the registered shapes could handle the frame
- // contents, try to fetch SVG it from an embedded link
-
- const KoXmlElement &frameElement = e;
- const int frameZIndex = SvgShapeFactory::calculateZIndex(frameElement, context);
-
- QList<KoShape*> resultShapes;
-
- QVector<ObjectEntry> objects = storeObjects(frameElement);
- Q_FOREACH (const ObjectEntry &object, objects) {
- if (object.objectName.isEmpty()) continue;
-
- boost::optional<FileEntry> file = storeFile(object.objectName, context);
- if (file && !file->contents.isEmpty()) {
- QMimeDatabase db;
- QMimeType mime = db.mimeTypeForData(file->contents);
-
- const int zIndex = SvgShapeFactory::calculateZIndex(element, context);
-
- if (mime.inherits("image/svg+xml")) {
-
-
- KoXmlDocument xmlDoc;
-
- int line, col;
- QString errormessage;
- const bool parsed = xmlDoc.setContent(file->contents, &errormessage, &line, &col);
- if (!parsed) continue;
-
- const QRectF bounds = context.documentResourceManager()->documentRectInPixels();
-
- // WARNING: Krita 3.x expects all the embedded objects to
- // be loaded in default resolution of 72.0 ppi.
- // Don't change it to the correct data in the image,
- // it will change back compatibility (and this code will
- // be deprecated some time soon
- // UPDATE (DK): There is actually no difference in what resolution we
- // load these shapes, because they will be scaled into
- // the bounds of the parent odf-frame
- const qreal pixelsPerInch = 72.0;
- const qreal forcedFontSizeResolution = 72.0;
-
- QPointF pos;
- pos.setX(KoUnit::parseValue(frameElement.attributeNS(KoXmlNS::svg, "x", QString::number(bounds.x()))));
- pos.setY(KoUnit::parseValue(frameElement.attributeNS(KoXmlNS::svg, "y", QString::number(bounds.y()))));
-
- QSizeF size;
- size.setWidth(KoUnit::parseValue(frameElement.attributeNS(KoXmlNS::svg, "width", QString::number(bounds.width()))));
- size.setHeight(KoUnit::parseValue(frameElement.attributeNS(KoXmlNS::svg, "height", QString::number(bounds.height()))));
-
- KoShape *shape = SvgShapeFactory::createShapeFromSvgDirect(xmlDoc.documentElement(),
- QRectF(pos, size),
- pixelsPerInch,
- forcedFontSizeResolution,
- zIndex,
- context);
-
- if (shape) {
- // NOTE: here we are expected to stretch the internal to the bounds of
- // the frame! Sounds weird, but it is what Krita 3.x did.
-
- const QRectF shapeRect = shape->absoluteOutlineRect();
- const QPointF offset = shapeRect.topLeft();
- const QSizeF fragmentSize = shapeRect.size();
-
- if (fragmentSize.isValid()) {
- /**
- * Yes, you see what you see. The previous versions of Krita used
- * QSvgRenderer to render the object, which allegedly truncated the
- * object on sides. Even though we don't use pre-rendering now,
- * we should still reproduce the old way...
- */
- const QSizeF newSize = QSizeF(int(size.width()), int(size.height()));
-
- shape->applyAbsoluteTransformation(
- QTransform::fromTranslate(-offset.x(), -offset.y()) *
- QTransform::fromScale(
- newSize.width() / fragmentSize.width(),
- newSize.height() / fragmentSize.height()) *
- QTransform::fromTranslate(pos.x(), pos.y()));
- resultShapes.append(shape);
- }
- }
-
- } else {
- // TODO: implement raster images?
- }
- }
- }
-
- if (resultShapes.size() == 1) {
- shape = resultShapes.takeLast();
- } else if (resultShapes.size() > 1) {
- KoShapeGroup *groupShape = new KoShapeGroup;
- KoShapeGroupCommand cmd(groupShape, resultShapes);
- cmd.redo();
- groupShape->setZIndex(frameZIndex);
- shape = groupShape;
- }
- }
- }
- }
-
- // Hardwire the group shape into the loading as it should not appear
- // in the shape selector
- else if (e.localName() == "g" && e.namespaceURI() == KoXmlNS::draw) {
- KoShapeGroup * group = new KoShapeGroup();
-
- context.odfLoadingContext().styleStack().save();
- bool loaded = group->loadOdf(e, context);
- context.odfLoadingContext().styleStack().restore();
-
- if (loaded) {
- shape = group;
- }
- else {
- delete group;
- }
- } else {
- shape = d->createShapeInternal(e, context, e);
- }
-
- if (shape) {
- context.shapeLoaded(shape);
- }
-
- return shape;
+ return 0;
}
KoShape *KoShapeRegistry::Private::createShapeInternal(const KoXmlElement &fullElement,
KoShapeLoadingContext &context,
const KoXmlElement &element) const
{
// Pair of namespace, tagname
QPair<QString, QString> p = QPair<QString, QString>(element.namespaceURI(), element.tagName());
// Remove duplicate lookup.
if (!factoryMap.contains(p))
return 0;
QMultiMap<int, KoShapeFactoryBase*> priorityMap = factoryMap.value(p);
QList<KoShapeFactoryBase*> factories = priorityMap.values();
#ifndef NDEBUG
debugFlake << "Supported factories for=" << p;
foreach (KoShapeFactoryBase *f, factories)
debugFlake << f->id() << f->name();
#endif
// Loop through all shape factories. If any of them supports this
// element, then we let the factory create a shape from it. This
// may fail because the element itself is too generic to draw any
// real conclusions from it - we actually have to try to load it.
// An example of this is the draw:image element which have
// potentially hundreds of different image formats to support,
// including vector formats.
//
// If it succeeds, then we use this shape, if it fails, then just
// try the next.
//
// Higher numbers are more specific, map is sorted by keys.
for (int i = factories.size() - 1; i >= 0; --i) {
KoShapeFactoryBase * factory = factories[i];
if (factory->supports(element, context)) {
- KoShape *shape = factory->createShapeFromOdf(fullElement, context);
+ KoShape *shape = factory->createShapeFromXML(fullElement, context);
if (shape) {
debugFlake << "Shape found for factory " << factory->id() << factory->name();
// we return the top-level most shape as that's the one that we'll have to
// add to the KoShapeManager for painting later (and also to avoid memory leaks)
// but don't go past a KoShapeLayer as KoShape adds those from the context
// during loading and those are already added.
while (shape->parent() && dynamic_cast<KoShapeLayer*>(shape->parent()) == 0)
shape = shape->parent();
return shape;
}
// Maybe a shape with a lower priority can load our
// element, but this attempt has failed.
}
else {
debugFlake << "No support for" << p << "by" << factory->id();
}
}
return 0;
}
QList<KoShapeFactoryBase*> KoShapeRegistry::factoriesForElement(const QString &nameSpace, const QString &elementName)
{
// Pair of namespace, tagname
QPair<QString, QString> p = QPair<QString, QString>(nameSpace, elementName);
QMultiMap<int, KoShapeFactoryBase*> priorityMap = d->factoryMap.value(p);
QList<KoShapeFactoryBase*> shapeFactories;
// sort list by priority
Q_FOREACH (KoShapeFactoryBase *f, priorityMap.values()) {
shapeFactories.prepend(f);
}
return shapeFactories;
}
diff --git a/libs/flake/KoShapeRegistry.h b/libs/flake/KoShapeRegistry.h
index 5465a6d5fe..7d1e56cace 100644
--- a/libs/flake/KoShapeRegistry.h
+++ b/libs/flake/KoShapeRegistry.h
@@ -1,86 +1,86 @@
/* This file is part of the KDE project
* Copyright (c) 2006 Boudewijn Rempt (boud@valdyas.org)
* Copyright (C) 2006, 2010 Thomas Zander <zander@kde.org>
*
* 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 KOSHAPEREGISTRY_H
#define KOSHAPEREGISTRY_H
#include <KoGenericRegistry.h>
#include <KoShapeFactoryBase.h>
#include <KoXmlReaderForward.h>
#include "kritaflake_export.h"
class KoShape;
class KoShapeLoadingContext;
/**
* This singleton class keeps a register of all available flake shapes,
* or rather, of the factories that applications can use to create flake
* shape objects.
*/
class KRITAFLAKE_EXPORT KoShapeRegistry : public KoGenericRegistry<KoShapeFactoryBase*>
{
public:
KoShapeRegistry();
~KoShapeRegistry() override;
/**
* Return an instance of the KoShapeRegistry
* Creates an instance if that has never happened before and returns the singleton instance.
*/
static KoShapeRegistry *instance();
/**
* Add shape factory for a shape that is not a plugin
* This can be used also if you want to have a shape only in one application
*
* @param factory The factory of the shape
*/
void addFactory(KoShapeFactoryBase *factory);
/**
* Use the element to find out which flake plugin can load it, and
* returns the loaded shape. The element expected is one of
* 'draw:line', 'draw:frame' / etc.
*
* @returns the shape or 0 if no shape could be created. The shape may have as its parent
* set a layer which was previously created and stored in the context.
* @see KoShapeLoadingContext::layer()
*/
- KoShape *createShapeFromOdf(const KoXmlElement &element, KoShapeLoadingContext &context) const;
+ KoShape *createShapeFromXML(const KoXmlElement &element, KoShapeLoadingContext &context) const;
/**
* Returns a list of shape factories supporting the specified xml element.
* @param nameSpace the namespace of the xml element, see KoXmlNS for valid namespaces
* @param elementName the tag name of the element
* @return the list of shape factories supporting the specified xml element
*/
QList<KoShapeFactoryBase*> factoriesForElement(const QString &nameSpace, const QString &elementName);
private:
KoShapeRegistry(const KoShapeRegistry&);
KoShapeRegistry operator=(const KoShapeRegistry&);
class Private;
Private * const d;
};
#endif
diff --git a/libs/flake/KoShapeSavingContext.cpp b/libs/flake/KoShapeSavingContext.cpp
index d7d2aa50a8..11d4a86271 100644
--- a/libs/flake/KoShapeSavingContext.cpp
+++ b/libs/flake/KoShapeSavingContext.cpp
@@ -1,346 +1,260 @@
/* This file is part of the KDE project
Copyright (C) 2004-2006 David Faure <faure@kde.org>
Copyright (C) 2007-2009, 2011 Thorsten Zachmann <zachmann@kde.org>
Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
Copyright (C) 2010 Benjamin Port <port.benjamin@gmail.com>
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 "KoShapeSavingContext.h"
#include "KoDataCenterBase.h"
#include "KoShapeLayer.h"
#include "KoImageData.h"
#include "KoMarker.h"
#include <KoXmlWriter.h>
#include <KoStore.h>
#include <KoStoreDevice.h>
#include <KoSharedSavingData.h>
-#include <KoElementReference.h>
-
#include <FlakeDebug.h>
#include <QUuid>
#include <QImage>
#include <KisMimeDatabase.h>
class KoShapeSavingContextPrivate {
public:
- KoShapeSavingContextPrivate(KoXmlWriter&, KoGenStyles&, KoEmbeddedDocumentSaver&);
+ KoShapeSavingContextPrivate(KoXmlWriter&);
~KoShapeSavingContextPrivate();
KoXmlWriter *xmlWriter;
KoShapeSavingContext::ShapeSavingOptions savingOptions;
QList<const KoShapeLayer*> layers;
QSet<KoDataCenterBase *> dataCenters;
QMap<QString, KoSharedSavingData*> sharedData;
QMap<qint64, QString> imageNames;
int imageId;
QMap<QString, QImage> images;
QHash<const KoShape *, QTransform> shapeOffsets;
QMap<const KoMarker *, QString> markerRefs;
- KoGenStyles& mainStyles;
- KoEmbeddedDocumentSaver& embeddedSaver;
-
- QMap<const void*, KoElementReference> references;
QMap<QString, int> referenceCounters;
QMap<QString, QList<const void*> > prefixedReferences;
};
-KoShapeSavingContextPrivate::KoShapeSavingContextPrivate(KoXmlWriter &w,
- KoGenStyles &s, KoEmbeddedDocumentSaver &e)
- : xmlWriter(&w),
- savingOptions(0),
- imageId(0),
- mainStyles(s),
- embeddedSaver(e)
+KoShapeSavingContextPrivate::KoShapeSavingContextPrivate(KoXmlWriter &w)
+ : xmlWriter(&w)
+ , savingOptions(0)
+ , imageId(0)
{
}
KoShapeSavingContextPrivate::~KoShapeSavingContextPrivate()
{
Q_FOREACH (KoSharedSavingData * data, sharedData) {
delete data;
}
}
-KoShapeSavingContext::KoShapeSavingContext(KoXmlWriter &xmlWriter, KoGenStyles &mainStyles,
- KoEmbeddedDocumentSaver &embeddedSaver)
- : d(new KoShapeSavingContextPrivate(xmlWriter, mainStyles, embeddedSaver))
+KoShapeSavingContext::KoShapeSavingContext(KoXmlWriter &xmlWriter)
+ : d(new KoShapeSavingContextPrivate(xmlWriter))
{
// by default allow saving of draw:id + xml:id
addOption(KoShapeSavingContext::DrawId);
}
KoShapeSavingContext::~KoShapeSavingContext()
{
delete d;
}
KoXmlWriter & KoShapeSavingContext::xmlWriter()
{
return *d->xmlWriter;
}
void KoShapeSavingContext::setXmlWriter(KoXmlWriter &xmlWriter)
{
d->xmlWriter = &xmlWriter;
}
-KoGenStyles & KoShapeSavingContext::mainStyles()
-{
- return d->mainStyles;
-}
-
-KoEmbeddedDocumentSaver &KoShapeSavingContext::embeddedSaver()
-{
- return d->embeddedSaver;
-}
-
bool KoShapeSavingContext::isSet(ShapeSavingOption option) const
{
return d->savingOptions & option;
}
void KoShapeSavingContext::setOptions(ShapeSavingOptions options)
{
d->savingOptions = options;
}
KoShapeSavingContext::ShapeSavingOptions KoShapeSavingContext::options() const
{
return d->savingOptions;
}
void KoShapeSavingContext::addOption(ShapeSavingOption option)
{
d->savingOptions = d->savingOptions | option;
}
void KoShapeSavingContext::removeOption(ShapeSavingOption option)
{
if (isSet(option))
d->savingOptions = d->savingOptions ^ option; // xor to remove it.
}
-KoElementReference KoShapeSavingContext::xmlid(const void *referent, const QString& prefix, KoElementReference::GenerationOption counter)
-{
- Q_ASSERT(counter == KoElementReference::UUID || (counter == KoElementReference::Counter && !prefix.isEmpty()));
-
- if (d->references.contains(referent)) {
- return d->references[referent];
- }
-
- KoElementReference ref;
-
- if (counter == KoElementReference::Counter) {
- int referenceCounter = d->referenceCounters[prefix];
- referenceCounter++;
- ref = KoElementReference(prefix, referenceCounter);
- d->references.insert(referent, ref);
- d->referenceCounters[prefix] = referenceCounter;
- }
- else {
- if (!prefix.isEmpty()) {
- ref = KoElementReference(prefix);
- d->references.insert(referent, ref);
- }
- else {
- d->references.insert(referent, ref);
- }
- }
-
- if (!prefix.isNull()) {
- d->prefixedReferences[prefix].append(referent);
- }
- return ref;
-}
-
-KoElementReference KoShapeSavingContext::existingXmlid(const void *referent)
-{
- if (d->references.contains(referent)) {
- return d->references[referent];
- }
- else {
- KoElementReference ref;
- ref.invalidate();
- return ref;
- }
-}
-
-void KoShapeSavingContext::clearXmlIds(const QString &prefix)
-{
-
- if (d->prefixedReferences.contains(prefix)) {
- Q_FOREACH (const void* ptr, d->prefixedReferences[prefix]) {
- d->references.remove(ptr);
- }
- d->prefixedReferences.remove(prefix);
- }
-
- if (d->referenceCounters.contains(prefix)) {
- d->referenceCounters[prefix] = 0;
- }
-}
-
void KoShapeSavingContext::addLayerForSaving(const KoShapeLayer *layer)
{
if (layer && ! d->layers.contains(layer))
d->layers.append(layer);
}
void KoShapeSavingContext::saveLayerSet(KoXmlWriter &xmlWriter) const
{
xmlWriter.startElement("draw:layer-set");
Q_FOREACH (const KoShapeLayer * layer, d->layers) {
xmlWriter.startElement("draw:layer");
xmlWriter.addAttribute("draw:name", layer->name());
if (layer->isGeometryProtected())
xmlWriter.addAttribute("draw:protected", "true");
if (! layer->isVisible(false))
xmlWriter.addAttribute("draw:display", "none");
xmlWriter.endElement(); // draw:layer
}
xmlWriter.endElement(); // draw:layer-set
}
void KoShapeSavingContext::clearLayers()
{
d->layers.clear();
}
QString KoShapeSavingContext::imageHref(const KoImageData *image)
{
QMap<qint64, QString>::iterator it(d->imageNames.find(image->key()));
if (it == d->imageNames.end()) {
QString suffix = image->suffix();
if (suffix.isEmpty()) {
it = d->imageNames.insert(image->key(), QString("Pictures/image%1").arg(++d->imageId));
}
else {
it = d->imageNames.insert(image->key(), QString("Pictures/image%1.%2").arg(++d->imageId).arg(suffix));
}
}
return it.value();
}
QString KoShapeSavingContext::imageHref(const QImage &image)
{
// TODO this can be optimized to recognize images which have the same content
// Also this can use quite a lot of memory as the qimage are all kept until
// they are saved to the store in memory
QString href = QString("Pictures/image%1.png").arg(++d->imageId);
d->images.insert(href, image);
return href;
}
QMap<qint64, QString> KoShapeSavingContext::imagesToSave()
{
return d->imageNames;
}
QString KoShapeSavingContext::markerRef(const KoMarker */*marker*/)
{
-// QMap<const KoMarker *, QString>::iterator it = d->markerRefs.find(marker);
-// if (it == d->markerRefs.end()) {
-// it = d->markerRefs.insert(marker, marker->saveOdf(*this));
-// }
-// return it.value();
-
return QString();
}
void KoShapeSavingContext::addDataCenter(KoDataCenterBase * dataCenter)
{
if (dataCenter) {
d->dataCenters.insert(dataCenter);
}
}
bool KoShapeSavingContext::saveDataCenter(KoStore *store, KoXmlWriter* manifestWriter)
{
bool ok = true;
Q_FOREACH (KoDataCenterBase *dataCenter, d->dataCenters) {
ok = ok && dataCenter->completeSaving(store, manifestWriter, this);
//debugFlake << "ok" << ok;
}
// Save images
for (QMap<QString, QImage>::iterator it(d->images.begin()); it != d->images.end(); ++it) {
if (store->open(it.key())) {
KoStoreDevice device(store);
ok = ok && it.value().save(&device, "PNG");
store->close();
// TODO error handling
if (ok) {
const QString mimetype = KisMimeDatabase::mimeTypeForFile(it.key(), false);
manifestWriter->addManifestEntry(it.key(), mimetype);
}
else {
warnFlake << "saving image failed";
}
}
else {
ok = false;
warnFlake << "saving image failed: open store failed";
}
}
return ok;
}
void KoShapeSavingContext::addSharedData(const QString &id, KoSharedSavingData * data)
{
QMap<QString, KoSharedSavingData*>::iterator it(d->sharedData.find(id));
// data will not be overwritten
if (it == d->sharedData.end()) {
d->sharedData.insert(id, data);
} else {
warnFlake << "The id" << id << "is already registered. Data not inserted";
Q_ASSERT(it == d->sharedData.end());
}
}
KoSharedSavingData * KoShapeSavingContext::sharedData(const QString &id) const
{
KoSharedSavingData * data = 0;
QMap<QString, KoSharedSavingData*>::const_iterator it(d->sharedData.constFind(id));
if (it != d->sharedData.constEnd()) {
data = it.value();
}
return data;
}
void KoShapeSavingContext::addShapeOffset(const KoShape *shape, const QTransform &m)
{
d->shapeOffsets.insert(shape, m);
}
void KoShapeSavingContext::removeShapeOffset(const KoShape *shape)
{
d->shapeOffsets.remove(shape);
}
QTransform KoShapeSavingContext::shapeOffset(const KoShape *shape) const
{
return d->shapeOffsets.value(shape, QTransform());
}
diff --git a/libs/flake/KoShapeSavingContext.h b/libs/flake/KoShapeSavingContext.h
index 6b0e3391a3..5435ffa7f1 100644
--- a/libs/flake/KoShapeSavingContext.h
+++ b/libs/flake/KoShapeSavingContext.h
@@ -1,291 +1,246 @@
/* This file is part of the KDE project
Copyright (C) 2004-2006 David Faure <faure@kde.org>
Copyright (C) 2007-2008 Thorsten Zachmann <zachmann@kde.org>
Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
Copyright (C) 2010 Benjamin Port <port.benjamin@gmail.com>
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 KOSHAPESAVINGCONTEXT_H
#define KOSHAPESAVINGCONTEXT_H
#include "kritaflake_export.h"
-#include <KoElementReference.h>
#include <QMap>
class KoShape;
class KoXmlWriter;
-class KoGenStyles;
class KoDataCenterBase;
-class KoEmbeddedDocumentSaver;
class KoImageData;
class KoMarker;
class KoShapeLayer;
class KoStore;
class KoSharedSavingData;
class KoShapeSavingContextPrivate;
class QImage;
class QTransform;
/**
* The set of data for the ODF file format used during saving of a shape.
*/
class KRITAFLAKE_EXPORT KoShapeSavingContext
{
public:
/// The Style used for saving the shape
enum ShapeSavingOption {
/**
* If set the style of family presentation is used, when not set the
* family graphic is used.
* See OpenDocument 9.2.15 Common Drawing Shape Attributes / Style
*/
PresentationShape = 1,
/**
* Save the draw:id used for referencing the shape. If draw:id is saved, xml:id is also
* saved.
* See OpenDocument 9.2.15 Common Drawing Shape Attributes / ID
*/
DrawId = 2,
/**
* If set the automatic style will be marked as being needed in styles.xml
*/
AutoStyleInStyleXml = 4,
/**
* If set duplicate master pages will be merged to one
*/
UniqueMasterPages = 8,
/**
* If set the z-index is saved in the shape
*/
ZIndex = 16
};
Q_DECLARE_FLAGS(ShapeSavingOptions, ShapeSavingOption)
/**
* @brief Constructor
* @param xmlWriter used for writing the xml
* @param mainStyles for saving the styles
* @param embeddedSaver for saving embedded documents
*/
- KoShapeSavingContext(KoXmlWriter &xmlWriter, KoGenStyles &mainStyles,
- KoEmbeddedDocumentSaver &embeddedSaver);
+ KoShapeSavingContext(KoXmlWriter &xmlWriter);
virtual ~KoShapeSavingContext();
/**
* @brief Get the xml writer
*
* @return xmlWriter
*/
KoXmlWriter &xmlWriter();
/**
* @brief Set the xml writer
*
* Change the xmlWriter that is used in the Context e.g. for saving to styles.xml
* instead of content.xml
*
* @param xmlWriter to use
*/
void setXmlWriter(KoXmlWriter &xmlWriter);
- /**
- * @brief Get the main styles
- *
- * @return main styles
- */
- KoGenStyles &mainStyles();
-
- /**
- * @brief Get the embedded document saver
- *
- * @return embedded document saver
- */
- KoEmbeddedDocumentSaver &embeddedSaver();
-
/**
* @brief Check if an option is set
*
* @return ture if the option is set, false otherwise
*/
bool isSet(ShapeSavingOption option) const;
/**
* @brief Set the options to use
*
* @param options to use
*/
void setOptions(ShapeSavingOptions options);
/// add an option to the set of options stored on this context, will leave the other options intact.
void addOption(ShapeSavingOption option);
/// remove an option, will leave the other options intact.
void removeOption(ShapeSavingOption option);
/**
* @brief Get the options used
*
* @return options used
*/
ShapeSavingOptions options() const;
-
- /**
- * @brief xmlid returns an element reference that can be related to the given referent. If there is a
- * prefix given, this prefix will be used in addition to either the counter or the uuid.
- * @param referent the object we are referring to
- * @param prefix a prefix for the xml:id string
- * @param counter if counter is true, shapesavingcontext will use a counter to create the xml:id
- * @return a KoElementReference; if insert is false and referent doesn't exist yet in the list, the elementreference will be invalid.
- */
- KoElementReference xmlid(const void *referent, const QString& prefix = QString(), KoElementReference::GenerationOption counter = KoElementReference::UUID);
-
- /**
- * @brief existingXmlid retrieve an existing xml id or invalid xml id if the referent object doesn't exist
- */
- KoElementReference existingXmlid(const void *referent);
-
- /**
- * @brief Clear out all given draw ids
- * @param prefix: removes all xml:id's that have the given prefix.
- *
- * This is needed for checking if master pages are the same. In normal saving
- * this should not be called.
- *
- * @see KoPAPastePage::process
- */
- void clearXmlIds(const QString &prefix);
-
/**
* Adds a layer to save into a layer-set in styles.xml according to 9.1.2/9.1.3 odf spec
* @param layer the layer to save
*/
void addLayerForSaving(const KoShapeLayer *layer);
/**
* Saves the layers added with addLayerForSaving to the xml writer
*/
void saveLayerSet(KoXmlWriter &xmlWriter) const;
/**
* remove all layers
*
* This can be used for saving different layer sets per page.
*/
void clearLayers();
/**
* Get the image href under which the image will be saved in the store
*/
QString imageHref(const KoImageData *image);
/**
* Get the image href under which the image will be save in the store
*
* This should only be used for temporary images that are onle there during
* saving, e.g. a pixmap representation of a draw:frame
*/
QString imageHref(const QImage &image);
/**
* Get the images that needs to be saved to the store
*/
QMap<qint64, QString> imagesToSave();
/**
* Get the reference to use for the marker lookup
*/
QString markerRef(const KoMarker *marker);
/**
* Add data center
*/
void addDataCenter(KoDataCenterBase *dataCenter);
/**
* Save the data centers
*
* This calls KoDataCenterBase::completeSaving()
* @returns false if an error occurred, which typically cancels the save.
*/
bool saveDataCenter(KoStore *store, KoXmlWriter *manifestWriter);
/**
* Add shared data
*
* This can be use to pass data between shapes on saving. E.g. The presentation page layout
* styles. With that e.g. the styles only need to be saved once and can be used everywhere
* without creating them again.
*
* The ownership of the added data is passed to the context. The KoShapeSavingContext will
* delete the added data when it is destroyed.
*
* Data inserted for a specific id will not be overwritten by calling addSharedData with
* the same id again.
*
* You get an assertion when the id is already existing.
*
* @see KoSharedSavingData
*/
void addSharedData(const QString &id, KoSharedSavingData *data);
/**
* Get the shared data.
*
* @see KoSharedLoadingData
*
* @param id The id used to identify the shared data.
* @return The shared data for the id or 0 if there is no shared data for the id.
*/
KoSharedSavingData *sharedData(const QString &id) const;
/**
* Add an offset that will be applied to the shape position when saved
*
* This is needed e.g. for shapes anchored to a text shape as the position is
* saved as offset to the anchor.
*
* @param shape The shape for which the offset should be added.
* @param matrix The offset which should be applied on saving the position.
*/
void addShapeOffset(const KoShape *shape, const QTransform &matrix);
/**
* Remove an offset from the saved offset list
*
* @param shape The shape for which the offset should be removed.
*/
void removeShapeOffset(const KoShape *shape);
/**
* Get the offest that will be applied to the shape position when saved.
*
* @param shape The shape for which the offset should be get.
* @return the saved offset or QTransform() when offset is not set.
*/
QTransform shapeOffset(const KoShape *shape) const;
private:
KoShapeSavingContextPrivate * const d;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(KoShapeSavingContext::ShapeSavingOptions)
#endif // KOSHAPESAVINGCONTEXT_H
diff --git a/libs/flake/KoShapeShadow.cpp b/libs/flake/KoShapeShadow.cpp
index a678275168..ae0971da21 100644
--- a/libs/flake/KoShapeShadow.cpp
+++ b/libs/flake/KoShapeShadow.cpp
@@ -1,357 +1,342 @@
/* This file is part of the KDE project
* Copyright (C) 2008-2009 Jan Hambrecht <jaham@gmx.net>
* Copyright (C) 2010 Thomas Zander <zander@kde.org>
* Copyright (C) 2010 Ariya Hidayat <ariya.hidayat@gmail.com>
* Copyright (C) 2010-2011 Yue Liu <yue.liu@mail.com>
*
* 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 "KoShapeShadow.h"
#include "KoShapeGroup.h"
#include "KoSelection.h"
#include "KoShapeSavingContext.h"
#include "KoShapeStrokeModel.h"
#include "KoShape.h"
#include "KoInsets.h"
#include "KoPathShape.h"
-#include <KoGenStyle.h>
#include <FlakeDebug.h>
#include <QPainter>
#include <QPainterPath>
#include <QAtomicInt>
#include <QImage>
#include <QRectF>
class Q_DECL_HIDDEN KoShapeShadow::Private
{
public:
Private()
: offset(2, 2), color(Qt::black), blur(8), visible(true), refCount(0) {
}
QPointF offset;
QColor color;
qreal blur;
bool visible;
QAtomicInt refCount;
/**
* Paints the shadow of the shape group to the buffer image.
* @param group the shape group to paint around
* @param painter the painter to paint on the image
* @param converter to convert between internal and view coordinates.
*/
void paintGroupShadow(KoShapeGroup *group, QPainter &painter);
/**
* Paints the shadow of the shape to the buffer image.
* @param shape the shape to paint around
* @param painter the painter to paint on the image
*/
void paintShadow(KoShape *shape, QPainter &painter);
void blurShadow(QImage &image, int radius, const QColor& shadowColor);
};
void KoShapeShadow::Private::paintGroupShadow(KoShapeGroup *group, QPainter &painter)
{
QList<KoShape*> shapes = group->shapes();
Q_FOREACH (KoShape *child, shapes) {
// we paint recursively here, so we do not have to check recursively for visibility
if (!child->isVisible(false))
continue;
painter.save();
//apply group child's transformation
painter.setTransform(child->absoluteTransformation(), true);
paintShadow(child, painter);
painter.restore();
}
}
void KoShapeShadow::Private::paintShadow(KoShape *shape, QPainter &painter)
{
QPainterPath path(shape->shadowOutline());
if (!path.isEmpty()) {
painter.save();
painter.setBrush(QBrush(color));
// Make sure the shadow has the same fill rule as the shape.
KoPathShape * pathShape = dynamic_cast<KoPathShape*>(shape);
if (pathShape)
path.setFillRule(pathShape->fillRule());
painter.drawPath(path);
painter.restore();
}
if (shape->stroke()) {
shape->stroke()->paint(shape, painter);
}
}
/* You can also find a BSD version to this method from
* https://github.com/ariya/X2/tree/master/graphics/shadowblur
*/
void KoShapeShadow::Private::blurShadow(QImage &image, int radius, const QColor& shadowColor)
{
static const int BlurSumShift = 15;
// Check http://www.w3.org/TR/SVG/filters.html#
// As noted in the SVG filter specification, ru
// approximates a real gaussian blur nicely.
// See comments in https://bugs.webkit.org/show_bug.cgi?id=40793, it seems sensible
// to follow Skia's limit of 128 pixels for the blur radius.
if (radius > 128)
radius = 128;
int channels[4] = { 3, 0, 1, 3 };
int dmax = radius >> 1;
int dmin = dmax - 1 + (radius & 1);
if (dmin < 0)
dmin = 0;
// Two stages: horizontal and vertical
for (int k = 0; k < 2; ++k) {
unsigned char* pixels = image.bits();
int stride = (k == 0) ? 4 : image.bytesPerLine();
int delta = (k == 0) ? image.bytesPerLine() : 4;
int jfinal = (k == 0) ? image.height() : image.width();
int dim = (k == 0) ? image.width() : image.height();
for (int j = 0; j < jfinal; ++j, pixels += delta) {
// For each step, we blur the alpha in a channel and store the result
// in another channel for the subsequent step.
// We use sliding window algorithm to accumulate the alpha values.
// This is much more efficient than computing the sum of each pixels
// covered by the box kernel size for each x.
for (int step = 0; step < 3; ++step) {
int side1 = (step == 0) ? dmin : dmax;
int side2 = (step == 1) ? dmin : dmax;
int pixelCount = side1 + 1 + side2;
int invCount = ((1 << BlurSumShift) + pixelCount - 1) / pixelCount;
int ofs = 1 + side2;
int alpha1 = pixels[channels[step]];
int alpha2 = pixels[(dim - 1) * stride + channels[step]];
unsigned char* ptr = pixels + channels[step + 1];
unsigned char* prev = pixels + stride + channels[step];
unsigned char* next = pixels + ofs * stride + channels[step];
int i;
int sum = side1 * alpha1 + alpha1;
int limit = (dim < side2 + 1) ? dim : side2 + 1;
for (i = 1; i < limit; ++i, prev += stride)
sum += *prev;
if (limit <= side2)
sum += (side2 - limit + 1) * alpha2;
limit = (side1 < dim) ? side1 : dim;
for (i = 0; i < limit; ptr += stride, next += stride, ++i, ++ofs) {
*ptr = (sum * invCount) >> BlurSumShift;
sum += ((ofs < dim) ? *next : alpha2) - alpha1;
}
prev = pixels + channels[step];
for (; ofs < dim; ptr += stride, prev += stride, next += stride, ++i, ++ofs) {
*ptr = (sum * invCount) >> BlurSumShift;
sum += (*next) - (*prev);
}
for (; i < dim; ptr += stride, prev += stride, ++i) {
*ptr = (sum * invCount) >> BlurSumShift;
sum += alpha2 - (*prev);
}
}
}
}
// "Colorize" with the right shadow color.
QPainter p(&image);
p.setCompositionMode(QPainter::CompositionMode_SourceIn);
p.fillRect(image.rect(), shadowColor);
p.end();
}
// ----------------------------------------------------------------
// KoShapeShadow
KoShapeShadow::KoShapeShadow()
: d(new Private())
{
}
KoShapeShadow::~KoShapeShadow()
{
delete d;
}
KoShapeShadow::KoShapeShadow(const KoShapeShadow &rhs)
: d(new Private(*rhs.d))
{
d->refCount = 0;
}
KoShapeShadow& KoShapeShadow::operator=(const KoShapeShadow &rhs)
{
*d = *rhs.d;
d->refCount = 0;
return *this;
}
-void KoShapeShadow::fillStyle(KoGenStyle &style, KoShapeSavingContext &context)
-{
- Q_UNUSED(context);
-
- style.addProperty("draw:shadow", d->visible ? "visible" : "hidden", KoGenStyle::GraphicType);
- style.addProperty("draw:shadow-color", d->color.name(), KoGenStyle::GraphicType);
- if (d->color.alphaF() != 1.0)
- style.addProperty("draw:shadow-opacity", QString("%1%").arg(d->color.alphaF() * 100.0), KoGenStyle::GraphicType);
- style.addProperty("draw:shadow-offset-x", QString("%1pt").arg(d->offset.x()), KoGenStyle::GraphicType);
- style.addProperty("draw:shadow-offset-y", QString("%1pt").arg(d->offset.y()), KoGenStyle::GraphicType);
- if (d->blur != 0)
- style.addProperty("calligra:shadow-blur-radius", QString("%1pt").arg(d->blur), KoGenStyle::GraphicType);
-}
-
void KoShapeShadow::paint(KoShape *shape, QPainter &painter)
{
if (! d->visible)
return;
// So the approach we are taking here is to draw into a buffer image the size of boundingRect
// We offset by the shadow offset at the time we draw into the buffer
// Then we filter the image and draw it at the position of the bounding rect on canvas
QTransform documentToView = painter.transform();
//the boundingRect of the shape or the KoSelection boundingRect of the group
QRectF shadowRect = shape->boundingRect();
QRectF zoomedClipRegion = documentToView.mapRect(shadowRect);
// Init the buffer image
QImage sourceGraphic(zoomedClipRegion.size().toSize(), QImage::Format_ARGB32_Premultiplied);
sourceGraphic.fill(qRgba(0,0,0,0));
// Init the buffer painter
QPainter imagePainter(&sourceGraphic);
imagePainter.setPen(Qt::NoPen);
imagePainter.setBrush(Qt::NoBrush);
imagePainter.setRenderHint(QPainter::Antialiasing, painter.testRenderHint(QPainter::Antialiasing));
// Since our imagebuffer and the canvas don't align we need to offset our drawings
imagePainter.translate(-1.0f*documentToView.map(shadowRect.topLeft()));
// Handle the shadow offset
imagePainter.translate(documentToView.map(offset()));
KoShapeGroup *group = dynamic_cast<KoShapeGroup*>(shape);
if (group) {
d->paintGroupShadow(group, imagePainter);
} else {
//apply shape's transformation
imagePainter.setTransform(shape->absoluteTransformation(), true);
d->paintShadow(shape, imagePainter);
}
imagePainter.end();
// Blur the shadow (well the entire buffer)
d->blurShadow(sourceGraphic, qRound(documentToView.m11() * d->blur), d->color);
// Paint the result
painter.save();
// The painter is initialized for us with canvas transform 'plus' shape transform
// we are only interested in the canvas transform so 'subtract' the shape transform part
painter.setTransform(shape->absoluteTransformation().inverted() * painter.transform());
painter.drawImage(zoomedClipRegion.topLeft(), sourceGraphic);
painter.restore();
}
void KoShapeShadow::setOffset(const QPointF & offset)
{
d->offset = offset;
}
QPointF KoShapeShadow::offset() const
{
return d->offset;
}
void KoShapeShadow::setColor(const QColor &color)
{
d->color = color;
}
QColor KoShapeShadow::color() const
{
return d->color;
}
void KoShapeShadow::setBlur(qreal blur)
{
// force positive blur radius
d->blur = qAbs(blur);
}
qreal KoShapeShadow::blur() const
{
return d->blur;
}
void KoShapeShadow::setVisible(bool visible)
{
d->visible = visible;
}
bool KoShapeShadow::isVisible() const
{
return d->visible;
}
void KoShapeShadow::insets(KoInsets &insets) const
{
if (!d->visible) {
insets.top = 0;
insets.bottom = 0;
insets.left = 0;
insets.right = 0;
return;
}
qreal expand = d->blur;
insets.left = (d->offset.x() < 0.0) ? qAbs(d->offset.x()) : 0.0;
insets.top = (d->offset.y() < 0.0) ? qAbs(d->offset.y()) : 0.0;
insets.right = (d->offset.x() > 0.0) ? d->offset.x() : 0.0;
insets.bottom = (d->offset.y() > 0.0) ? d->offset.y() : 0.0;
insets.left += expand;
insets.top += expand;
insets.right += expand;
insets.bottom += expand;
}
bool KoShapeShadow::ref()
{
return d->refCount.ref();
}
bool KoShapeShadow::deref()
{
return d->refCount.deref();
}
int KoShapeShadow::useCount() const
{
return d->refCount;
}
diff --git a/libs/flake/KoShapeShadow.h b/libs/flake/KoShapeShadow.h
index 6f6270481d..d25359baa3 100644
--- a/libs/flake/KoShapeShadow.h
+++ b/libs/flake/KoShapeShadow.h
@@ -1,114 +1,106 @@
/* This file is part of the KDE project
* Copyright (C) 2008 Jan Hambrecht <jaham@gmx.net>
* Copyright (C) 2010 Thomas Zander <zander@kde.org>
*
* 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 KOSHAPESHADOW_H
#define KOSHAPESHADOW_H
#include "kritaflake_export.h"
#include <QtGlobal>
class KoShape;
-class KoGenStyle;
class KoShapeSavingContext;
class QPainter;
class QPointF;
class QColor;
struct KoInsets;
class KRITAFLAKE_EXPORT KoShapeShadow
{
public:
KoShapeShadow();
~KoShapeShadow();
KoShapeShadow(const KoShapeShadow &rhs);
KoShapeShadow& operator=(const KoShapeShadow &rhs);
- /**
- * Fills the style object
- * @param style object
- * @param context used for saving
- */
- void fillStyle(KoGenStyle &style, KoShapeSavingContext &context);
-
/**
* Paints the shadow of the shape.
* @param shape the shape to paint around
* @param painter the painter to paint shadows to canvas
* @param converter to convert between internal and view coordinates.
*/
void paint(KoShape *shape, QPainter &painter);
/**
* Sets the shadow offset from the topleft corner of the shape
* @param offset the shadow offset
*/
void setOffset(const QPointF &offset);
/// Returns the shadow offset
QPointF offset() const;
/**
* Sets the shadow color, including the shadow opacity.
* @param color the shadow color and opacity
*/
void setColor(const QColor &color);
/// Returns the shadow color including opacity
QColor color() const;
/**
* Sets the shadow blur radius of the shape
* @param blur the shadow blur radius
*/
void setBlur(qreal blur);
/// Returns the shadow blur radius
qreal blur() const;
/// Sets the shadow visibility
void setVisible(bool visible);
/// Returns if shadow is visible
bool isVisible() const;
/// Fills the insets object with the space the shadow takes around a shape
void insets(KoInsets &insets) const;
/**
* Increments the use-value.
* Returns true if the new value is non-zero, false otherwise.
*/
bool ref();
/**
* Decrements the use-value.
* Returns true if the new value is non-zero, false otherwise.
*/
bool deref();
/// Return the usage count
int useCount() const;
private:
class Private;
Private * const d;
};
#endif // KOSHAPESHADOW_H
diff --git a/libs/flake/KoShapeStroke.cpp b/libs/flake/KoShapeStroke.cpp
index 2f84aa4a63..1117806a4c 100644
--- a/libs/flake/KoShapeStroke.cpp
+++ b/libs/flake/KoShapeStroke.cpp
@@ -1,418 +1,406 @@
/* This file is part of the KDE project
*
* Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
* Copyright (C) 2006-2008 Jan Hambrecht <jaham@gmx.net>
* Copyright (C) 2007,2009 Thorsten Zachmann <zachmann@kde.org>
* Copyright (C) 2012 Inge Wallin <inge@lysator.liu.se>
*
* 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.
*/
// Own
#include "KoShapeStroke.h"
// Posix
#include <math.h>
// Qt
#include <QPainterPath>
#include <QPainter>
// Calligra
-#include <KoGenStyles.h>
-#include <KoOdfGraphicStyles.h>
// Flake
#include "KoShape.h"
#include "KoShapeSavingContext.h"
#include "KoPathShape.h"
#include "KoMarker.h"
#include "KoInsets.h"
#include <KoPathSegment.h>
#include <KoPathPoint.h>
#include <cmath>
#include "KisQPainterStateSaver.h"
#include "kis_global.h"
class Q_DECL_HIDDEN KoShapeStroke::Private
{
public:
Private(KoShapeStroke *_q) : q(_q) {}
KoShapeStroke *q;
void paintBorder(const KoShape *shape, QPainter &painter, const QPen &pen) const;
QColor color;
QPen pen;
QBrush brush;
};
namespace {
QPair<qreal, qreal> anglesForSegment(KoPathSegment segment) {
const qreal eps = 1e-6;
if (segment.degree() < 3) {
segment = segment.toCubic();
}
QList<QPointF> points = segment.controlPoints();
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(points.size() == 4, qMakePair(0.0, 0.0));
QPointF vec1 = points[1] - points[0];
QPointF vec2 = points[3] - points[2];
if (vec1.manhattanLength() < eps) {
points[1] = segment.pointAt(eps);
vec1 = points[1] - points[0];
}
if (vec2.manhattanLength() < eps) {
points[2] = segment.pointAt(1.0 - eps);
vec2 = points[3] - points[2];
}
const qreal angle1 = std::atan2(vec1.y(), vec1.x());
const qreal angle2 = std::atan2(vec2.y(), vec2.x());
return qMakePair(angle1, angle2);
}
}
void KoShapeStroke::Private::paintBorder(const KoShape *shape, QPainter &painter, const QPen &pen) const
{
if (!pen.isCosmetic() && pen.style() != Qt::NoPen) {
const KoPathShape *pathShape = dynamic_cast<const KoPathShape *>(shape);
if (pathShape) {
QPainterPath path = pathShape->pathStroke(pen);
painter.fillPath(path, pen.brush());
if (!pathShape->hasMarkers()) return;
const bool autoFillMarkers = pathShape->autoFillMarkers();
KoMarker *startMarker = pathShape->marker(KoFlake::StartMarker);
KoMarker *midMarker = pathShape->marker(KoFlake::MidMarker);
KoMarker *endMarker = pathShape->marker(KoFlake::EndMarker);
for (int i = 0; i < pathShape->subpathCount(); i++) {
const int numSubPoints = pathShape->subpathPointCount(i);
if (numSubPoints < 2) continue;
const bool isClosedSubpath = pathShape->isClosedSubpath(i);
qreal firstAngle = 0.0;
{
KoPathSegment segment = pathShape->segmentByIndex(KoPathPointIndex(i, 0));
firstAngle= anglesForSegment(segment).first;
}
const int numSegments = isClosedSubpath ? numSubPoints : numSubPoints - 1;
qreal lastAngle = 0.0;
{
KoPathSegment segment = pathShape->segmentByIndex(KoPathPointIndex(i, numSegments - 1));
lastAngle = anglesForSegment(segment).second;
}
qreal previousAngle = 0.0;
for (int j = 0; j < numSegments; j++) {
KoPathSegment segment = pathShape->segmentByIndex(KoPathPointIndex(i, j));
QPair<qreal, qreal> angles = anglesForSegment(segment);
const qreal angle1 = angles.first;
const qreal angle2 = angles.second;
if (j == 0 && startMarker) {
const qreal angle = isClosedSubpath ? bisectorAngle(firstAngle, lastAngle) : firstAngle;
if (autoFillMarkers) {
startMarker->applyShapeStroke(shape, q, segment.first()->point(), pen.widthF(), angle);
}
startMarker->paintAtPosition(&painter, segment.first()->point(), pen.widthF(), angle);
}
if (j > 0 && midMarker) {
const qreal angle = bisectorAngle(previousAngle, angle1);
if (autoFillMarkers) {
midMarker->applyShapeStroke(shape, q, segment.first()->point(), pen.widthF(), angle);
}
midMarker->paintAtPosition(&painter, segment.first()->point(), pen.widthF(), angle);
}
if (j == numSegments - 1 && endMarker) {
const qreal angle = isClosedSubpath ? bisectorAngle(firstAngle, lastAngle) : lastAngle;
if (autoFillMarkers) {
endMarker->applyShapeStroke(shape, q, segment.second()->point(), pen.widthF(), angle);
}
endMarker->paintAtPosition(&painter, segment.second()->point(), pen.widthF(), angle);
}
previousAngle = angle2;
}
}
return;
}
painter.strokePath(shape->outline(), pen);
}
}
KoShapeStroke::KoShapeStroke()
: d(new Private(this))
{
d->color = QColor(Qt::black);
// we are not rendering stroke with zero width anymore
// so lets use a default width of 1.0
d->pen.setWidthF(1.0);
}
KoShapeStroke::KoShapeStroke(const KoShapeStroke &other)
: KoShapeStrokeModel(), d(new Private(this))
{
d->color = other.d->color;
d->pen = other.d->pen;
d->brush = other.d->brush;
}
KoShapeStroke::KoShapeStroke(qreal lineWidth, const QColor &color)
: d(new Private(this))
{
d->pen.setWidthF(qMax(qreal(0.0), lineWidth));
d->pen.setJoinStyle(Qt::MiterJoin);
d->color = color;
}
KoShapeStroke::~KoShapeStroke()
{
delete d;
}
KoShapeStroke &KoShapeStroke::operator = (const KoShapeStroke &rhs)
{
if (this == &rhs)
return *this;
d->pen = rhs.d->pen;
d->color = rhs.d->color;
d->brush = rhs.d->brush;
return *this;
}
-void KoShapeStroke::fillStyle(KoGenStyle &style, KoShapeSavingContext &context) const
-{
- QPen pen = d->pen;
- if (d->brush.gradient())
- pen.setBrush(d->brush);
- else
- pen.setColor(d->color);
- KoOdfGraphicStyles::saveOdfStrokeStyle(style, context.mainStyles(), pen);
-}
-
void KoShapeStroke::strokeInsets(const KoShape *shape, KoInsets &insets) const
{
Q_UNUSED(shape);
// '0.5' --- since we draw a line half inside, and half outside the object.
qreal extent = 0.5 * (d->pen.widthF() >= 0 ? d->pen.widthF() : 1.0);
// if we have square cap, we need a little more space
// -> sqrt((0.5*penWidth)^2 + (0.5*penWidth)^2)
if (capStyle() == Qt::SquareCap) {
extent *= M_SQRT2;
}
if (joinStyle() == Qt::MiterJoin) {
// miter limit in Qt is normalized by the line width (and not half-width)
extent = qMax(extent, d->pen.widthF() * miterLimit());
}
insets.top = extent;
insets.bottom = extent;
insets.left = extent;
insets.right = extent;
}
qreal KoShapeStroke::strokeMaxMarkersInset(const KoShape *shape) const
{
qreal result = 0.0;
const KoPathShape *pathShape = dynamic_cast<const KoPathShape *>(shape);
if (pathShape && pathShape->hasMarkers()) {
const qreal lineWidth = d->pen.widthF();
QVector<const KoMarker*> markers;
markers << pathShape->marker(KoFlake::StartMarker);
markers << pathShape->marker(KoFlake::MidMarker);
markers << pathShape->marker(KoFlake::EndMarker);
Q_FOREACH (const KoMarker *marker, markers) {
if (marker) {
result = qMax(result, marker->maxInset(lineWidth));
}
}
}
return result;
}
bool KoShapeStroke::hasTransparency() const
{
return d->color.alpha() > 0;
}
QPen KoShapeStroke::resultLinePen() const
{
QPen pen = d->pen;
if (d->brush.gradient()) {
pen.setBrush(d->brush);
} else {
pen.setColor(d->color);
}
return pen;
}
void KoShapeStroke::paint(const KoShape *shape, QPainter &painter) const
{
KisQPainterStateSaver saver(&painter);
d->paintBorder(shape, painter, resultLinePen());
}
bool KoShapeStroke::compareFillTo(const KoShapeStrokeModel *other)
{
if (!other) return false;
const KoShapeStroke *stroke = dynamic_cast<const KoShapeStroke*>(other);
if (!stroke) return false;
return (d->brush.gradient() && d->brush == stroke->d->brush) ||
(!d->brush.gradient() && d->color == stroke->d->color);
}
bool KoShapeStroke::compareStyleTo(const KoShapeStrokeModel *other)
{
if (!other) return false;
const KoShapeStroke *stroke = dynamic_cast<const KoShapeStroke*>(other);
if (!stroke) return false;
QPen pen1 = d->pen;
QPen pen2 = stroke->d->pen;
// just a random color top avoid comparison of that property
pen1.setColor(Qt::magenta);
pen2.setColor(Qt::magenta);
return pen1 == pen2;
}
bool KoShapeStroke::isVisible() const
{
return d->pen.widthF() > 0 &&
(d->brush.gradient() || d->color.alpha() > 0);
}
void KoShapeStroke::setCapStyle(Qt::PenCapStyle style)
{
d->pen.setCapStyle(style);
}
Qt::PenCapStyle KoShapeStroke::capStyle() const
{
return d->pen.capStyle();
}
void KoShapeStroke::setJoinStyle(Qt::PenJoinStyle style)
{
d->pen.setJoinStyle(style);
}
Qt::PenJoinStyle KoShapeStroke::joinStyle() const
{
return d->pen.joinStyle();
}
void KoShapeStroke::setLineWidth(qreal lineWidth)
{
d->pen.setWidthF(qMax(qreal(0.0), lineWidth));
}
qreal KoShapeStroke::lineWidth() const
{
return d->pen.widthF();
}
void KoShapeStroke::setMiterLimit(qreal miterLimit)
{
d->pen.setMiterLimit(miterLimit);
}
qreal KoShapeStroke::miterLimit() const
{
return d->pen.miterLimit();
}
QColor KoShapeStroke::color() const
{
return d->color;
}
void KoShapeStroke::setColor(const QColor &color)
{
d->color = color;
}
void KoShapeStroke::setLineStyle(Qt::PenStyle style, const QVector<qreal> &dashes)
{
if (style < Qt::CustomDashLine) {
d->pen.setStyle(style);
} else {
d->pen.setDashPattern(dashes);
}
}
Qt::PenStyle KoShapeStroke::lineStyle() const
{
return d->pen.style();
}
QVector<qreal> KoShapeStroke::lineDashes() const
{
return d->pen.dashPattern();
}
void KoShapeStroke::setDashOffset(qreal dashOffset)
{
d->pen.setDashOffset(dashOffset);
}
qreal KoShapeStroke::dashOffset() const
{
return d->pen.dashOffset();
}
void KoShapeStroke::setLineBrush(const QBrush &brush)
{
d->brush = brush;
}
QBrush KoShapeStroke::lineBrush() const
{
return d->brush;
}
diff --git a/libs/flake/KoShapeStroke.h b/libs/flake/KoShapeStroke.h
index 154e8c0de2..aa00fcea11 100644
--- a/libs/flake/KoShapeStroke.h
+++ b/libs/flake/KoShapeStroke.h
@@ -1,122 +1,121 @@
/* This file is part of the KDE project
*
* Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
* Copyright (C) 2006-2008 Jan Hambrecht <jaham@gmx.net>
* Copyright (C) 2007,2009 Thorsten Zachmann <zachmann@kde.org>
* Copyright (C) 2012 Inge Wallin <inge@lysator.liu.se>
*
* 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 KOSHAPESTROKE_H
#define KOSHAPESTROKE_H
#include "KoFlakeTypes.h"
#include "KoShapeStrokeModel.h"
#include "kritaflake_export.h"
#include <QMetaType>
#include <QColor>
class KoShape;
class QPainter;
class QBrush;
class QPen;
struct KoInsets;
/**
* A border for shapes that draws a single line around the object.
*/
class KRITAFLAKE_EXPORT KoShapeStroke : public KoShapeStrokeModel
{
public:
/// Constructor for a thin line in black
KoShapeStroke();
/// Copy constructor
KoShapeStroke(const KoShapeStroke &other);
/**
* Constructor for a Stroke
* @param lineWidth the width, in pt
* @param color the color we draw the outline in.
*/
explicit KoShapeStroke(qreal lineWidth, const QColor &color = Qt::black);
~KoShapeStroke() override;
/// Assignment operator
KoShapeStroke& operator = (const KoShapeStroke &rhs);
/// Sets the lines cap style
void setCapStyle(Qt::PenCapStyle style);
/// Returns the lines cap style
Qt::PenCapStyle capStyle() const;
/// Sets the lines join style
void setJoinStyle(Qt::PenJoinStyle style);
/// Returns the lines join style
Qt::PenJoinStyle joinStyle() const;
/// Sets the line width
void setLineWidth(qreal lineWidth);
/// Returns the line width
qreal lineWidth() const;
/// Sets the miter limit
void setMiterLimit(qreal miterLimit);
/// Returns the miter limit
qreal miterLimit() const;
/// Sets the line style
void setLineStyle(Qt::PenStyle style, const QVector<qreal> &dashes);
/// Returns the line style
Qt::PenStyle lineStyle() const;
/// Returns the line dashes
QVector<qreal> lineDashes() const;
/// Sets the dash offset
void setDashOffset(qreal dashOffset);
/// Returns the dash offset
qreal dashOffset() const;
/// Returns the color
QColor color() const;
/// Sets the color
void setColor(const QColor &color);
/// Sets the strokes brush used to fill strokes of this border
void setLineBrush(const QBrush & brush);
/// Returns the strokes brush
QBrush lineBrush() const;
// pure virtuals from KoShapeStrokeModel implemented here.
- void fillStyle(KoGenStyle &style, KoShapeSavingContext &context) const override;
void strokeInsets(const KoShape *shape, KoInsets &insets) const override;
qreal strokeMaxMarkersInset(const KoShape *shape) const override;
bool hasTransparency() const override;
void paint(const KoShape *shape, QPainter &painter) const override;
QPen resultLinePen() const;
bool compareFillTo(const KoShapeStrokeModel *other) override;
bool compareStyleTo(const KoShapeStrokeModel *other) override;
bool isVisible() const override;
private:
class Private;
Private * const d;
};
Q_DECLARE_METATYPE( KoShapeStroke )
#endif // KOSHAPESTROKE_H
diff --git a/libs/flake/KoShapeStrokeModel.h b/libs/flake/KoShapeStrokeModel.h
index 45c5ab145d..edd6b901e2 100644
--- a/libs/flake/KoShapeStrokeModel.h
+++ b/libs/flake/KoShapeStrokeModel.h
@@ -1,91 +1,82 @@
/* This file is part of the KDE project
*
* Copyright (C) 2006 Thomas Zander <zander@kde.org>
* Copyright (C) 2007,2009 Thorsten Zachmann <zachmann@kde.org>
* Copyright (C) 2012 Inge Wallin <inge@lysator.liu.se>
*
* 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 KOSHAPESTROKEMODEL_H
#define KOSHAPESTROKEMODEL_H
#include "kritaflake_export.h"
#include <QtGlobal>
class KoShape;
-class KoGenStyle;
class KoShapeSavingContext;
struct KoInsets;
class QColor;
class QPainter;
/**
* A model for strokes of KoShapes.
* Classes that implement this model will be allowed to draw the stroke of the outline
* of a shape.
* Note that since the important members take a KoShape as argument it is possible,
* and preferred behavior, to have one instance of a stroke that is reused on several
* objects.
*/
class KRITAFLAKE_EXPORT KoShapeStrokeModel
{
public:
virtual ~KoShapeStrokeModel();
- /**
- * @brief Fill the style object (aka save)
- *
- * @param style object
- * @param context used for saving
- */
- virtual void fillStyle(KoGenStyle &style, KoShapeSavingContext &context) const = 0;
-
/**
* Return a strokeInsets object filled with the size inside the shape that this stroke takes.
* @param shape the shape the insets will be calculated for
* @param insets the insets object that will be filled and returned.
*/
virtual void strokeInsets(const KoShape *shape, KoInsets &insets) const = 0;
/**
* Return a maximum distance that the markers of the shape can take outside the
* shape itself
*/
virtual qreal strokeMaxMarkersInset(const KoShape *shape) const = 0;
/**
* Returns true if there is some transparency, false if the stroke is fully opaque.
* @return if the stroke is transparent.
*/
virtual bool hasTransparency() const = 0;
/**
* Paint the stroke.
* This method should paint the stroke around shape.
* @param shape the shape to paint around
* @param painter the painter to paint to, the painter will have the topleft of the
* shape as its start coordinate.
*/
virtual void paint(const KoShape *shape, QPainter &painter) const = 0;
virtual bool compareFillTo(const KoShapeStrokeModel *other) = 0;
virtual bool compareStyleTo(const KoShapeStrokeModel *other) = 0;
virtual bool isVisible() const = 0;
};
#endif
diff --git a/libs/flake/KoShape_p.h b/libs/flake/KoShape_p.h
index fbd34abf42..0683e1028b 100644
--- a/libs/flake/KoShape_p.h
+++ b/libs/flake/KoShape_p.h
@@ -1,121 +1,97 @@
/* This file is part of the KDE project
* Copyright (C) 2009 Thomas Zander <zander@kde.org>
* Copyright (C) 2010 Boudewijn Rempt <boud@valdyas.org>
*
* 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 KOSHAPEPRIVATE_H
#define KOSHAPEPRIVATE_H
#include "KoShape.h"
#include <QPoint>
#include <QPaintDevice>
#include <QTransform>
#include <QScopedPointer>
#include <QSharedData>
#include <KoClipMask.h>
-class KoBorder;
class KoShapeManager;
class KoShape::SharedData : public QSharedData
{
public:
explicit SharedData();
virtual ~SharedData();
explicit SharedData(const SharedData &rhs);
- /**
- * Fills the style stack and returns the value of the given style property (e.g fill, stroke).
- */
- static QString getStyleProperty(const char *property, KoShapeLoadingContext &context);
-
- /// Loads the shadow style
- KoShapeShadow *loadOdfShadow(KoShapeLoadingContext &context) const;
-
- // Loads the border style.
- KoBorder *loadOdfBorder(KoShapeLoadingContext &context) const;
-
public:
// Members
mutable QSizeF size; // size in pt
QString shapeId;
QString name; ///< the shapes names
QTransform localMatrix; ///< the shapes local transformation matrix
- KoConnectionPoints connectors; ///< glue point id to data mapping
-
QScopedPointer<KoShapeUserData> userData;
QSharedPointer<KoShapeStrokeModel> stroke; ///< points to a stroke, or 0 if there is no stroke
QSharedPointer<KoShapeBackground> fill; ///< Stands for the background color / fill etc.
bool inheritBackground = false;
bool inheritStroke = false;
KoShapeShadow * shadow; ///< the current shape shadow
- KoBorder *border; ///< the current shape border
// XXX: change this to instance instead of pointer
QScopedPointer<KoClipPath> clipPath; ///< the current clip path
QScopedPointer<KoClipMask> clipMask; ///< the current clip mask
QMap<QString, QString> additionalAttributes;
QMap<QByteArray, QString> additionalStyleAttributes;
KoFilterEffectStack *filterEffectStack; ///< stack of filter effects applied to the shape
qreal transparency; ///< the shapes transparency
QString hyperLink; //hyperlink for this shape
int zIndex : 16; // keep maxZIndex in sync!
int runThrough : 16;
int visible : 1;
int printable : 1;
int geometryProtected : 1;
int keepAspect : 1;
int selectable : 1;
int protectContent : 1;
KoShape::TextRunAroundSide textRunAroundSide;
qreal textRunAroundDistanceLeft;
qreal textRunAroundDistanceTop;
qreal textRunAroundDistanceRight;
qreal textRunAroundDistanceBottom;
qreal textRunAroundThreshold;
KoShape::TextRunAroundContour textRunAroundContour;
-
-public:
- /// Connection point converters
-
- /// Convert connection point position from shape coordinates, taking alignment into account
- void convertFromShapeCoordinates(KoConnectionPoint &point, const QSizeF &shapeSize) const;
-
- /// Convert connection point position to shape coordinates, taking alignment into account
- void convertToShapeCoordinates(KoConnectionPoint &point, const QSizeF &shapeSize) const;
};
class KoShape::Private
{
public:
KoShapeContainer *parent;
QSet<KoShapeManager *> shapeManagers;
QSet<KoShape *> toolDelegates;
QList<KoShape*> dependees; ///< list of shape dependent on this shape
QList<KoShape::ShapeChangeListener*> listeners;
};
#endif
diff --git a/libs/flake/KoTextShapeDataBase.h b/libs/flake/KoTextShapeDataBase.h
index a5aab94bc1..1ef4d151eb 100644
--- a/libs/flake/KoTextShapeDataBase.h
+++ b/libs/flake/KoTextShapeDataBase.h
@@ -1,145 +1,119 @@
/* This file is part of the KDE project
* Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
*
* 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 KOTEXTSHAPEDATABASE_H
#define KOTEXTSHAPEDATABASE_H
#include "kritaflake_export.h"
#include "KoShapeUserData.h"
class KoTextShapeDataBasePrivate;
#include <KoXmlReaderForward.h>
class KoShapeLoadingContext;
class KoShapeSavingContext;
-class KoGenStyle;
struct KoInsets;
class QTextDocument;
/**
* \internal
*/
class KRITAFLAKE_EXPORT KoTextShapeDataBase : public KoShapeUserData
{
Q_OBJECT
public:
/// constructor
KoTextShapeDataBase();
~KoTextShapeDataBase() override;
/// return the document
QTextDocument *document() const;
/**
* Set the margins that will make the shapes text area smaller.
* The shape that owns this textShapeData object will layout text in an area
* confined by the shape size made smaller by the margins set here.
* @param margins the margins that shrink the text area.
*/
void setShapeMargins(const KoInsets &margins);
/**
* returns the currently set margins for the shape.
*/
KoInsets shapeMargins() const;
- /**
- * Load the text from ODF.
- */
- virtual bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) = 0;
-
- /**
- * Save the text to ODF.
- */
- virtual void saveOdf(KoShapeSavingContext &context, int from = 0, int to = -1) const = 0;
-
- /**
- * Load the style of the element
- *
- * This method is used to load the style in case the TextShape is used as TOS. In this case
- * the paragraph style of the shape e.g. a custom-shape needs to be applied before we load the
- * text so all looks as it should look.
- */
- virtual void loadStyle(const KoXmlElement &element, KoShapeLoadingContext &context) = 0;
- /**
- * Save the style of the element
- *
- * This method save the style in case the TextShape is used as TOS. In this case the paragraph
- * style of the shape e.g. a custom-shape needs to be saved with the style of the shape.
- */
- virtual void saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const = 0;
-
/** Sets the vertical alignment of all the text inside the shape. */
void setVerticalAlignment(Qt::Alignment alignment);
+
/** Returns the vertical alignment of all the text in the shape */
Qt::Alignment verticalAlignment() const;
/**
* Enum to describe the text document's automatic resizing behaviour.
*/
enum ResizeMethod {
/// Resize the shape to fit the content. This makes sure that the text shape takes op
/// only as much space as absolutely necessary to fit the entire text into its boundaries.
AutoResize,
/// Specifies whether or not to automatically increase the width of the drawing object
/// if text is added to fit the entire width of the text into its boundaries.
/// Compared to AutoResize above this only applied to the width whereas the height is
/// not resized. Also this only grows but does not shrink again if text is removed again.
AutoGrowWidth,
/// Specifies whether or not to automatically increase the height of the drawing object
/// if text is added to fit the entire height of the text into its boundaries.
AutoGrowHeight,
/// This combines the AutoGrowWidth and AutoGrowHeight and automatically increase width
/// and height to fit the entire text into its boundaries.
AutoGrowWidthAndHeight,
/// Shrink the content displayed within the shape to match into the shape's boundaries. This
/// will scale the content down as needed to display the whole document.
ShrinkToFitResize,
/// Deactivates auto-resizing. This is the default resizing method.
NoResize
};
/**
* Specifies how the document should be resized upon a change in the document.
*
* If auto-resizing is turned on, text will not be wrapped unless enforced by e.g. a newline.
*
* By default, NoResize is set.
*/
void setResizeMethod(ResizeMethod method);
/**
* Returns the auto-resizing mode. By default, this is NoResize.
*
* @see setResizeMethod
*/
ResizeMethod resizeMethod() const;
protected:
/// constructor
KoTextShapeDataBase(KoTextShapeDataBasePrivate *);
KoTextShapeDataBasePrivate *d_ptr;
private:
Q_DECLARE_PRIVATE(KoTextShapeDataBase)
};
#endif
diff --git a/libs/flake/KoToolProxy.cpp b/libs/flake/KoToolProxy.cpp
index 55d4a4b29a..3144a8d8d7 100644
--- a/libs/flake/KoToolProxy.cpp
+++ b/libs/flake/KoToolProxy.cpp
@@ -1,496 +1,495 @@
/* This file is part of the KDE project
* Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
* Copyright (c) 2006-2011 Boudewijn Rempt <boud@valdyas.org>
*
* 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 "KoToolProxy.h"
#include "KoToolProxy_p.h"
#include <QMimeData>
#include <QUrl>
#include <QTimer>
#include <QApplication>
#include <QTouchEvent>
#include <QClipboard>
#include <kundo2command.h>
#include <KoProperties.h>
#include <FlakeDebug.h>
#include <klocalizedstring.h>
#include "KoToolBase.h"
#include "KoPointerEvent.h"
#include "KoInputDevice.h"
#include "KoToolManager_p.h"
#include "KoToolSelection.h"
#include "KoCanvasBase.h"
#include "KoCanvasController.h"
#include "KoShapeManager.h"
#include "KoSelection.h"
#include "KoShapeLayer.h"
#include "KoShapeRegistry.h"
#include "KoShapeController.h"
-#include "KoOdf.h"
#include "KoViewConverter.h"
#include "KoShapeFactoryBase.h"
KoToolProxyPrivate::KoToolProxyPrivate(KoToolProxy *p)
: parent(p)
{
scrollTimer.setInterval(100);
}
void KoToolProxyPrivate::timeout() // Auto scroll the canvas
{
Q_ASSERT(controller);
QPoint offset = QPoint(controller->canvasOffsetX(), controller->canvasOffsetY());
QPoint origin = controller->canvas()->documentOrigin();
QPoint viewPoint = widgetScrollPoint - origin - offset;
QRectF mouseArea(viewPoint, QSizeF(10, 10));
mouseArea.setTopLeft(mouseArea.center());
controller->ensureVisible(mouseArea, true);
QPoint newOffset = QPoint(controller->canvasOffsetX(), controller->canvasOffsetY());
QPoint moved = offset - newOffset;
if (moved.isNull())
return;
widgetScrollPoint += moved;
QPointF documentPoint = parent->widgetToDocument(widgetScrollPoint);
QMouseEvent event(QEvent::MouseMove, widgetScrollPoint, Qt::LeftButton, Qt::LeftButton, 0);
KoPointerEvent ev(&event, documentPoint);
activeTool->mouseMoveEvent(&ev);
}
void KoToolProxyPrivate::checkAutoScroll(const KoPointerEvent &event)
{
if (controller == 0) return;
if (!activeTool) return;
if (!activeTool->wantsAutoScroll()) return;
if (!event.isAccepted()) return;
if (!isToolPressed) return;
if (event.buttons() != Qt::LeftButton) return;
widgetScrollPoint = event.pos();
if (! scrollTimer.isActive())
scrollTimer.start();
}
void KoToolProxyPrivate::selectionChanged(bool newSelection)
{
if (hasSelection == newSelection)
return;
hasSelection = newSelection;
emit parent->selectionChanged(hasSelection);
}
bool KoToolProxyPrivate::isActiveLayerEditable()
{
if (!activeTool)
return false;
KoShapeManager * shapeManager = activeTool->canvas()->shapeManager();
KoShapeLayer * activeLayer = shapeManager->selection()->activeLayer();
if (activeLayer && !activeLayer->isShapeEditable())
return false;
return true;
}
KoToolProxy::KoToolProxy(KoCanvasBase *canvas, QObject *parent)
: QObject(parent),
d(new KoToolProxyPrivate(this))
{
KoToolManager::instance()->priv()->registerToolProxy(this, canvas);
connect(&d->scrollTimer, SIGNAL(timeout()), this, SLOT(timeout()));
}
KoToolProxy::~KoToolProxy()
{
delete d;
}
void KoToolProxy::paint(QPainter &painter, const KoViewConverter &converter)
{
if (d->activeTool) d->activeTool->paint(painter, converter);
}
void KoToolProxy::repaintDecorations()
{
if (d->activeTool) d->activeTool->repaintDecorations();
}
QPointF KoToolProxy::widgetToDocument(const QPointF &widgetPoint) const
{
QPoint offset = QPoint(d->controller->canvasOffsetX(), d->controller->canvasOffsetY());
QPoint origin = d->controller->canvas()->documentOrigin();
QPointF viewPoint = widgetPoint.toPoint() - QPointF(origin - offset);
return d->controller->canvas()->viewConverter()->viewToDocument(viewPoint);
}
KoCanvasBase* KoToolProxy::canvas() const
{
return d->controller->canvas();
}
void KoToolProxy::tabletEvent(QTabletEvent *event, const QPointF &point)
{
// We get these events exclusively from KisToolProxy - accept them
event->accept();
KoInputDevice id(event->device(), event->pointerType(), event->uniqueId());
KoToolManager::instance()->priv()->switchInputDevice(id);
KoPointerEvent ev(event, point);
switch (event->type()) {
case QEvent::TabletPress:
ev.setTabletButton(Qt::LeftButton);
if (!d->tabletPressed && d->activeTool)
d->activeTool->mousePressEvent(&ev);
d->tabletPressed = true;
break;
case QEvent::TabletRelease:
ev.setTabletButton(Qt::LeftButton);
d->tabletPressed = false;
d->scrollTimer.stop();
if (d->activeTool)
d->activeTool->mouseReleaseEvent(&ev);
break;
case QEvent::TabletMove:
if (d->tabletPressed)
ev.setTabletButton(Qt::LeftButton);
if (d->activeTool)
d->activeTool->mouseMoveEvent(&ev);
d->checkAutoScroll(ev);
default:
; // ignore the rest.
}
d->mouseLeaveWorkaround = true;
}
void KoToolProxy::mousePressEvent(KoPointerEvent *ev)
{
d->mouseLeaveWorkaround = false;
KoInputDevice id;
KoToolManager::instance()->priv()->switchInputDevice(id);
d->mouseDownPoint = ev->pos();
// this tries to make sure another mouse press event doesn't happen
// before a release event happens
if (d->isToolPressed) {
mouseReleaseEvent(ev);
d->tabletPressed = false;
d->scrollTimer.stop();
if (d->activeTool) {
d->activeTool->mouseReleaseEvent(ev);
}
d->isToolPressed = false;
return;
}
QPointF globalPoint = ev->globalPos();
if (d->multiClickGlobalPoint != globalPoint) {
if (qAbs(globalPoint.x() - d->multiClickGlobalPoint.x()) > 5||
qAbs(globalPoint.y() - d->multiClickGlobalPoint.y()) > 5) {
d->multiClickCount = 0;
}
d->multiClickGlobalPoint = globalPoint;
}
if (d->multiClickCount && d->multiClickTimeStamp.elapsed() < QApplication::doubleClickInterval()) {
// One more multiclick;
d->multiClickCount++;
} else {
d->multiClickTimeStamp.start();
d->multiClickCount = 1;
}
if (d->activeTool) {
switch (d->multiClickCount) {
case 0:
case 1:
d->activeTool->mousePressEvent(ev);
break;
case 2:
d->activeTool->mouseDoubleClickEvent(ev);
break;
case 3:
default:
d->activeTool->mouseTripleClickEvent(ev);
break;
}
} else {
d->multiClickCount = 0;
ev->ignore();
}
d->isToolPressed = true;
}
void KoToolProxy::mousePressEvent(QMouseEvent *event, const QPointF &point)
{
KoPointerEvent ev(event, point);
mousePressEvent(&ev);
}
void KoToolProxy::mouseDoubleClickEvent(QMouseEvent *event, const QPointF &point)
{
KoPointerEvent ev(event, point);
mouseDoubleClickEvent(&ev);
}
void KoToolProxy::mouseDoubleClickEvent(KoPointerEvent *event)
{
// let us handle it as any other mousepress (where we then detect multi clicks
mousePressEvent(event);
}
void KoToolProxy::mouseMoveEvent(QMouseEvent *event, const QPointF &point)
{
KoPointerEvent ev(event, point);
mouseMoveEvent(&ev);
}
void KoToolProxy::mouseMoveEvent(KoPointerEvent *event)
{
if (d->mouseLeaveWorkaround) {
d->mouseLeaveWorkaround = false;
return;
}
KoInputDevice id;
KoToolManager::instance()->priv()->switchInputDevice(id);
if (d->activeTool == 0) {
event->ignore();
return;
}
d->activeTool->mouseMoveEvent(event);
d->checkAutoScroll(*event);
}
void KoToolProxy::mouseReleaseEvent(QMouseEvent *event, const QPointF &point)
{
KoPointerEvent ev(event, point);
mouseReleaseEvent(&ev);
}
void KoToolProxy::mouseReleaseEvent(KoPointerEvent* event)
{
d->mouseLeaveWorkaround = false;
KoInputDevice id;
KoToolManager::instance()->priv()->switchInputDevice(id);
d->scrollTimer.stop();
if (d->activeTool) {
d->activeTool->mouseReleaseEvent(event);
} else {
event->ignore();
}
d->isToolPressed = false;
}
void KoToolProxy::keyPressEvent(QKeyEvent *event)
{
if (d->activeTool)
d->activeTool->keyPressEvent(event);
else
event->ignore();
}
void KoToolProxy::keyReleaseEvent(QKeyEvent *event)
{
if (d->activeTool)
d->activeTool->keyReleaseEvent(event);
else
event->ignore();
d->isToolPressed = false;
}
void KoToolProxy::explicitUserStrokeEndRequest()
{
if (d->activeTool) {
d->activeTool->explicitUserStrokeEndRequest();
}
}
QVariant KoToolProxy::inputMethodQuery(Qt::InputMethodQuery query, const KoViewConverter &converter) const
{
if (d->activeTool)
return d->activeTool->inputMethodQuery(query, converter);
return QVariant();
}
void KoToolProxy::inputMethodEvent(QInputMethodEvent *event)
{
if (d->activeTool) d->activeTool->inputMethodEvent(event);
}
QMenu *KoToolProxy::popupActionsMenu()
{
return d->activeTool ? d->activeTool->popupActionsMenu() : 0;
}
void KoToolProxy::setActiveTool(KoToolBase *tool)
{
if (d->activeTool)
disconnect(d->activeTool, SIGNAL(selectionChanged(bool)), this, SLOT(selectionChanged(bool)));
d->activeTool = tool;
if (tool) {
connect(d->activeTool, SIGNAL(selectionChanged(bool)), this, SLOT(selectionChanged(bool)));
d->selectionChanged(hasSelection());
emit toolChanged(tool->toolId());
}
}
void KoToolProxy::touchEvent(QTouchEvent* event, const QPointF& point)
{
// only one "touchpoint" events should be here
KoPointerEvent ev(event, point);
if (!d->activeTool) return;
switch (event->touchPointStates())
{
case Qt::TouchPointPressed:
d->activeTool->mousePressEvent(&ev);
break;
case Qt::TouchPointMoved:
d->activeTool->mouseMoveEvent(&ev);
break;
case Qt::TouchPointReleased:
d->activeTool->mouseReleaseEvent(&ev);
break;
default: // don't care
;
}
}
void KoToolProxyPrivate::setCanvasController(KoCanvasController *c)
{
controller = c;
}
bool KoToolProxy::hasSelection() const
{
return d->activeTool ? d->activeTool->hasSelection() : false;
}
void KoToolProxy::cut()
{
if (d->activeTool && d->isActiveLayerEditable())
d->activeTool->cut();
}
void KoToolProxy::copy() const
{
if (d->activeTool)
d->activeTool->copy();
}
bool KoToolProxy::paste()
{
bool success = false;
if (d->activeTool && d->isActiveLayerEditable()) {
success = d->activeTool->paste();
}
return success;
}
void KoToolProxy::dragMoveEvent(QDragMoveEvent *event, const QPointF &point)
{
if (d->activeTool)
d->activeTool->dragMoveEvent(event, point);
}
void KoToolProxy::dragLeaveEvent(QDragLeaveEvent *event)
{
if (d->activeTool)
d->activeTool->dragLeaveEvent(event);
}
void KoToolProxy::dropEvent(QDropEvent *event, const QPointF &point)
{
if (d->activeTool)
d->activeTool->dropEvent(event, point);
}
void KoToolProxy::deleteSelection()
{
if (d->activeTool)
d->activeTool->deleteSelection();
}
void KoToolProxy::processEvent(QEvent *e) const
{
if(e->type()==QEvent::ShortcutOverride
&& d->activeTool
&& d->activeTool->isInTextMode()
&& (static_cast<QKeyEvent*>(e)->modifiers()==Qt::NoModifier ||
static_cast<QKeyEvent*>(e)->modifiers()==Qt::ShiftModifier)) {
e->accept();
}
}
void KoToolProxy::requestUndoDuringStroke()
{
if (d->activeTool) {
d->activeTool->requestUndoDuringStroke();
}
}
void KoToolProxy::requestStrokeCancellation()
{
if (d->activeTool) {
d->activeTool->requestStrokeCancellation();
}
}
void KoToolProxy::requestStrokeEnd()
{
if (d->activeTool) {
d->activeTool->requestStrokeEnd();
}
}
KoToolProxyPrivate *KoToolProxy::priv()
{
return d;
}
//have to include this because of Q_PRIVATE_SLOT
#include "moc_KoToolProxy.cpp"
diff --git a/libs/flake/KoTosContainer.cpp b/libs/flake/KoTosContainer.cpp
index 484530451f..d13f4a6d9e 100644
--- a/libs/flake/KoTosContainer.cpp
+++ b/libs/flake/KoTosContainer.cpp
@@ -1,349 +1,248 @@
/* This file is part of the KDE project
* Copyright (C) 2010 Thomas Zander <zander@kde.org>
* Copyright (C) 2010 KO GmbH <boud@valdyas.org>
* Copyright (C) 2010 Thorsten Zachmann <zachmann@kde.org>
*
* 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 "KoTosContainer.h"
#include "KoTosContainer_p.h"
#include "KoShapeRegistry.h"
#include "KoShapeFactoryBase.h"
#include "KoShapeLoadingContext.h"
#include "KoTextShapeDataBase.h"
#include "KoTosContainerModel.h"
-#include "KoStyleStack.h"
-#include "KoOdfLoadingContext.h"
#include "KoXmlNS.h"
-#include "KoGenStyle.h"
#include <FlakeDebug.h>
#include <QTextCursor>
#include <QTextDocument>
KoTosContainer::Private::Private()
: QSharedData()
, resizeBehavior(KoTosContainer::IndependentSizes)
{
}
KoTosContainer::Private::Private(const Private &rhs)
: QSharedData()
, resizeBehavior(rhs.resizeBehavior)
, preferredTextRect(rhs.preferredTextRect)
, alignment(rhs.alignment)
{
}
KoTosContainer::Private::~Private()
{
}
KoTosContainer::KoTosContainer()
: KoShapeContainer()
, d(new Private)
{
}
KoTosContainer::KoTosContainer(const KoTosContainer &rhs)
: KoShapeContainer(rhs)
, d(rhs.d)
{
}
KoTosContainer::~KoTosContainer()
{
delete textShape();
}
void KoTosContainer::paintComponent(QPainter &, KoShapePaintingContext &) const
{
}
bool KoTosContainer::loadText(const KoXmlElement &element, KoShapeLoadingContext &context)
{
- KoXmlElement child;
- forEachElement(child, element) {
- // only recreate the text shape if there's something to be loaded
- if (child.localName() == "p" || child.localName() == "list") {
-
- KoShape *textShape = createTextShape(context.documentResourceManager());
- if (!textShape) {
- return false;
- }
- //apply the style properties to the loaded text
- setTextAlignment(d->alignment);
-
- // In the case of text on shape, we cannot ask the text shape to load
- // the odf, since it expects a complete document with style info and
- // everything, so we have to use the KoTextShapeData object instead.
- KoTextShapeDataBase *shapeData = qobject_cast<KoTextShapeDataBase*>(textShape->userData());
- Q_ASSERT(shapeData);
- shapeData->loadStyle(element, context);
- bool loadOdf = shapeData->loadOdf(element, context);
-
- return loadOdf;
- }
- }
- return true;
+ return false;
}
-void KoTosContainer::loadStyle(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- KoShapeContainer::loadStyle(element, context);
-
- KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
- styleStack.setTypeProperties("graphic");
-
- QString verticalAlign(styleStack.property(KoXmlNS::draw, "textarea-vertical-align"));
- Qt::Alignment vAlignment(Qt::AlignTop);
- if (verticalAlign == "bottom") {
- vAlignment = Qt::AlignBottom;
- } else if (verticalAlign == "justify") {
- // not yet supported
- vAlignment = Qt::AlignVCenter;
- } else if (verticalAlign == "middle") {
- vAlignment = Qt::AlignVCenter;
- }
-
- QString horizontalAlign(styleStack.property(KoXmlNS::draw, "textarea-horizontal-align"));
- Qt::Alignment hAlignment(Qt::AlignLeft);
- if (horizontalAlign == "center") {
- hAlignment = Qt::AlignCenter;
- } else if (horizontalAlign == "justify") {
- // not yet supported
- hAlignment = Qt::AlignCenter;
- } else if (horizontalAlign == "right") {
- hAlignment = Qt::AlignRight;
- }
-
- d->alignment = vAlignment | hAlignment;
-}
-
-QString KoTosContainer::saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const
-{
- Qt::Alignment alignment = textAlignment();
- QString verticalAlignment = "top";
- Qt::Alignment vAlignment(alignment & Qt::AlignVertical_Mask);
- if (vAlignment == Qt::AlignBottom) {
- verticalAlignment = "bottom";
- } else if (vAlignment == Qt::AlignVCenter || vAlignment == Qt::AlignCenter) {
- verticalAlignment = "middle";
- }
-
- style.addProperty("draw:textarea-vertical-align", verticalAlignment);
-
- QString horizontalAlignment = "left";
- Qt::Alignment hAlignment(alignment & Qt::AlignHorizontal_Mask);
- if (hAlignment == Qt::AlignCenter || hAlignment == Qt::AlignHCenter) {
- horizontalAlignment = "center";
- } else if (hAlignment == Qt::AlignJustify) {
- horizontalAlignment = "justify";
- } else if (hAlignment == Qt::AlignRight) {
- horizontalAlignment = "right";
- }
-
- style.addProperty("draw:textarea-horizontal-align", horizontalAlignment);
-
- return KoShapeContainer::saveStyle(style, context);
-}
-
-void KoTosContainer::saveText(KoShapeSavingContext &context) const
-{
- KoShape *textShape = this->textShape();
- if (!textShape) {
- return;
- }
- // In the case of text on shape, we cannot ask the text shape to save
- // the odf, since it would save all the frame information as well, which
- // is wrong.
- // Only save the text shape if it has content.
- KoTextShapeDataBase *shapeData = qobject_cast<KoTextShapeDataBase*>(textShape->userData());
- if (shapeData && !shapeData->document()->isEmpty()) {
- shapeData->saveOdf(context);
- }
-}
void KoTosContainer::setPlainText(const QString &text)
{
KoShape *textShape = this->textShape();
if (textShape == 0) {
warnFlake << "No text shape present in KoTosContainer";
return;
}
KoTextShapeDataBase *shapeData = qobject_cast<KoTextShapeDataBase*>(textShape->userData());
Q_ASSERT(shapeData->document());
shapeData->document()->setPlainText(text);
}
void KoTosContainer::setResizeBehavior(ResizeBehavior resizeBehavior)
{
if (d->resizeBehavior == resizeBehavior) {
return;
}
d->resizeBehavior = resizeBehavior;
if (model()) {
model()->containerChanged(this, KoShape::SizeChanged);
}
}
KoTosContainer::ResizeBehavior KoTosContainer::resizeBehavior() const
{
return d->resizeBehavior;
}
void KoTosContainer::setTextAlignment(Qt::Alignment alignment)
{
KoShape *textShape = this->textShape();
if (textShape == 0) {
warnFlake << "No text shape present in KoTosContainer";
return;
}
// vertical
KoTextShapeDataBase *shapeData = qobject_cast<KoTextShapeDataBase*>(textShape->userData());
shapeData->setVerticalAlignment(alignment);
// horizontal
Q_ASSERT(shapeData->document());
QTextBlockFormat bf;
bf.setAlignment(alignment & Qt::AlignHorizontal_Mask);
QTextCursor cursor(shapeData->document());
cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
cursor.mergeBlockFormat(bf);
d->alignment = alignment;
}
Qt::Alignment KoTosContainer::textAlignment() const
{
KoShape *textShape = this->textShape();
if (textShape == 0) {
warnFlake << "No text shape present in KoTosContainer";
return Qt::AlignTop;
}
// vertical
KoTextShapeDataBase *shapeData = qobject_cast<KoTextShapeDataBase*>(textShape->userData());
// the model makes sure it contains a shape that has a KoTextShapeDataBase set so no need to check that
Qt::Alignment answer = shapeData->verticalAlignment() & Qt::AlignVertical_Mask;
// horizontal
Q_ASSERT(shapeData->document());
QTextCursor cursor(shapeData->document());
answer = answer | (cursor.blockFormat().alignment() & Qt::AlignHorizontal_Mask);
return answer;
}
void KoTosContainer::setPreferredTextRect(const QRectF &rect)
{
d->preferredTextRect = rect;
KoShape *textShape = this->textShape();
//debugFlake << rect << textShape << d->resizeBehavior;
if (d->resizeBehavior == TextFollowsPreferredTextRect && textShape) {
//debugFlake << rect;
textShape->setPosition(rect.topLeft());
textShape->setSize(rect.size());
}
}
QRectF KoTosContainer::preferredTextRect() const
{
return d->preferredTextRect;
}
KoShape *KoTosContainer::createTextShape(KoDocumentResourceManager *documentResources)
{
if (!documentResources) {
warnFlake << "KoDocumentResourceManager not found";
return 0;
}
delete textShape();
delete model();
setModel(new KoTosContainerModel());
QSet<KoShape*> delegates;
delegates << this;
KoShape *textShape = 0;
KoShapeFactoryBase *factory = KoShapeRegistry::instance()->get("TextShapeID");
if (factory) { // not installed, that's too bad, but allowed
textShape = factory->createDefaultShape(documentResources);
Q_ASSERT(textShape); // would be a bug in the text shape;
if (d->resizeBehavior == TextFollowsPreferredTextRect) {
textShape->setSize(d->preferredTextRect.size());
} else {
textShape->setSize(size());
}
if (d->resizeBehavior == TextFollowsPreferredTextRect) {
textShape->setPosition(d->preferredTextRect.topLeft());
} else {
textShape->setPosition(QPointF(0, 0));
}
textShape->setSelectable(false);
textShape->setRunThrough(runThrough());
KoTextShapeDataBase *shapeData = qobject_cast<KoTextShapeDataBase*>(textShape->userData());
Q_ASSERT(shapeData); // would be a bug in kotext
// TODO check if that is correct depending on the resize mode
shapeData->setVerticalAlignment(Qt::AlignVCenter);
addShape(textShape);
// textShape->setZIndex(zIndex() + 1); // not needed as there as the text shape is the only sub shape
delegates << textShape;
} else {
warnFlake << "Text shape factory not found";
}
setToolDelegates(delegates);
return textShape;
}
KoShape *KoTosContainer::textShape() const
{
const QList<KoShape*> subShapes = shapes();
return subShapes.isEmpty() ? 0 : subShapes.at(0);
}
void KoTosContainer::shapeChanged(ChangeType type, KoShape *shape)
{
Q_UNUSED(shape);
if (model() == 0) {
return;
}
if (type == SizeChanged || type == ContentChanged) {
model()->containerChanged(this, type);
}
// TODO is this needed?
#if 0
Q_FOREACH (KoShape *shape, model()->shapes())
shape->notifyChanged();
#endif
}
void KoTosContainer::setRunThrough(short int runThrough)
{
KoShape::setRunThrough(runThrough);
KoShape *textShape = this->textShape();
if (textShape) {
textShape->setRunThrough(runThrough);
}
}
diff --git a/libs/flake/KoTosContainer.h b/libs/flake/KoTosContainer.h
index 7a94999bb6..0bef3d9255 100644
--- a/libs/flake/KoTosContainer.h
+++ b/libs/flake/KoTosContainer.h
@@ -1,131 +1,123 @@
/* This file is part of the KDE project
* Copyright (C) 2010 Thomas Zander <zander@kde.org>
* Copyright (C) 2010 KO GmbH <boud@kogbmh.com>
* Copyright (C) 2010 Thorsten Zachmann <zachmann@kde.org>
*
* 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 KOTOSCONTAINER_H
#define KOTOSCONTAINER_H
#include "KoShapeContainer.h"
#include "kritaflake_export.h"
class KoDocumentResourceManager;
/**
* Container that is used to wrap a shape with a text on top.
* Path shapes inherit from this class to make it possible to have text associated
* with them.
*/
class KRITAFLAKE_EXPORT KoTosContainer : public KoShapeContainer
{
public:
KoTosContainer();
~KoTosContainer() override;
// reimplemented
void paintComponent(QPainter &painter, KoShapePaintingContext &paintcontext) const override;
// reimplemented
virtual bool loadText(const KoXmlElement &element, KoShapeLoadingContext &context);
- // reimplemented
- virtual void saveText(KoShapeSavingContext &context) const;
/// different kinds of resizing behavior to determine how to treat text overflow
enum ResizeBehavior {
TextFollowsSize, ///< Text area is same size as content, extra text will be clipped
FollowTextSize, ///< Content shape will get resized if text grows/shrinks
IndependentSizes, ///< The text can get bigger than the content
TextFollowsPreferredTextRect ///< The size/position of the text area will follow the preferredTextRect property
};
/**
* Set the behavior that is used to resize the text or content.
* In order to determine what to do when there is too much text to fit or suddenly less
* text the user can define the wanted behavior using the ResizeBehavior
* @param resizeBehavior the new ResizeBehavior
*/
void setResizeBehavior(ResizeBehavior resizeBehavior);
/**
* Returns the current ResizeBehavior.
*/
ResizeBehavior resizeBehavior() const;
/** Sets the alignment of the text. */
void setTextAlignment(Qt::Alignment alignment);
/** Returns the alignment of all text */
Qt::Alignment textAlignment() const;
/**
* Set some plain text to be displayed on the shape.
* @param text the full text.
*/
void setPlainText(const QString &text);
/**
* Add text the current shape with the specified document resource manager.
*
* @param documentResources
* @return The created text shape or 0 in case it failed
*/
KoShape *createTextShape(KoDocumentResourceManager *documentResources = 0);
void setRunThrough(short int runThrough) override;
protected:
KoTosContainer(const KoTosContainer &rhs);
- //reimplemented
- void loadStyle(const KoXmlElement &element, KoShapeLoadingContext &context) override;
-
- //reimplemented
- QString saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const override;
-
- /**
+ /**
* Set the current preferred text rectangle. This rect contains the coordinates of
* the embedded text shape relative to the content shape. This value is ignored if
* resizeBehavior is not TextFollowsPreferredTextRect.
* @param rect the new preferred text rectangle
*/
void setPreferredTextRect(const QRectF &rect);
/**
* Returns the current preferred text rectangle.
*/
QRectF preferredTextRect() const;
/**
* Returns the text shape
*
* @returns textshape if set or 0 in case it is not yet set
*/
KoShape *textShape() const;
void shapeChanged(ChangeType type, KoShape *shape = 0) override;
private:
class Private;
QSharedDataPointer<Private> d;
};
#endif
diff --git a/libs/flake/KoVectorPatternBackground.cpp b/libs/flake/KoVectorPatternBackground.cpp
index a07e721141..9f1fef1b5e 100644
--- a/libs/flake/KoVectorPatternBackground.cpp
+++ b/libs/flake/KoVectorPatternBackground.cpp
@@ -1,162 +1,150 @@
/*
* Copyright (c) 2016 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "KoVectorPatternBackground.h"
#include <QTransform>
#include <KoShape.h>
#include <KoShapePainter.h>
#include <KoBakedShapeRenderer.h>
class KoVectorPatternBackground::Private : public QSharedData
{
public:
Private()
: QSharedData()
{
}
~Private()
{
qDeleteAll(shapes);
shapes.clear();
}
QList<KoShape*> shapes;
KoFlake::CoordinateSystem referenceCoordinates =
KoFlake::ObjectBoundingBox;
KoFlake::CoordinateSystem contentCoordinates =
KoFlake::UserSpaceOnUse;
QRectF referenceRect;
QTransform patternTransform;
};
KoVectorPatternBackground::KoVectorPatternBackground()
: KoShapeBackground()
, d(new Private)
{
}
KoVectorPatternBackground::~KoVectorPatternBackground()
{
}
bool KoVectorPatternBackground::compareTo(const KoShapeBackground *other) const
{
Q_UNUSED(other);
return false;
}
void KoVectorPatternBackground::setReferenceCoordinates(KoFlake::CoordinateSystem value)
{
d->referenceCoordinates = value;
}
KoFlake::CoordinateSystem KoVectorPatternBackground::referenceCoordinates() const
{
return d->referenceCoordinates;
}
void KoVectorPatternBackground::setContentCoordinates(KoFlake::CoordinateSystem value)
{
d->contentCoordinates = value;
}
KoFlake::CoordinateSystem KoVectorPatternBackground::contentCoordinates() const
{
return d->contentCoordinates;
}
void KoVectorPatternBackground::setReferenceRect(const QRectF &value)
{
d->referenceRect = value;
}
QRectF KoVectorPatternBackground::referenceRect() const
{
return d->referenceRect;
}
void KoVectorPatternBackground::setPatternTransform(const QTransform &value)
{
d->patternTransform = value;
}
QTransform KoVectorPatternBackground::patternTransform() const
{
return d->patternTransform;
}
void KoVectorPatternBackground::setShapes(const QList<KoShape*> value)
{
qDeleteAll(d->shapes);
d->shapes.clear();
d->shapes = value;
}
QList<KoShape *> KoVectorPatternBackground::shapes() const
{
return d->shapes;
}
void KoVectorPatternBackground::paint(QPainter &painter, KoShapePaintingContext &context_Unused, const QPainterPath &fillPath) const
{
Q_UNUSED(context_Unused);
const QPainterPath dstShapeOutline = fillPath;
const QRectF dstShapeBoundingBox = dstShapeOutline.boundingRect();
KoBakedShapeRenderer renderer(dstShapeOutline, QTransform(),
QTransform(),
d->referenceRect,
d->contentCoordinates != KoFlake::UserSpaceOnUse,
dstShapeBoundingBox,
d->referenceCoordinates != KoFlake::UserSpaceOnUse,
d->patternTransform);
QPainter *patchPainter = renderer.bakeShapePainter();
KoShapePainter p;
p.setShapes(d->shapes);
p.paint(*patchPainter);
// uncomment for debug
// renderer.patchImage().save("dd_patch_image.png");
painter.setPen(Qt::NoPen);
renderer.renderShape(painter);
}
bool KoVectorPatternBackground::hasTransparency() const
{
return true;
}
-
-void KoVectorPatternBackground::fillStyle(KoGenStyle &, KoShapeSavingContext &)
-{
- // noop
-}
-
-bool KoVectorPatternBackground::loadStyle(KoOdfLoadingContext &, const QSizeF &Size)
-{
- Q_UNUSED(Size);
- return true;
-}
-
diff --git a/libs/flake/KoVectorPatternBackground.h b/libs/flake/KoVectorPatternBackground.h
index d60d7d8f59..a7faa5f595 100644
--- a/libs/flake/KoVectorPatternBackground.h
+++ b/libs/flake/KoVectorPatternBackground.h
@@ -1,67 +1,65 @@
/*
* Copyright (c) 2016 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KOVECTORPATTERNBACKGROUND_H
#define KOVECTORPATTERNBACKGROUND_H
#include <KoShapeBackground.h>
#include <KoFlakeCoordinateSystem.h>
#include <QSharedDataPointer>
class KoShape;
class QPointF;
class QRectF;
class QTransform;
class KoVectorPatternBackground : public KoShapeBackground
{
public:
KoVectorPatternBackground();
~KoVectorPatternBackground() override;
bool compareTo(const KoShapeBackground *other) const override;
void setReferenceCoordinates(KoFlake::CoordinateSystem value);
KoFlake::CoordinateSystem referenceCoordinates() const;
/**
* In ViewBox just use the same mode as for referenceCoordinates
*/
void setContentCoordinates(KoFlake::CoordinateSystem value);
KoFlake::CoordinateSystem contentCoordinates() const;
void setReferenceRect(const QRectF &value);
QRectF referenceRect() const;
void setPatternTransform(const QTransform &value);
QTransform patternTransform() const;
void setShapes(const QList<KoShape*> value);
QList<KoShape*> shapes() const;
void paint(QPainter &painter, KoShapePaintingContext &context_Unused, const QPainterPath &fillPath) const override;
bool hasTransparency() const override;
- void fillStyle(KoGenStyle &style, KoShapeSavingContext &context) override;
- bool loadStyle(KoOdfLoadingContext &context, const QSizeF &shapeSize) override;
private:
class Private;
QSharedDataPointer<Private> d;
};
#endif // KOVECTORPATTERNBACKGROUND_H
diff --git a/libs/flake/SimpleShapeContainerModel.h b/libs/flake/SimpleShapeContainerModel.h
index 8a777b36c5..ff2c935adc 100644
--- a/libs/flake/SimpleShapeContainerModel.h
+++ b/libs/flake/SimpleShapeContainerModel.h
@@ -1,126 +1,167 @@
/* This file is part of the KDE project
* Copyright (C) 2006-2007, 2010 Thomas Zander <zander@kde.org>
* Copyright (C) 2011 Boudewijn Rempt <boud@valdyas.org>
*
* 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 SIMPLESHAPECONTAINERMODEL_H
#define SIMPLESHAPECONTAINERMODEL_H
#include "KoShapeContainerModel.h"
#include <kis_debug.h>
+#include <KoShapeManager.h>
/// \internal
class SimpleShapeContainerModel: public KoShapeContainerModel
{
public:
SimpleShapeContainerModel() {}
~SimpleShapeContainerModel() override {}
SimpleShapeContainerModel(const SimpleShapeContainerModel &rhs)
: KoShapeContainerModel(rhs),
m_inheritsTransform(rhs.m_inheritsTransform),
m_clipped(rhs.m_clipped)
{
Q_FOREACH (KoShape *shape, rhs.m_members) {
KoShape *clone = shape->cloneShape();
KIS_SAFE_ASSERT_RECOVER_NOOP(clone && "Copying this shape is not implemented!");
if (clone) {
m_members << clone;
}
}
KIS_ASSERT_RECOVER(m_members.size() == m_inheritsTransform.size() &&
m_members.size() == m_clipped.size())
{
qDeleteAll(m_members);
m_members.clear();
m_inheritsTransform.clear();
m_clipped.clear();
}
}
void add(KoShape *child) override {
if (m_members.contains(child))
return;
m_members.append(child);
m_clipped.append(false);
m_inheritsTransform.append(true);
}
void setClipped(const KoShape *shape, bool value) override {
const int index = indexOf(shape);
KIS_SAFE_ASSERT_RECOVER_RETURN(index >= 0);
m_clipped[index] = value;
}
bool isClipped(const KoShape *shape) const override {
const int index = indexOf(shape);
KIS_SAFE_ASSERT_RECOVER(index >= 0) { return false;}
return m_clipped[index];
}
void remove(KoShape *shape) override {
const int index = indexOf(shape);
KIS_SAFE_ASSERT_RECOVER_RETURN(index >= 0);
m_members.removeAt(index);
m_clipped.removeAt(index);
m_inheritsTransform.removeAt(index);
}
int count() const override {
return m_members.count();
}
QList<KoShape*> shapes() const override {
return QList<KoShape*>(m_members);
}
void containerChanged(KoShapeContainer *, KoShape::ChangeType) override { }
void setInheritsTransform(const KoShape *shape, bool value) override {
const int index = indexOf(shape);
KIS_SAFE_ASSERT_RECOVER_RETURN(index >= 0);
m_inheritsTransform[index] = value;
}
bool inheritsTransform(const KoShape *shape) const override {
const int index = indexOf(shape);
KIS_SAFE_ASSERT_RECOVER(index >= 0) { return true;}
return m_inheritsTransform[index];
}
void proposeMove(KoShape *shape, QPointF &move) override
{
KoShapeContainer *parent = shape->parent();
bool allowedToMove = true;
while (allowedToMove && parent) {
allowedToMove = parent->isShapeEditable();
parent = parent->parent();
}
if (! allowedToMove) {
move.setX(0);
move.setY(0);
}
}
+ void shapeHasBeenAddedToHierarchy(KoShape *shape, KoShapeContainer *addedToSubtree) override {
+ if (m_associatedRootShapeManager) {
+ m_associatedRootShapeManager->addShape(shape);
+ }
+ KoShapeContainerModel::shapeHasBeenAddedToHierarchy(shape, addedToSubtree);
+ }
+
+ void shapeToBeRemovedFromHierarchy(KoShape *shape, KoShapeContainer *removedFromSubtree) override {
+ if (m_associatedRootShapeManager) {
+ m_associatedRootShapeManager->remove(shape);
+ }
+ KoShapeContainerModel::shapeToBeRemovedFromHierarchy(shape, removedFromSubtree);
+ }
+
+ KoShapeManager *associatedRootShapeManager() const {
+ return m_associatedRootShapeManager;
+ }
+
+ /**
+ * If the container is the root of shapes hierarchy, it should also track the content
+ * of the shape manager. Add all added/removed shapes should be also
+ * added to \p shapeManager.
+ */
+ void setAssociatedRootShapeManager(KoShapeManager *manager) {
+ if (m_associatedRootShapeManager) {
+ Q_FOREACH(KoShape *shape, this->shapes()) {
+ m_associatedRootShapeManager->remove(shape);
+ }
+ }
+
+ m_associatedRootShapeManager = manager;
+
+ if (m_associatedRootShapeManager) {
+ Q_FOREACH(KoShape *shape, this->shapes()) {
+ m_associatedRootShapeManager->addShape(shape);
+ }
+ }
+ }
+
private:
int indexOf(const KoShape *shape) const {
// workaround indexOf constness!
return m_members.indexOf(const_cast<KoShape*>(shape));
}
private: // members
QList <KoShape *> m_members;
QList <bool> m_inheritsTransform;
QList <bool> m_clipped;
+ KoShapeManager *m_associatedRootShapeManager = 0;
};
#endif
diff --git a/libs/flake/commands/KoAddRemoveShapeCommands.cpp b/libs/flake/commands/KoAddRemoveShapeCommands.cpp
new file mode 100644
index 0000000000..1b4181431e
--- /dev/null
+++ b/libs/flake/commands/KoAddRemoveShapeCommands.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 Dmitry Kazakov <dimula73@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "KoAddRemoveShapeCommands.h"
+
+#include <KoShapeContainer.h>
+#include <kis_assert.h>
+
+
+KoAddRemoveShapeCommandImpl::KoAddRemoveShapeCommandImpl(KoShape *shape, KoShapeContainer *parent, KisCommandUtils::FlipFlopCommand::State state, KUndo2Command *parentCommand)
+ : KisCommandUtils::FlipFlopCommand(state, parentCommand),
+ m_shape(shape),
+ m_parent(parent)
+{
+}
+
+KoAddRemoveShapeCommandImpl::~KoAddRemoveShapeCommandImpl() {
+ if (m_ownShape) {
+ delete m_shape;
+ }
+}
+
+void KoAddRemoveShapeCommandImpl::partB()
+{
+ KIS_SAFE_ASSERT_RECOVER_RETURN(m_shape);
+ KIS_SAFE_ASSERT_RECOVER_RETURN(m_parent);
+
+ m_parent->removeShape(m_shape);
+ m_ownShape = true;
+}
+
+void KoAddRemoveShapeCommandImpl::partA()
+{
+ KIS_SAFE_ASSERT_RECOVER_RETURN(m_shape);
+ KIS_SAFE_ASSERT_RECOVER_RETURN(m_parent);
+
+ m_parent->addShape(m_shape);
+ m_ownShape = false;
+}
+
+KoAddShapeCommand::KoAddShapeCommand(KoShape *shape, KoShapeContainer *parent, KUndo2Command *parentCommand)
+ : KoAddRemoveShapeCommandImpl(shape, parent, INITIALIZING, parentCommand)
+{
+}
+
+KoRemoveShapeCommand::KoRemoveShapeCommand(KoShape *shape, KoShapeContainer *parent, KUndo2Command *parentCommand)
+ : KoAddRemoveShapeCommandImpl(shape, parent, FINALIZING, parentCommand)
+{
+}
diff --git a/libs/flake/commands/KoAddRemoveShapeCommands.h b/libs/flake/commands/KoAddRemoveShapeCommands.h
new file mode 100644
index 0000000000..410093de36
--- /dev/null
+++ b/libs/flake/commands/KoAddRemoveShapeCommands.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2020 Dmitry Kazakov <dimula73@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KoAddRemoveShapeCommands_H
+#define KoAddRemoveShapeCommands_H
+
+#include "kritaflake_export.h"
+
+#include "kis_command_utils.h"
+
+class KoShape;
+class KoShapeContainer;
+
+
+struct KRITAFLAKE_EXPORT KoAddRemoveShapeCommandImpl : public KisCommandUtils::FlipFlopCommand
+{
+ KoAddRemoveShapeCommandImpl(KoShape *shape, KoShapeContainer *parent, State state, KUndo2Command *parentCommand);
+ ~KoAddRemoveShapeCommandImpl();
+
+ void partA() override;
+ void partB() override;
+
+private:
+ bool m_ownShape = true;
+ KoShape *m_shape = 0;
+ KoShapeContainer *m_parent = 0;
+};
+
+struct KRITAFLAKE_EXPORT KoAddShapeCommand : public KoAddRemoveShapeCommandImpl
+{
+ KoAddShapeCommand(KoShape *shape, KoShapeContainer *parent, KUndo2Command *parentCommand = 0);
+};
+
+struct KRITAFLAKE_EXPORT KoRemoveShapeCommand : public KoAddRemoveShapeCommandImpl
+{
+ KoRemoveShapeCommand(KoShape *shape, KoShapeContainer *parent, KUndo2Command *parentCommand = 0);
+};
+
+#endif // KoAddRemoveShapeCommands_H
diff --git a/libs/flake/commands/KoConnectionShapeTypeCommand.cpp b/libs/flake/commands/KoConnectionShapeTypeCommand.cpp
deleted file mode 100644
index 3bffb9f229..0000000000
--- a/libs/flake/commands/KoConnectionShapeTypeCommand.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "KoConnectionShapeTypeCommand.h"
-#include <klocalizedstring.h>
-
-KoConnectionShapeTypeCommand::KoConnectionShapeTypeCommand(
- KoConnectionShape * connection, KoConnectionShape::Type type, KUndo2Command *parent)
- : KUndo2Command(parent)
- , m_connection(connection)
- , m_newType(type)
-{
- Q_ASSERT(m_connection);
-
- setText(kundo2_i18n("Change Connection"));
-
- m_oldType = m_connection->type();
-}
-
-void KoConnectionShapeTypeCommand::redo()
-{
- KUndo2Command::redo();
-
- m_connection->update();
-
- if (m_oldType != m_newType)
- m_connection->setType(m_newType);
-
- m_connection->update();
-}
-
-void KoConnectionShapeTypeCommand::undo()
-{
- KUndo2Command::undo();
-
- m_connection->update();
-
- if (m_oldType != m_newType)
- m_connection->setType(m_oldType);
-
- m_connection->update();
-}
diff --git a/libs/flake/commands/KoConnectionShapeTypeCommand.h b/libs/flake/commands/KoConnectionShapeTypeCommand.h
deleted file mode 100644
index ff275bdb72..0000000000
--- a/libs/flake/commands/KoConnectionShapeTypeCommand.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 KoConnectionShapeTypeCommand_H
-#define KoConnectionShapeTypeCommand_H
-
-#include "KoConnectionShape.h"
-#include <kundo2command.h>
-
-/// The undo / redo command for configuring an KoConnection shape
-class KoConnectionShapeTypeCommand : public KUndo2Command
-{
-public:
- /**
- * Changes the tyoe of a connection shape
- * @param connection the connection shape to change type of
- * @param type the connection type
- * @param parent the optional parent command
- */
- KoConnectionShapeTypeCommand(KoConnectionShape *connection, KoConnectionShape::Type type, KUndo2Command *parent = 0);
- /// redo the command
- void redo() override;
- /// revert the actions done in redo
- void undo() override;
-private:
- KoConnectionShape *m_connection;
- KoConnectionShape::Type m_oldType;
- KoConnectionShape::Type m_newType;
-};
-
-#endif // KoConnectionShapeTypeCommand_H
-
diff --git a/libs/flake/commands/KoPathCombineCommand.cpp b/libs/flake/commands/KoPathCombineCommand.cpp
index ae2334e88c..9b9d472292 100644
--- a/libs/flake/commands/KoPathCombineCommand.cpp
+++ b/libs/flake/commands/KoPathCombineCommand.cpp
@@ -1,144 +1,140 @@
/* This file is part of the KDE project
* Copyright (C) 2006,2008 Jan Hambrecht <jaham@gmx.net>
* Copyright (C) 2006,2007 Thorsten Zachmann <zachmann@kde.org>
*
* 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 "KoPathCombineCommand.h"
#include "KoShapeControllerBase.h"
#include "KoShapeContainer.h"
#include "KoPathShape.h"
#include <klocalizedstring.h>
#include "kis_assert.h"
#include <KoPathPointData.h>
#include <QHash>
class Q_DECL_HIDDEN KoPathCombineCommand::Private
{
public:
Private(KoShapeControllerBase *c, const QList<KoPathShape*> &p)
: controller(c), paths(p)
, combinedPath(0)
, combinedPathParent(0)
, isCombined(false)
{
foreach (KoPathShape * path, paths) {
oldParents.append(path->parent());
}
}
~Private() {
if (isCombined && controller) {
Q_FOREACH (KoPathShape* path, paths) {
delete path;
}
} else {
delete combinedPath;
}
}
KoShapeControllerBase *controller;
QList<KoPathShape*> paths;
QList<KoShapeContainer*> oldParents;
KoPathShape *combinedPath;
KoShapeContainer *combinedPathParent;
QHash<KoPathShape*, int> shapeStartSegmentIndex;
bool isCombined;
};
KoPathCombineCommand::KoPathCombineCommand(KoShapeControllerBase *controller,
const QList<KoPathShape*> &paths, KUndo2Command *parent)
: KUndo2Command(kundo2_i18n("Combine paths"), parent)
, d(new Private(controller, paths))
{
KIS_SAFE_ASSERT_RECOVER_RETURN(!paths.isEmpty());
Q_FOREACH (KoPathShape* path, d->paths) {
if (!d->combinedPath) {
KoPathShape *clone = dynamic_cast<KoPathShape*>(path->cloneShape());
KIS_ASSERT_RECOVER_BREAK(clone);
d->combinedPath = clone;
d->combinedPathParent = path->parent();
d->shapeStartSegmentIndex[path] = 0;
} else {
const int startSegmentIndex = d->combinedPath->combine(path);
d->shapeStartSegmentIndex[path] = startSegmentIndex;
}
}
}
KoPathCombineCommand::~KoPathCombineCommand()
{
delete d;
}
void KoPathCombineCommand::redo()
{
KUndo2Command::redo();
if (d->paths.isEmpty()) return;
d->isCombined = true;
if (d->controller) {
Q_FOREACH (KoPathShape* p, d->paths) {
- d->controller->removeShape(p);
p->setParent(0);
}
d->combinedPath->setParent(d->combinedPathParent);
- d->controller->addShape(d->combinedPath);
}
}
void KoPathCombineCommand::undo()
{
if (! d->paths.size())
return;
d->isCombined = false;
if (d->controller) {
- d->controller->removeShape(d->combinedPath);
d->combinedPath->setParent(0);
auto parentIt = d->oldParents.begin();
Q_FOREACH (KoPathShape* p, d->paths) {
p->setParent(*parentIt);
- d->controller->addShape(p);
++parentIt;
}
}
KUndo2Command::undo();
}
KoPathShape *KoPathCombineCommand::combinedPath() const
{
return d->combinedPath;
}
KoPathPointData KoPathCombineCommand::originalToCombined(KoPathPointData pd) const
{
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(d->shapeStartSegmentIndex.contains(pd.pathShape), pd);
const int segmentOffet = d->shapeStartSegmentIndex[pd.pathShape];
KoPathPointIndex newIndex(segmentOffet + pd.pointIndex.first, pd.pointIndex.second);
return KoPathPointData(d->combinedPath, newIndex);
}
diff --git a/libs/flake/commands/KoShapeClipCommand.cpp b/libs/flake/commands/KoShapeClipCommand.cpp
index 7acfdddc51..f753a71c33 100644
--- a/libs/flake/commands/KoShapeClipCommand.cpp
+++ b/libs/flake/commands/KoShapeClipCommand.cpp
@@ -1,132 +1,131 @@
/* This file is part of the KDE project
* Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
*
* 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 "KoShapeClipCommand.h"
#include "KoClipPath.h"
#include "KoShape.h"
#include "KoShapeContainer.h"
#include "KoPathShape.h"
#include "KoShapeControllerBase.h"
#include <klocalizedstring.h>
#include "kis_pointer_utils.h"
class Q_DECL_HIDDEN KoShapeClipCommand::Private
{
public:
Private(KoShapeControllerBase *c)
: controller(c), executed(false) {
}
~Private() {
if (executed) {
qDeleteAll(oldClipPaths);
} else {
qDeleteAll(newClipPaths);
}
}
QList<KoShape*> shapesToClip;
QList<KoClipPath*> oldClipPaths;
QList<KoPathShape*> clipPathShapes;
QList<KoClipPath*> newClipPaths;
QList<KoShapeContainer*> oldParents;
KoShapeControllerBase *controller;
bool executed;
};
KoShapeClipCommand::KoShapeClipCommand(KoShapeControllerBase *controller, const QList<KoShape*> &shapes, const QList<KoPathShape*> &clipPathShapes, KUndo2Command *parent)
: KUndo2Command(parent), d(new Private(controller))
{
d->shapesToClip = shapes;
d->clipPathShapes = clipPathShapes;
Q_FOREACH (KoShape *shape, d->shapesToClip) {
d->oldClipPaths.append(shape->clipPath());
d->newClipPaths.append(new KoClipPath(implicitCastList<KoShape*>(clipPathShapes), KoFlake::UserSpaceOnUse));
}
Q_FOREACH (KoPathShape *path, clipPathShapes) {
d->oldParents.append(path->parent());
}
setText(kundo2_i18n("Clip Shape"));
}
KoShapeClipCommand::KoShapeClipCommand(KoShapeControllerBase *controller, KoShape *shape, const QList<KoPathShape*> &clipPathShapes, KUndo2Command *parent)
: KUndo2Command(parent), d(new Private(controller))
{
d->shapesToClip.append(shape);
d->clipPathShapes = clipPathShapes;
d->oldClipPaths.append(shape->clipPath());
d->newClipPaths.append(new KoClipPath(implicitCastList<KoShape*>(clipPathShapes), KoFlake::UserSpaceOnUse));
Q_FOREACH (KoPathShape *path, clipPathShapes) {
d->oldParents.append(path->parent());
}
setText(kundo2_i18n("Clip Shape"));
}
KoShapeClipCommand::~KoShapeClipCommand()
{
delete d;
}
void KoShapeClipCommand::redo()
{
const uint shapeCount = d->shapesToClip.count();
for (uint i = 0; i < shapeCount; ++i) {
d->shapesToClip[i]->setClipPath(d->newClipPaths[i]);
d->shapesToClip[i]->update();
}
const uint clipPathCount = d->clipPathShapes.count();
for (uint i = 0; i < clipPathCount; ++i) {
- d->controller->removeShape(d->clipPathShapes[i]);
- if (d->oldParents.at(i))
+ if (d->oldParents.at(i)) {
d->oldParents.at(i)->removeShape(d->clipPathShapes[i]);
+ }
}
d->executed = true;
KUndo2Command::redo();
}
void KoShapeClipCommand::undo()
{
KUndo2Command::undo();
const uint shapeCount = d->shapesToClip.count();
for (uint i = 0; i < shapeCount; ++i) {
d->shapesToClip[i]->setClipPath(d->oldClipPaths[i]);
d->shapesToClip[i]->update();
}
const uint clipPathCount = d->clipPathShapes.count();
for (uint i = 0; i < clipPathCount; ++i) {
- if (d->oldParents.at(i))
+ if (d->oldParents.at(i)) {
d->oldParents.at(i)->addShape(d->clipPathShapes[i]);
- // the parent has to be there when it is added to the KoShapeControllerBase
- d->controller->addShape(d->clipPathShapes[i]);
+ }
}
d->executed = false;
}
diff --git a/libs/flake/commands/KoShapeCreateCommand.cpp b/libs/flake/commands/KoShapeCreateCommand.cpp
index bada674723..72b566e4d6 100644
--- a/libs/flake/commands/KoShapeCreateCommand.cpp
+++ b/libs/flake/commands/KoShapeCreateCommand.cpp
@@ -1,129 +1,106 @@
/* This file is part of the KDE project
* Copyright (C) 2006 Thomas Zander <zander@kde.org>
* Copyright (C) 2006 Jan Hambrecht <jaham@gmx.net>
*
* 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 "KoShapeCreateCommand.h"
#include "KoShape.h"
#include "KoShapeContainer.h"
#include "KoShapeControllerBase.h"
#include <klocalizedstring.h>
#include "kis_assert.h"
#include <KoShapeLayer.h>
#include <KoShapeReorderCommand.h>
#include <vector>
#include <memory>
+#include <kis_undo_stores.h>
+#include <KoAddRemoveShapeCommands.h>
+
class Q_DECL_HIDDEN KoShapeCreateCommand::Private
{
public:
Private(KoShapeControllerBase *_document, const QList<KoShape*> &_shapes, KoShapeContainer *_parentShape)
: shapesDocument(_document),
shapes(_shapes),
- explicitParentShape(_parentShape),
- deleteShapes(true)
+ explicitParentShape(_parentShape)
{
}
- ~Private() {
- if (deleteShapes) {
- qDeleteAll(shapes);
- }
- }
-
KoShapeControllerBase *shapesDocument;
QList<KoShape*> shapes;
KoShapeContainer *explicitParentShape;
- bool deleteShapes;
- std::vector<std::unique_ptr<KUndo2Command>> reorderingCommands;
+ KisSurrogateUndoStore undoStore;
+ bool firstRedo = true;
+
};
KoShapeCreateCommand::KoShapeCreateCommand(KoShapeControllerBase *controller, KoShape *shape, KoShapeContainer *parentShape, KUndo2Command *parent)
: KoShapeCreateCommand(controller, QList<KoShape *>() << shape, parentShape, parent)
{
}
KoShapeCreateCommand::KoShapeCreateCommand(KoShapeControllerBase *controller, const QList<KoShape *> shapes, KoShapeContainer *parentShape, KUndo2Command *parent)
: KoShapeCreateCommand(controller, shapes, parentShape, parent, kundo2_i18np("Create shape", "Create %1 shapes", shapes.size()))
{
}
KoShapeCreateCommand::KoShapeCreateCommand(KoShapeControllerBase *controller, const QList<KoShape *> shapes, KoShapeContainer *parentShape, KUndo2Command *parent, const KUndo2MagicString &undoString)
: KUndo2Command(undoString, parent)
, d(new Private(controller, shapes, parentShape))
{
}
KoShapeCreateCommand::~KoShapeCreateCommand()
{
delete d;
}
void KoShapeCreateCommand::redo()
{
KUndo2Command::redo();
- KIS_ASSERT(d->shapesDocument);
-
- d->deleteShapes = false;
- d->reorderingCommands.clear();
-
- Q_FOREACH(KoShape *shape, d->shapes) {
- if (d->explicitParentShape) {
- shape->setParent(d->explicitParentShape);
- }
-
- d->shapesDocument->addShape(shape);
+ KIS_SAFE_ASSERT_RECOVER_RETURN(d->explicitParentShape);
- KoShapeContainer *shapeParent = shape->parent();
+ if (d->firstRedo) {
+ Q_FOREACH(KoShape *shape, d->shapes) {
- KIS_SAFE_ASSERT_RECOVER_NOOP(shape->parent() ||
- dynamic_cast<KoShapeLayer*>(shape));
+ d->undoStore.addCommand(new KoAddShapeCommand(shape, d->explicitParentShape));
- if (shapeParent) {
- KUndo2Command *cmd = KoShapeReorderCommand::mergeInShape(shapeParent->shapes(), shape);
+ KoShapeContainer *shapeParent = shape->parent();
+ KIS_SAFE_ASSERT_RECOVER_NOOP(shape->parent() ||
+ dynamic_cast<KoShapeLayer*>(shape));
- if (cmd) {
- cmd->redo();
- d->reorderingCommands.push_back(
- std::unique_ptr<KUndo2Command>(cmd));
+ if (shapeParent) {
+ d->undoStore.addCommand(KoShapeReorderCommand::mergeInShape(shapeParent->shapes(), shape));
}
}
+ d->firstRedo = false;
+ } else {
+ d->undoStore.redoAll();
}
}
void KoShapeCreateCommand::undo()
{
+ d->undoStore.undoAll();
KUndo2Command::undo();
- KIS_ASSERT(d->shapesDocument);
-
- while (!d->reorderingCommands.empty()) {
- std::unique_ptr<KUndo2Command> cmd = std::move(d->reorderingCommands.back());
- cmd->undo();
- d->reorderingCommands.pop_back();
- }
-
- Q_FOREACH(KoShape *shape, d->shapes) {
- d->shapesDocument->removeShape(shape);
- }
-
- d->deleteShapes = true;
}
diff --git a/libs/flake/commands/KoShapeDeleteCommand.cpp b/libs/flake/commands/KoShapeDeleteCommand.cpp
index 3d369bdfdd..9bc335e9d2 100644
--- a/libs/flake/commands/KoShapeDeleteCommand.cpp
+++ b/libs/flake/commands/KoShapeDeleteCommand.cpp
@@ -1,105 +1,103 @@
/* This file is part of the KDE project
* Copyright (C) 2006 Thomas Zander <zander@kde.org>
* Copyright (C) 2006 Jan Hambrecht <jaham@gmx.net>
*
* 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 "KoShapeDeleteCommand.h"
#include "KoShapeContainer.h"
#include "KoShapeControllerBase.h"
#include <klocalizedstring.h>
class Q_DECL_HIDDEN KoShapeDeleteCommand::Private
{
public:
Private(KoShapeControllerBase *c)
: controller(c),
deleteShapes(false) {
}
~Private() {
if (! deleteShapes)
return;
Q_FOREACH (KoShape *shape, shapes)
delete shape;
}
KoShapeControllerBase *controller; ///< the shape controller to use for removing/readding
QList<KoShape*> shapes; ///< the list of shapes to delete
QList<KoShapeContainer*> oldParents; ///< the old parents of the shapes
bool deleteShapes; ///< shows if shapes should be deleted when deleting the command
};
KoShapeDeleteCommand::KoShapeDeleteCommand(KoShapeControllerBase *controller, KoShape *shape, KUndo2Command *parent)
: KUndo2Command(parent),
d(new Private(controller))
{
d->shapes.append(shape);
d->oldParents.append(shape->parent());
setText(kundo2_i18n("Delete shape"));
}
KoShapeDeleteCommand::KoShapeDeleteCommand(KoShapeControllerBase *controller, const QList<KoShape*> &shapes,
KUndo2Command *parent)
: KUndo2Command(parent),
d(new Private(controller))
{
d->shapes = shapes;
Q_FOREACH (KoShape *shape, d->shapes) {
d->oldParents.append(shape->parent());
}
setText(kundo2_i18np("Delete shape", "Delete shapes", shapes.count()));
}
KoShapeDeleteCommand::~KoShapeDeleteCommand()
{
delete d;
}
void KoShapeDeleteCommand::redo()
{
KUndo2Command::redo();
if (! d->controller)
return;
for (int i = 0; i < d->shapes.count(); i++) {
- // the parent has to be there when it is removed from the KoShapeControllerBase
- d->controller->removeShape(d->shapes[i]);
- if (d->oldParents.at(i))
+ if (d->oldParents.at(i)) {
d->oldParents.at(i)->removeShape(d->shapes[i]);
+ }
}
d->deleteShapes = true;
}
void KoShapeDeleteCommand::undo()
{
KUndo2Command::undo();
if (! d->controller)
return;
for (int i = 0; i < d->shapes.count(); i++) {
- if (d->oldParents.at(i))
+ if (d->oldParents.at(i)) {
d->oldParents.at(i)->addShape(d->shapes[i]);
- // the parent has to be there when it is added to the KoShapeControllerBase
- d->controller->addShape(d->shapes[i]);
+ }
}
d->deleteShapes = false;
}
diff --git a/libs/flake/commands/KoShapeUnclipCommand.cpp b/libs/flake/commands/KoShapeUnclipCommand.cpp
index 7d365df77f..61c250946c 100644
--- a/libs/flake/commands/KoShapeUnclipCommand.cpp
+++ b/libs/flake/commands/KoShapeUnclipCommand.cpp
@@ -1,154 +1,153 @@
/* This file is part of the KDE project
* Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
*
* 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 "KoShapeUnclipCommand.h"
#include "KoClipPath.h"
#include "KoShape.h"
#include "KoShapeContainer.h"
#include "KoPathShape.h"
#include "KoShapeControllerBase.h"
#include <kis_assert.h>
#include <klocalizedstring.h>
class KoShapeUnclipCommand::Private
{
public:
Private(KoShapeControllerBase *c)
: controller(c), executed(false) {
}
~Private() {
if (executed) {
qDeleteAll(oldClipPaths);
} else {
qDeleteAll(clipPathShapes);
}
}
void createClipPathShapes() {
// check if we have already created the clip path shapes
if (!clipPathShapes.isEmpty())
return;
Q_FOREACH (KoShape *shape, shapesToUnclip) {
KoClipPath *clipPath = shape->clipPath();
if (!clipPath)
continue;
Q_FOREACH (KoShape *clipShape, clipPath->clipPathShapes()) {
KoShape *clone = clipShape->cloneShape();
KoPathShape *pathShape = dynamic_cast<KoPathShape*>(clone);
KIS_SAFE_ASSERT_RECOVER(pathShape) {
delete clone;
continue;
}
clipPathShapes.append(pathShape);
}
// apply transformations
Q_FOREACH (KoPathShape *pathShape, clipPathShapes) {
// apply transformation so that it matches the current clipped shapes clip path
pathShape->applyAbsoluteTransformation(clipPath->clipDataTransformation(shape));
pathShape->setZIndex(shape->zIndex() + 1);
clipPathParents.append(shape->parent());
}
}
}
QList<KoShape*> shapesToUnclip;
QList<KoClipPath*> oldClipPaths;
QList<KoPathShape*> clipPathShapes;
QList<KoShapeContainer*> clipPathParents;
// TODO: damn! this is not a controller, this is a document! Needs refactoring!
KoShapeControllerBase *controller;
bool executed;
};
KoShapeUnclipCommand::KoShapeUnclipCommand(KoShapeControllerBase *controller, const QList<KoShape*> &shapes, KUndo2Command *parent)
: KUndo2Command(parent), d(new Private(controller))
{
d->shapesToUnclip = shapes;
Q_FOREACH (KoShape *shape, d->shapesToUnclip) {
d->oldClipPaths.append(shape->clipPath());
}
setText(kundo2_i18n("Unclip Shape"));
}
KoShapeUnclipCommand::KoShapeUnclipCommand(KoShapeControllerBase *controller, KoShape *shape, KUndo2Command *parent)
: KUndo2Command(parent), d(new Private(controller))
{
d->shapesToUnclip.append(shape);
d->oldClipPaths.append(shape->clipPath());
setText(kundo2_i18n("Unclip Shapes"));
}
KoShapeUnclipCommand::~KoShapeUnclipCommand()
{
delete d;
}
void KoShapeUnclipCommand::redo()
{
d->createClipPathShapes();
const uint shapeCount = d->shapesToUnclip.count();
for (uint i = 0; i < shapeCount; ++i) {
d->shapesToUnclip[i]->setClipPath(0);
d->shapesToUnclip[i]->update();
}
const uint clipPathCount = d->clipPathShapes.count();
for (uint i = 0; i < clipPathCount; ++i) {
- // the parent has to be there when it is added to the KoShapeControllerBase
- if (d->clipPathParents.at(i))
+ if (d->clipPathParents.at(i)) {
d->clipPathParents.at(i)->addShape(d->clipPathShapes[i]);
- d->controller->addShape(d->clipPathShapes[i]);
+ }
}
d->executed = true;
KUndo2Command::redo();
}
void KoShapeUnclipCommand::undo()
{
KUndo2Command::undo();
const uint shapeCount = d->shapesToUnclip.count();
for (uint i = 0; i < shapeCount; ++i) {
d->shapesToUnclip[i]->setClipPath(d->oldClipPaths[i]);
d->shapesToUnclip[i]->update();
}
const uint clipPathCount = d->clipPathShapes.count();
for (uint i = 0; i < clipPathCount; ++i) {
- d->controller->removeShape(d->clipPathShapes[i]);
- if (d->clipPathParents.at(i))
+ if (d->clipPathParents.at(i)) {
d->clipPathParents.at(i)->removeShape(d->clipPathShapes[i]);
+ }
}
d->executed = false;
}
diff --git a/libs/flake/svg/SvgShapeFactory.cpp b/libs/flake/svg/SvgShapeFactory.cpp
index e4fb34b2c8..3d37bb8c2e 100644
--- a/libs/flake/svg/SvgShapeFactory.cpp
+++ b/libs/flake/svg/SvgShapeFactory.cpp
@@ -1,174 +1,173 @@
/* This file is part of the KDE project
* Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
*
* 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 "SvgShapeFactory.h"
#include "SvgParser.h"
#include "KoShapeGroup.h"
#include "KoShapeGroupCommand.h"
#include "KoShapeLoadingContext.h"
#include "KoShapeRegistry.h"
#include "FlakeDebug.h"
-#include <KoOdfLoadingContext.h>
#include <KoXmlNS.h>
#include <KoStore.h>
#include <KoStoreDevice.h>
#include <klocalizedstring.h>
#define SVGSHAPEFACTORYID "SvgShapeFactory"
SvgShapeFactory::SvgShapeFactory()
: KoShapeFactoryBase(SVGSHAPEFACTORYID, i18n("Embedded svg shape"))
{
setLoadingPriority(4);
setXmlElementNames(QString(KoXmlNS::draw), QStringList("image"));
// hide from add shapes docker as the shape is not able to be dragged onto
// the canvas as createDefaultShape returns 0.
setHidden(true);
}
SvgShapeFactory::~SvgShapeFactory()
{
}
bool SvgShapeFactory::supports(const KoXmlElement &element, KoShapeLoadingContext &context) const
{
if (element.localName() == "image" && element.namespaceURI() == KoXmlNS::draw) {
QString href = element.attribute("href");
if (href.isEmpty())
return false;
// check the mimetype
if (href.startsWith(QLatin1String("./"))) {
href.remove(0,2);
}
- QString mimetype = context.odfLoadingContext().mimeTypeForPath(href, true);
+ QString mimetype = context.mimeTypeForPath(href, true);
return (mimetype == "image/svg+xml");
}
return false;
}
-KoShape *SvgShapeFactory::createShapeFromOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
+KoShape *SvgShapeFactory::createShapeFromXML(const KoXmlElement &element, KoShapeLoadingContext &context)
{
const KoXmlElement & imageElement(KoXml::namedItemNS(element, KoXmlNS::draw, "image"));
if (imageElement.isNull()) {
errorFlake << "svg image element not found";
return 0;
}
if (imageElement.tagName() == "image") {
debugFlake << "trying to create shapes form svg image";
QString href = imageElement.attribute("href");
if (href.isEmpty())
return 0;
// check the mimetype
if (href.startsWith(QLatin1String("./"))) {
href.remove(0,2);
}
- QString mimetype = context.odfLoadingContext().mimeTypeForPath(href);
+ QString mimetype = context.mimeTypeForPath(href);
debugFlake << mimetype;
if (mimetype != "image/svg+xml")
return 0;
- if (!context.odfLoadingContext().store()->open(href))
+ if (!context.store()->open(href))
return 0;
- KoStoreDevice dev(context.odfLoadingContext().store());
+ KoStoreDevice dev(context.store());
KoXmlDocument xmlDoc;
int line, col;
QString errormessage;
const bool parsed = xmlDoc.setContent(&dev, &errormessage, &line, &col);
- context.odfLoadingContext().store()->close();
+ context.store()->close();
if (! parsed) {
errorFlake << "Error while parsing file: "
<< "at line " << line << " column: " << col
<< " message: " << errormessage << endl;
return 0;
}
const int zIndex = calculateZIndex(element, context);
/**
* In Krita 3.x we used hardcoded values for shape resolution and font resolution.
* Override them here explicitly, because ODF-based files can be created only in
* Krita 3.x.
*
* NOTE: don't ask me why they differ...
*/
const qreal hardcodedImageResolution = 90.0;
const qreal hardcodedFontResolution = 96.0;
return createShapeFromSvgDirect(xmlDoc.documentElement(), QRect(0,0,300,300),
hardcodedImageResolution,
hardcodedFontResolution, zIndex, context);
}
return 0;
}
int SvgShapeFactory::calculateZIndex(const KoXmlElement &element, KoShapeLoadingContext &context)
{
int zIndex = 0;
if (element.hasAttributeNS(KoXmlNS::draw, "z-index")) {
zIndex = element.attributeNS(KoXmlNS::draw, "z-index").toInt();
} else {
zIndex = context.zIndex();
}
return zIndex;
}
KoShape *SvgShapeFactory::createShapeFromSvgDirect(const KoXmlElement &root,
const QRectF &boundsInPixels,
const qreal pixelsPerInch,
const qreal forcedFontSizeResolution,
int zIndex,
KoShapeLoadingContext &context,
QSizeF *fragmentSize)
{
SvgParser parser(context.documentResourceManager());
parser.setResolution(boundsInPixels, pixelsPerInch);
parser.setForcedFontSizeResolution(forcedFontSizeResolution);
QList<KoShape*> shapes = parser.parseSvg(root, fragmentSize);
if (shapes.isEmpty())
return 0;
if (shapes.count() == 1) {
KoShape *shape = shapes.first();
shape->setZIndex(zIndex);
return shape;
}
KoShapeGroup *svgGroup = new KoShapeGroup;
KoShapeGroupCommand cmd(svgGroup, shapes);
cmd.redo();
svgGroup->setZIndex(zIndex);
return svgGroup;
}
diff --git a/libs/flake/svg/SvgShapeFactory.h b/libs/flake/svg/SvgShapeFactory.h
index 164a4cdd4e..3c9365982c 100644
--- a/libs/flake/svg/SvgShapeFactory.h
+++ b/libs/flake/svg/SvgShapeFactory.h
@@ -1,42 +1,42 @@
/* This file is part of the KDE project
* Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
*
* 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 SVGSHAPEFACTORY_H
#define SVGSHAPEFACTORY_H
#include "kritaflake_export.h"
#include "KoShapeFactoryBase.h"
/// Use this shape factory to load embedded svg files from odf
class KRITAFLAKE_EXPORT SvgShapeFactory : public KoShapeFactoryBase
{
public:
SvgShapeFactory();
~SvgShapeFactory() override;
// reimplemented from KoShapeFactoryBase
bool supports(const KoXmlElement &element, KoShapeLoadingContext &context) const override;
// reimplemented from KoShapeFactoryBase
- KoShape *createShapeFromOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
+ KoShape *createShapeFromXML(const KoXmlElement &element, KoShapeLoadingContext &context) override;
static int calculateZIndex(const KoXmlElement &element, KoShapeLoadingContext &context);
static KoShape *createShapeFromSvgDirect(const KoXmlElement &root, const QRectF &boundsInPixels, const qreal pixelsPerInch, const qreal forcedFontSizeResolution, int zIndex, KoShapeLoadingContext &context, QSizeF *fragmentSize = 0);
};
#endif // SVGSHAPEFACTORY_H
diff --git a/libs/flake/tests/MockShapes.h b/libs/flake/tests/MockShapes.h
index d6d878d990..05514e7213 100644
--- a/libs/flake/tests/MockShapes.h
+++ b/libs/flake/tests/MockShapes.h
@@ -1,248 +1,240 @@
/*
* This file is part of Calligra tests
*
* Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
*
* 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 MOCKSHAPES_H
#define MOCKSHAPES_H
#include <KoSelectedShapesProxySimple.h>
#include <KoShapeGroup.h>
#include <KoCanvasBase.h>
#include <KoShapeControllerBase.h>
#include <KoShapeContainerModel.h>
#include <QPainter>
#include "KoShapeManager.h"
#include "FlakeDebug.h"
#include "KoSnapData.h"
#include "KoUnit.h"
#include "kritaflake_export.h"
+#include "kis_assert.h"
class KRITAFLAKE_EXPORT MockShape : public KoShape
{
public:
MockShape() : paintedCount(0) {}
void paint(QPainter &painter, KoShapePaintingContext &) const override {
Q_UNUSED(painter);
//qDebug() << "Shape" << kBacktrace( 10 );
paintedCount++;
}
- void saveOdf(KoShapeSavingContext &) const override {}
- bool loadOdf(const KoXmlElement &, KoShapeLoadingContext &) override {
- return true;
- }
mutable int paintedCount;
};
+#include <SimpleShapeContainerModel.h>
+
class KRITAFLAKE_EXPORT MockContainer : public KoShapeContainer
{
public:
- MockContainer(KoShapeContainerModel *model = 0) : KoShapeContainer(model), paintedCount(0) {}
+ MockContainer(KoShapeContainerModel *model = new SimpleShapeContainerModel()) : KoShapeContainer(model), paintedCount(0) {}
void paintComponent(QPainter &painter, KoShapePaintingContext &) const override {
Q_UNUSED(painter);
//qDebug() << "Container:" << kBacktrace( 10 );
paintedCount++;
}
- void saveOdf(KoShapeSavingContext &) const override {}
- bool loadOdf(const KoXmlElement &, KoShapeLoadingContext &) override {
- return true;
- }
mutable int paintedCount;
+
+ bool contains(KoShape *shape) const {
+ return shapes().contains(shape);
+ }
+
+ void setAssociatedRootShapeManager(KoShapeManager *shapeManager)
+ {
+ SimpleShapeContainerModel *model = dynamic_cast<SimpleShapeContainerModel*>(this->model());
+ KIS_SAFE_ASSERT_RECOVER_RETURN(model);
+ model->setAssociatedRootShapeManager(shapeManager);
+ }
+
+ KoShapeManager* associatedRootShapeManager() const
+ {
+ SimpleShapeContainerModel *model = dynamic_cast<SimpleShapeContainerModel*>(this->model());
+ KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(model, 0);
+ return model->associatedRootShapeManager();
+ }
+
};
class KRITAFLAKE_EXPORT MockGroup : public KoShapeGroup
{
void paintComponent(QPainter &painter, KoShapePaintingContext &) const override {
Q_UNUSED(painter);
+ paintedCount++;
+ }
+public:
+ bool contains(KoShape *shape) const {
+ return shapes().contains(shape);
}
+
+ mutable int paintedCount;
};
class KoToolProxy;
class KRITAFLAKE_EXPORT MockShapeController : public KoShapeControllerBase
{
public:
- void addShapes(const QList<KoShape*> shapes) override {
- Q_FOREACH (KoShape *shape, shapes) {
- m_shapes.insert(shape);
- if (m_shapeManager) {
- m_shapeManager->addShape(shape);
- }
- }
- }
- void removeShape(KoShape* shape) override {
- m_shapes.remove(shape);
- if (m_shapeManager) {
- m_shapeManager->remove(shape);
- }
- }
- bool contains(KoShape* shape) {
- return m_shapes.contains(shape);
- }
-
- void setShapeManager(KoShapeManager *shapeManager) {
- m_shapeManager = shapeManager;
- }
-
QRectF documentRectInPixels() const override {
return QRectF(0,0,100,100);
}
qreal pixelsPerInch() const override {
return 72.0;
}
-
-private:
- QSet<KoShape * > m_shapes;
- KoShapeManager *m_shapeManager = 0;
};
class KRITAFLAKE_EXPORT MockCanvas : public KoCanvasBase
{
Q_OBJECT
public:
MockCanvas(KoShapeControllerBase *aKoShapeControllerBase =0)//made for TestSnapStrategy.cpp
: KoCanvasBase(aKoShapeControllerBase),
m_shapeManager(new KoShapeManager(this)),
m_selectedShapesProxy(new KoSelectedShapesProxySimple(m_shapeManager.data()))
{
- if (MockShapeController *controller = dynamic_cast<MockShapeController*>(aKoShapeControllerBase)) {
- controller->setShapeManager(m_shapeManager.data());
- }
}
~MockCanvas() override {}
void setHorz(qreal pHorz){
m_horz = pHorz;
}
void setVert(qreal pVert){
m_vert = pVert;
}
void gridSize(QPointF *offset, QSizeF *spacing) const override {
Q_UNUSED(offset);
spacing->setWidth(m_horz);
spacing->setHeight(m_vert);
}
bool snapToGrid() const override {
return true;
}
void addCommand(KUndo2Command*) override { }
KoShapeManager *shapeManager() const override {
return m_shapeManager.data();
}
KoSelectedShapesProxy *selectedShapesProxy() const override {
return m_selectedShapesProxy.data();
}
void updateCanvas(const QRectF&) override {}
KoToolProxy * toolProxy() const override {
return 0;
}
KoViewConverter *viewConverter() const override {
return 0;
}
QWidget* canvasWidget() override {
return 0;
}
const QWidget* canvasWidget() const override {
return 0;
}
KoUnit unit() const override {
return KoUnit(KoUnit::Millimeter);
}
void updateInputMethodInfo() override {}
void setCursor(const QCursor &) override {}
private:
QScopedPointer<KoShapeManager> m_shapeManager;
QScopedPointer<KoSelectedShapesProxy> m_selectedShapesProxy;
qreal m_horz;
qreal m_vert;
};
class KRITAFLAKE_EXPORT MockContainerModel : public KoShapeContainerModel
{
public:
MockContainerModel() {
resetCounts();
}
/// reimplemented
void add(KoShape *child) override {
m_children.append(child); // note that we explicitly do not check for duplicates here!
}
/// reimplemented
void remove(KoShape *child) override {
m_children.removeAll(child);
}
/// reimplemented
void setClipped(const KoShape *, bool) override { } // ignored
/// reimplemented
bool isClipped(const KoShape *) const override {
return false;
}// ignored
/// reimplemented
int count() const override {
return m_children.count();
}
/// reimplemented
QList<KoShape*> shapes() const override {
return m_children;
}
/// reimplemented
void containerChanged(KoShapeContainer *, KoShape::ChangeType) override {
m_containerChangedCalled++;
}
/// reimplemented
void proposeMove(KoShape *, QPointF &) override {
m_proposeMoveCalled++;
}
/// reimplemented
void childChanged(KoShape *, KoShape::ChangeType) override {
m_childChangedCalled++;
}
void setInheritsTransform(const KoShape *, bool) override {
}
bool inheritsTransform(const KoShape *) const override {
return false;
}
int containerChangedCalled() const {
return m_containerChangedCalled;
}
int childChangedCalled() const {
return m_childChangedCalled;
}
int proposeMoveCalled() const {
return m_proposeMoveCalled;
}
void resetCounts() {
m_containerChangedCalled = 0;
m_childChangedCalled = 0;
m_proposeMoveCalled = 0;
}
private:
QList<KoShape*> m_children;
int m_containerChangedCalled, m_childChangedCalled, m_proposeMoveCalled;
};
#endif
diff --git a/libs/flake/tests/TestKoShapeFactory.cpp b/libs/flake/tests/TestKoShapeFactory.cpp
index af4e7f54f9..9c9bb37bd5 100644
--- a/libs/flake/tests/TestKoShapeFactory.cpp
+++ b/libs/flake/tests/TestKoShapeFactory.cpp
@@ -1,130 +1,67 @@
/* This file is part of the KDE project
* Copyright (c) 2007 Boudewijn Rempt (boud@valdyas.org)
*
* 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 "TestKoShapeFactory.h"
#include <QTest>
#include <QBuffer>
-#include <KoOdfLoadingContext.h>
-#include <KoOdfStylesReader.h>
#include <KoShapeLoadingContext.h>
#include <KoPathShapeFactory.h>
#include <KoShape.h>
#include <KoShapeFactoryBase.h>
#include <KoXmlNS.h>
#include <FlakeDebug.h>
void TestKoShapeFactory::testCreateFactory()
{
KoShapeFactoryBase * factory = new KoPathShapeFactory(QStringList());
QVERIFY(factory != 0);
delete factory;
}
void TestKoShapeFactory::testSupportsKoXmlElement()
{
}
void TestKoShapeFactory::testPriority()
{
KoShapeFactoryBase * factory = new KoPathShapeFactory(QStringList());
QVERIFY(factory->loadingPriority() == 0);
delete factory;
}
void TestKoShapeFactory::testCreateDefaultShape()
{
KoShapeFactoryBase * factory = new KoPathShapeFactory(QStringList());
KoShape *shape = factory->createDefaultShape();
QVERIFY(shape != 0);
delete shape;
delete factory;
}
void TestKoShapeFactory::testCreateShape()
{
KoShapeFactoryBase * factory = new KoPathShapeFactory(QStringList());
KoShape *shape = factory->createShape(0);
QVERIFY(shape != 0);
delete shape;
delete factory;
}
-void TestKoShapeFactory::testOdfElement()
-{
- KoShapeFactoryBase * factory = new KoPathShapeFactory(QStringList());
- QVERIFY(factory->odfElements().front().second.contains("path"));
- QVERIFY(factory->odfElements().front().second.contains("line"));
- QVERIFY(factory->odfElements().front().second.contains("polyline"));
- QVERIFY(factory->odfElements().front().second.contains("polygon"));
- QVERIFY(factory->odfElements().front().first == KoXmlNS::draw);
-
- QBuffer xmldevice;
- xmldevice.open(QIODevice::WriteOnly);
- QTextStream xmlstream(&xmldevice);
- xmlstream.setCodec("UTF-8");
-
- xmlstream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
- xmlstream << "<office:document-content xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\" xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\" xmlns:math=\"http://www.w3.org/1998/Math/MathML\" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\" xmlns:calligra=\"http://www.calligra.org/2005/\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">";
- xmlstream << "<office:body>";
- xmlstream << "<office:text>";
- xmlstream << "<text:p text:style-name=\"P1\"><?opendocument cursor-position?></text:p>";
- xmlstream << "<draw:path svg:d=\"M10,10L100,100\"></draw:path>";
- xmlstream << "</office:text>";
- xmlstream << "</office:body>";
- xmlstream << "</office:document-content>";
- xmldevice.close();
-
- KoXmlDocument doc;
- QString errorMsg;
- int errorLine = 0;
- int errorColumn = 0;
-
- QCOMPARE(doc.setContent(&xmldevice, true, &errorMsg, &errorLine, &errorColumn), true);
- QCOMPARE(errorMsg.isEmpty(), true);
- QCOMPARE(errorLine, 0);
- QCOMPARE(errorColumn, 0);
-
- KoXmlElement contentElement = doc.documentElement();
- KoXmlElement bodyElement = contentElement.firstChild().toElement();
-
- // XXX: When loading is implemented, these no doubt have to be
- // sensibly filled.
- KoOdfStylesReader stylesReader;
- KoOdfLoadingContext odfContext(stylesReader, 0);
- KoShapeLoadingContext shapeContext(odfContext, 0);
-
- KoXmlElement textElement = bodyElement.firstChild().firstChild().toElement();
- QVERIFY(textElement.tagName() == "p");
- QCOMPARE(factory->supports(textElement, shapeContext), false);
-
- KoXmlElement pathElement = bodyElement.firstChild().lastChild().toElement();
- QVERIFY(pathElement.tagName() == "path");
- QCOMPARE(factory->supports(pathElement, shapeContext), true);
-
- KoShape *shape = factory->createDefaultShape();
- QVERIFY(shape);
-
- QVERIFY(shape->loadOdf(pathElement, shapeContext));
-
- delete shape;
- delete factory;
-}
-
QTEST_GUILESS_MAIN(TestKoShapeFactory)
diff --git a/libs/flake/tests/TestKoShapeFactory.h b/libs/flake/tests/TestKoShapeFactory.h
index cec01d0bc9..61144289f2 100644
--- a/libs/flake/tests/TestKoShapeFactory.h
+++ b/libs/flake/tests/TestKoShapeFactory.h
@@ -1,39 +1,38 @@
/* This file is part of the KDE project
* Copyright (c) 2007 Boudewijn Rempt (boud@valdyas.org)
*
* 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 TestKoShapeFactoryBase_H
#define TestKoShapeFactoryBase_H
#include <QObject>
class TestKoShapeFactory : public QObject
{
Q_OBJECT
private Q_SLOTS:
// tests
void testCreateFactory();
void testSupportsKoXmlElement();
void testPriority();
void testCreateDefaultShape();
void testCreateShape();
- void testOdfElement();
};
#endif
diff --git a/libs/flake/tests/TestKoShapeRegistry.cpp b/libs/flake/tests/TestKoShapeRegistry.cpp
index fc96f26f12..316beb0037 100644
--- a/libs/flake/tests/TestKoShapeRegistry.cpp
+++ b/libs/flake/tests/TestKoShapeRegistry.cpp
@@ -1,214 +1,197 @@
/* This file is part of the KDE project
* Copyright (c) 2007 Boudewijn Rempt (boud@valdyas.org)
*
* 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 "TestKoShapeRegistry.h"
#include <QTest>
#include <QBuffer>
#include <QFile>
#include <QDateTime>
#include <QProcess>
#include <QString>
#include <QTextStream>
#include <QtXml>
-#include <KoOdfLoadingContext.h>
-#include <KoOdfStylesReader.h>
-
#include "KoShapeRegistry.h"
#include "KoShape.h"
#include "KoPathShape.h"
#include "KoShapeLoadingContext.h"
#include <KoXmlReader.h>
#include <FlakeDebug.h>
#include "kis_debug.h"
#include <sdk/tests/kistest.h>
void TestKoShapeRegistry::testGetKoShapeRegistryInstance()
{
KoShapeRegistry * registry = KoShapeRegistry::instance();
QVERIFY(registry != 0);
}
void TestKoShapeRegistry::testCreateShapes()
{
QBuffer xmldevice;
xmldevice.open(QIODevice::WriteOnly);
QTextStream xmlstream(&xmldevice);
xmlstream.setCodec("UTF-8");
xmlstream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
xmlstream << "<office:document-content xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\" xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\" xmlns:math=\"http://www.w3.org/1998/Math/MathML\" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\" xmlns:calligra=\"http://www.calligra.org/2005/\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">";
xmlstream << "<office:body>";
xmlstream << "<office:text>";
xmlstream << "<draw:path svg:d=\"M0,0L100,100\"></draw:path>";
xmlstream << "</office:text>";
xmlstream << "</office:body>";
xmlstream << "</office:document-content>";
xmldevice.close();
KoXmlDocument doc;
QString errorMsg;
int errorLine = 0;
int errorColumn = 0;
QCOMPARE(doc.setContent(&xmldevice, true, &errorMsg, &errorLine, &errorColumn), true);
QCOMPARE(errorMsg.isEmpty(), true);
QCOMPARE(errorLine, 0);
QCOMPARE(errorColumn, 0);
KoXmlElement contentElement = doc.documentElement();
KoXmlElement bodyElement = contentElement.firstChild().toElement();
KoShapeRegistry * registry = KoShapeRegistry::instance();
- // XXX: When loading is implemented, these no doubt have to be
- // sensibly filled.
- KoOdfStylesReader stylesReader;
- KoOdfLoadingContext odfContext(stylesReader, 0);
- KoShapeLoadingContext shapeContext(odfContext, 0);
+ KoShapeLoadingContext shapeContext(0, 0);
- KoShape * shape = registry->createShapeFromOdf(bodyElement, shapeContext);
+ KoShape * shape = registry->createShapeFromXML(bodyElement, shapeContext);
QVERIFY(shape == 0);
KoXmlElement pathElement = bodyElement.firstChild().firstChild().toElement();
- shape = registry->createShapeFromOdf(pathElement, shapeContext);
+ shape = registry->createShapeFromXML(pathElement, shapeContext);
QVERIFY(shape != 0);
QVERIFY(shape->shapeId() == KoPathShapeId);
}
void TestKoShapeRegistry::testCreateFramedShapes()
{
QBuffer xmldevice;
xmldevice.open(QIODevice::WriteOnly);
QTextStream xmlstream(&xmldevice);
xmlstream.setCodec("UTF-8");
xmlstream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
xmlstream << "<office:document-content xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\" xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\" xmlns:math=\"http://www.w3.org/1998/Math/MathML\" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\" xmlns:calligra=\"http://www.calligra.org/2005/\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">";
xmlstream << "<office:body>";
xmlstream << "<office:text>";
xmlstream << "<draw:path svg:d=\"M0,0L100,100\"></draw:path>";
xmlstream << "</office:text>";
xmlstream << "</office:body>";
xmlstream << "</office:document-content>";
xmldevice.close();
KoXmlDocument doc;
QString errorMsg;
int errorLine = 0;
int errorColumn = 0;
QCOMPARE(doc.setContent(&xmldevice, true, &errorMsg, &errorLine, &errorColumn), true);
QCOMPARE(errorMsg.isEmpty(), true);
QCOMPARE(errorLine, 0);
QCOMPARE(errorColumn, 0);
KoXmlElement contentElement = doc.documentElement();
KoXmlElement bodyElement = contentElement.firstChild().toElement();
KoShapeRegistry * registry = KoShapeRegistry::instance();
- // XXX: When loading is implemented, these no doubt have to be
- // sensibly filled.
- KoOdfStylesReader stylesReader;
- KoOdfLoadingContext odfContext(stylesReader, 0);
- KoShapeLoadingContext shapeContext(odfContext, 0);
+ KoShapeLoadingContext shapeContext(0, 0);
- KoShape * shape = registry->createShapeFromOdf(bodyElement, shapeContext);
+ KoShape * shape = registry->createShapeFromXML(bodyElement, shapeContext);
QVERIFY(shape == 0);
KoXmlElement pathElement = bodyElement.firstChild().firstChild().toElement();
- shape = registry->createShapeFromOdf(pathElement, shapeContext);
+ shape = registry->createShapeFromXML(pathElement, shapeContext);
QVERIFY(shape != 0);
QVERIFY(shape->shapeId() == KoPathShapeId);
}
#include <KoStore.h>
#include <KoDocumentResourceManager.h>
#include <KoShapeController.h>
#include <MockShapes.h>
#include "../../sdk/tests/qimage_test_util.h"
void TestKoShapeRegistry::testFramedSvgShapes()
{
QBuffer xmldevice;
xmldevice.open(QIODevice::WriteOnly);
QTextStream xmlstream(&xmldevice);
xmlstream.setCodec("UTF-8");
xmlstream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
xmlstream << "<office:document-content xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\" xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\" xmlns:math=\"http://www.w3.org/1998/Math/MathML\" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\" xmlns:calligra=\"http://www.calligra.org/2005/\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">";
xmlstream << "<office:body>";
xmlstream << "<office:text>";
xmlstream << "<draw:frame xml:id=\"shape-1\" draw:z-index=\"2\" draw:id=\"shape-1\" draw:layer=\"\" svg:width=\"226pt\" svg:height=\"141pt\" svg:x=\"83pt\" svg:y=\"41pt\">";
xmlstream << " <draw:image xlink:type=\"simple\" draw:z-index=\"3\" xlink:show=\"embed\" xlink:actuate=\"onLoad\" xlink:href=\"VectorImages/Image1\"/>";
xmlstream << "</draw:frame>";
xmlstream << "</office:text>";
xmlstream << "</office:body>";
xmlstream << "</office:document-content>";
xmldevice.close();
KoXmlDocument doc;
QString errorMsg;
int errorLine = 0;
int errorColumn = 0;
QCOMPARE(doc.setContent(&xmldevice, true, &errorMsg, &errorLine, &errorColumn), true);
QCOMPARE(errorMsg.isEmpty(), true);
QCOMPARE(errorLine, 0);
QCOMPARE(errorColumn, 0);
KoXmlElement contentElement = doc.documentElement();
KoXmlElement bodyElement = contentElement.firstChild().toElement();
KoShapeRegistry * registry = KoShapeRegistry::instance();
- // XXX: When loading is implemented, these no doubt have to be
- // sensibly filled.
- KoOdfStylesReader stylesReader;
-
const QString resourcesBlob = TestUtil::fetchDataFileLazy("odf_frame_resource_store.zip");
QScopedPointer<KoStore> store(KoStore::createStore(resourcesBlob, KoStore::Read, "krita", KoStore::Zip));
QScopedPointer<KoDocumentResourceManager> resourceManager(new KoDocumentResourceManager());
resourceManager->setResource(KoDocumentResourceManager::DocumentRectInPixels, QRect(0,0,1000,1000));
QScopedPointer<MockShapeController> document(new MockShapeController());
QScopedPointer<MockCanvas> canvas(new MockCanvas(document.data()));
QScopedPointer<KoShapeController> shapeController(new KoShapeController(canvas.data(), document.data()));
resourceManager->setGlobalShapeController(shapeController.data());
-
- KoOdfLoadingContext odfContext(stylesReader, store.data());
- KoShapeLoadingContext shapeContext(odfContext, resourceManager.data());
+ KoShapeLoadingContext shapeContext(store.data(), resourceManager.data());
KoXmlElement frameElement = bodyElement.firstChild().firstChild().toElement();
QCOMPARE(frameElement.tagName(), QString("frame"));
- KoShape *shape = registry->createShapeFromOdf(frameElement, shapeContext);
+ KoShape *shape = registry->createShapeFromXML(frameElement, shapeContext);
QVERIFY(shape);
QCOMPARE(shape->absoluteOutlineRect(), QRectF(83, 41, 226,141));
}
KISTEST_MAIN(TestKoShapeRegistry)
diff --git a/libs/odf/tests/TestKoUnit.cpp b/libs/flake/tests/TestKoUnit.cpp
similarity index 100%
rename from libs/odf/tests/TestKoUnit.cpp
rename to libs/flake/tests/TestKoUnit.cpp
diff --git a/libs/odf/tests/TestKoUnit.h b/libs/flake/tests/TestKoUnit.h
similarity index 100%
rename from libs/odf/tests/TestKoUnit.h
rename to libs/flake/tests/TestKoUnit.h
diff --git a/libs/flake/tests/TestPointMergeCommand.cpp b/libs/flake/tests/TestPointMergeCommand.cpp
index 5c6cf20cbe..54d60c9c01 100644
--- a/libs/flake/tests/TestPointMergeCommand.cpp
+++ b/libs/flake/tests/TestPointMergeCommand.cpp
@@ -1,578 +1,571 @@
/* This file is part of the KDE project
* Copyright (C) 2009 Jan Hambrecht <jaham@gmx.net>
*
* 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 "TestPointMergeCommand.h"
#include "KoPathPointMergeCommand.h"
#include "KoPathShape.h"
#include "KoPathPoint.h"
#include "KoPathPointData.h"
#include <sdk/tests/kistest.h>
#include <QPainterPath>
#include <QTest>
#include <FlakeDebug.h>
void TestPointMergeCommand::closeSingleLinePath()
{
KoPathShape path1;
path1.moveTo(QPointF(40, 0));
path1.lineTo(QPointF(60, 0));
path1.lineTo(QPointF(60, 30));
path1.lineTo(QPointF(0, 30));
path1.lineTo(QPointF(0, 0));
path1.lineTo(QPointF(20, 0));
KoPathPointIndex index1(0,0);
KoPathPointIndex index2(0,5);
KoPathPointData pd1(&path1, index1);
KoPathPointData pd2(&path1, index2);
KoPathPoint * p1 = path1.pointByIndex(index1);
KoPathPoint * p2 = path1.pointByIndex(index2);
QVERIFY(!path1.isClosedSubpath(0));
QCOMPARE(path1.subpathPointCount(0), 6);
QCOMPARE(p1->point(), QPointF(40,0));
QCOMPARE(p2->point(), QPointF(20,0));
KoPathPointMergeCommand cmd1(pd1,pd2);
cmd1.redo();
QVERIFY(path1.isClosedSubpath(0));
QCOMPARE(path1.subpathPointCount(0), 5);
QCOMPARE(p2->point(), QPointF(20,0));
cmd1.undo();
QVERIFY(!path1.isClosedSubpath(0));
QCOMPARE(path1.subpathPointCount(0), 6);
QCOMPARE(p1->point(), QPointF(40,0));
QCOMPARE(p2->point(), QPointF(20,0));
KoPathPointMergeCommand cmd2(pd2,pd1);
cmd2.redo();
QVERIFY(path1.isClosedSubpath(0));
QCOMPARE(path1.subpathPointCount(0), 5);
QCOMPARE(p2->point(), QPointF(20,0));
cmd2.undo();
QVERIFY(!path1.isClosedSubpath(0));
QCOMPARE(path1.subpathPointCount(0), 6);
QCOMPARE(p1->point(), QPointF(40,0));
QCOMPARE(p2->point(), QPointF(20,0));
}
void TestPointMergeCommand::closeSingleCurvePath()
{
KoPathShape path1;
path1.moveTo(QPointF(40, 0));
path1.curveTo(QPointF(60, 0), QPointF(60,0), QPointF(60,60));
path1.lineTo(QPointF(0, 60));
path1.curveTo(QPointF(0, 0), QPointF(0,0), QPointF(20,0));
KoPathPointIndex index1(0,0);
KoPathPointIndex index2(0,3);
KoPathPointData pd1(&path1, index1);
KoPathPointData pd2(&path1, index2);
KoPathPoint * p1 = path1.pointByIndex(index1);
KoPathPoint * p2 = path1.pointByIndex(index2);
QVERIFY(!path1.isClosedSubpath(0));
QCOMPARE(path1.subpathPointCount(0), 4);
QCOMPARE(p1->point(), QPointF(40,0));
QVERIFY(!p1->activeControlPoint1());
QCOMPARE(p2->point(), QPointF(20,0));
QVERIFY(!p2->activeControlPoint2());
KoPathPointMergeCommand cmd1(pd1,pd2);
cmd1.redo();
QVERIFY(path1.isClosedSubpath(0));
QCOMPARE(path1.subpathPointCount(0), 3);
QCOMPARE(p2->point(), QPointF(20,0));
QVERIFY(p2->activeControlPoint1());
QVERIFY(!p2->activeControlPoint2());
cmd1.undo();
QVERIFY(!path1.isClosedSubpath(0));
QCOMPARE(path1.subpathPointCount(0), 4);
QCOMPARE(p1->point(), QPointF(40,0));
QVERIFY(!p1->activeControlPoint1());
QCOMPARE(p2->point(), QPointF(20,0));
QVERIFY(!p2->activeControlPoint2());
KoPathPointMergeCommand cmd2(pd2,pd1);
cmd2.redo();
QVERIFY(path1.isClosedSubpath(0));
QCOMPARE(path1.subpathPointCount(0), 3);
QCOMPARE(p2->point(), QPointF(20,0));
QVERIFY(p2->activeControlPoint1());
QVERIFY(!p2->activeControlPoint2());
cmd2.undo();
QVERIFY(!path1.isClosedSubpath(0));
QCOMPARE(path1.subpathPointCount(0), 4);
QCOMPARE(p1->point(), QPointF(40,0));
QVERIFY(!p1->activeControlPoint1());
QCOMPARE(p2->point(), QPointF(20,0));
QVERIFY(!p2->activeControlPoint2());
}
void TestPointMergeCommand::connectLineSubpaths()
{
KoPathShape path1;
path1.moveTo(QPointF(0,0));
path1.lineTo(QPointF(10,0));
path1.moveTo(QPointF(20,0));
path1.lineTo(QPointF(30,0));
KoPathPointIndex index1(0,1);
KoPathPointIndex index2(1,0);
KoPathPointData pd1(&path1, index1);
KoPathPointData pd2(&path1, index2);
QCOMPARE(path1.subpathCount(), 2);
QCOMPARE(path1.pointByIndex(index1)->point(), QPointF(10,0));
QCOMPARE(path1.pointByIndex(index2)->point(), QPointF(20,0));
KoPathPointMergeCommand cmd1(pd1, pd2);
cmd1.redo();
QCOMPARE(path1.subpathCount(), 1);
QCOMPARE(path1.pointByIndex(index1)->point(), QPointF(15,0));
cmd1.undo();
QCOMPARE(path1.subpathCount(), 2);
QCOMPARE(path1.pointByIndex(index1)->point(), QPointF(10,0));
QCOMPARE(path1.pointByIndex(index2)->point(), QPointF(20,0));
KoPathPointMergeCommand cmd2(pd2, pd1);
cmd2.redo();
QCOMPARE(path1.subpathCount(), 1);
QCOMPARE(path1.pointByIndex(index1)->point(), QPointF(15,0));
cmd2.undo();
QCOMPARE(path1.subpathCount(), 2);
QCOMPARE(path1.pointByIndex(index1)->point(), QPointF(10,0));
QCOMPARE(path1.pointByIndex(index2)->point(), QPointF(20,0));
}
void TestPointMergeCommand::connectCurveSubpaths()
{
KoPathShape path1;
path1.moveTo(QPointF(0,0));
path1.curveTo(QPointF(20,0),QPointF(0,20),QPointF(20,20));
path1.moveTo(QPointF(50,0));
path1.curveTo(QPointF(30,0), QPointF(50,20), QPointF(30,20));
KoPathPointIndex index1(0,1);
KoPathPointIndex index2(1,1);
KoPathPointData pd1(&path1, index1);
KoPathPointData pd2(&path1, index2);
QCOMPARE(path1.subpathCount(), 2);
QCOMPARE(path1.pointByIndex(index1)->point(), QPointF(20,20));
QCOMPARE(path1.pointByIndex(index1)->controlPoint1(), QPointF(0,20));
QCOMPARE(path1.pointByIndex(index2)->point(), QPointF(30,20));
QCOMPARE(path1.pointByIndex(index2)->controlPoint1(), QPointF(50,20));
QVERIFY(path1.pointByIndex(index1)->activeControlPoint1());
QVERIFY(!path1.pointByIndex(index1)->activeControlPoint2());
KoPathPointMergeCommand cmd1(pd1, pd2);
cmd1.redo();
QCOMPARE(path1.subpathCount(), 1);
QCOMPARE(path1.pointByIndex(index1)->point(), QPointF(25,20));
QCOMPARE(path1.pointByIndex(index1)->controlPoint1(), QPointF(5,20));
QCOMPARE(path1.pointByIndex(index1)->controlPoint2(), QPointF(45,20));
QVERIFY(path1.pointByIndex(index1)->activeControlPoint1());
QVERIFY(path1.pointByIndex(index1)->activeControlPoint2());
cmd1.undo();
QCOMPARE(path1.subpathCount(), 2);
QCOMPARE(path1.pointByIndex(index1)->point(), QPointF(20,20));
QCOMPARE(path1.pointByIndex(index1)->controlPoint1(), QPointF(0,20));
QCOMPARE(path1.pointByIndex(index2)->point(), QPointF(30,20));
QCOMPARE(path1.pointByIndex(index2)->controlPoint1(), QPointF(50,20));
QVERIFY(path1.pointByIndex(index1)->activeControlPoint1());
QVERIFY(!path1.pointByIndex(index1)->activeControlPoint2());
KoPathPointMergeCommand cmd2(pd2, pd1);
cmd2.redo();
QCOMPARE(path1.subpathCount(), 1);
QCOMPARE(path1.pointByIndex(index1)->point(), QPointF(25,20));
QCOMPARE(path1.pointByIndex(index1)->controlPoint1(), QPointF(5,20));
QCOMPARE(path1.pointByIndex(index1)->controlPoint2(), QPointF(45,20));
QVERIFY(path1.pointByIndex(index1)->activeControlPoint1());
QVERIFY(path1.pointByIndex(index1)->activeControlPoint2());
cmd2.undo();
QCOMPARE(path1.subpathCount(), 2);
QCOMPARE(path1.pointByIndex(index1)->point(), QPointF(20,20));
QCOMPARE(path1.pointByIndex(index1)->controlPoint1(), QPointF(0,20));
QCOMPARE(path1.pointByIndex(index2)->point(), QPointF(30,20));
QCOMPARE(path1.pointByIndex(index2)->controlPoint1(), QPointF(50,20));
QVERIFY(path1.pointByIndex(index1)->activeControlPoint1());
QVERIFY(!path1.pointByIndex(index1)->activeControlPoint2());
}
#include <MockShapes.h>
#include <commands/KoPathCombineCommand.h>
#include "kis_debug.h"
void TestPointMergeCommand::testCombineShapes()
{
MockShapeController mockController;
MockCanvas canvas(&mockController);
+ QScopedPointer<MockContainer> rootContainer(new MockContainer());
+ rootContainer->setAssociatedRootShapeManager(canvas.shapeManager());
QList<KoPathShape*> shapesToCombine;
for (int i = 0; i < 3; i++) {
const QPointF step(15,15);
const QRectF rect = QRectF(5,5,10,10).translated(step * i);
QPainterPath p;
p.addRect(rect);
KoPathShape *shape = KoPathShape::createShapeFromPainterPath(p);
QCOMPARE(shape->absoluteOutlineRect(), rect);
shapesToCombine << shape;
- mockController.addShape(shape);
+ rootContainer->addShape(shape);
}
KoPathCombineCommand cmd(&mockController, shapesToCombine);
cmd.redo();
- QCOMPARE(canvas.shapeManager()->shapes().size(), 1);
+ QCOMPARE(rootContainer->shapes().size(), 1);
- KoPathShape *combinedShape = dynamic_cast<KoPathShape*>(canvas.shapeManager()->shapes().first());
+ KoPathShape *combinedShape = dynamic_cast<KoPathShape*>(rootContainer->shapes().first());
QCOMPARE(combinedShape, cmd.combinedPath());
QCOMPARE(combinedShape->subpathCount(), 3);
QCOMPARE(combinedShape->absoluteOutlineRect(), QRectF(5,5,40,40));
QList<KoPathPointData> tstPoints;
QList<KoPathPointData> expPoints;
tstPoints << KoPathPointData(shapesToCombine[0], KoPathPointIndex(0,1));
expPoints << KoPathPointData(combinedShape, KoPathPointIndex(0,1));
tstPoints << KoPathPointData(shapesToCombine[1], KoPathPointIndex(0,2));
expPoints << KoPathPointData(combinedShape, KoPathPointIndex(1,2));
tstPoints << KoPathPointData(shapesToCombine[2], KoPathPointIndex(0,3));
expPoints << KoPathPointData(combinedShape, KoPathPointIndex(2,3));
for (int i = 0; i < tstPoints.size(); i++) {
KoPathPointData convertedPoint = cmd.originalToCombined(tstPoints[i]);
QCOMPARE(convertedPoint, expPoints[i]);
}
- Q_FOREACH (KoShape *shape, canvas.shapeManager()->shapes()) {
- mockController.removeShape(shape);
- shape->setParent(0);
- delete shape;
- }
-
+ rootContainer.reset();
// 'shapesToCombine' will be deleted by KoPathCombineCommand
}
#include <commands/KoMultiPathPointMergeCommand.h>
#include <commands/KoMultiPathPointJoinCommand.h>
#include <KoSelection.h>
#include "kis_algebra_2d.h"
inline QPointF fetchPoint(KoPathShape *shape, int subpath, int pointIndex) {
return shape->absoluteTransformation().map(
shape->pointByIndex(KoPathPointIndex(subpath, pointIndex))->point());
}
void dumpShape(KoPathShape *shape, const QString &fileName)
{
QImage tmp(50,50, QImage::Format_ARGB32);
tmp.fill(0);
QPainter p(&tmp);
p.drawPath(shape->absoluteTransformation().map(shape->outline()));
tmp.save(fileName);
}
template <class MergeCommand = KoMultiPathPointMergeCommand>
void testMultipathMergeShapesImpl(const int srcPointIndex1,
const int srcPointIndex2,
const QList<QPointF> &expectedResultPoints,
bool singleShape = false)
{
MockShapeController mockController;
MockCanvas canvas(&mockController);
+ QScopedPointer<MockContainer> rootContainer(new MockContainer());
+ rootContainer->setAssociatedRootShapeManager(canvas.shapeManager());
QList<KoPathShape*> shapes;
for (int i = 0; i < 3; i++) {
const QPointF step(15,15);
const QRectF rect = QRectF(5,5,10,10).translated(step * i);
QPainterPath p;
p.moveTo(rect.topLeft());
p.lineTo(rect.bottomRight());
p.lineTo(rect.topRight());
KoPathShape *shape = KoPathShape::createShapeFromPainterPath(p);
QCOMPARE(shape->absoluteOutlineRect(), rect);
shapes << shape;
- mockController.addShape(shape);
+ rootContainer->addShape(shape);
}
-
{
KoPathPointData pd1(shapes[0], KoPathPointIndex(0,srcPointIndex1));
KoPathPointData pd2(shapes[singleShape ? 0 : 1], KoPathPointIndex(0,srcPointIndex2));
MergeCommand cmd(pd1, pd2, &mockController, canvas.shapeManager()->selection());
cmd.redo();
const int expectedShapesCount = singleShape ? 3 : 2;
- QCOMPARE(canvas.shapeManager()->shapes().size(), expectedShapesCount);
+ QCOMPARE(rootContainer->shapes().size(), expectedShapesCount);
KoPathShape *combinedShape = 0;
if (!singleShape) {
- combinedShape = dynamic_cast<KoPathShape*>(canvas.shapeManager()->shapes()[1]);
+ combinedShape = dynamic_cast<KoPathShape*>(rootContainer->shapes()[1]);
QCOMPARE(combinedShape, cmd.testingCombinedPath());
} else {
- combinedShape = dynamic_cast<KoPathShape*>(canvas.shapeManager()->shapes()[0]);
+ combinedShape = dynamic_cast<KoPathShape*>(rootContainer->shapes()[0]);
QCOMPARE(combinedShape, shapes[0]);
}
QCOMPARE(combinedShape->subpathCount(), 1);
QRectF expectedOutlineRect;
KisAlgebra2D::accumulateBounds(expectedResultPoints, &expectedOutlineRect);
QVERIFY(KisAlgebra2D::fuzzyCompareRects(combinedShape->absoluteOutlineRect(), expectedOutlineRect, 0.01));
if (singleShape) {
QCOMPARE(combinedShape->isClosedSubpath(0), true);
}
QCOMPARE(combinedShape->subpathPointCount(0), expectedResultPoints.size());
for (int i = 0; i < expectedResultPoints.size(); i++) {
if (fetchPoint(combinedShape, 0, i) != expectedResultPoints[i]) {
qDebug() << ppVar(i);
qDebug() << ppVar(fetchPoint(combinedShape, 0, i));
qDebug() << ppVar(expectedResultPoints[i]);
QFAIL("Resulting shape points are different!");
}
}
QList<KoShape*> shapes = canvas.shapeManager()->selection()->selectedEditableShapes();
QCOMPARE(shapes.size(), 1);
QCOMPARE(shapes.first(), combinedShape);
//dumpShape(combinedShape, "tmp_0_seq.png");
cmd.undo();
- QCOMPARE(canvas.shapeManager()->shapes().size(), 3);
- }
-
- Q_FOREACH (KoShape *shape, canvas.shapeManager()->shapes()) {
- mockController.removeShape(shape);
- shape->setParent(0);
- delete shape;
+ QCOMPARE(rootContainer->shapes().size(), 3);
}
+ rootContainer.reset();
// combined shapes will be deleted by the corresponding commands
}
void TestPointMergeCommand::testMultipathMergeShapesBothSequential()
{
// both sequential
testMultipathMergeShapesImpl(2, 0,
{
QPointF(5,5),
QPointF(15,15),
QPointF(17.5,12.5), // merged by melding the points!
QPointF(30,30),
QPointF(30,20)
});
}
void TestPointMergeCommand::testMultipathMergeShapesFirstReversed()
{
// first reversed
testMultipathMergeShapesImpl(0, 0,
{
QPointF(15,5),
QPointF(15,15),
QPointF(12.5,12.5), // merged by melding the points!
QPointF(30,30),
QPointF(30,20)
});
}
void TestPointMergeCommand::testMultipathMergeShapesSecondReversed()
{
// second reversed
testMultipathMergeShapesImpl(2, 2,
{
QPointF(5,5),
QPointF(15,15),
QPointF(22.5,12.5), // merged by melding the points!
QPointF(30,30),
QPointF(20,20)
});
}
void TestPointMergeCommand::testMultipathMergeShapesBothReversed()
{
// both reversed
testMultipathMergeShapesImpl(0, 2,
{
QPointF(15,5),
QPointF(15,15),
QPointF(17.5,12.5), // merged by melding the points!
QPointF(30,30),
QPointF(20,20)
});
}
void TestPointMergeCommand::testMultipathMergeShapesSingleShapeEndToStart()
{
// close end->start
testMultipathMergeShapesImpl(2, 0,
{
QPointF(10,5),
QPointF(15,15)
}, true);
}
void TestPointMergeCommand::testMultipathMergeShapesSingleShapeStartToEnd()
{
// close start->end
testMultipathMergeShapesImpl(0, 2,
{
QPointF(10,5),
QPointF(15,15)
}, true);
}
void TestPointMergeCommand::testMultipathJoinShapesBothSequential()
{
// both sequential
testMultipathMergeShapesImpl<KoMultiPathPointJoinCommand>
(2, 0,
{
QPointF(5,5),
QPointF(15,15),
QPointF(15,5),
QPointF(20,20),
QPointF(30,30),
QPointF(30,20)
});
}
void TestPointMergeCommand::testMultipathJoinShapesFirstReversed()
{
// first reversed
testMultipathMergeShapesImpl<KoMultiPathPointJoinCommand>
(0, 0,
{
QPointF(15,5),
QPointF(15,15),
QPointF(5,5),
QPointF(20,20),
QPointF(30,30),
QPointF(30,20)
});
}
void TestPointMergeCommand::testMultipathJoinShapesSecondReversed()
{
// second reversed
testMultipathMergeShapesImpl<KoMultiPathPointJoinCommand>
(2, 2,
{
QPointF(5,5),
QPointF(15,15),
QPointF(15,5),
QPointF(30,20),
QPointF(30,30),
QPointF(20,20)
});
}
void TestPointMergeCommand::testMultipathJoinShapesBothReversed()
{
// both reversed
testMultipathMergeShapesImpl<KoMultiPathPointJoinCommand>
(0, 2,
{
QPointF(15,5),
QPointF(15,15),
QPointF(5,5),
QPointF(30,20),
QPointF(30,30),
QPointF(20,20)
});
}
void TestPointMergeCommand::testMultipathJoinShapesSingleShapeEndToStart()
{
// close end->start
testMultipathMergeShapesImpl<KoMultiPathPointJoinCommand>
(2, 0,
{
QPointF(5,5),
QPointF(15,15),
QPointF(15,5)
}, true);
}
void TestPointMergeCommand::testMultipathJoinShapesSingleShapeStartToEnd()
{
// close start->end
testMultipathMergeShapesImpl<KoMultiPathPointJoinCommand>
(0, 2,
{
QPointF(5,5),
QPointF(15,15),
QPointF(15,5)
}, true);
}
KISTEST_MAIN(TestPointMergeCommand)
diff --git a/libs/flake/tests/TestPointRemoveCommand.cpp b/libs/flake/tests/TestPointRemoveCommand.cpp
index 0c3adcf0cf..207dfd3f0e 100644
--- a/libs/flake/tests/TestPointRemoveCommand.cpp
+++ b/libs/flake/tests/TestPointRemoveCommand.cpp
@@ -1,303 +1,304 @@
/* This file is part of the KDE project
Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
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 "TestPointRemoveCommand.h"
#include <QPainterPath>
#include "KoPathShape.h"
#include "KoPathPointRemoveCommand.h"
#include "KoShapeController.h"
#include <MockShapes.h>
#include <sdk/tests/kistest.h>
#include <QTest>
void TestPointRemoveCommand::redoUndoPointRemove()
{
KoPathShape path1;
path1.moveTo(QPointF(0, 0));
path1.lineTo(QPointF(0, 100));
KoPathPoint *point1 = path1.curveTo(QPointF(0, 50), QPointF(100, 50), QPointF(100, 100));
KoPathPoint *point2 = path1.lineTo(QPointF(200, 100));
path1.curveTo(QPointF(200, 50), QPointF(300, 50), QPointF(300, 100));
QPainterPath orig1(QPointF(0, 0));
orig1.lineTo(0, 100);
orig1.cubicTo(0, 50, 100, 50, 100, 100);
orig1.lineTo(200, 100);
orig1.cubicTo(200, 50, 300, 50, 300, 100);
QVERIFY(orig1 == path1.outline());
KoPathShape path2;
path2.moveTo(QPointF(0, 0));
KoPathPoint *point3 = path2.curveTo(QPointF(50, 0), QPointF(100, 50), QPointF(100, 100));
path2.curveTo(QPointF(50, 100), QPointF(0, 50), QPointF(0, 0));
path2.closeMerge();
QList<KoPathPointData> pd;
pd.append(KoPathPointData(&path1, path1.pathPointIndex(point1)));
pd.append(KoPathPointData(&path1, path1.pathPointIndex(point2)));
pd.append(KoPathPointData(&path2, path2.pathPointIndex(point3)));
QPainterPath ppath1Org = path1.outline();
QPainterPath ppath2Org = path2.outline();
MockShapeController mockController;
KoShapeController shapeController(0, &mockController);
KUndo2Command *cmd = KoPathPointRemoveCommand::createCommand(pd, &shapeController);
cmd->redo();
QPainterPath ppath1(QPointF(0, 0));
ppath1.lineTo(0, 100);
ppath1.cubicTo(0, 50, 300, 50, 300, 100);
QPainterPath ppath2(QPointF(0, 0));
ppath2.cubicTo(50, 0, 0, 50, 0, 0);
ppath2.closeSubpath();
QVERIFY(ppath1 == path1.outline());
QVERIFY(ppath2 == path2.outline());
cmd->undo();
QVERIFY(ppath1Org == path1.outline());
QVERIFY(ppath2Org == path2.outline());
delete cmd;
}
void TestPointRemoveCommand::redoUndoSubpathRemove()
{
KoPathShape path1;
KoPathPoint *point11 = path1.moveTo(QPointF(0, 0));
KoPathPoint *point12 = path1.lineTo(QPointF(0, 100));
KoPathPoint *point13 = path1.curveTo(QPointF(0, 50), QPointF(100, 50), QPointF(100, 100));
KoPathPoint *point14 = path1.lineTo(QPointF(200, 100));
KoPathPoint *point15 = path1.curveTo(QPointF(200, 50), QPointF(300, 50), QPointF(300, 100));
KoPathPoint *point21 = path1.moveTo(QPointF(0, 0));
KoPathPoint *point22 = path1.curveTo(QPointF(50, 0), QPointF(100, 50), QPointF(100, 100));
path1.curveTo(QPointF(50, 100), QPointF(0, 50), QPointF(0, 0));
path1.closeMerge();
path1.moveTo(QPointF(100, 0));
path1.lineTo(QPointF(100, 100));
QList<KoPathPointData> pd;
pd.append(KoPathPointData(&path1, path1.pathPointIndex(point11)));
pd.append(KoPathPointData(&path1, path1.pathPointIndex(point12)));
pd.append(KoPathPointData(&path1, path1.pathPointIndex(point13)));
pd.append(KoPathPointData(&path1, path1.pathPointIndex(point14)));
pd.append(KoPathPointData(&path1, path1.pathPointIndex(point15)));
QPainterPath ppath1Org = path1.outline();
MockShapeController mockController;
KoShapeController shapeController(0, &mockController);
KUndo2Command *cmd1 = KoPathPointRemoveCommand::createCommand(pd, &shapeController);
cmd1->redo();
QPainterPath ppath1(QPointF(0, 0));
ppath1.cubicTo(50, 0, 100, 50, 100, 100);
ppath1.cubicTo(50, 100, 0, 50, 0, 0);
ppath1.closeSubpath();
ppath1.moveTo(100, 0);
ppath1.lineTo(100, 100);
QPainterPath ppath1mod = path1.outline();
QVERIFY(ppath1 == ppath1mod);
QList<KoPathPointData> pd2;
pd2.append(KoPathPointData(&path1, path1.pathPointIndex(point21)));
pd2.append(KoPathPointData(&path1, path1.pathPointIndex(point22)));
KUndo2Command *cmd2 = KoPathPointRemoveCommand::createCommand(pd2, &shapeController);
cmd2->redo();
QPainterPath ppath2(QPointF(0, 0));
ppath2.lineTo(0, 100);
QVERIFY(ppath2 == path1.outline());
cmd2->undo();
QVERIFY(ppath1mod == path1.outline());
cmd1->undo();
QVERIFY(ppath1Org == path1.outline());
delete cmd2;
delete cmd1;
}
void TestPointRemoveCommand::redoUndoShapeRemove()
{
KoPathShape *path1 = new KoPathShape();
KoPathPoint *point11 = path1->moveTo(QPointF(0, 0));
KoPathPoint *point12 = path1->lineTo(QPointF(0, 100));
KoPathPoint *point13 = path1->curveTo(QPointF(0, 50), QPointF(100, 50), QPointF(100, 100));
KoPathPoint *point14 = path1->lineTo(QPointF(200, 100));
KoPathPoint *point15 = path1->curveTo(QPointF(200, 50), QPointF(300, 50), QPointF(300, 100));
KoPathShape *path2 = new KoPathShape();
KoPathPoint *point21 = path2->moveTo(QPointF(0, 0));
KoPathPoint *point22 = path2->curveTo(QPointF(50, 0), QPointF(100, 50), QPointF(100, 100));
path2->curveTo(QPointF(50, 100), QPointF(0, 50), QPointF(0, 0));
path2->closeMerge();
QList<KoPathPointData> pd;
pd.append(KoPathPointData(path1, path1->pathPointIndex(point12)));
pd.append(KoPathPointData(path1, path1->pathPointIndex(point11)));
pd.append(KoPathPointData(path1, path1->pathPointIndex(point13)));
pd.append(KoPathPointData(path1, path1->pathPointIndex(point15)));
pd.append(KoPathPointData(path1, path1->pathPointIndex(point14)));
pd.append(KoPathPointData(path2, path2->pathPointIndex(point22)));
pd.append(KoPathPointData(path2, path2->pathPointIndex(point21)));
QPainterPath ppath1Org = path1->outline();
QPainterPath ppath2Org = path2->outline();
MockShapeController mockController;
- mockController.addShape(path1);
- mockController.addShape(path2);
KoShapeController shapeController(0, &mockController);
+ QScopedPointer<MockContainer> rootContainer(new MockContainer());
+ rootContainer->addShape(path1);
+ rootContainer->addShape(path2);
KUndo2Command *cmd = KoPathPointRemoveCommand::createCommand(pd, &shapeController);
cmd->redo();
- QVERIFY(!mockController.contains(path1));
- QVERIFY(!mockController.contains(path2));
+ QVERIFY(!rootContainer->contains(path1));
+ QVERIFY(!rootContainer->contains(path2));
cmd->undo();
- QVERIFY(mockController.contains(path1));
- QVERIFY(mockController.contains(path2));
+ QVERIFY(rootContainer->contains(path1));
+ QVERIFY(rootContainer->contains(path2));
QVERIFY(ppath1Org == path1->outline());
QVERIFY(ppath2Org == path2->outline());
delete cmd;
- delete path1;
- delete path2;
+ rootContainer.reset();
}
void TestPointRemoveCommand::redoUndo()
{
KoPathShape *path1 = new KoPathShape();
KoPathPoint *point11 = path1->moveTo(QPointF(0, 0));
KoPathPoint *point12 = path1->lineTo(QPointF(0, 100));
KoPathPoint *point13 = path1->curveTo(QPointF(0, 50), QPointF(100, 50), QPointF(100, 100));
KoPathPoint *point14 = path1->lineTo(QPointF(200, 100));
KoPathPoint *point15 = path1->curveTo(QPointF(200, 50), QPointF(300, 50), QPointF(300, 100));
KoPathPoint *point16 = path1->moveTo(QPointF(100, 0));
KoPathPoint *point17 = path1->curveTo(QPointF(150, 0), QPointF(200, 50), QPointF(200, 100));
path1->curveTo(QPointF(150, 100), QPointF(100, 50), QPointF(100, 0));
path1->closeMerge();
KoPathPoint *point18 = path1->moveTo(QPointF(200, 0));
KoPathPoint *point19 = path1->lineTo(QPointF(200, 100));
KoPathShape *path2 = new KoPathShape();
KoPathPoint *point21 = path2->moveTo(QPointF(0, 0));
KoPathPoint *point22 = path2->curveTo(QPointF(50, 0), QPointF(100, 50), QPointF(100, 100));
path2->curveTo(QPointF(50, 100), QPointF(0, 50), QPointF(0, 0));
path2->closeMerge();
KoPathShape *path3 = new KoPathShape();
KoPathPoint *point31 = path3->moveTo(QPointF(0, 0));
KoPathPoint *point32 = path3->lineTo(QPointF(100, 100));
KoPathPoint *point33 = path3->lineTo(QPointF(200, 150));
MockShapeController mockController;
- mockController.addShape(path1);
- mockController.addShape(path2);
- mockController.addShape(path3);
+ QScopedPointer<MockContainer> rootContainer(new MockContainer());
+ rootContainer->addShape(path1);
+ rootContainer->addShape(path2);
+ rootContainer->addShape(path3);
QList<KoPathPointData> pd;
pd.append(KoPathPointData(path2, path2->pathPointIndex(point21)));
pd.append(KoPathPointData(path1, path1->pathPointIndex(point13)));
pd.append(KoPathPointData(path1, path1->pathPointIndex(point11)));
pd.append(KoPathPointData(path3, path3->pathPointIndex(point31)));
pd.append(KoPathPointData(path1, path1->pathPointIndex(point12)));
pd.append(KoPathPointData(path1, path1->pathPointIndex(point15)));
pd.append(KoPathPointData(path2, path2->pathPointIndex(point22)));
pd.append(KoPathPointData(path1, path1->pathPointIndex(point14)));
KoShapeController shapeController(0, &mockController);
QPainterPath ppath1Org = path1->outline();
QPainterPath ppath2Org = path2->outline();
QPainterPath ppath3Org = path3->outline();
KUndo2Command *cmd1 = KoPathPointRemoveCommand::createCommand(pd, &shapeController);
cmd1->redo();
- QVERIFY(mockController.contains(path1));
- QVERIFY(!mockController.contains(path2));
- QVERIFY(mockController.contains(path3));
+ QVERIFY(rootContainer->contains(path1));
+ QVERIFY(!rootContainer->contains(path2));
+ QVERIFY(rootContainer->contains(path3));
QPainterPath ppath1(QPointF(0, 0));
ppath1.cubicTo(50, 0, 100, 50, 100, 100);
ppath1.cubicTo(50, 100, 0, 50, 0, 0);
ppath1.closeSubpath();
ppath1.moveTo(100, 0);
ppath1.lineTo(100, 100);
QPainterPath ppath1mod = path1->outline();
QVERIFY(ppath1 == ppath1mod);
QPainterPath ppath3(QPointF(0, 0));
ppath3.lineTo(100, 50);
QPainterPath ppath3mod = path3->outline();
QVERIFY(ppath3 == ppath3mod);
QList<KoPathPointData> pd2;
pd2.append(KoPathPointData(path1, path1->pathPointIndex(point16)));
pd2.append(KoPathPointData(path1, path1->pathPointIndex(point17)));
pd2.append(KoPathPointData(path1, path1->pathPointIndex(point18)));
pd2.append(KoPathPointData(path1, path1->pathPointIndex(point19)));
pd2.append(KoPathPointData(path3, path3->pathPointIndex(point32)));
pd2.append(KoPathPointData(path3, path3->pathPointIndex(point33)));
KUndo2Command *cmd2 = KoPathPointRemoveCommand::createCommand(pd2, &shapeController);
cmd2->redo();
- QVERIFY(!mockController.contains(path1));
- QVERIFY(!mockController.contains(path2));
- QVERIFY(!mockController.contains(path3));
+ QVERIFY(!rootContainer->contains(path1));
+ QVERIFY(!rootContainer->contains(path2));
+ QVERIFY(!rootContainer->contains(path3));
cmd2->undo();
- QVERIFY(mockController.contains(path1));
- QVERIFY(!mockController.contains(path2));
- QVERIFY(mockController.contains(path3));
+ QVERIFY(rootContainer->contains(path1));
+ QVERIFY(!rootContainer->contains(path2));
+ QVERIFY(rootContainer->contains(path3));
QVERIFY(ppath1 == ppath1mod);
QVERIFY(ppath3 == ppath3mod);
cmd1->undo();
QVERIFY(ppath1Org == path1->outline());
QVERIFY(ppath2Org == path2->outline());
QVERIFY(ppath3Org == path3->outline());
cmd1->redo();
cmd2->redo();
delete cmd2;
delete cmd1;
}
KISTEST_MAIN(TestPointRemoveCommand)
diff --git a/libs/flake/tests/TestShapePainting.cpp b/libs/flake/tests/TestShapePainting.cpp
index e5bfb25157..284cc2a1d4 100644
--- a/libs/flake/tests/TestShapePainting.cpp
+++ b/libs/flake/tests/TestShapePainting.cpp
@@ -1,317 +1,315 @@
/*
* This file is part of Calligra tests
*
* Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
*
* 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 "TestShapePainting.h"
#include <QtGui>
#include "KoShapeContainer.h"
#include "KoShapeManager.h"
#include "KoShapePaintingContext.h"
#include <sdk/tests/kistest.h>
#include <MockShapes.h>
#include <QTest>
void TestShapePainting::testPaintShape()
{
MockShape *shape1 = new MockShape();
MockShape *shape2 = new MockShape();
QScopedPointer<MockContainer> container(new MockContainer());
container->addShape(shape1);
container->addShape(shape2);
QCOMPARE(shape1->parent(), container.data());
QCOMPARE(shape2->parent(), container.data());
container->setClipped(shape1, false);
container->setClipped(shape2, false);
QCOMPARE(container->isClipped(shape1), false);
QCOMPARE(container->isClipped(shape2), false);
MockCanvas canvas;
KoShapeManager manager(&canvas);
manager.addShape(container.data());
QCOMPARE(manager.shapes().count(), 3);
QImage image(100, 100, QImage::Format_Mono);
QPainter painter(&image);
manager.paint(painter, false);
// with the shape not being clipped, the shapeManager will paint it for us.
QCOMPARE(shape1->paintedCount, 1);
QCOMPARE(shape2->paintedCount, 1);
QCOMPARE(container->paintedCount, 1);
// the container should thus not paint the shape
shape1->paintedCount = 0;
shape2->paintedCount = 0;
container->paintedCount = 0;
KoShapePaintingContext paintContext;
container->paint(painter, paintContext);
QCOMPARE(shape1->paintedCount, 0);
QCOMPARE(shape2->paintedCount, 0);
QCOMPARE(container->paintedCount, 1);
container->setClipped(shape1, false);
container->setClipped(shape2, true);
QCOMPARE(container->isClipped(shape1), false);
QCOMPARE(container->isClipped(shape2), true);
shape1->paintedCount = 0;
shape2->paintedCount = 0;
container->paintedCount = 0;
manager.paint(painter, false);
// with this shape not being clipped, the shapeManager will paint the container and this shape
QCOMPARE(shape1->paintedCount, 1);
// with this shape being clipped, the container will paint it for us.
QCOMPARE(shape2->paintedCount, 1);
QCOMPARE(container->paintedCount, 1);
}
void TestShapePainting::testPaintHiddenShape()
{
QScopedPointer<MockContainer> top(new MockContainer());
MockShape *shape = new MockShape();
MockContainer *fourth = new MockContainer();
MockContainer *thirth = new MockContainer();
MockContainer *second = new MockContainer();
top->addShape(second);
second->addShape(thirth);
thirth->addShape(fourth);
fourth->addShape(shape);
second->setVisible(false);
MockCanvas canvas;
KoShapeManager manager(&canvas);
manager.addShape(top.data());
QCOMPARE(manager.shapes().count(), 5);
QImage image(100, 100, QImage::Format_Mono);
QPainter painter(&image);
manager.paint(painter, false);
QCOMPARE(top->paintedCount, 1);
QCOMPARE(second->paintedCount, 0);
QCOMPARE(thirth->paintedCount, 0);
QCOMPARE(fourth->paintedCount, 0);
QCOMPARE(shape->paintedCount, 0);
}
void TestShapePainting::testPaintOrder()
{
// the stacking order determines the painting order so things on top
// get their paint called last.
// Each shape has a zIndex and within the children a container has
// it determines the stacking order. Its important to realize that
// the zIndex is thus local to a container, if you have layer1 and layer2
// with both various child shapes the stacking order of the layer shapes
// is most important, then within this the child shape index is used.
class OrderedMockShape : public MockShape {
public:
OrderedMockShape(QList<const MockShape*> *list) : order(list) {}
void paint(QPainter &painter, KoShapePaintingContext &paintcontext) const override {
order->append(this);
MockShape::paint(painter, paintcontext);
}
mutable QList<const MockShape*> *order;
};
QList<const MockShape*> order;
{
QScopedPointer<MockContainer> top(new MockContainer());
top->setZIndex(2);
OrderedMockShape *shape1 = new OrderedMockShape(&order);
shape1->setZIndex(5);
OrderedMockShape *shape2 = new OrderedMockShape(&order);
shape2->setZIndex(0);
top->addShape(shape1);
top->addShape(shape2);
QScopedPointer<MockContainer> bottom(new MockContainer());
bottom->setZIndex(1);
OrderedMockShape *shape3 = new OrderedMockShape(&order);
shape3->setZIndex(-1);
OrderedMockShape *shape4 = new OrderedMockShape(&order);
shape4->setZIndex(9);
bottom->addShape(shape3);
bottom->addShape(shape4);
MockCanvas canvas;
KoShapeManager manager(&canvas);
manager.addShape(top.data());
manager.addShape(bottom.data());
QCOMPARE(manager.shapes().count(), 6);
QImage image(100, 100, QImage::Format_Mono);
QPainter painter(&image);
manager.paint(painter, false);
QCOMPARE(top->paintedCount, 1);
QCOMPARE(bottom->paintedCount, 1);
QCOMPARE(shape1->paintedCount, 1);
QCOMPARE(shape2->paintedCount, 1);
QCOMPARE(shape3->paintedCount, 1);
QCOMPARE(shape4->paintedCount, 1);
QCOMPARE(order.count(), 4);
QVERIFY(order[0] == shape3); // lowest first
QVERIFY(order[1] == shape4);
QVERIFY(order[2] == shape2);
QVERIFY(order[3] == shape1);
// again, with clipping.
order.clear();
painter.setClipRect(0, 0, 100, 100);
manager.paint(painter, false);
QCOMPARE(top->paintedCount, 2);
QCOMPARE(bottom->paintedCount, 2);
QCOMPARE(shape1->paintedCount, 2);
QCOMPARE(shape2->paintedCount, 2);
QCOMPARE(shape3->paintedCount, 2);
QCOMPARE(shape4->paintedCount, 2);
QCOMPARE(order.count(), 4);
QVERIFY(order[0] == shape3); // lowest first
QVERIFY(order[1] == shape4);
QVERIFY(order[2] == shape2);
QVERIFY(order[3] == shape1);
}
order.clear();
{
QScopedPointer<MockContainer> root(new MockContainer());
root->setZIndex(0);
MockContainer *branch1 = new MockContainer();
branch1->setZIndex(1);
OrderedMockShape *child1_1 = new OrderedMockShape(&order);
child1_1->setZIndex(1);
OrderedMockShape *child1_2 = new OrderedMockShape(&order);
child1_2->setZIndex(2);
branch1->addShape(child1_1);
branch1->addShape(child1_2);
MockContainer *branch2 = new MockContainer();
branch2->setZIndex(2);
OrderedMockShape *child2_1 = new OrderedMockShape(&order);
child2_1->setZIndex(1);
OrderedMockShape *child2_2 = new OrderedMockShape(&order);
child2_2->setZIndex(2);
branch2->addShape(child2_1);
branch2->addShape(child2_2);
root->addShape(branch1);
root->addShape(branch2);
QList<KoShape*> sortedShapes;
sortedShapes.append(root.data());
sortedShapes.append(branch1);
sortedShapes.append(branch2);
sortedShapes.append(branch1->shapes());
sortedShapes.append(branch2->shapes());
std::sort(sortedShapes.begin(), sortedShapes.end(), KoShape::compareShapeZIndex);
QCOMPARE(sortedShapes.count(), 7);
QVERIFY(sortedShapes[0] == root.data());
QVERIFY(sortedShapes[1] == branch1);
QVERIFY(sortedShapes[2] == child1_1);
QVERIFY(sortedShapes[3] == child1_2);
QVERIFY(sortedShapes[4] == branch2);
QVERIFY(sortedShapes[5] == child2_1);
QVERIFY(sortedShapes[6] == child2_2);
}
}
#include <kundo2command.h>
#include <KoShapeController.h>
#include <KoShapeGroupCommand.h>
#include <KoShapeUngroupCommand.h>
#include "kis_debug.h"
void TestShapePainting::testGroupUngroup()
{
- QScopedPointer<MockContainer> shapesFakeLayer(new MockContainer);
+ MockShapeController controller;
+ MockCanvas canvas(&controller);
+
+ KoShapeManager *manager = canvas.shapeManager();
+
+ QScopedPointer<MockContainer> shapesFakeLayer(new MockContainer());
+ shapesFakeLayer->setAssociatedRootShapeManager(manager);
+
MockShape *shape1(new MockShape());
MockShape *shape2(new MockShape());
shape1->setName("shape1");
shape2->setName("shape2");
shape1->setParent(shapesFakeLayer.data());
shape2->setParent(shapesFakeLayer.data());
QList<KoShape*> groupedShapes = {shape1, shape2};
-
- MockShapeController controller;
- MockCanvas canvas(&controller);
- KoShapeManager *manager = canvas.shapeManager();
-
- controller.addShape(shape1);
- controller.addShape(shape2);
-
QImage image(100, 100, QImage::Format_Mono);
QPainter painter(&image);
painter.setClipRect(image.rect());
for (int i = 0; i < 3; i++) {
KoShapeGroup *group = new KoShapeGroup();
- group->setParent(shapesFakeLayer.data());
{
group->setName("group");
KUndo2Command groupingCommand;
- canvas.shapeController()->addShapeDirect(group, 0, &groupingCommand);
+ canvas.shapeController()->addShapeDirect(group, shapesFakeLayer.data(), &groupingCommand);
new KoShapeGroupCommand(group, groupedShapes, true, &groupingCommand);
groupingCommand.redo();
manager->paint(painter, false);
QCOMPARE(shape1->paintedCount, 2 * i + 1);
QCOMPARE(shape2->paintedCount, 2 * i + 1);
QCOMPARE(manager->shapes().size(), 3);
}
{
KUndo2Command ungroupingCommand;
new KoShapeUngroupCommand(group, group->shapes(), QList<KoShape*>(), &ungroupingCommand);
canvas.shapeController()->removeShape(group, &ungroupingCommand);
// NOTE: group will be deleted in ungroupingCommand's d-tor
ungroupingCommand.redo();
manager->paint(painter, false);
QCOMPARE(shape1->paintedCount, 2 * i + 2);
QCOMPARE(shape2->paintedCount, 2 * i + 2);
QCOMPARE(manager->shapes().size(), 2);
}
}
}
KISTEST_MAIN(TestShapePainting)
diff --git a/libs/flake/text/KoSvgTextChunkShape.cpp b/libs/flake/text/KoSvgTextChunkShape.cpp
index 8b760d2b2c..d96c8d6c01 100644
--- a/libs/flake/text/KoSvgTextChunkShape.cpp
+++ b/libs/flake/text/KoSvgTextChunkShape.cpp
@@ -1,983 +1,971 @@
/*
* Copyright (c) 2017 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
v * 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 "KoSvgTextChunkShape.h"
#include "KoSvgTextChunkShape_p.h"
#include "KoSvgText.h"
#include "KoSvgTextProperties.h"
#include "kis_debug.h"
#include <KoXmlReader.h>
#include <KoXmlWriter.h>
#include <KoXmlNS.h>
#include <SvgLoadingContext.h>
#include <SvgGraphicContext.h>
#include <SvgUtil.h>
#include <SimpleShapeContainerModel.h>
#include <SvgSavingContext.h>
#include <SvgStyleWriter.h>
#include <kis_dom_utils.h>
#include <text/KoSvgTextChunkShapeLayoutInterface.h>
#include <commands/KoShapeUngroupCommand.h>
#include <html/HtmlSavingContext.h>
#include <FlakeDebug.h>
namespace {
void appendLazy(QVector<qreal> *list, boost::optional<qreal> value, int iteration, bool hasDefault = true, qreal defaultValue = 0.0)
{
if (!value) return;
if (value && *value == defaultValue && hasDefault == true && list->isEmpty()) return;
while (list->size() < iteration) {
list->append(defaultValue);
}
list->append(*value);
}
void fillTransforms(QVector<qreal> *xPos, QVector<qreal> *yPos, QVector<qreal> *dxPos, QVector<qreal> *dyPos, QVector<qreal> *rotate,
QVector<KoSvgText::CharTransformation> localTransformations)
{
for (int i = 0; i < localTransformations.size(); i++) {
const KoSvgText::CharTransformation &t = localTransformations[i];
appendLazy(xPos, t.xPos, i, false);
appendLazy(yPos, t.yPos, i, false);
appendLazy(dxPos, t.dxPos, i);
appendLazy(dyPos, t.dyPos, i);
appendLazy(rotate, t.rotate, i);
}
}
QVector<qreal> parseListAttributeX(const QString &value, SvgLoadingContext &context)
{
QVector<qreal> result;
QStringList list = SvgUtil::simplifyList(value);
Q_FOREACH (const QString &str, list) {
result << SvgUtil::parseUnitX(context.currentGC(), str);
}
return result;
}
QVector<qreal> parseListAttributeY(const QString &value, SvgLoadingContext &context)
{
QVector<qreal> result;
QStringList list = SvgUtil::simplifyList(value);
Q_FOREACH (const QString &str, list) {
result << SvgUtil::parseUnitY(context.currentGC(), str);
}
return result;
}
QVector<qreal> parseListAttributeAngular(const QString &value, SvgLoadingContext &context)
{
QVector<qreal> result;
QStringList list = SvgUtil::simplifyList(value);
Q_FOREACH (const QString &str, list) {
result << SvgUtil::parseUnitAngular(context.currentGC(), str);
}
return result;
}
QString convertListAttribute(const QVector<qreal> &values) {
QStringList stringValues;
Q_FOREACH (qreal value, values) {
stringValues.append(KisDomUtils::toString(value));
}
return stringValues.join(',');
}
}
struct KoSvgTextChunkShape::Private::LayoutInterface : public KoSvgTextChunkShapeLayoutInterface
{
LayoutInterface(KoSvgTextChunkShape *_q) : q(_q) {}
KoSvgText::AutoValue textLength() const override {
return q->s->textLength;
}
KoSvgText::LengthAdjust lengthAdjust() const override {
return q->s->lengthAdjust;
}
int numChars() const override {
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!q->shapeCount() || q->s->text.isEmpty(), 0);
int result = 0;
if (!q->shapeCount()) {
result = q->s->text.size();
} else {
Q_FOREACH (KoShape *shape, q->shapes()) {
KoSvgTextChunkShape *chunkShape = dynamic_cast<KoSvgTextChunkShape*>(shape);
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(chunkShape, 0);
result += chunkShape->layoutInterface()->numChars();
}
}
return result;
}
int relativeCharPos(KoSvgTextChunkShape *child, int pos) const override {
QList<KoShape*> childShapes = q->shapes();
int result = -1;
int numCharsPassed = 0;
Q_FOREACH (KoShape *shape, q->shapes()) {
KoSvgTextChunkShape *chunkShape = dynamic_cast<KoSvgTextChunkShape*>(shape);
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(chunkShape, 0);
if (chunkShape == child) {
result = pos + numCharsPassed;
break;
} else {
numCharsPassed += chunkShape->layoutInterface()->numChars();
}
}
return result;
}
bool isTextNode() const override {
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!q->shapeCount() || q->s->text.isEmpty(), false);
return !q->shapeCount();
}
QString nodeText() const override {
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!q->shapeCount() || q->s->text.isEmpty(), 0);
return !q->shapeCount() ? q->s->text : QString();
}
QVector<KoSvgText::CharTransformation> localCharTransformations() const override {
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(isTextNode(), QVector<KoSvgText::CharTransformation>());
const QVector<KoSvgText::CharTransformation> t = q->s->localTransformations;
return t.mid(0, qMin(t.size(), q->s->text.size()));
}
static QString getBidiOpening(KoSvgText::Direction direction, KoSvgText::UnicodeBidi bidi) {
using namespace KoSvgText;
QString result;
if (bidi == BidiEmbed) {
result = direction == DirectionLeftToRight ? "\u202a" : "\u202b";
} else if (bidi == BidiOverride) {
result = direction == DirectionLeftToRight ? "\u202d" : "\u202e";
}
return result;
}
QVector<SubChunk> collectSubChunks() const override {
QVector<SubChunk> result;
if (isTextNode()) {
const QString text = q->s->text;
const KoSvgText::KoSvgCharChunkFormat format = q->fetchCharFormat();
QVector<KoSvgText::CharTransformation> transforms = q->s->localTransformations;
/**
* Sometimes SVG can contain the X,Y offsets for the pieces of text that
* do not exist, just skip them.
*/
if (text.size() <= transforms.size()) {
transforms.resize(text.size());
}
KoSvgText::UnicodeBidi bidi = KoSvgText::UnicodeBidi(q->s->properties.propertyOrDefault(KoSvgTextProperties::UnicodeBidiId).toInt());
KoSvgText::Direction direction = KoSvgText::Direction(q->s->properties.propertyOrDefault(KoSvgTextProperties::DirectionId).toInt());
const QString bidiOpening = getBidiOpening(direction, bidi);
if (!bidiOpening.isEmpty()) {
result << SubChunk(bidiOpening, format);
}
if (transforms.isEmpty()) {
result << SubChunk(text, format);
} else {
for (int i = 0; i < transforms.size(); i++) {
const KoSvgText::CharTransformation baseTransform = transforms[i];
int subChunkLength = 1;
for (int j = i + 1; j < transforms.size(); j++) {
if (transforms[j].isNull()) {
subChunkLength++;
} else {
break;
}
}
if (i + subChunkLength >= transforms.size()) {
subChunkLength = text.size() - i;
}
result << SubChunk(text.mid(i, subChunkLength), format, baseTransform);
i += subChunkLength - 1;
}
}
if (!bidiOpening.isEmpty()) {
result << SubChunk("\u202c", format);
}
} else {
Q_FOREACH (KoShape *shape, q->shapes()) {
KoSvgTextChunkShape *chunkShape = dynamic_cast<KoSvgTextChunkShape*>(shape);
KIS_SAFE_ASSERT_RECOVER_BREAK(chunkShape);
result += chunkShape->layoutInterface()->collectSubChunks();
}
}
return result;
}
void addAssociatedOutline(const QRectF &rect) override {
KIS_SAFE_ASSERT_RECOVER_RETURN(isTextNode());
QPainterPath path;
path.addRect(rect);
path |= q->s->associatedOutline;
path.setFillRule(Qt::WindingFill);
path = path.simplified();
q->s->associatedOutline = path;
q->setSize(path.boundingRect().size());
q->notifyChanged();
q->shapeChangedPriv(KoShape::SizeChanged);
}
void clearAssociatedOutline() override {
q->s->associatedOutline = QPainterPath();
q->setSize(QSizeF());
q->notifyChanged();
q->shapeChangedPriv(KoShape::SizeChanged);
}
private:
KoSvgTextChunkShape *q;
};
KoSvgTextChunkShape::KoSvgTextChunkShape()
: KoShapeContainer()
, d(new Private)
, s(new SharedData)
{
d->layoutInterface.reset(new KoSvgTextChunkShape::Private::LayoutInterface(this));
}
KoSvgTextChunkShape::KoSvgTextChunkShape(const KoSvgTextChunkShape &rhs)
: KoShapeContainer(rhs)
, d(new Private)
, s(rhs.s)
{
if (rhs.model()) {
SimpleShapeContainerModel *otherModel = dynamic_cast<SimpleShapeContainerModel*>(rhs.model());
KIS_ASSERT_RECOVER_RETURN(otherModel);
setModelInit(new SimpleShapeContainerModel(*otherModel));
}
d->layoutInterface.reset(new KoSvgTextChunkShape::Private::LayoutInterface(this));
}
KoSvgTextChunkShape::~KoSvgTextChunkShape()
{
}
KoShape *KoSvgTextChunkShape::cloneShape() const
{
return new KoSvgTextChunkShape(*this);
}
QSizeF KoSvgTextChunkShape::size() const
{
return outlineRect().size();
}
void KoSvgTextChunkShape::setSize(const QSizeF &size)
{
Q_UNUSED(size);
// we do not support resizing!
}
QRectF KoSvgTextChunkShape::outlineRect() const
{
return outline().boundingRect();
}
QPainterPath KoSvgTextChunkShape::outline() const
{
QPainterPath result;
result.setFillRule(Qt::WindingFill);
if (d->layoutInterface->isTextNode()) {
result = s->associatedOutline;
} else {
Q_FOREACH (KoShape *shape, shapes()) {
KoSvgTextChunkShape *chunkShape = dynamic_cast<KoSvgTextChunkShape*>(shape);
KIS_SAFE_ASSERT_RECOVER_BREAK(chunkShape);
result |= chunkShape->outline();
}
}
return result.simplified();
}
void KoSvgTextChunkShape::paintComponent(QPainter &painter, KoShapePaintingContext &paintContext) const
{
Q_UNUSED(painter);
Q_UNUSED(paintContext);
}
-void KoSvgTextChunkShape::saveOdf(KoShapeSavingContext &context) const
-{
- Q_UNUSED(context);
-}
-
-bool KoSvgTextChunkShape::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- Q_UNUSED(element);
- Q_UNUSED(context);
- return false;
-}
-
bool KoSvgTextChunkShape::saveHtml(HtmlSavingContext &context)
{
// Should we add a newline? Check for vertical movement if we're using rtl or ltr text
// XXX: if vertical text, check horizontal movement.
QVector<qreal> xPos;
QVector<qreal> yPos;
QVector<qreal> dxPos;
QVector<qreal> dyPos;
QVector<qreal> rotate;
fillTransforms(&xPos, &yPos, &dxPos, &dyPos, &rotate, s->localTransformations);
for (int i = 0; i < s->localTransformations.size(); i++) {
const KoSvgText::CharTransformation &t = s->localTransformations[i];
appendLazy(&xPos, t.xPos, i, false);
appendLazy(&yPos, t.yPos, i, false);
appendLazy(&dxPos, t.dxPos, i);
appendLazy(&dyPos, t.dyPos, i);
}
KoSvgTextChunkShape *parent = !isRootTextNode() ? dynamic_cast<KoSvgTextChunkShape*>(this->parent()) : 0;
KoSvgTextProperties parentProperties =
parent ? parent->textProperties() : KoSvgTextProperties::defaultProperties();
// XXX: we don't save fill, stroke, text length, length adjust or spacing and glyphs.
KoSvgTextProperties ownProperties = textProperties().ownProperties(parentProperties);
if (isRootTextNode()) {
context.shapeWriter().startElement("body", false);
if (layoutInterface()->isTextNode()) {
context.shapeWriter().startElement("p", false);
}
// XXX: Save the style?
} else if (parent && parent->isRootTextNode()) {
context.shapeWriter().startElement("p", false);
} else {
context.shapeWriter().startElement("span", false);
// XXX: Save the style?
}
QMap<QString, QString> attributes = ownProperties.convertToSvgTextAttributes();
if (attributes.size() > 0) {
QString styleString;
for (auto it = attributes.constBegin(); it != attributes.constEnd(); ++it) {
if (QString(it.key().toLatin1().data()).contains("text-anchor")) {
QString val = it.value();
if (it.value()=="middle") {
val = "center";
} else if (it.value()=="end") {
val = "right";
} else {
val = "left";
}
styleString.append("text-align")
.append(": ")
.append(val)
.append(";" );
} else if (QString(it.key().toLatin1().data()).contains("fill")){
styleString.append("color")
.append(": ")
.append(it.value())
.append(";" );
} else if (QString(it.key().toLatin1().data()).contains("font-size")){
QString val = it.value();
if (QRegExp ("\\d*").exactMatch(val)) {
val.append("pt");
}
styleString.append(it.key().toLatin1().data())
.append(": ")
.append(val)
.append(";" );
} else {
styleString.append(it.key().toLatin1().data())
.append(": ")
.append(it.value())
.append(";" );
}
}
context.shapeWriter().addAttribute("style", styleString);
}
if (layoutInterface()->isTextNode()) {
debugFlake << "saveHTML" << this << s->text << xPos << yPos << dxPos << dyPos;
// After adding all the styling to the <p> element, add the text
context.shapeWriter().addTextNode(s->text);
}
else {
Q_FOREACH (KoShape *child, this->shapes()) {
KoSvgTextChunkShape *childText = dynamic_cast<KoSvgTextChunkShape*>(child);
KIS_SAFE_ASSERT_RECOVER(childText) { continue; }
childText->saveHtml(context);
}
}
if (isRootTextNode() && layoutInterface()->isTextNode()) {
context.shapeWriter().endElement(); // body
}
context.shapeWriter().endElement(); // p or span
return true;
}
void writeTextListAttribute(const QString &attribute, const QVector<qreal> &values, KoXmlWriter &writer)
{
const QString value = convertListAttribute(values);
if (!value.isEmpty()) {
writer.addAttribute(attribute.toLatin1().data(), value);
}
}
bool KoSvgTextChunkShape::saveSvg(SvgSavingContext &context)
{
if (isRootTextNode()) {
context.shapeWriter().startElement("text", false);
if (!context.strippedTextMode()) {
context.shapeWriter().addAttribute("id", context.getID(this));
context.shapeWriter().addAttribute("krita:useRichText", s->isRichTextPreferred ? "true" : "false");
SvgUtil::writeTransformAttributeLazy("transform", transformation(), context.shapeWriter());
SvgStyleWriter::saveSvgStyle(this, context);
} else {
SvgStyleWriter::saveSvgFill(this, context);
SvgStyleWriter::saveSvgStroke(this, context);
}
} else {
context.shapeWriter().startElement("tspan", false);
if (!context.strippedTextMode()) {
SvgStyleWriter::saveSvgBasicStyle(this, context);
}
}
if (layoutInterface()->isTextNode()) {
QVector<qreal> xPos;
QVector<qreal> yPos;
QVector<qreal> dxPos;
QVector<qreal> dyPos;
QVector<qreal> rotate;
fillTransforms(&xPos, &yPos, &dxPos, &dyPos, &rotate, s->localTransformations);
writeTextListAttribute("x", xPos, context.shapeWriter());
writeTextListAttribute("y", yPos, context.shapeWriter());
writeTextListAttribute("dx", dxPos, context.shapeWriter());
writeTextListAttribute("dy", dyPos, context.shapeWriter());
writeTextListAttribute("rotate", rotate, context.shapeWriter());
}
if (!s->textLength.isAuto) {
context.shapeWriter().addAttribute("textLength", KisDomUtils::toString(s->textLength.customValue));
if (s->lengthAdjust == KoSvgText::LengthAdjustSpacingAndGlyphs) {
context.shapeWriter().addAttribute("lengthAdjust", "spacingAndGlyphs");
}
}
KoSvgTextChunkShape *parent = !isRootTextNode() ? dynamic_cast<KoSvgTextChunkShape*>(this->parent()) : 0;
KoSvgTextProperties parentProperties =
parent ? parent->textProperties() : KoSvgTextProperties::defaultProperties();
KoSvgTextProperties ownProperties = textProperties().ownProperties(parentProperties);
// we write down stroke/fill iff they are different from the parent's value
if (!isRootTextNode()) {
if (ownProperties.hasProperty(KoSvgTextProperties::FillId)) {
SvgStyleWriter::saveSvgFill(this, context);
}
if (ownProperties.hasProperty(KoSvgTextProperties::StrokeId)) {
SvgStyleWriter::saveSvgStroke(this, context);
}
}
QMap<QString, QString> attributes = ownProperties.convertToSvgTextAttributes();
for (auto it = attributes.constBegin(); it != attributes.constEnd(); ++it) {
context.shapeWriter().addAttribute(it.key().toLatin1().data(), it.value());
}
if (layoutInterface()->isTextNode()) {
context.shapeWriter().addTextNode(s->text);
} else {
Q_FOREACH (KoShape *child, this->shapes()) {
KoSvgTextChunkShape *childText = dynamic_cast<KoSvgTextChunkShape*>(child);
KIS_SAFE_ASSERT_RECOVER(childText) { continue; }
childText->saveSvg(context);
}
}
context.shapeWriter().endElement();
return true;
}
void KoSvgTextChunkShape::SharedData::loadContextBasedProperties(SvgGraphicsContext *gc)
{
properties = gc->textProperties;
font = gc->font;
fontFamiliesList = gc->fontFamiliesList;
}
void KoSvgTextChunkShape::resetTextShape()
{
using namespace KoSvgText;
s->properties = KoSvgTextProperties();
s->font = QFont();
s->fontFamiliesList = QStringList();
s->textLength = AutoValue();
s->lengthAdjust = LengthAdjustSpacing;
s->localTransformations.clear();
s->text.clear();
// all the subchunks are destroyed!
// (first detach, then destroy)
QList<KoShape*> shapesToReset = shapes();
Q_FOREACH (KoShape *shape, shapesToReset) {
shape->setParent(0);
delete shape;
}
}
bool KoSvgTextChunkShape::loadSvg(const KoXmlElement &e, SvgLoadingContext &context)
{
SvgGraphicsContext *gc = context.currentGC();
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(gc, false);
s->loadContextBasedProperties(gc);
s->textLength = KoSvgText::parseAutoValueXY(e.attribute("textLength", ""), context, "");
s->lengthAdjust = KoSvgText::parseLengthAdjust(e.attribute("lengthAdjust", "spacing"));
QVector<qreal> xPos = parseListAttributeX(e.attribute("x", ""), context);
QVector<qreal> yPos = parseListAttributeY(e.attribute("y", ""), context);
QVector<qreal> dxPos = parseListAttributeX(e.attribute("dx", ""), context);
QVector<qreal> dyPos = parseListAttributeY(e.attribute("dy", ""), context);
QVector<qreal> rotate = parseListAttributeAngular(e.attribute("rotate", ""), context);
const int numLocalTransformations =
std::max({xPos.size(), yPos.size(),
dxPos.size(), dyPos.size(),
rotate.size()});
s->localTransformations.resize(numLocalTransformations);
for (int i = 0; i < numLocalTransformations; i++) {
if (i < xPos.size()) {
s->localTransformations[i].xPos = xPos[i];
}
if (i < yPos.size()) {
s->localTransformations[i].yPos = yPos[i];
}
if (i < dxPos.size() && dxPos[i] != 0.0) {
s->localTransformations[i].dxPos = dxPos[i];
}
if (i < dyPos.size() && dyPos[i] != 0.0) {
s->localTransformations[i].dyPos = dyPos[i];
}
if (i < rotate.size()) {
s->localTransformations[i].rotate = rotate[i];
}
}
return true;
}
namespace {
QString cleanUpString(QString text) {
text.replace(QRegExp("[\\r\\n\u2028]"), "");
text.replace(QRegExp(" {2,}"), " ");
return text;
}
enum Result {
FoundNothing,
FoundText,
FoundSpace
};
Result hasPreviousSibling(KoXmlNode node)
{
while (!node.isNull()) {
if (node.isElement()) {
KoXmlElement element = node.toElement();
if (element.tagName() == "text") break;
}
while (!node.previousSibling().isNull()) {
node = node.previousSibling();
while (!node.lastChild().isNull()) {
node = node.lastChild();
}
if (node.isText()) {
KoXmlText textNode = node.toText();
const QString text = cleanUpString(textNode.data());
if (!text.isEmpty()) {
// if we are the leading whitespace, we should report that
// we are the last
if (text == " ") {
return hasPreviousSibling(node) == FoundNothing ? FoundNothing : FoundSpace;
}
return text[text.size() - 1] != ' ' ? FoundText : FoundSpace;
}
}
}
node = node.parentNode();
}
return FoundNothing;
}
Result hasNextSibling(KoXmlNode node)
{
while (!node.isNull()) {
while (!node.nextSibling().isNull()) {
node = node.nextSibling();
while (!node.firstChild().isNull()) {
node = node.firstChild();
}
if (node.isText()) {
KoXmlText textNode = node.toText();
const QString text = cleanUpString(textNode.data());
// if we are the trailing whitespace, we should report that
// we are the last
if (text == " ") {
return hasNextSibling(node) == FoundNothing ? FoundNothing : FoundSpace;
}
if (!text.isEmpty()) {
return text[0] != ' ' ? FoundText : FoundSpace;
}
}
}
node = node.parentNode();
}
return FoundNothing;
}
}
bool KoSvgTextChunkShape::loadSvgTextNode(const KoXmlText &text, SvgLoadingContext &context)
{
SvgGraphicsContext *gc = context.currentGC();
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(gc, false);
s->loadContextBasedProperties(gc);
QString data = cleanUpString(text.data());
const Result leftBorder = hasPreviousSibling(text);
const Result rightBorder = hasNextSibling(text);
if (data.startsWith(' ') && leftBorder == FoundNothing) {
data.remove(0, 1);
}
if (data.endsWith(' ') && rightBorder != FoundText) {
data.remove(data.size() - 1, 1);
}
if (data == " " && (leftBorder == FoundNothing || rightBorder == FoundNothing)) {
data = "";
}
//ENTER_FUNCTION() << text.data() << "-->" << data;
s->text = data;
return !data.isEmpty();
}
void KoSvgTextChunkShape::normalizeCharTransformations()
{
applyParentCharTransformations(s->localTransformations);
}
void KoSvgTextChunkShape::simplifyFillStrokeInheritance()
{
if (!isRootTextNode()) {
KoShape *parentShape = parent();
KIS_SAFE_ASSERT_RECOVER_RETURN(parentShape);
QSharedPointer<KoShapeBackground> bg = background();
QSharedPointer<KoShapeBackground> parentBg = parentShape->background();
if (!inheritBackground() &&
((!bg && !parentBg) ||
(bg && parentBg &&
bg->compareTo(parentShape->background().data())))) {
setInheritBackground(true);
}
KoShapeStrokeModelSP stroke = this->stroke();
KoShapeStrokeModelSP parentStroke= parentShape->stroke();
if (!inheritStroke() &&
((!stroke && !parentStroke) ||
(stroke && parentStroke &&
stroke->compareFillTo(parentShape->stroke().data()) &&
stroke->compareStyleTo(parentShape->stroke().data())))) {
setInheritStroke(true);
}
}
Q_FOREACH (KoShape *shape, shapes()) {
KoSvgTextChunkShape *chunkShape = dynamic_cast<KoSvgTextChunkShape*>(shape);
KIS_SAFE_ASSERT_RECOVER_RETURN(chunkShape);
chunkShape->simplifyFillStrokeInheritance();
}
}
KoSvgTextProperties KoSvgTextChunkShape::textProperties() const
{
KoSvgTextProperties properties = s->properties;
properties.setProperty(KoSvgTextProperties::FillId, QVariant::fromValue(KoSvgText::BackgroundProperty(background())));
properties.setProperty(KoSvgTextProperties::StrokeId, QVariant::fromValue(KoSvgText::StrokeProperty(stroke())));
return properties;
}
bool KoSvgTextChunkShape::isTextNode() const
{
return d->layoutInterface->isTextNode();
}
KoSvgTextChunkShapeLayoutInterface *KoSvgTextChunkShape::layoutInterface() const
{
return d->layoutInterface.data();
}
bool KoSvgTextChunkShape::isRichTextPreferred() const
{
return isRootTextNode() && s->isRichTextPreferred;
}
void KoSvgTextChunkShape::setRichTextPreferred(bool value)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(isRootTextNode());
s->isRichTextPreferred = value;
}
bool KoSvgTextChunkShape::isRootTextNode() const
{
return false;
}
/**************************************************************************************************/
/* KoSvgTextChunkShape::Private */
/**************************************************************************************************/
KoSvgTextChunkShape::SharedData::SharedData()
: QSharedData()
{
}
KoSvgTextChunkShape::SharedData::SharedData(const SharedData &rhs)
: QSharedData()
, properties(rhs.properties)
, font(rhs.font)
, fontFamiliesList(rhs.fontFamiliesList)
, localTransformations(rhs.localTransformations)
, textLength(rhs.textLength)
, lengthAdjust(rhs.lengthAdjust)
, text(rhs.text)
, isRichTextPreferred(rhs.isRichTextPreferred)
{
}
KoSvgTextChunkShape::SharedData::~SharedData()
{
}
#include <QBrush>
#include <KoColorBackground.h>
#include <KoShapeStroke.h>
KoSvgText::KoSvgCharChunkFormat KoSvgTextChunkShape::fetchCharFormat() const
{
KoSvgText::KoSvgCharChunkFormat format;
format.setFont(s->font);
format.setTextAnchor(KoSvgText::TextAnchor(s->properties.propertyOrDefault(KoSvgTextProperties::TextAnchorId).toInt()));
KoSvgText::Direction direction =
KoSvgText::Direction(s->properties.propertyOrDefault(KoSvgTextProperties::DirectionId).toInt());
format.setLayoutDirection(direction == KoSvgText::DirectionLeftToRight ? Qt::LeftToRight : Qt::RightToLeft);
KoSvgText::BaselineShiftMode shiftMode =
KoSvgText::BaselineShiftMode(s->properties.propertyOrDefault(KoSvgTextProperties::BaselineShiftModeId).toInt());
// FIXME: we support only 'none', 'sub' and 'super' shifts at the moment.
// Please implement 'percentage' as well!
// WARNING!!! Qt's setVerticalAlignment() also changes the size of the font! And SVG does not(!) imply it!
if (shiftMode == KoSvgText::ShiftSub) {
format.setVerticalAlignment(QTextCharFormat::AlignSubScript);
} else if (shiftMode == KoSvgText::ShiftSuper) {
format.setVerticalAlignment(QTextCharFormat::AlignSuperScript);
}
KoSvgText::AutoValue letterSpacing = s->properties.propertyOrDefault(KoSvgTextProperties::LetterSpacingId).value<KoSvgText::AutoValue>();
if (!letterSpacing.isAuto) {
format.setFontLetterSpacingType(QFont::AbsoluteSpacing);
format.setFontLetterSpacing(letterSpacing.customValue);
}
KoSvgText::AutoValue wordSpacing = s->properties.propertyOrDefault(KoSvgTextProperties::WordSpacingId).value<KoSvgText::AutoValue>();
if (!wordSpacing.isAuto) {
format.setFontWordSpacing(wordSpacing.customValue);
}
KoSvgText::AutoValue kerning = s->properties.propertyOrDefault(KoSvgTextProperties::KerningId).value<KoSvgText::AutoValue>();
if (!kerning.isAuto) {
format.setFontKerning(false);
format.setFontLetterSpacingType(QFont::AbsoluteSpacing);
format.setFontLetterSpacing(format.fontLetterSpacing() + kerning.customValue);
}
QBrush textBrush = Qt::NoBrush;
if (background()) {
KoColorBackground *colorBackground = dynamic_cast<KoColorBackground*>(background().data());
if (!colorBackground) {
qWarning() << "TODO: support gradient and pattern backgrounds for text";
textBrush = Qt::red;
}
if (colorBackground) {
textBrush = colorBackground->brush();
}
}
format.setForeground(textBrush);
QPen textPen = Qt::NoPen;
if (stroke()) {
KoShapeStroke *stroke = dynamic_cast<KoShapeStroke*>(this->stroke().data());
if (stroke) {
textPen = stroke->resultLinePen();
}
}
format.setTextOutline(textPen);
// TODO: avoid const_cast somehow...
format.setAssociatedShape(const_cast<KoSvgTextChunkShape*>(this));
return format;
}
void KoSvgTextChunkShape::applyParentCharTransformations(const QVector<KoSvgText::CharTransformation> transformations)
{
if (shapeCount()) {
int numCharsPassed = 0;
Q_FOREACH (KoShape *shape, shapes()) {
KoSvgTextChunkShape *chunkShape = dynamic_cast<KoSvgTextChunkShape*>(shape);
KIS_SAFE_ASSERT_RECOVER_RETURN(chunkShape);
const int numCharsInSubtree = chunkShape->layoutInterface()->numChars();
QVector<KoSvgText::CharTransformation> t = transformations.mid(numCharsPassed, numCharsInSubtree);
if (t.isEmpty()) break;
chunkShape->applyParentCharTransformations(t);
numCharsPassed += numCharsInSubtree;
if (numCharsPassed >= transformations.size()) break;
}
} else {
for (int i = 0; i < qMin(transformations.size(), s->text.size()); i++) {
KIS_SAFE_ASSERT_RECOVER_RETURN(s->localTransformations.size() >= i);
if (s->localTransformations.size() == i) {
s->localTransformations.append(transformations[i]);
} else {
s->localTransformations[i].mergeInParentTransformation(transformations[i]);
}
}
}
}
diff --git a/libs/flake/text/KoSvgTextChunkShape.h b/libs/flake/text/KoSvgTextChunkShape.h
index 87f4dbb1d0..ff89beff55 100644
--- a/libs/flake/text/KoSvgTextChunkShape.h
+++ b/libs/flake/text/KoSvgTextChunkShape.h
@@ -1,184 +1,182 @@
/*
* Copyright (c) 2017 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KOSVGTEXTCHUNKSHAPE_H
#define KOSVGTEXTCHUNKSHAPE_H
#include "kritaflake_export.h"
#include <KoShapeContainer.h>
#include <SvgShape.h>
#include <KoSvgText.h>
class HtmlSavingContext;
class KoSvgTextProperties;
class KoSvgTextChunkShapePrivate;
class KoSvgTextChunkShapeLayoutInterface;
/**
* KoSvgTextChunkShape is an elementary block of SVG text object.
*
* KoSvgTextChunkShape represents either a \<tspan\> or \<text\> element of SVG.
* The chunk shape uses flake hierarchy to represent the DOM hierarchy of the
* supplied text. All the attributes of text blocks can be fetched using
* textProperties() method.
*
* KoSvgTextChunkShape uses special text properties object to overcome the
* flake's "property inheritance" limitation. Basically, flake doesn't support
* the inheritance of shape properties: every shape stores all the properties
* that were defined at the stage of loading/creation. KoSvgTextProperties is a
* wrapper that allows the user to compare the properties of the two shapes and
* return only the ones that are unique for a child shape. That allows us to
* generate a correct SVG/markup code that can be edited by the user easily.
*
* WARNING: beware the difference between "svg-text-chunk" and
* KoSvgTextChunkShape! The chunk shape is **not** a "text chunk" in SVG's
* definition. According to SVG, "text chunk" is a set of characters anchored to
* a specific absolute position on canvas. And KoSvgTextChunkShape is just one
* \<tspan\> or \<text\> element. Obviously, one \<tspan\> can contain multiple "text
* chunks" and, vice versa, a "text chunk" can spread onto multiple \<span\>'s.
*/
class KRITAFLAKE_EXPORT KoSvgTextChunkShape : public KoShapeContainer, public SvgShape
{
public:
KoSvgTextChunkShape();
KoSvgTextChunkShape(const KoSvgTextChunkShape &rhs);
~KoSvgTextChunkShape() override;
KoShape* cloneShape() const override;
QSizeF size() const override;
void setSize(const QSizeF &size) override;
QRectF outlineRect() const override;
QPainterPath outline() const override;
void paintComponent(QPainter &painter, KoShapePaintingContext &paintContext) const override;
- void saveOdf(KoShapeSavingContext &Context) const override;
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &Context) override;
bool saveHtml(HtmlSavingContext &context);
/**
* Reset the text shape into initial state, removing all the child shapes.
* This method is used by text-updating code to upload the updated text
* into shape. The uploading code first calls resetTextShape() and then adds
* new children.
*/
virtual void resetTextShape();
bool saveSvg(SvgSavingContext &context) override;
bool loadSvg(const KoXmlElement &element, SvgLoadingContext &context) override;
bool loadSvgTextNode(const KoXmlText &text, SvgLoadingContext &context);
/**
* Normalize the SVG character transformations
*
* In SVG x,y,dx,dy,rotate attributes are inherited from the parent shapes
* in a curious ways. We do not want to unwind the links on the fly, so we
* just parse and adjust them right when the loading completed. After
* normalizeCharTransformations() is finished, all the child shapes will
* have local transformations set according to the parent's lists.
*/
void normalizeCharTransformations();
/**
* Compress the inheritance of 'fill' and 'stroke'.
*
* The loading code makes no difference if the fill or stroke was inherited
* or not. That is not a problem for normal shapes, but it cannot work for
* text shapes. The text has different inheritance rules: if the parent
* text chunk has a gradient fill, its inheriting descendants will
* **smoothly continue** this gradient. They will not start a new gradient
* in their local coordinate system.
*
* Therefore, after loading, the loading code calls
* simplifyFillStrokeInheritance() which marks the coinciding strokes and
* fills so that the rendering code will be able to distinguish them in the
* future.
*
* Proper fill inheritance is also needed for the GUI. When the user
* changes the color of the parent text chunk, all the inheriting children
* should update its color automatically, without GUI recursively
* traversing the shapes.
*
*/
void simplifyFillStrokeInheritance();
/**
* SVG properties of the text chunk
* @return the properties object with fill and stroke included as a property
*/
KoSvgTextProperties textProperties() const;
/**
* Return the type of the chunk.
*
* The chunk can be either a "text chunk", that contains a text string
* itself, of an "intermediate chunk" that doesn't contain any text itself,
* but works as a group for a set of child chunks, which might be either
* text (leaf) or intermediate chunks. Such groups are needed to define a
* common text style for a group of '\<tspan\>' objects.
*
* @return true if the chunk is a "text chunk" false if it is "intermediate chunk"
*/
bool isTextNode() const;
/**
* A special interface for KoSvgTextShape's layout code. Don't use it
* unless you are KoSvgTextShape.
*/
KoSvgTextChunkShapeLayoutInterface* layoutInterface() const;
/**
* WARNING: this propperty is available only if isRootTextNode() is true
*
* @return true if the shape should be edited in a rich-text editor
*/
bool isRichTextPreferred() const;
/**
* WARNING: this propperty is available only if isRootTextNode() is true
*
* Sets whether the shape should be edited in rich-text editor
*/
void setRichTextPreferred(bool value);
protected:
/**
* Show if the shape is a root of the text hierarchy. Always true for
* KoSvgTextShape and always false for KoSvgTextChunkShape
*/
virtual bool isRootTextNode() const;
protected:
KoSvgTextChunkShape(KoSvgTextChunkShapePrivate *dd);
private:
KoSvgText::KoSvgCharChunkFormat fetchCharFormat() const;
void applyParentCharTransformations(const QVector<KoSvgText::CharTransformation> transformations);
private:
class Private;
QScopedPointer<Private> d;
class SharedData;
QSharedDataPointer<SharedData> s;
};
#endif // KOSVGTEXTCHUNKSHAPE_H
diff --git a/libs/flake/text/KoSvgTextShape.cpp b/libs/flake/text/KoSvgTextShape.cpp
index ab3baf8219..cdda1199ac 100644
--- a/libs/flake/text/KoSvgTextShape.cpp
+++ b/libs/flake/text/KoSvgTextShape.cpp
@@ -1,642 +1,641 @@
/*
* Copyright (c) 2017 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "KoSvgTextShape.h"
#include <QTextLayout>
#include <klocalizedstring.h>
#include "KoSvgText.h"
#include "KoSvgTextProperties.h"
#include <KoShapeContainer_p.h>
#include <text/KoSvgTextChunkShape_p.h>
#include <text/KoSvgTextShapeMarkupConverter.h>
#include <KoDocumentResourceManager.h>
#include <KoShapeController.h>
#include "kis_debug.h"
#include <KoXmlReader.h>
#include <KoXmlNS.h>
#include <KoShapeLoadingContext.h>
-#include <KoOdfLoadingContext.h>
#include <KoIcon.h>
#include <KoProperties.h>
#include <KoColorBackground.h>
#include <SvgLoadingContext.h>
#include <SvgGraphicContext.h>
#include <SvgUtil.h>
#include <QApplication>
#include <QThread>
#include <vector>
#include <memory>
#include <QPainter>
#include <QPainterPath>
#include <boost/optional.hpp>
#include <text/KoSvgTextChunkShapeLayoutInterface.h>
#include <FlakeDebug.h>
#include <QSharedData>
class KoSvgTextShape::Private
{
public:
// NOTE: the cache data is shared between all the instances of
// the shape, though it will be reset locally if the
// accessing thread changes
std::vector<std::shared_ptr<QTextLayout>> cachedLayouts;
std::vector<QPointF> cachedLayoutsOffsets;
QThread *cachedLayoutsWorkingThread = 0;
void clearAssociatedOutlines(const KoShape *rootShape);
};
KoSvgTextShape::KoSvgTextShape()
: KoSvgTextChunkShape()
, d(new Private)
{
setShapeId(KoSvgTextShape_SHAPEID);
}
KoSvgTextShape::KoSvgTextShape(const KoSvgTextShape &rhs)
: KoSvgTextChunkShape(rhs)
, d(new Private)
{
setShapeId(KoSvgTextShape_SHAPEID);
// QTextLayout has no copy-ctor, so just relayout everything!
relayout();
}
KoSvgTextShape::~KoSvgTextShape()
{
}
KoShape *KoSvgTextShape::cloneShape() const
{
return new KoSvgTextShape(*this);
}
void KoSvgTextShape::shapeChanged(ChangeType type, KoShape *shape)
{
KoSvgTextChunkShape::shapeChanged(type, shape);
if (type == StrokeChanged || type == BackgroundChanged || type == ContentChanged) {
relayout();
}
}
void KoSvgTextShape::paintComponent(QPainter &painter, KoShapePaintingContext &paintContext) const
{
Q_UNUSED(paintContext);
/**
* HACK ALERT:
* QTextLayout should only be accessed from the thread it has been created in.
* If the cached layout has been created in a different thread, we should just
* recreate the layouts in the current thread to be able to render them.
*/
if (QThread::currentThread() != d->cachedLayoutsWorkingThread) {
relayout();
}
for (int i = 0; i < (int)d->cachedLayouts.size(); i++) {
d->cachedLayouts[i]->draw(&painter, d->cachedLayoutsOffsets[i]);
}
/**
* HACK ALERT:
* The layouts of non-gui threads must be destroyed in the same thread
* they have been created. Because the thread might be restarted in the
* meantime or just destroyed, meaning that the per-thread freetype data
* will not be available.
*/
if (QThread::currentThread() != qApp->thread()) {
d->cachedLayouts.clear();
d->cachedLayoutsOffsets.clear();
d->cachedLayoutsWorkingThread = 0;
}
}
void KoSvgTextShape::paintStroke(QPainter &painter, KoShapePaintingContext &paintContext) const
{
Q_UNUSED(painter);
Q_UNUSED(paintContext);
// do nothing! everything is painted in paintComponent()
}
QPainterPath KoSvgTextShape::textOutline()
{
QPainterPath result;
result.setFillRule(Qt::WindingFill);
for (int i = 0; i < (int)d->cachedLayouts.size(); i++) {
const QPointF layoutOffset = d->cachedLayoutsOffsets[i];
const QTextLayout *layout = d->cachedLayouts[i].get();
for (int j = 0; j < layout->lineCount(); j++) {
QTextLine line = layout->lineAt(j);
Q_FOREACH (const QGlyphRun &run, line.glyphRuns()) {
const QVector<quint32> indexes = run.glyphIndexes();
const QVector<QPointF> positions = run.positions();
const QRawFont font = run.rawFont();
KIS_SAFE_ASSERT_RECOVER(indexes.size() == positions.size()) { continue; }
for (int k = 0; k < indexes.size(); k++) {
QPainterPath glyph = font.pathForGlyph(indexes[k]);
glyph.translate(positions[k] + layoutOffset);
result += glyph;
}
const qreal thickness = font.lineThickness();
const QRectF runBounds = run.boundingRect();
if (run.overline()) {
// the offset is calculated to be consistent with the way how Qt renders the text
const qreal y = line.y();
QRectF overlineBlob(runBounds.x(), y, runBounds.width(), thickness);
overlineBlob.translate(layoutOffset);
QPainterPath path;
path.addRect(overlineBlob);
// don't use direct addRect, because it doesn't care about Qt::WindingFill
result += path;
}
if (run.strikeOut()) {
// the offset is calculated to be consistent with the way how Qt renders the text
const qreal y = line.y() + 0.5 * line.height();
QRectF strikeThroughBlob(runBounds.x(), y, runBounds.width(), thickness);
strikeThroughBlob.translate(layoutOffset);
QPainterPath path;
path.addRect(strikeThroughBlob);
// don't use direct addRect, because it doesn't care about Qt::WindingFill
result += path;
}
if (run.underline()) {
const qreal y = line.y() + line.ascent() + font.underlinePosition();
QRectF underlineBlob(runBounds.x(), y, runBounds.width(), thickness);
underlineBlob.translate(layoutOffset);
QPainterPath path;
path.addRect(underlineBlob);
// don't use direct addRect, because it doesn't care about Qt::WindingFill
result += path;
}
}
}
}
return result;
}
void KoSvgTextShape::resetTextShape()
{
KoSvgTextChunkShape::resetTextShape();
relayout();
}
struct TextChunk {
QString text;
QVector<QTextLayout::FormatRange> formats;
Qt::LayoutDirection direction = Qt::LeftToRight;
Qt::Alignment alignment = Qt::AlignLeading;
struct SubChunkOffset {
QPointF offset;
int start = 0;
};
QVector<SubChunkOffset> offsets;
boost::optional<qreal> xStartPos;
boost::optional<qreal> yStartPos;
QPointF applyStartPosOverride(const QPointF &pos) const {
QPointF result = pos;
if (xStartPos) {
result.rx() = *xStartPos;
}
if (yStartPos) {
result.ry() = *yStartPos;
}
return result;
}
};
QVector<TextChunk> mergeIntoChunks(const QVector<KoSvgTextChunkShapeLayoutInterface::SubChunk> &subChunks)
{
QVector<TextChunk> chunks;
for (auto it = subChunks.begin(); it != subChunks.end(); ++it) {
if (it->transformation.startsNewChunk() || it == subChunks.begin()) {
TextChunk newChunk = TextChunk();
newChunk.direction = it->format.layoutDirection();
newChunk.alignment = it->format.calculateAlignment();
newChunk.xStartPos = it->transformation.xPos;
newChunk.yStartPos = it->transformation.yPos;
chunks.append(newChunk);
}
TextChunk &currentChunk = chunks.last();
if (it->transformation.hasRelativeOffset()) {
TextChunk::SubChunkOffset o;
o.start = currentChunk.text.size();
o.offset = it->transformation.relativeOffset();
KIS_SAFE_ASSERT_RECOVER_NOOP(!o.offset.isNull());
currentChunk.offsets.append(o);
}
QTextLayout::FormatRange formatRange;
formatRange.start = currentChunk.text.size();
formatRange.length = it->text.size();
formatRange.format = it->format;
currentChunk.formats.append(formatRange);
currentChunk.text += it->text;
}
return chunks;
}
/**
* Qt's QTextLayout has a weird trait, it doesn't count space characters as
* distinct characters in QTextLayout::setNumColumns(), that is, if we want to
* position a block of text that starts with a space character in a specific
* position, QTextLayout will drop this space and will move the text to the left.
*
* That is why we have a special wrapper object that ensures that no spaces are
* dropped and their horizontal advance parameter is taken into account.
*/
struct LayoutChunkWrapper
{
LayoutChunkWrapper(QTextLayout *layout)
: m_layout(layout)
{
}
QPointF addTextChunk(int startPos, int length, const QPointF &textChunkStartPos)
{
QPointF currentTextPos = textChunkStartPos;
const int lastPos = startPos + length - 1;
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(startPos == m_addedChars, currentTextPos);
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(lastPos < m_layout->text().size(), currentTextPos);
// qDebug() << m_layout->text();
QTextLine line;
std::swap(line, m_danglingLine);
if (!line.isValid()) {
line = m_layout->createLine();
}
// skip all the space characters that were not included into the Qt's text line
const int currentLineStart = line.isValid() ? line.textStart() : startPos + length;
while (startPos < currentLineStart && startPos <= lastPos) {
currentTextPos.rx() += skipSpaceCharacter(startPos);
startPos++;
}
if (startPos <= lastPos) {
// defines the number of columns to look for glyphs
const int numChars = lastPos - startPos + 1;
// Tabs break the normal column flow
// grow to avoid missing glyphs
int charOffset = 0;
int noChangeCount = 0;
while (line.textLength() < numChars) {
int tl = line.textLength();
line.setNumColumns(numChars + charOffset);
if (tl == line.textLength()) {
noChangeCount++;
// 5 columns max are needed to discover tab char. Set to 10 to be safe.
if (noChangeCount > 10) break;
} else {
noChangeCount = 0;
}
charOffset++;
}
line.setPosition(currentTextPos - QPointF(0, line.ascent()));
currentTextPos.rx() += line.horizontalAdvance();
// skip all the space characters that were not included into the Qt's text line
for (int i = line.textStart() + line.textLength(); i < lastPos; i++) {
currentTextPos.rx() += skipSpaceCharacter(i);
}
} else {
// keep the created but unused line for future use
std::swap(line, m_danglingLine);
}
m_addedChars += length;
return currentTextPos;
}
private:
qreal skipSpaceCharacter(int pos) {
const QTextCharFormat format =
formatForPos(pos, m_layout->formats());
const QChar skippedChar = m_layout->text()[pos];
KIS_SAFE_ASSERT_RECOVER_NOOP(skippedChar.isSpace() || !skippedChar.isPrint());
QFontMetrics metrics(format.font());
#if QT_VERSION >= QT_VERSION_CHECK(5,11,0)
return metrics.horizontalAdvance(skippedChar);
#else
return metrics.width(skippedChar);
#endif
}
static QTextCharFormat formatForPos(int pos, const QVector<QTextLayout::FormatRange> &formats)
{
Q_FOREACH (const QTextLayout::FormatRange &range, formats) {
if (pos >= range.start && pos < range.start + range.length) {
return range.format;
}
}
KIS_SAFE_ASSERT_RECOVER_NOOP(0 && "pos should be within the bounds of the layouted text");
return QTextCharFormat();
}
private:
int m_addedChars = 0;
QTextLayout *m_layout;
QTextLine m_danglingLine;
};
void KoSvgTextShape::relayout() const
{
d->cachedLayouts.clear();
d->cachedLayoutsOffsets.clear();
d->cachedLayoutsWorkingThread = QThread::currentThread();
QPointF currentTextPos;
QVector<TextChunk> textChunks = mergeIntoChunks(layoutInterface()->collectSubChunks());
Q_FOREACH (const TextChunk &chunk, textChunks) {
std::shared_ptr<QTextLayout> layout(new QTextLayout());
QTextOption option;
// WARNING: never activate this option! It breaks the RTL text layout!
//option.setFlags(QTextOption::ShowTabsAndSpaces);
option.setWrapMode(QTextOption::WrapAnywhere);
option.setUseDesignMetrics(true); // TODO: investigate if it is needed?
option.setTextDirection(chunk.direction);
layout->setText(chunk.text);
layout->setTextOption(option);
layout->setFormats(chunk.formats);
layout->setCacheEnabled(true);
layout->beginLayout();
currentTextPos = chunk.applyStartPosOverride(currentTextPos);
const QPointF anchorPointPos = currentTextPos;
int lastSubChunkStart = 0;
QPointF lastSubChunkOffset;
LayoutChunkWrapper wrapper(layout.get());
for (int i = 0; i <= chunk.offsets.size(); i++) {
const bool isFinalPass = i == chunk.offsets.size();
const int length =
!isFinalPass ?
chunk.offsets[i].start - lastSubChunkStart :
chunk.text.size() - lastSubChunkStart;
if (length > 0) {
currentTextPos += lastSubChunkOffset;
currentTextPos = wrapper.addTextChunk(lastSubChunkStart,
length,
currentTextPos);
}
if (!isFinalPass) {
lastSubChunkOffset = chunk.offsets[i].offset;
lastSubChunkStart = chunk.offsets[i].start;
}
}
layout->endLayout();
QPointF diff;
if (chunk.alignment & Qt::AlignTrailing || chunk.alignment & Qt::AlignHCenter) {
if (chunk.alignment & Qt::AlignTrailing) {
diff = currentTextPos - anchorPointPos;
} else if (chunk.alignment & Qt::AlignHCenter) {
diff = 0.5 * (currentTextPos - anchorPointPos);
}
// TODO: fix after t2b text implemented
diff.ry() = 0;
}
d->cachedLayouts.push_back(layout);
d->cachedLayoutsOffsets.push_back(-diff);
}
d->clearAssociatedOutlines(this);
for (int i = 0; i < int(d->cachedLayouts.size()); i++) {
const QTextLayout &layout = *d->cachedLayouts[i];
const QPointF layoutOffset = d->cachedLayoutsOffsets[i];
using namespace KoSvgText;
Q_FOREACH (const QTextLayout::FormatRange &range, layout.formats()) {
const KoSvgCharChunkFormat &format =
static_cast<const KoSvgCharChunkFormat&>(range.format);
AssociatedShapeWrapper wrapper = format.associatedShapeWrapper();
const int rangeStart = range.start;
const int safeRangeLength = range.length > 0 ? range.length : layout.text().size() - rangeStart;
if (safeRangeLength <= 0) continue;
const int rangeEnd = range.start + safeRangeLength - 1;
const int firstLineIndex = layout.lineForTextPosition(rangeStart).lineNumber();
const int lastLineIndex = layout.lineForTextPosition(rangeEnd).lineNumber();
for (int i = firstLineIndex; i <= lastLineIndex; i++) {
const QTextLine line = layout.lineAt(i);
// It might happen that the range contains only one (or two)
// symbol that is a whitespace symbol. In such a case we should
// just skip this (invalid) line.
if (!line.isValid()) continue;
const int posStart = qMax(line.textStart(), rangeStart);
const int posEnd = qMin(line.textStart() + line.textLength() - 1, rangeEnd);
const QList<QGlyphRun> glyphRuns = line.glyphRuns(posStart, posEnd - posStart + 1);
Q_FOREACH (const QGlyphRun &run, glyphRuns) {
const QPointF firstPosition = run.positions().first();
const quint32 firstGlyphIndex = run.glyphIndexes().first();
const QPointF lastPosition = run.positions().last();
const quint32 lastGlyphIndex = run.glyphIndexes().last();
const QRawFont rawFont = run.rawFont();
const QRectF firstGlyphRect = rawFont.boundingRect(firstGlyphIndex).translated(firstPosition);
const QRectF lastGlyphRect = rawFont.boundingRect(lastGlyphIndex).translated(lastPosition);
QRectF rect = run.boundingRect();
/**
* HACK ALERT: there is a bug in a way how Qt calculates boundingRect()
* of the glyph run. It doesn't care about left and right bearings
* of the border chars in the run, therefore it becomes cropped.
*
* Here we just add a half-char width margin to both sides
* of the glyph run to make sure the glyphs are fully painted.
*
* BUG: 389528
* BUG: 392068
*/
rect.setLeft(qMin(rect.left(), lastGlyphRect.left()) - 0.5 * firstGlyphRect.width());
rect.setRight(qMax(rect.right(), lastGlyphRect.right()) + 0.5 * lastGlyphRect.width());
wrapper.addCharacterRect(rect.translated(layoutOffset));
}
}
}
}
}
void KoSvgTextShape::Private::clearAssociatedOutlines(const KoShape *rootShape)
{
const KoSvgTextChunkShape *chunkShape = dynamic_cast<const KoSvgTextChunkShape*>(rootShape);
KIS_SAFE_ASSERT_RECOVER_RETURN(chunkShape);
chunkShape->layoutInterface()->clearAssociatedOutline();
Q_FOREACH (KoShape *child, chunkShape->shapes()) {
clearAssociatedOutlines(child);
}
}
bool KoSvgTextShape::isRootTextNode() const
{
return true;
}
KoSvgTextShapeFactory::KoSvgTextShapeFactory()
: KoShapeFactoryBase(KoSvgTextShape_SHAPEID, i18n("Text"))
{
setToolTip(i18n("SVG Text Shape"));
setIconName(koIconNameCStr("x-shape-text"));
setLoadingPriority(5);
setXmlElementNames(KoXmlNS::svg, QStringList("text"));
KoShapeTemplate t;
t.name = i18n("SVG Text");
t.iconName = koIconName("x-shape-text");
t.toolTip = i18n("SVG Text Shape");
addTemplate(t);
}
KoShape *KoSvgTextShapeFactory::createDefaultShape(KoDocumentResourceManager *documentResources) const
{
debugFlake << "Create default svg text shape";
KoSvgTextShape *shape = new KoSvgTextShape();
shape->setShapeId(KoSvgTextShape_SHAPEID);
KoSvgTextShapeMarkupConverter converter(shape);
converter.convertFromSvg(i18nc("Default text for the text shape", "<text>Placeholder Text</text>"),
"<defs/>",
QRectF(0, 0, 200, 60),
documentResources->documentResolution());
debugFlake << converter.errors() << converter.warnings();
return shape;
}
KoShape *KoSvgTextShapeFactory::createShape(const KoProperties *params, KoDocumentResourceManager *documentResources) const
{
KoSvgTextShape *shape = new KoSvgTextShape();
shape->setShapeId(KoSvgTextShape_SHAPEID);
- QString svgText = params->stringProperty("svgText", "<text>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</text>");
+ QString svgText = params->stringProperty("svgText", i18nc("Default text for the text shape", "<text>Placeholder Text</text>"));
QString defs = params->stringProperty("defs" , "<defs/>");
QRectF shapeRect = QRectF(0, 0, 200, 60);
QVariant rect = params->property("shapeRect");
if (rect.type()==QVariant::RectF) {
shapeRect = rect.toRectF();
}
KoSvgTextShapeMarkupConverter converter(shape);
converter.convertFromSvg(svgText,
defs,
shapeRect,
documentResources->documentResolution());
shape->setPosition(shapeRect.topLeft());
return shape;
}
bool KoSvgTextShapeFactory::supports(const KoXmlElement &/*e*/, KoShapeLoadingContext &/*context*/) const
{
return false;
}
diff --git a/libs/flake/tools/KoPathConnectionPointStrategy.cpp b/libs/flake/tools/KoPathConnectionPointStrategy.cpp
deleted file mode 100644
index 7c23db8a5c..0000000000
--- a/libs/flake/tools/KoPathConnectionPointStrategy.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2007 Boudewijn Rempt <boud@kde.org>
- * Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2007,2009,2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "KoPathConnectionPointStrategy.h"
-#include "KoPathConnectionPointStrategy_p.h"
-#include "KoConnectionShape.h"
-#include "KoCanvasBase.h"
-#include "KoShapeManager.h"
-#include "KoShapeConnectionChangeCommand.h"
-
-#include <float.h>
-#include <math.h>
-
-const int InvalidConnectionPointId = INT_MIN;
-
-KoPathConnectionPointStrategy::KoPathConnectionPointStrategy(KoToolBase *tool, KoConnectionShape *shape, int handleId)
- : KoParameterChangeStrategy(*(new KoPathConnectionPointStrategyPrivate(tool, shape, handleId)))
-{
-}
-
-KoPathConnectionPointStrategy::~KoPathConnectionPointStrategy()
-{
-}
-
-void KoPathConnectionPointStrategy::handleMouseMove(const QPointF &mouseLocation, Qt::KeyboardModifiers modifiers)
-{
- Q_D(KoPathConnectionPointStrategy);
-
- const qreal MAX_DISTANCE = 20.0; // TODO make user definable
- const qreal MAX_DISTANCE_SQR = MAX_DISTANCE * MAX_DISTANCE;
-
- d->newConnectionShape = 0;
- d->newConnectionId = InvalidConnectionPointId;
-
- QRectF roi(mouseLocation - QPointF(MAX_DISTANCE, MAX_DISTANCE), QSizeF(2*MAX_DISTANCE, 2*MAX_DISTANCE));
- QList<KoShape*> shapes = d->tool->canvas()->shapeManager()->shapesAt(roi, true);
- if (shapes.count() < 2) {
- // we are not near any other shape, so remove the corresponding connection
- if (d->handleId == 0)
- d->connectionShape->connectFirst(0, InvalidConnectionPointId);
- else
- d->connectionShape->connectSecond(0, InvalidConnectionPointId);
-
- KoParameterChangeStrategy::handleMouseMove(mouseLocation, modifiers);
- } else {
- qreal minimalDistance = DBL_MAX;
- QPointF nearestPoint;
- KoShape *nearestShape = 0;
- int nearestPointId = InvalidConnectionPointId;
-
- Q_FOREACH (KoShape* shape, shapes) {
- // we do not want to connect to ourself
- if (shape == d->connectionShape)
- continue;
-
- KoConnectionPoints connectionPoints = shape->connectionPoints();
- if (! connectionPoints.count()) {
- QSizeF size = shape->size();
- connectionPoints[-1] = QPointF(0.0, 0.0);
- connectionPoints[-2] = QPointF(size.width(), 0.0);
- connectionPoints[-3] = QPointF(size.width(), size.height());
- connectionPoints[-4] = QPointF(0.0, size.height());
- connectionPoints[-5] = 0.5 * (connectionPoints[-1].position + connectionPoints[-2].position);
- connectionPoints[-6] = 0.5 * (connectionPoints[-2].position + connectionPoints[-3].position);
- connectionPoints[-7] = 0.5 * (connectionPoints[-3].position + connectionPoints[-4].position);
- connectionPoints[-8] = 0.5 * (connectionPoints[-4].position + connectionPoints[-1].position);
- }
- QPointF localMousePosition = shape->absoluteTransformation().inverted().map(mouseLocation);
- KoConnectionPoints::const_iterator cp = connectionPoints.constBegin();
- KoConnectionPoints::const_iterator lastCp = connectionPoints.constEnd();
- for(; cp != lastCp; ++cp) {
- QPointF difference = localMousePosition - cp.value().position;
- qreal distance = difference.x() * difference.x() + difference.y() * difference.y();
- if (distance > MAX_DISTANCE_SQR)
- continue;
- if (distance < minimalDistance) {
- nearestShape = shape;
- nearestPoint = cp.value().position;
- nearestPointId = cp.key();
- minimalDistance = distance;
- }
- }
- }
-
- if (nearestShape) {
- nearestPoint = nearestShape->absoluteTransformation().map(nearestPoint);
- } else {
- nearestPoint = mouseLocation;
- }
- d->newConnectionShape = nearestShape;
- d->newConnectionId = nearestPointId;
- if (d->handleId == 0)
- d->connectionShape->connectFirst(nearestShape, nearestPointId);
- else
- d->connectionShape->connectSecond(nearestShape, nearestPointId);
- KoParameterChangeStrategy::handleMouseMove(nearestPoint, modifiers);
- }
-}
-
-void KoPathConnectionPointStrategy::finishInteraction(Qt::KeyboardModifiers modifiers)
-{
- KoParameterChangeStrategy::finishInteraction(modifiers);
-}
-
-KUndo2Command* KoPathConnectionPointStrategy::createCommand()
-{
- Q_D(KoPathConnectionPointStrategy);
-
- // check if we connect to a shape and if the connection point is already present
- if (d->newConnectionShape && d->newConnectionId < 0 && d->newConnectionId != InvalidConnectionPointId) {
- // map handle position into document coordinates
- QPointF p = d->connectionShape->shapeToDocument(d->connectionShape->handlePosition(d->handleId));
- // and add as connection point in shape coordinates
- d->newConnectionId = d->newConnectionShape->addConnectionPoint(d->newConnectionShape->absoluteTransformation().inverted().map(p));
- }
-
- KUndo2Command *cmd = KoParameterChangeStrategy::createCommand();
- if (!cmd)
- return 0;
-
- // change connection
- new KoShapeConnectionChangeCommand(d->connectionShape, static_cast<KoConnectionShape::HandleId>(d->handleId),
- d->oldConnectionShape, d->oldConnectionId, d->newConnectionShape, d->newConnectionId, cmd);
- return cmd;
-}
diff --git a/libs/flake/tools/KoPathConnectionPointStrategy.h b/libs/flake/tools/KoPathConnectionPointStrategy.h
deleted file mode 100644
index 33d78779f1..0000000000
--- a/libs/flake/tools/KoPathConnectionPointStrategy.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2007 Boudewijn Rempt <boud@kde.org>
- * Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- *
- * 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_PATH_CONNECTION_POINT_STRATEGY
-#define KO_PATH_CONNECTION_POINT_STRATEGY
-
-#include "kritaflake_export.h"
-#include "KoParameterChangeStrategy.h"
-
-class KoConnectionShape;
-class QPointF;
-class KoPathConnectionPointStrategyPrivate;
-
-/**
- * @brief Strategy for moving end points of a connection shape.
- */
-class KRITAFLAKE_EXPORT KoPathConnectionPointStrategy : public KoParameterChangeStrategy
-{
-public:
- KoPathConnectionPointStrategy(KoToolBase *tool, KoConnectionShape *parameterShape, int handleId);
- ~KoPathConnectionPointStrategy() override;
- void handleMouseMove(const QPointF &mouseLocation, Qt::KeyboardModifiers modifiers) override;
- void finishInteraction(Qt::KeyboardModifiers modifiers) override;
- KUndo2Command* createCommand() override;
-
-private:
- Q_DECLARE_PRIVATE(KoPathConnectionPointStrategy)
-};
-
-
-#endif
diff --git a/libs/flake/tools/KoPathConnectionPointStrategy_p.h b/libs/flake/tools/KoPathConnectionPointStrategy_p.h
deleted file mode 100644
index 81f6a522a9..0000000000
--- a/libs/flake/tools/KoPathConnectionPointStrategy_p.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2007 Boudewijn Rempt <boud@kde.org>
- * Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 KOPATHCONNECTIONPOINTSTRATEGYPRIVATE_H
-#define KOPATHCONNECTIONPOINTSTRATEGYPRIVATE_H
-
-#include "KoParameterChangeStrategy_p.h"
-#include "KoConnectionShape.h"
-
-class KoPathConnectionPointStrategyPrivate : public KoParameterChangeStrategyPrivate
-{
-public:
- KoPathConnectionPointStrategyPrivate(KoToolBase* owner, KoConnectionShape* connectionShape, int handle)
- : KoParameterChangeStrategyPrivate(owner, connectionShape, handle)
- , connectionShape(connectionShape)
- , oldConnectionShape(0), oldConnectionId(-1)
- , newConnectionShape(0), newConnectionId(-1)
- {
- if (handleId == 0) {
- oldConnectionShape = connectionShape->firstShape();
- oldConnectionId = connectionShape->firstConnectionId();
- } else {
- oldConnectionShape = connectionShape->secondShape();
- oldConnectionId = connectionShape->secondConnectionId();
- }
- }
-
- KoConnectionShape *connectionShape; ///< the parametric shape we are working on
- KoShape *oldConnectionShape;
- int oldConnectionId;
- KoShape *newConnectionShape;
- int newConnectionId;
-};
-
-#endif // KOPATHCONNECTIONPOINTSTRATEGYPRIVATE_H
diff --git a/libs/flake/tools/KoPathTool.cpp b/libs/flake/tools/KoPathTool.cpp
index 5bf9607d73..2fd674c234 100644
--- a/libs/flake/tools/KoPathTool.cpp
+++ b/libs/flake/tools/KoPathTool.cpp
@@ -1,1315 +1,1304 @@
/* This file is part of the KDE project
* Copyright (C) 2006-2012 Jan Hambrecht <jaham@gmx.net>
* Copyright (C) 2006,2007 Thorsten Zachmann <zachmann@kde.org>
* Copyright (C) 2007, 2010 Thomas Zander <zander@kde.org>
* Copyright (C) 2007 Boudewijn Rempt <boud@valdyas.org>
*
* 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 "KoPathTool.h"
#include "KoToolBase_p.h"
#include "KoPathShape_p.h"
#include "KoPathToolHandle.h"
#include "KoCanvasBase.h"
#include "KoShapeManager.h"
#include "KoSelectedShapesProxy.h"
#include "KoDocumentResourceManager.h"
#include "KoViewConverter.h"
#include "KoSelection.h"
#include "KoPointerEvent.h"
#include "commands/KoPathPointTypeCommand.h"
#include "commands/KoPathPointInsertCommand.h"
#include "commands/KoPathPointRemoveCommand.h"
#include "commands/KoPathSegmentTypeCommand.h"
#include "commands/KoPathBreakAtPointCommand.h"
#include "commands/KoPathSegmentBreakCommand.h"
#include "commands/KoParameterToPathCommand.h"
#include "commands/KoSubpathJoinCommand.h"
#include <commands/KoMultiPathPointMergeCommand.h>
#include <commands/KoMultiPathPointJoinCommand.h>
#include <commands/KoKeepShapesSelectedCommand.h>
#include "KoParameterShape.h"
#include <text/KoSvgTextShape.h>
#include "KoPathPoint.h"
#include "KoPathPointRubberSelectStrategy.h"
#include "KoPathSegmentChangeStrategy.h"
-#include "KoPathConnectionPointStrategy.h"
#include "KoParameterChangeStrategy.h"
#include "PathToolOptionWidget.h"
-#include "KoConnectionShape.h"
#include "KoSnapGuide.h"
#include "KoShapeController.h"
#include "kis_action_registry.h"
#include <KisHandlePainterHelper.h>
#include <KoShapeStrokeModel.h>
#include "kis_command_utils.h"
#include "kis_pointer_utils.h"
#include <KoIcon.h>
#include <QMenu>
#include <QAction>
#include <FlakeDebug.h>
#include <klocalizedstring.h>
#include <QPainter>
#include <QPainterPath>
#include <QBitmap>
#include <QTabWidget>
#include <math.h>
static const unsigned char needle_bits[] = {
0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x60, 0x00, 0xc0, 0x00, 0xc0, 0x01,
0x80, 0x03, 0x80, 0x07, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x3e, 0x00, 0x7e,
0x00, 0x7c, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x00
};
static const unsigned char needle_move_bits[] = {
0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x60, 0x00, 0xc0, 0x00, 0xc0, 0x01,
0x80, 0x03, 0x80, 0x07, 0x10, 0x0f, 0x38, 0x1f, 0x54, 0x3e, 0xfe, 0x7e,
0x54, 0x7c, 0x38, 0x1c, 0x10, 0x18, 0x00, 0x00
};
// helper function to calculate the squared distance between two points
qreal squaredDistance(const QPointF& p1, const QPointF &p2)
{
qreal dx = p1.x()-p2.x();
qreal dy = p1.y()-p2.y();
return dx*dx + dy*dy;
}
struct KoPathTool::PathSegment {
PathSegment()
: path(0), segmentStart(0), positionOnSegment(0)
{
}
bool isValid() {
return path && segmentStart;
}
KoPathShape *path;
KoPathPoint *segmentStart;
qreal positionOnSegment;
};
KoPathTool::KoPathTool(KoCanvasBase *canvas)
: KoToolBase(canvas)
, m_pointSelection(this)
, m_activeHandle(0)
, m_handleRadius(3)
, m_activeSegment(0)
, m_currentStrategy(0)
, m_activatedTemporarily(false)
{
m_points = new QActionGroup(this);
// m_pointTypeGroup->setExclusive(true);
m_actionPathPointCorner = action("pathpoint-corner");
if (m_actionPathPointCorner) {
m_actionPathPointCorner->setData(KoPathPointTypeCommand::Corner);
m_points->addAction(m_actionPathPointCorner);
}
m_actionPathPointSmooth = action("pathpoint-smooth");
if (m_actionPathPointSmooth) {
m_actionPathPointSmooth->setData(KoPathPointTypeCommand::Smooth);
m_points->addAction(m_actionPathPointSmooth);
}
m_actionPathPointSymmetric = action("pathpoint-symmetric");
if (m_actionPathPointSymmetric) {
m_actionPathPointSymmetric->setData(KoPathPointTypeCommand::Symmetric);
m_points->addAction(m_actionPathPointSymmetric);
}
m_actionCurvePoint = action("pathpoint-curve");
m_actionLinePoint = action("pathpoint-line");
m_actionLineSegment = action("pathsegment-line");
m_actionCurveSegment = action("pathsegment-curve");
m_actionAddPoint = action("pathpoint-insert");
m_actionRemovePoint = action("pathpoint-remove");
m_actionBreakPoint = action("path-break-point");
m_actionBreakSegment = action("path-break-segment");
m_actionJoinSegment = action("pathpoint-join");
m_actionMergePoints = action("pathpoint-merge");
m_actionConvertToPath = action("convert-to-path");
m_contextMenu.reset(new QMenu());
QBitmap b = QBitmap::fromData(QSize(16, 16), needle_bits);
QBitmap m = b.createHeuristicMask(false);
m_selectCursor = QCursor(b, m, 2, 0);
b = QBitmap::fromData(QSize(16, 16), needle_move_bits);
m = b.createHeuristicMask(false);
m_moveCursor = QCursor(b, m, 2, 0);
}
KoPathTool::~KoPathTool()
{
delete m_activeHandle;
delete m_activeSegment;
delete m_currentStrategy;
}
QList<QPointer<QWidget> > KoPathTool::createOptionWidgets()
{
QList<QPointer<QWidget> > list;
PathToolOptionWidget * toolOptions = new PathToolOptionWidget(this);
connect(this, SIGNAL(typeChanged(int)), toolOptions, SLOT(setSelectionType(int)));
connect(this, SIGNAL(singleShapeChanged(KoPathShape*)), toolOptions, SLOT(setCurrentShape(KoPathShape*)));
connect(toolOptions, SIGNAL(sigRequestUpdateActions()), this, SLOT(updateActions()));
updateOptionsWidget();
toolOptions->setWindowTitle(i18n("Edit Shape"));
list.append(toolOptions);
return list;
}
void KoPathTool::pointTypeChanged(QAction *type)
{
Q_D(KoToolBase);
if (m_pointSelection.hasSelection()) {
QList<KoPathPointData> selectedPoints = m_pointSelection.selectedPointsData();
KUndo2Command *initialConversionCommand = createPointToCurveCommand(selectedPoints);
// conversion should happen before the c-tor
// of KoPathPointTypeCommand is executed!
if (initialConversionCommand) {
initialConversionCommand->redo();
}
KUndo2Command *command =
new KoPathPointTypeCommand(selectedPoints,
static_cast<KoPathPointTypeCommand::PointType>(type->data().toInt()));
if (initialConversionCommand) {
using namespace KisCommandUtils;
CompositeCommand *parent = new CompositeCommand();
parent->setText(command->text());
parent->addCommand(new SkipFirstRedoWrapper(initialConversionCommand));
parent->addCommand(command);
command = parent;
}
d->canvas->addCommand(command);
}
}
void KoPathTool::insertPoints()
{
Q_D(KoToolBase);
QList<KoPathPointData> segments(m_pointSelection.selectedSegmentsData());
if (segments.size() == 1) {
qreal positionInSegment = 0.5;
if (m_activeSegment && m_activeSegment->isValid()) {
positionInSegment = m_activeSegment->positionOnSegment;
}
KoPathPointInsertCommand *cmd = new KoPathPointInsertCommand(segments, positionInSegment);
d->canvas->addCommand(cmd);
// TODO: this construction is dangerous. The canvas can remove the command right after
// it has been added to it!
m_pointSelection.clear();
foreach (KoPathPoint * p, cmd->insertedPoints()) {
m_pointSelection.add(p, false);
}
}
}
void KoPathTool::removePoints()
{
Q_D(KoToolBase);
if (m_pointSelection.size() > 0) {
KUndo2Command *cmd = KoPathPointRemoveCommand::createCommand(m_pointSelection.selectedPointsData(), d->canvas->shapeController());
PointHandle *pointHandle = dynamic_cast<PointHandle*>(m_activeHandle);
if (pointHandle && m_pointSelection.contains(pointHandle->activePoint())) {
delete m_activeHandle;
m_activeHandle = 0;
}
clearActivePointSelectionReferences();
d->canvas->addCommand(cmd);
}
}
void KoPathTool::pointToLine()
{
Q_D(KoToolBase);
if (m_pointSelection.hasSelection()) {
QList<KoPathPointData> selectedPoints = m_pointSelection.selectedPointsData();
QList<KoPathPointData> pointToChange;
QList<KoPathPointData>::const_iterator it(selectedPoints.constBegin());
for (; it != selectedPoints.constEnd(); ++it) {
KoPathPoint *point = it->pathShape->pointByIndex(it->pointIndex);
if (point && (point->activeControlPoint1() || point->activeControlPoint2()))
pointToChange.append(*it);
}
if (! pointToChange.isEmpty()) {
d->canvas->addCommand(new KoPathPointTypeCommand(pointToChange, KoPathPointTypeCommand::Line));
}
}
}
void KoPathTool::pointToCurve()
{
Q_D(KoToolBase);
if (m_pointSelection.hasSelection()) {
QList<KoPathPointData> selectedPoints = m_pointSelection.selectedPointsData();
KUndo2Command *command = createPointToCurveCommand(selectedPoints);
if (command) {
d->canvas->addCommand(command);
}
}
}
KUndo2Command* KoPathTool::createPointToCurveCommand(const QList<KoPathPointData> &points)
{
KUndo2Command *command = 0;
QList<KoPathPointData> pointToChange;
QList<KoPathPointData>::const_iterator it(points.constBegin());
for (; it != points.constEnd(); ++it) {
KoPathPoint *point = it->pathShape->pointByIndex(it->pointIndex);
if (point && (! point->activeControlPoint1() || ! point->activeControlPoint2()))
pointToChange.append(*it);
}
if (!pointToChange.isEmpty()) {
command = new KoPathPointTypeCommand(pointToChange, KoPathPointTypeCommand::Curve);
}
return command;
}
void KoPathTool::segmentToLine()
{
Q_D(KoToolBase);
if (m_pointSelection.size() > 1) {
QList<KoPathPointData> segments(m_pointSelection.selectedSegmentsData());
if (segments.size() > 0) {
d->canvas->addCommand(new KoPathSegmentTypeCommand(segments, KoPathSegmentTypeCommand::Line));
}
}
}
void KoPathTool::segmentToCurve()
{
Q_D(KoToolBase);
if (m_pointSelection.size() > 1) {
QList<KoPathPointData> segments(m_pointSelection.selectedSegmentsData());
if (segments.size() > 0) {
d->canvas->addCommand(new KoPathSegmentTypeCommand(segments, KoPathSegmentTypeCommand::Curve));
}
}
}
void KoPathTool::convertToPath()
{
Q_D(KoToolBase);
KoSelection *selection = canvas()->selectedShapesProxy()->selection();
QList<KoParameterShape*> parameterShapes;
Q_FOREACH (KoShape *shape, m_pointSelection.selectedShapes()) {
KoParameterShape * parameteric = dynamic_cast<KoParameterShape*>(shape);
if (parameteric && parameteric->isParametricShape()) {
parameterShapes.append(parameteric);
}
}
if (!parameterShapes.isEmpty()) {
d->canvas->addCommand(new KoParameterToPathCommand(parameterShapes));
}
QList<KoSvgTextShape*> textShapes;
Q_FOREACH (KoShape *shape, selection->selectedEditableShapes()) {
if (KoSvgTextShape *text = dynamic_cast<KoSvgTextShape*>(shape)) {
textShapes.append(text);
}
}
if (!textShapes.isEmpty()) {
KUndo2Command *cmd = new KUndo2Command(kundo2_i18n("Convert to Path")); // TODO: reuse the text from KoParameterToPathCommand
const QList<KoShape*> oldSelectedShapes = implicitCastList<KoShape*>(textShapes);
new KoKeepShapesSelectedCommand(oldSelectedShapes, {}, canvas()->selectedShapesProxy(),
KisCommandUtils::FlipFlopCommand::State::INITIALIZING, cmd);
QList<KoShape*> newSelectedShapes;
Q_FOREACH (KoSvgTextShape *shape, textShapes) {
const QPainterPath path = shape->textOutline();
if (path.isEmpty()) continue;
KoPathShape *pathShape = KoPathShape::createShapeFromPainterPath(path);
pathShape->setBackground(shape->background());
pathShape->setStroke(shape->stroke());
pathShape->setZIndex(shape->zIndex());
pathShape->setTransformation(shape->transformation());
KoShapeContainer *parent = shape->parent();
canvas()->shapeController()->addShapeDirect(pathShape, parent, cmd);
newSelectedShapes << pathShape;
}
canvas()->shapeController()->removeShapes(oldSelectedShapes, cmd);
new KoKeepShapesSelectedCommand({}, newSelectedShapes, canvas()->selectedShapesProxy(),
KisCommandUtils::FlipFlopCommand::State::FINALIZING, cmd);
canvas()->addCommand(cmd);
}
updateOptionsWidget();
}
namespace {
bool checkCanJoinToPoints(const KoPathPointData & pd1, const KoPathPointData & pd2)
{
const KoPathPointIndex & index1 = pd1.pointIndex;
const KoPathPointIndex & index2 = pd2.pointIndex;
KoPathShape *path1 = pd1.pathShape;
KoPathShape *path2 = pd2.pathShape;
// check if subpaths are already closed
if (path1->isClosedSubpath(index1.first) || path2->isClosedSubpath(index2.first))
return false;
// check if first point is an endpoint
if (index1.second != 0 && index1.second != path1->subpathPointCount(index1.first)-1)
return false;
// check if second point is an endpoint
if (index2.second != 0 && index2.second != path2->subpathPointCount(index2.first)-1)
return false;
return true;
}
}
void KoPathTool::mergePointsImpl(bool doJoin)
{
Q_D(KoToolBase);
if (m_pointSelection.size() != 2)
return;
QList<KoPathPointData> pointData = m_pointSelection.selectedPointsData();
if (pointData.size() != 2) return;
const KoPathPointData & pd1 = pointData.at(0);
const KoPathPointData & pd2 = pointData.at(1);
if (!checkCanJoinToPoints(pd1, pd2)) {
return;
}
clearActivePointSelectionReferences();
KUndo2Command *cmd = 0;
if (doJoin) {
cmd = new KoMultiPathPointJoinCommand(pd1, pd2, d->canvas->shapeController()->documentBase(), d->canvas->shapeManager()->selection());
} else {
cmd = new KoMultiPathPointMergeCommand(pd1, pd2, d->canvas->shapeController()->documentBase(), d->canvas->shapeManager()->selection());
}
d->canvas->addCommand(cmd);
}
void KoPathTool::joinPoints()
{
mergePointsImpl(true);
}
void KoPathTool::mergePoints()
{
mergePointsImpl(false);
}
void KoPathTool::breakAtPoint()
{
Q_D(KoToolBase);
if (m_pointSelection.hasSelection()) {
d->canvas->addCommand(new KoPathBreakAtPointCommand(m_pointSelection.selectedPointsData()));
}
}
void KoPathTool::breakAtSegment()
{
Q_D(KoToolBase);
// only try to break a segment when 2 points of the same object are selected
if (m_pointSelection.objectCount() == 1 && m_pointSelection.size() == 2) {
QList<KoPathPointData> segments(m_pointSelection.selectedSegmentsData());
if (segments.size() == 1) {
d->canvas->addCommand(new KoPathSegmentBreakCommand(segments.at(0)));
}
}
}
void KoPathTool::paint(QPainter &painter, const KoViewConverter &converter)
{
Q_D(KoToolBase);
Q_FOREACH (KoPathShape *shape, m_pointSelection.selectedShapes()) {
KisHandlePainterHelper helper =
KoShape::createHandlePainterHelperView(&painter, shape, converter, m_handleRadius);
helper.setHandleStyle(KisHandleStyle::primarySelection());
KoParameterShape * parameterShape = dynamic_cast<KoParameterShape*>(shape);
if (parameterShape && parameterShape->isParametricShape()) {
parameterShape->paintHandles(helper);
} else {
shape->paintPoints(helper);
}
if (!shape->stroke() || !shape->stroke()->isVisible()) {
helper.setHandleStyle(KisHandleStyle::secondarySelection());
helper.drawPath(shape->outline());
}
}
if (m_currentStrategy) {
painter.save();
m_currentStrategy->paint(painter, converter);
painter.restore();
}
m_pointSelection.paint(painter, converter, m_handleRadius);
if (m_activeHandle) {
if (m_activeHandle->check(m_pointSelection.selectedShapes())) {
m_activeHandle->paint(painter, converter, m_handleRadius);
} else {
delete m_activeHandle;
m_activeHandle = 0;
}
} else if (m_activeSegment && m_activeSegment->isValid()) {
KoPathShape *shape = m_activeSegment->path;
// if the stroke is invisible, then we already painted the outline of the shape!
if (shape->stroke() && shape->stroke()->isVisible()) {
KoPathPointIndex index = shape->pathPointIndex(m_activeSegment->segmentStart);
KoPathSegment segment = shape->segmentByIndex(index).toCubic();
KIS_SAFE_ASSERT_RECOVER_RETURN(segment.isValid());
KisHandlePainterHelper helper =
KoShape::createHandlePainterHelperView(&painter, shape, converter, m_handleRadius);
helper.setHandleStyle(KisHandleStyle::secondarySelection());
QPainterPath path;
path.moveTo(segment.first()->point());
path.cubicTo(segment.first()->controlPoint2(),
segment.second()->controlPoint1(),
segment.second()->point());
helper.drawPath(path);
}
}
if (m_currentStrategy) {
painter.save();
painter.setTransform(converter.documentToView(), true);
d->canvas->snapGuide()->paint(painter, converter);
painter.restore();
}
}
void KoPathTool::repaintDecorations()
{
Q_FOREACH (KoShape *shape, m_pointSelection.selectedShapes()) {
repaint(shape->boundingRect());
}
m_pointSelection.repaint();
updateOptionsWidget();
}
void KoPathTool::mousePressEvent(KoPointerEvent *event)
{
// we are moving if we hit a point and use the left mouse button
event->ignore();
if (m_activeHandle) {
m_currentStrategy = m_activeHandle->handleMousePress(event);
event->accept();
} else {
if (event->button() & Qt::LeftButton) {
// check if we hit a path segment
if (m_activeSegment && m_activeSegment->isValid()) {
KoPathShape *shape = m_activeSegment->path;
KoPathPointIndex index = shape->pathPointIndex(m_activeSegment->segmentStart);
KoPathSegment segment = shape->segmentByIndex(index);
m_pointSelection.add(segment.first(), !(event->modifiers() & Qt::ShiftModifier));
m_pointSelection.add(segment.second(), false);
KoPathPointData data(shape, index);
m_currentStrategy = new KoPathSegmentChangeStrategy(this, event->point, data, m_activeSegment->positionOnSegment);
event->accept();
} else {
KoShapeManager *shapeManager = canvas()->shapeManager();
KoSelection *selection = shapeManager->selection();
KoShape *shape = shapeManager->shapeAt(event->point, KoFlake::ShapeOnTop);
if (shape && !selection->isSelected(shape)) {
if (!(event->modifiers() & Qt::ShiftModifier)) {
selection->deselectAll();
}
selection->select(shape);
} else {
KIS_ASSERT_RECOVER_RETURN(m_currentStrategy == 0);
m_currentStrategy = new KoPathPointRubberSelectStrategy(this, event->point);
event->accept();
}
}
}
}
}
void KoPathTool::mouseMoveEvent(KoPointerEvent *event)
{
if (event->button() & Qt::RightButton)
return;
if (m_currentStrategy) {
m_lastPoint = event->point;
m_currentStrategy->handleMouseMove(event->point, event->modifiers());
// repaint new handle positions
m_pointSelection.repaint();
if (m_activeHandle) {
m_activeHandle->repaint();
}
if (m_activeSegment) {
repaintSegment(m_activeSegment);
}
return;
}
if (m_activeSegment) {
KoPathPointIndex index = m_activeSegment->path->pathPointIndex(m_activeSegment->segmentStart);
KoPathSegment segment = m_activeSegment->path->segmentByIndex(index);
repaint(segment.boundingRect());
delete m_activeSegment;
m_activeSegment = 0;
}
Q_FOREACH (KoPathShape *shape, m_pointSelection.selectedShapes()) {
QRectF roi = handleGrabRect(shape->documentToShape(event->point));
KoParameterShape * parameterShape = dynamic_cast<KoParameterShape*>(shape);
if (parameterShape && parameterShape->isParametricShape()) {
int handleId = parameterShape->handleIdAt(roi);
if (handleId != -1) {
useCursor(m_moveCursor);
emit statusTextChanged(i18n("Drag to move handle."));
if (m_activeHandle)
m_activeHandle->repaint();
delete m_activeHandle;
-
- if (KoConnectionShape * connectionShape = dynamic_cast<KoConnectionShape*>(parameterShape)) {
- //debugFlake << "handleId" << handleId;
- m_activeHandle = new ConnectionHandle(this, connectionShape, handleId);
- m_activeHandle->repaint();
- return;
- } else {
- //debugFlake << "handleId" << handleId;
- m_activeHandle = new ParameterHandle(this, parameterShape, handleId);
- m_activeHandle->repaint();
- return;
- }
+ //debugFlake << "handleId" << handleId;
+ m_activeHandle = new ParameterHandle(this, parameterShape, handleId);
+ m_activeHandle->repaint();
+ return;
}
-
} else {
QList<KoPathPoint*> points = shape->pointsAt(roi);
if (! points.empty()) {
// find the nearest control point from all points within the roi
KoPathPoint * bestPoint = 0;
KoPathPoint::PointType bestPointType = KoPathPoint::Node;
qreal minDistance = HUGE_VAL;
Q_FOREACH (KoPathPoint *p, points) {
// the node point must be hit if the point is not selected yet
if (! m_pointSelection.contains(p) && ! roi.contains(p->point()))
continue;
// check for the control points first as otherwise it is no longer
// possible to change the control points when they are the same as the point
if (p->activeControlPoint1() && roi.contains(p->controlPoint1())) {
qreal dist = squaredDistance(roi.center(), p->controlPoint1());
if (dist < minDistance) {
bestPoint = p;
bestPointType = KoPathPoint::ControlPoint1;
minDistance = dist;
}
}
if (p->activeControlPoint2() && roi.contains(p->controlPoint2())) {
qreal dist = squaredDistance(roi.center(), p->controlPoint2());
if (dist < minDistance) {
bestPoint = p;
bestPointType = KoPathPoint::ControlPoint2;
minDistance = dist;
}
}
// check the node point at last
qreal dist = squaredDistance(roi.center(), p->point());
if (dist < minDistance) {
bestPoint = p;
bestPointType = KoPathPoint::Node;
minDistance = dist;
}
}
if (! bestPoint)
return;
useCursor(m_moveCursor);
if (bestPointType == KoPathPoint::Node)
emit statusTextChanged(i18n("Drag to move point. Shift click to change point type."));
else
emit statusTextChanged(i18n("Drag to move control point."));
PointHandle *prev = dynamic_cast<PointHandle*>(m_activeHandle);
if (prev && prev->activePoint() == bestPoint && prev->activePointType() == bestPointType)
return; // no change;
if (m_activeHandle)
m_activeHandle->repaint();
delete m_activeHandle;
m_activeHandle = new PointHandle(this, bestPoint, bestPointType);
m_activeHandle->repaint();
return;
}
}
}
useCursor(m_selectCursor);
if (m_activeHandle) {
m_activeHandle->repaint();
}
delete m_activeHandle;
m_activeHandle = 0;
PathSegment *hoveredSegment = segmentAtPoint(event->point);
if(hoveredSegment) {
useCursor(Qt::PointingHandCursor);
emit statusTextChanged(i18n("Drag to change curve directly. Double click to insert new path point."));
m_activeSegment = hoveredSegment;
repaintSegment(m_activeSegment);
} else {
uint selectedPointCount = m_pointSelection.size();
if (selectedPointCount == 0)
emit statusTextChanged(QString());
else if (selectedPointCount == 1)
emit statusTextChanged(i18n("Press B to break path at selected point."));
else
emit statusTextChanged(i18n("Press B to break path at selected segments."));
}
}
void KoPathTool::repaintSegment(PathSegment *pathSegment)
{
if (!pathSegment || !pathSegment->isValid()) return;
KoPathPointIndex index = pathSegment->path->pathPointIndex(pathSegment->segmentStart);
KoPathSegment segment = pathSegment->path->segmentByIndex(index);
repaint(segment.boundingRect());
}
void KoPathTool::mouseReleaseEvent(KoPointerEvent *event)
{
Q_D(KoToolBase);
if (m_currentStrategy) {
const bool hadNoSelection = !m_pointSelection.hasSelection();
m_currentStrategy->finishInteraction(event->modifiers());
KUndo2Command *command = m_currentStrategy->createCommand();
if (command)
d->canvas->addCommand(command);
if (hadNoSelection && dynamic_cast<KoPathPointRubberSelectStrategy*>(m_currentStrategy)
&& !m_pointSelection.hasSelection()) {
// the click didn't do anything at all. Allow it to be used by others.
event->ignore();
}
delete m_currentStrategy;
m_currentStrategy = 0;
}
}
void KoPathTool::keyPressEvent(QKeyEvent *event)
{
if (m_currentStrategy) {
switch (event->key()) {
case Qt::Key_Control:
case Qt::Key_Alt:
case Qt::Key_Shift:
case Qt::Key_Meta:
if (! event->isAutoRepeat()) {
m_currentStrategy->handleMouseMove(m_lastPoint, event->modifiers());
}
break;
case Qt::Key_Escape:
m_currentStrategy->cancelInteraction();
delete m_currentStrategy;
m_currentStrategy = 0;
break;
default:
event->ignore();
return;
}
} else {
switch (event->key()) {
#ifndef NDEBUG
// case Qt::Key_D:
// if (m_pointSelection.objectCount() == 1) {
// QList<KoPathPointData> selectedPoints = m_pointSelection.selectedPointsData();
// KoPathShapePrivate *p = static_cast<KoPathShapePrivate*>(selectedPoints[0].pathShape->priv());
// p->debugPath();
// }
// break;
#endif
case Qt::Key_B:
if (m_pointSelection.size() == 1)
breakAtPoint();
else if (m_pointSelection.size() >= 2)
breakAtSegment();
break;
default:
event->ignore();
return;
}
}
event->accept();
}
void KoPathTool::keyReleaseEvent(QKeyEvent *event)
{
if (m_currentStrategy) {
switch (event->key()) {
case Qt::Key_Control:
case Qt::Key_Alt:
case Qt::Key_Shift:
case Qt::Key_Meta:
if (! event->isAutoRepeat()) {
m_currentStrategy->handleMouseMove(m_lastPoint, Qt::NoModifier);
}
break;
default:
break;
}
}
event->accept();
}
void KoPathTool::mouseDoubleClickEvent(KoPointerEvent *event)
{
Q_D(KoToolBase);
event->ignore();
// check if we are doing something else at the moment
if (m_currentStrategy) return;
if (!m_activeHandle && m_activeSegment && m_activeSegment->isValid()) {
QList<KoPathPointData> segments;
segments.append(
KoPathPointData(m_activeSegment->path,
m_activeSegment->path->pathPointIndex(m_activeSegment->segmentStart)));
KoPathPointInsertCommand *cmd = new KoPathPointInsertCommand(segments, m_activeSegment->positionOnSegment);
d->canvas->addCommand(cmd);
m_pointSelection.clear();
foreach (KoPathPoint * p, cmd->insertedPoints()) {
m_pointSelection.add(p, false);
}
updateActions();
event->accept();
} else if (!m_activeHandle && !m_activeSegment && m_activatedTemporarily) {
emit done();
event->accept();
} else if (!m_activeHandle && !m_activeSegment) {
KoShapeManager *shapeManager = canvas()->shapeManager();
KoSelection *selection = shapeManager->selection();
selection->deselectAll();
event->accept();
}
}
KoPathTool::PathSegment* KoPathTool::segmentAtPoint(const QPointF &point)
{
// the max allowed distance from a segment
const QRectF grabRoi = handleGrabRect(point);
const qreal distanceThreshold = 0.5 * KisAlgebra2D::maxDimension(grabRoi);
QScopedPointer<PathSegment> segment(new PathSegment);
Q_FOREACH (KoPathShape *shape, m_pointSelection.selectedShapes()) {
KoParameterShape * parameterShape = dynamic_cast<KoParameterShape*>(shape);
if (parameterShape && parameterShape->isParametricShape())
continue;
// convert document point to shape coordinates
const QPointF p = shape->documentToShape(point);
// our region of interest, i.e. a region around our mouse position
const QRectF roi = shape->documentToShape(grabRoi);
qreal minDistance = std::numeric_limits<qreal>::max();
// check all segments of this shape which intersect the region of interest
const QList<KoPathSegment> segments = shape->segmentsAt(roi);
foreach (const KoPathSegment &s, segments) {
const qreal nearestPointParam = s.nearestPoint(p);
const QPointF nearestPoint = s.pointAt(nearestPointParam);
const qreal distance = kisDistance(p, nearestPoint);
// are we within the allowed distance ?
if (distance > distanceThreshold)
continue;
// are we closer to the last closest point ?
if (distance < minDistance) {
segment->path = shape;
segment->segmentStart = s.first();
segment->positionOnSegment = nearestPointParam;
}
}
}
if (!segment->isValid()) {
segment.reset();
}
return segment.take();
}
void KoPathTool::activate(ToolActivation activation, const QSet<KoShape*> &shapes)
{
KoToolBase::activate(activation, shapes);
Q_D(KoToolBase);
m_activatedTemporarily = activation == TemporaryActivation;
// retrieve the actual global handle radius
m_handleRadius = handleRadius();
d->canvas->snapGuide()->reset();
useCursor(m_selectCursor);
m_canvasConnections.addConnection(d->canvas->selectedShapesProxy(), SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged()));
m_canvasConnections.addConnection(d->canvas->selectedShapesProxy(), SIGNAL(selectionContentChanged()), this, SLOT(updateActions()));
m_shapeFillResourceConnector.connectToCanvas(d->canvas);
#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
initializeWithShapes(QList<KoShape*>(shapes.begin(), shapes.end()));
#else
initializeWithShapes(QList<KoShape*>::fromSet(shapes));
#endif
connect(m_actionCurvePoint, SIGNAL(triggered()), this, SLOT(pointToCurve()), Qt::UniqueConnection);
connect(m_actionLinePoint, SIGNAL(triggered()), this, SLOT(pointToLine()), Qt::UniqueConnection);
connect(m_actionLineSegment, SIGNAL(triggered()), this, SLOT(segmentToLine()), Qt::UniqueConnection);
connect(m_actionCurveSegment, SIGNAL(triggered()), this, SLOT(segmentToCurve()), Qt::UniqueConnection);
connect(m_actionAddPoint, SIGNAL(triggered()), this, SLOT(insertPoints()), Qt::UniqueConnection);
connect(m_actionRemovePoint, SIGNAL(triggered()), this, SLOT(removePoints()), Qt::UniqueConnection);
connect(m_actionBreakPoint, SIGNAL(triggered()), this, SLOT(breakAtPoint()), Qt::UniqueConnection);
connect(m_actionBreakSegment, SIGNAL(triggered()), this, SLOT(breakAtSegment()), Qt::UniqueConnection);
connect(m_actionJoinSegment, SIGNAL(triggered()), this, SLOT(joinPoints()), Qt::UniqueConnection);
connect(m_actionMergePoints, SIGNAL(triggered()), this, SLOT(mergePoints()), Qt::UniqueConnection);
connect(m_actionConvertToPath, SIGNAL(triggered()), this, SLOT(convertToPath()), Qt::UniqueConnection);
connect(m_points, SIGNAL(triggered(QAction*)), this, SLOT(pointTypeChanged(QAction*)), Qt::UniqueConnection);
connect(&m_pointSelection, SIGNAL(selectionChanged()), this, SLOT(pointSelectionChanged()), Qt::UniqueConnection);
}
void KoPathTool::slotSelectionChanged()
{
Q_D(KoToolBase);
QList<KoShape*> shapes =
d->canvas->selectedShapesProxy()->selection()->selectedEditableShapesAndDelegates();
initializeWithShapes(shapes);
}
void KoPathTool::notifyPathPointsChanged(KoPathShape *shape)
{
Q_UNUSED(shape);
// active handle and selection might have already become invalid, so just
// delete them without dereferencing anything...
delete m_activeHandle;
m_activeHandle = 0;
delete m_activeSegment;
m_activeSegment = 0;
}
void KoPathTool::clearActivePointSelectionReferences()
{
delete m_activeHandle;
m_activeHandle = 0;
delete m_activeSegment;
m_activeSegment = 0;
m_pointSelection.clear();
}
void KoPathTool::initializeWithShapes(const QList<KoShape*> shapes)
{
QList<KoPathShape*> selectedShapes;
Q_FOREACH (KoShape *shape, shapes) {
KoPathShape *pathShape = dynamic_cast<KoPathShape*>(shape);
if (pathShape && pathShape->isShapeEditable()) {
selectedShapes.append(pathShape);
}
}
const QRectF oldBoundingRect =
KoShape::boundingRect(implicitCastList<KoShape*>(m_pointSelection.selectedShapes()));
if (selectedShapes != m_pointSelection.selectedShapes()) {
clearActivePointSelectionReferences();
m_pointSelection.setSelectedShapes(selectedShapes);
repaintDecorations();
}
Q_FOREACH (KoPathShape *shape, selectedShapes) {
// as the tool is just in activation repaintDecorations does not yet get called
// so we need to use repaint of the tool and it is only needed to repaint the
// current canvas
repaint(shape->boundingRect());
}
repaint(oldBoundingRect);
updateOptionsWidget();
updateActions();
}
void KoPathTool::updateOptionsWidget()
{
PathToolOptionWidget::Types type;
QList<KoPathShape*> selectedShapes = m_pointSelection.selectedShapes();
Q_FOREACH (KoPathShape *shape, selectedShapes) {
KoParameterShape * parameterShape = dynamic_cast<KoParameterShape*>(shape);
type |= parameterShape && parameterShape->isParametricShape() ?
PathToolOptionWidget::ParametricShape : PathToolOptionWidget::PlainPath;
}
emit singleShapeChanged(selectedShapes.size() == 1 ? selectedShapes.first() : 0);
emit typeChanged(type);
}
void KoPathTool::updateActions()
{
QList<KoPathPointData> pointData = m_pointSelection.selectedPointsData();
bool canBreakAtPoint = false;
bool hasNonSmoothPoints = false;
bool hasNonSymmetricPoints = false;
bool hasNonSplitPoints = false;
bool hasNonLinePoints = false;
bool hasNonCurvePoints = false;
bool canJoinSubpaths = false;
if (!pointData.isEmpty()) {
Q_FOREACH (const KoPathPointData &pd, pointData) {
const int subpathIndex = pd.pointIndex.first;
const int pointIndex = pd.pointIndex.second;
canBreakAtPoint |= pd.pathShape->isClosedSubpath(subpathIndex) ||
(pointIndex > 0 && pointIndex < pd.pathShape->subpathPointCount(subpathIndex) - 1);
KoPathPoint *point = pd.pathShape->pointByIndex(pd.pointIndex);
hasNonSmoothPoints |= !(point->properties() & KoPathPoint::IsSmooth);
hasNonSymmetricPoints |= !(point->properties() & KoPathPoint::IsSymmetric);
hasNonSplitPoints |=
point->properties() & KoPathPoint::IsSymmetric ||
point->properties() & KoPathPoint::IsSmooth;
hasNonLinePoints |= point->activeControlPoint1() || point->activeControlPoint2();
hasNonCurvePoints |= !point->activeControlPoint1() && !point->activeControlPoint2();
}
if (pointData.size() == 2) {
const KoPathPointData & pd1 = pointData.at(0);
const KoPathPointData & pd2 = pointData.at(1);
canJoinSubpaths = checkCanJoinToPoints(pd1, pd2);
}
}
m_actionPathPointCorner->setEnabled(hasNonSplitPoints);
m_actionPathPointSmooth->setEnabled(hasNonSmoothPoints);
m_actionPathPointSymmetric->setEnabled(hasNonSymmetricPoints);
m_actionRemovePoint->setEnabled(!pointData.isEmpty());
m_actionBreakPoint->setEnabled(canBreakAtPoint);
m_actionCurvePoint->setEnabled(hasNonCurvePoints);
m_actionLinePoint->setEnabled(hasNonLinePoints);
m_actionJoinSegment->setEnabled(canJoinSubpaths);
m_actionMergePoints->setEnabled(canJoinSubpaths);
QList<KoPathPointData> segments(m_pointSelection.selectedSegmentsData());
bool canSplitAtSegment = false;
bool canConvertSegmentToLine = false;
bool canConvertSegmentToCurve= false;
if (!segments.isEmpty()) {
canSplitAtSegment = segments.size() == 1;
bool hasLines = false;
bool hasCurves = false;
Q_FOREACH (const KoPathPointData &pd, segments) {
KoPathSegment segment = pd.pathShape->segmentByIndex(pd.pointIndex);
hasLines |= segment.degree() == 1;
hasCurves |= segment.degree() > 1;
}
canConvertSegmentToLine = !segments.isEmpty() && hasCurves;
canConvertSegmentToCurve= !segments.isEmpty() && hasLines;
}
m_actionAddPoint->setEnabled(canSplitAtSegment);
m_actionLineSegment->setEnabled(canConvertSegmentToLine);
m_actionCurveSegment->setEnabled(canConvertSegmentToCurve);
m_actionBreakSegment->setEnabled(canSplitAtSegment);
KoSelection *selection = canvas()->selectedShapesProxy()->selection();
bool haveConvertibleShapes = false;
Q_FOREACH (KoShape *shape, selection->selectedEditableShapes()) {
KoParameterShape * parameterShape = dynamic_cast<KoParameterShape*>(shape);
KoSvgTextShape *textShape = dynamic_cast<KoSvgTextShape*>(shape);
if (textShape ||
(parameterShape && parameterShape->isParametricShape())) {
haveConvertibleShapes = true;
break;
}
}
m_actionConvertToPath->setEnabled(haveConvertibleShapes);
}
void KoPathTool::deactivate()
{
Q_D(KoToolBase);
m_shapeFillResourceConnector.disconnect();
m_canvasConnections.clear();
m_pointSelection.clear();
m_pointSelection.setSelectedShapes(QList<KoPathShape*>());
delete m_activeHandle;
m_activeHandle = 0;
delete m_activeSegment;
m_activeSegment = 0;
delete m_currentStrategy;
m_currentStrategy = 0;
d->canvas->snapGuide()->reset();
disconnect(m_actionCurvePoint, 0, this, 0);
disconnect(m_actionLinePoint, 0, this, 0);
disconnect(m_actionLineSegment, 0, this, 0);
disconnect(m_actionCurveSegment, 0, this, 0);
disconnect(m_actionAddPoint, 0, this, 0);
disconnect(m_actionRemovePoint, 0, this, 0);
disconnect(m_actionBreakPoint, 0, this, 0);
disconnect(m_actionBreakSegment, 0, this, 0);
disconnect(m_actionJoinSegment, 0, this, 0);
disconnect(m_actionMergePoints, 0, this, 0);
disconnect(m_actionConvertToPath, 0, this, 0);
disconnect(m_points, 0, this, 0);
disconnect(&m_pointSelection, 0, this, 0);
KoToolBase::deactivate();
}
void KoPathTool::documentResourceChanged(int key, const QVariant & res)
{
if (key == KoDocumentResourceManager::HandleRadius) {
int oldHandleRadius = m_handleRadius;
m_handleRadius = res.toUInt();
// repaint with the bigger of old and new handle radius
int maxRadius = qMax(m_handleRadius, oldHandleRadius);
Q_FOREACH (KoPathShape *shape, m_pointSelection.selectedShapes()) {
QRectF controlPointRect = shape->absoluteTransformation().map(shape->outline()).controlPointRect();
repaint(controlPointRect.adjusted(-maxRadius, -maxRadius, maxRadius, maxRadius));
}
}
}
void KoPathTool::pointSelectionChanged()
{
Q_D(KoToolBase);
updateActions();
#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
d->canvas->snapGuide()->setIgnoredPathPoints(QList<KoPathPoint*>(m_pointSelection.selectedPoints().begin(), m_pointSelection.selectedPoints().end()));
#else
d->canvas->snapGuide()->setIgnoredPathPoints(QList<KoPathPoint*>::fromSet(m_pointSelection.selectedPoints()));
#endif
emit selectionChanged(m_pointSelection.hasSelection());
}
void KoPathTool::repaint(const QRectF &repaintRect)
{
Q_D(KoToolBase);
//debugFlake <<"KoPathTool::repaint(" << repaintRect <<")" << m_handleRadius;
// widen border to take antialiasing into account
qreal radius = m_handleRadius + 1;
d->canvas->updateCanvas(repaintRect.adjusted(-radius, -radius, radius, radius));
}
namespace {
void addActionsGroupIfEnabled(QMenu *menu, QAction *a1, QAction *a2)
{
if (a1->isEnabled() || a2->isEnabled()) {
menu->addAction(a1);
menu->addAction(a2);
menu->addSeparator();
}
}
void addActionsGroupIfEnabled(QMenu *menu, QAction *a1, QAction *a2, QAction *a3)
{
if (a1->isEnabled() || a2->isEnabled()) {
menu->addAction(a1);
menu->addAction(a2);
menu->addAction(a3);
menu->addSeparator();
}
}
}
QMenu *KoPathTool::popupActionsMenu()
{
if (m_activeHandle) {
m_activeHandle->trySelectHandle();
}
if (m_activeSegment && m_activeSegment->isValid()) {
KoPathShape *shape = m_activeSegment->path;
KoPathSegment segment = shape->segmentByIndex(shape->pathPointIndex(m_activeSegment->segmentStart));
m_pointSelection.add(segment.first(), true);
m_pointSelection.add(segment.second(), false);
}
if (m_contextMenu) {
m_contextMenu->clear();
addActionsGroupIfEnabled(m_contextMenu.data(),
m_actionPathPointCorner,
m_actionPathPointSmooth,
m_actionPathPointSymmetric);
addActionsGroupIfEnabled(m_contextMenu.data(),
m_actionCurvePoint,
m_actionLinePoint);
addActionsGroupIfEnabled(m_contextMenu.data(),
m_actionAddPoint,
m_actionRemovePoint);
addActionsGroupIfEnabled(m_contextMenu.data(),
m_actionLineSegment,
m_actionCurveSegment);
addActionsGroupIfEnabled(m_contextMenu.data(),
m_actionBreakPoint,
m_actionBreakSegment);
addActionsGroupIfEnabled(m_contextMenu.data(),
m_actionJoinSegment,
m_actionMergePoints);
m_contextMenu->addAction(m_actionConvertToPath);
m_contextMenu->addSeparator();
}
return m_contextMenu.data();
}
void KoPathTool::deleteSelection()
{
removePoints();
}
KoToolSelection * KoPathTool::selection()
{
return &m_pointSelection;
}
void KoPathTool::requestUndoDuringStroke()
{
// noop!
}
void KoPathTool::requestStrokeCancellation()
{
explicitUserStrokeEndRequest();
}
void KoPathTool::requestStrokeEnd()
{
// noop!
}
void KoPathTool::explicitUserStrokeEndRequest()
{
if (m_activatedTemporarily) {
emit done();
}
}
diff --git a/libs/flake/tools/KoPathToolHandle.cpp b/libs/flake/tools/KoPathToolHandle.cpp
index 57caea09bf..78ed1a2db6 100644
--- a/libs/flake/tools/KoPathToolHandle.cpp
+++ b/libs/flake/tools/KoPathToolHandle.cpp
@@ -1,237 +1,215 @@
/* This file is part of the KDE project
* Copyright (C) 2006,2008 Jan Hambrecht <jaham@gmx.net>
* Copyright (C) 2006,2007 Thorsten Zachmann <zachmann@kde.org>
* Copyright (C) 2007,2010 Thomas Zander <zander@kde.org>
* Copyright (C) 2007 Boudewijn Rempt <boud@valdyas.org>
*
* 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 "KoPathToolHandle.h"
#include "KoPathTool.h"
#include "KoPathPointMoveStrategy.h"
#include "KoPathControlPointMoveStrategy.h"
-#include "KoPathConnectionPointStrategy.h"
#include "KoSelection.h"
#include "commands/KoPathPointTypeCommand.h"
#include "KoParameterChangeStrategy.h"
#include "KoParameterShape.h"
#include "KoCanvasBase.h"
#include "KoDocumentResourceManager.h"
-#include "KoConnectionShape.h"
#include "KoViewConverter.h"
#include "KoPointerEvent.h"
#include "KoShapeController.h"
#include <QPainter>
#include <KisHandlePainterHelper.h>
KoPathToolHandle::KoPathToolHandle(KoPathTool *tool)
: m_tool(tool)
{
}
KoPathToolHandle::~KoPathToolHandle()
{
}
uint KoPathToolHandle::handleRadius() const
{
return m_tool->canvas()->shapeController()->resourceManager()->handleRadius();
}
PointHandle::PointHandle(KoPathTool *tool, KoPathPoint *activePoint, KoPathPoint::PointType activePointType)
: KoPathToolHandle(tool)
, m_activePoint(activePoint)
, m_activePointType(activePointType)
{
}
void PointHandle::paint(QPainter &painter, const KoViewConverter &converter, qreal handleRadius)
{
KoPathToolSelection * selection = dynamic_cast<KoPathToolSelection*>(m_tool->selection());
KoPathPoint::PointTypes allPaintedTypes = KoPathPoint::Node;
if (selection && selection->contains(m_activePoint)) {
allPaintedTypes = KoPathPoint::All;
}
KisHandlePainterHelper helper = KoShape::createHandlePainterHelperView(&painter, m_activePoint->parent(), converter, handleRadius);
if (allPaintedTypes != m_activePointType) {
KoPathPoint::PointTypes nonHighlightedType = allPaintedTypes & ~m_activePointType;
KoPathPoint::PointTypes nonNodeType = nonHighlightedType & ~KoPathPoint::Node;
if (nonNodeType != KoPathPoint::None) {
helper.setHandleStyle(KisHandleStyle::selectedPrimaryHandles());
m_activePoint->paint(helper, nonHighlightedType);
}
if (nonHighlightedType & KoPathPoint::Node) {
helper.setHandleStyle(KisHandleStyle::partiallyHighlightedPrimaryHandles());
m_activePoint->paint(helper, KoPathPoint::Node);
}
}
helper.setHandleStyle(KisHandleStyle::highlightedPrimaryHandles());
m_activePoint->paint(helper, m_activePointType);
}
void PointHandle::repaint() const
{
m_tool->repaint(m_oldRepaintedRect);
bool active = false;
KoPathToolSelection * selection = dynamic_cast<KoPathToolSelection*>(m_tool->selection());
if (selection && selection->contains(m_activePoint))
active = true;
m_oldRepaintedRect = m_activePoint->boundingRect(!active);
m_tool->repaint(m_oldRepaintedRect);
}
KoInteractionStrategy * PointHandle::handleMousePress(KoPointerEvent *event)
{
if ((event->button() & Qt::LeftButton) == 0)
return 0;
if ((event->modifiers() & Qt::ControlModifier) == 0) { // no shift pressed.
KoPathToolSelection * selection = dynamic_cast<KoPathToolSelection*>(m_tool->selection());
// control select adds/removes points to/from the selection
if (event->modifiers() & Qt::ShiftModifier) {
if (selection->contains(m_activePoint)) {
selection->remove(m_activePoint);
} else {
selection->add(m_activePoint, false);
}
m_tool->repaint(m_activePoint->boundingRect(false));
} else {
// no control modifier, so clear selection and select active point
if (!selection->contains(m_activePoint)) {
selection->add(m_activePoint, true);
m_tool->repaint(m_activePoint->boundingRect(false));
}
}
// TODO remove canvas from call ?
if (m_activePointType == KoPathPoint::Node) {
QPointF startPoint = m_activePoint->parent()->shapeToDocument(m_activePoint->point());
return new KoPathPointMoveStrategy(m_tool, startPoint);
} else {
KoPathShape * pathShape = m_activePoint->parent();
KoPathPointData pd(pathShape, pathShape->pathPointIndex(m_activePoint));
return new KoPathControlPointMoveStrategy(m_tool, pd, m_activePointType, event->point);
}
} else {
KoPathPoint::PointProperties props = m_activePoint->properties();
if (! m_activePoint->activeControlPoint1() || ! m_activePoint->activeControlPoint2())
return 0;
KoPathPointTypeCommand::PointType pointType = KoPathPointTypeCommand::Smooth;
// cycle the smooth->symmetric->unsmooth state of the path point
if (props & KoPathPoint::IsSmooth)
pointType = KoPathPointTypeCommand::Symmetric;
else if (props & KoPathPoint::IsSymmetric)
pointType = KoPathPointTypeCommand::Corner;
QList<KoPathPointData> pointData;
pointData.append(KoPathPointData(m_activePoint->parent(), m_activePoint->parent()->pathPointIndex(m_activePoint)));
m_tool->canvas()->addCommand(new KoPathPointTypeCommand(pointData, pointType));
}
return 0;
}
bool PointHandle::check(const QList<KoPathShape*> &selectedShapes)
{
if (selectedShapes.contains(m_activePoint->parent())) {
return m_activePoint->parent()->pathPointIndex(m_activePoint) != KoPathPointIndex(-1, -1);
}
return false;
}
KoPathPoint * PointHandle::activePoint() const
{
return m_activePoint;
}
KoPathPoint::PointType PointHandle::activePointType() const
{
return m_activePointType;
}
void PointHandle::trySelectHandle()
{
KoPathToolSelection * selection = dynamic_cast<KoPathToolSelection*>(m_tool->selection());
if (!selection->contains(m_activePoint) && m_activePointType == KoPathPoint::Node) {
selection->clear();
selection->add(m_activePoint, false);
}
}
ParameterHandle::ParameterHandle(KoPathTool *tool, KoParameterShape *parameterShape, int handleId)
: KoPathToolHandle(tool)
, m_parameterShape(parameterShape)
, m_handleId(handleId)
{
}
void ParameterHandle::paint(QPainter &painter, const KoViewConverter &converter, qreal handleRadius)
{
KisHandlePainterHelper helper = KoShape::createHandlePainterHelperView(&painter, m_parameterShape, converter, handleRadius);
helper.setHandleStyle(KisHandleStyle::highlightedPrimaryHandles());
m_parameterShape->paintHandle(helper, m_handleId);
}
void ParameterHandle::repaint() const
{
m_tool->repaint(m_parameterShape->shapeToDocument(QRectF(m_parameterShape->handlePosition(m_handleId), QSize(1, 1))));
}
KoInteractionStrategy * ParameterHandle::handleMousePress(KoPointerEvent *event)
{
if (event->button() & Qt::LeftButton) {
KoPathToolSelection * selection = dynamic_cast<KoPathToolSelection*>(m_tool->selection());
if (selection)
selection->clear();
return new KoParameterChangeStrategy(m_tool, m_parameterShape, m_handleId);
}
return 0;
}
bool ParameterHandle::check(const QList<KoPathShape*> &selectedShapes)
{
return selectedShapes.contains(m_parameterShape);
}
-
-
-ConnectionHandle::ConnectionHandle(KoPathTool *tool, KoParameterShape *parameterShape, int handleId)
- : ParameterHandle(tool, parameterShape, handleId)
-{
-}
-
-KoInteractionStrategy * ConnectionHandle::handleMousePress(KoPointerEvent *event)
-{
- if (event->button() & Qt::LeftButton) {
- KoPathToolSelection * selection = dynamic_cast<KoPathToolSelection*>(m_tool->selection());
- if (selection)
- selection->clear();
- KoConnectionShape * shape = dynamic_cast<KoConnectionShape*>(m_parameterShape);
- if (! shape)
- return 0;
- return new KoPathConnectionPointStrategy(m_tool, shape, m_handleId);
- }
- return 0;
-}
diff --git a/libs/flake/tools/KoPathToolHandle.h b/libs/flake/tools/KoPathToolHandle.h
index 76fdac465a..39c77eab8c 100644
--- a/libs/flake/tools/KoPathToolHandle.h
+++ b/libs/flake/tools/KoPathToolHandle.h
@@ -1,99 +1,89 @@
/* This file is part of the KDE project
* Copyright (C) 2006,2008 Jan Hambrecht <jaham@gmx.net>
* Copyright (C) 2006,2007 Thorsten Zachmann <zachmann@kde.org>
* Copyright (C) 2007,2010 Thomas Zander <zander@kde.org>
* Copyright (C) 2007 Boudewijn Rempt <boud@valdyas.org>
*
* 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 KOPATHTOOLHANDLE_H
#define KOPATHTOOLHANDLE_H
#include <KoPathPoint.h>
#include "KoInteractionStrategy.h"
#include <QList>
#include <QRect>
class KoPathTool;
class KoParameterShape;
class KoViewConverter;
class KoPointerEvent;
class QPainter;
class KoPathShape;
class KisHandlePainterHelper;
class KoPathToolHandle
{
public:
explicit KoPathToolHandle(KoPathTool *tool);
virtual ~KoPathToolHandle();
virtual void paint(QPainter &painter, const KoViewConverter &converter, qreal handleRadius) = 0;
virtual void repaint() const = 0;
virtual KoInteractionStrategy * handleMousePress(KoPointerEvent *event) = 0;
// test if handle is still valid
virtual bool check(const QList<KoPathShape*> &selectedShapes) = 0;
virtual void trySelectHandle() {};
protected:
uint handleRadius() const;
KoPathTool *m_tool;
};
class PointHandle : public KoPathToolHandle
{
public:
PointHandle(KoPathTool *tool, KoPathPoint *activePoint, KoPathPoint::PointType activePointType);
void paint(QPainter &painter, const KoViewConverter &converter, qreal handleRadius) override;
void repaint() const override;
KoInteractionStrategy *handleMousePress(KoPointerEvent *event) override;
bool check(const QList<KoPathShape*> &selectedShapes) override;
KoPathPoint *activePoint() const;
KoPathPoint::PointType activePointType() const;
void trySelectHandle() override;
private:
KoPathPoint *m_activePoint;
KoPathPoint::PointType m_activePointType;
mutable QRectF m_oldRepaintedRect;
};
class ParameterHandle : public KoPathToolHandle
{
public:
ParameterHandle(KoPathTool *tool, KoParameterShape *parameterShape, int handleId);
void paint(QPainter &painter, const KoViewConverter &converter, qreal handleRadius) override;
void repaint() const override;
KoInteractionStrategy *handleMousePress(KoPointerEvent *event) override;
bool check(const QList<KoPathShape*> &selectedShapes) override;
protected:
KoParameterShape *m_parameterShape;
int m_handleId;
};
-class ConnectionHandle : public ParameterHandle
-{
-public:
- ConnectionHandle(KoPathTool *tool, KoParameterShape *parameterShape, int handleId);
-
- // XXX: Later: create a paint even to distinguish a connection
- // handle from another handle type
- KoInteractionStrategy *handleMousePress(KoPointerEvent *event) override;
-};
-
#endif // KOPATHTOOLHANDLE_H
diff --git a/libs/global/CMakeLists.txt b/libs/global/CMakeLists.txt
index e8162c5e46..b5703b9c32 100644
--- a/libs/global/CMakeLists.txt
+++ b/libs/global/CMakeLists.txt
@@ -1,61 +1,62 @@
add_subdirectory( tests )
include(CheckFunctionExists)
check_function_exists(backtrace HAVE_BACKTRACE)
configure_file(config-debug.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-debug.h)
option(HAVE_MEMORY_LEAK_TRACKER "Enable memory leak tracker (always disabled in release build)" OFF)
option(HAVE_BACKTRACE_SUPPORT "Enable recording of backtrace in memory leak tracker" OFF)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config-memory-leak-tracker.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-memory-leak-tracker.h) ### WRONG PLACE???
include_directories(SYSTEM
${EIGEN3_INCLUDE_DIR}
)
set(kritaglobal_LIB_SRCS
kis_assert.cpp
kis_debug.cpp
kis_algebra_2d.cpp
kis_memory_leak_tracker.cpp
kis_shared.cpp
kis_dom_utils.cpp
kis_painting_tweaks.cpp
KisHandlePainterHelper.cpp
KisHandleStyle.cpp
kis_signal_compressor.cpp
kis_signal_compressor_with_param.cpp
kis_thread_safe_signal_compressor.cpp
kis_acyclic_signal_connector.cpp
kis_latency_tracker.cpp
KisQPainterStateSaver.cpp
KisSharedThreadPoolAdapter.cpp
KisSharedRunnable.cpp
KisRollingMeanAccumulatorWrapper.cpp
kis_config_notifier.cpp
KisDeleteLaterWrapper.cpp
KisUsageLogger.cpp
KisFileUtils.cpp
KisSignalMapper.cpp
KisRegion.cpp
+ KoUnit.cpp
)
add_library(kritaglobal SHARED ${kritaglobal_LIB_SRCS} )
generate_export_header(kritaglobal BASE_NAME kritaglobal)
target_link_libraries(kritaglobal
PUBLIC
kritaversion
Qt5::Concurrent
Qt5::Core
Qt5::Gui
Qt5::Widgets
Qt5::Xml
KF5::I18n
)
set_target_properties(kritaglobal PROPERTIES
VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION}
)
install(TARGETS kritaglobal ${INSTALL_TARGETS_DEFAULT_ARGS})
diff --git a/libs/global/KisRegion.cpp b/libs/global/KisRegion.cpp
index 915dfa14c3..d346a0924f 100644
--- a/libs/global/KisRegion.cpp
+++ b/libs/global/KisRegion.cpp
@@ -1,209 +1,406 @@
/*
* Copyright (c) 2020 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "KisRegion.h"
#include <QRegion>
+#include "kis_debug.h"
namespace detail {
struct HorizontalMergePolicy
{
static int col(const QRect &rc) {
return rc.x();
}
static int nextCol(const QRect &rc) {
return rc.x() + rc.width();
}
static int rowHeight(const QRect &rc) {
return rc.height();
}
static bool rowIsLess(const QRect &lhs, const QRect &rhs) {
return lhs.y() < rhs.y();
}
static bool elementIsLess(const QRect &lhs, const QRect &rhs) {
return lhs.y() < rhs.y() || (lhs.y() == rhs.y() && lhs.x() < rhs.x());
}
};
struct VerticalMergePolicy
{
static int col(const QRect &rc) {
return rc.y();
}
static int nextCol(const QRect &rc) {
return rc.y() + rc.height();
}
static int rowHeight(const QRect &rc) {
return rc.width();
}
static bool rowIsLess(const QRect &lhs, const QRect &rhs) {
return lhs.x() < rhs.x();
}
static bool elementIsLess(const QRect &lhs, const QRect &rhs) {
return lhs.x() < rhs.x() || (lhs.x() == rhs.x() && lhs.y() < rhs.y());
}
};
template <typename MergePolicy>
QVector<QRect>::iterator mergeRects(QVector<QRect>::iterator beginIt,
QVector<QRect>::iterator endIt,
MergePolicy policy)
{
if (beginIt == endIt) return endIt;
std::sort(beginIt, endIt, MergePolicy::elementIsLess);
auto resultIt = beginIt;
auto it = std::next(beginIt);
while (it != endIt) {
auto rowEnd = std::upper_bound(it, endIt, *it, MergePolicy::rowIsLess);
for (auto rowIt = it; rowIt != rowEnd; ++rowIt) {
if (policy.rowHeight(*resultIt) == policy.rowHeight(*rowIt) &&
policy.nextCol(*resultIt) == policy.col(*rowIt)) {
*resultIt |= *rowIt;
} else {
resultIt++;
*resultIt = *rowIt;
}
}
it = rowEnd;
}
return std::next(resultIt);
}
+
+struct VerticalSplitPolicy
+{
+ static int rowStart(const QRect &rc) {
+ return rc.y();
+ }
+ static int rowEnd(const QRect &rc) {
+ return rc.bottom();
+ }
+ static int rowHeight(const QRect &rc) {
+ return rc.height();
+ }
+ static void setRowEnd(QRect &rc, int rowEnd) {
+ return rc.setBottom(rowEnd);
+ }
+ static bool rowIsLess(const QRect &lhs, const QRect &rhs) {
+ return lhs.y() < rhs.y();
+ }
+ static QRect splitRectHi(const QRect &rc, int rowEnd) {
+ return QRect(rc.x(), rc.y(),
+ rc.width(), rowEnd - rc.y() + 1);
+ }
+ static QRect splitRectLo(const QRect &rc, int rowEnd) {
+ return QRect(rc.x(), rowEnd + 1,
+ rc.width(), rc.height() - (rowEnd - rc.y() + 1));
+ }
+};
+
+struct HorizontalSplitPolicy
+{
+ static int rowStart(const QRect &rc) {
+ return rc.x();
+ }
+ static int rowEnd(const QRect &rc) {
+ return rc.right();
+ }
+ static int rowHeight(const QRect &rc) {
+ return rc.width();
+ }
+ static void setRowEnd(QRect &rc, int rowEnd) {
+ return rc.setRight(rowEnd);
+ }
+ static bool rowIsLess(const QRect &lhs, const QRect &rhs) {
+ return lhs.x() < rhs.x();
+ }
+ static QRect splitRectHi(const QRect &rc, int rowEnd) {
+ return QRect(rc.x(), rc.y(),
+ rowEnd - rc.x() + 1, rc.height());
+ }
+ static QRect splitRectLo(const QRect &rc, int rowEnd) {
+ return QRect(rowEnd + 1, rc.y(),
+ rc.width() - (rowEnd - rc.x() + 1), rc.height());
+ }
+};
+
+
+struct VoidNoOp {
+ void operator()() const { };
+ template<typename P1, typename... Params>
+ void operator()(P1 p1, Params... parameters) {
+ Q_UNUSED(p1);
+ operator()(parameters...);
+ }
+};
+
+struct MergeRectsOp
+{
+ MergeRectsOp(QVector<QRect> &source, QVector<QRect> &destination)
+ : m_source(source),
+ m_destination(destination)
+ {
+ }
+
+ void operator()() {
+ m_destination.append(std::accumulate(m_source.begin(), m_source.end(),
+ QRect(), std::bit_or<QRect>()));
+ m_source.clear();
+ }
+
+private:
+ QVector<QRect> &m_source;
+ QVector<QRect> &m_destination;
+};
+
+template <typename Policy, typename RowMergeOp, typename OutIt>
+void splitRects(QVector<QRect>::iterator beginIt, QVector<QRect>::iterator endIt,
+ OutIt resultIt,
+ QVector<QRect> tempBuf[2],
+ int gridSize,
+ RowMergeOp rowMergeOp)
+{
+ if (beginIt == endIt) return;
+
+ QVector<QRect> &nextRowExtra = tempBuf[0];
+ QVector<QRect> &nextRowExtraTmp = tempBuf[1];
+
+ std::sort(beginIt, endIt, Policy::rowIsLess);
+ int rowStart = Policy::rowStart(*beginIt);
+ int rowEnd = rowStart + gridSize - 1;
+
+ auto it = beginIt;
+ while (1) {
+ bool switchToNextRow = false;
+
+ if (it == endIt) {
+ if (nextRowExtra.isEmpty()) {
+ rowMergeOp();
+ break;
+ } else {
+ switchToNextRow = true;
+ }
+ } else if (Policy::rowStart(*it) > rowEnd) {
+ switchToNextRow = true;
+ }
+
+ if (switchToNextRow) {
+ rowMergeOp();
+
+ if (!nextRowExtra.isEmpty()) {
+ rowStart = Policy::rowStart(nextRowExtra.first());
+ rowEnd = rowStart + gridSize - 1;
+
+ for (auto nextIt = nextRowExtra.begin(); nextIt != nextRowExtra.end(); ++nextIt) {
+ if (Policy::rowEnd(*nextIt) > rowEnd) {
+ nextRowExtraTmp.append(Policy::splitRectLo(*nextIt, rowEnd));
+ *resultIt++ = Policy::splitRectHi(*nextIt, rowEnd);
+ } else {
+ *resultIt++ = *nextIt;
+ }
+ }
+ nextRowExtra.clear();
+ std::swap(nextRowExtra, nextRowExtraTmp);
+
+ continue;
+ } else {
+ rowStart = Policy::rowStart(*it);
+ rowEnd = rowStart + gridSize - 1;
+ }
+ }
+
+ if (Policy::rowEnd(*it) > rowEnd) {
+ nextRowExtra.append(Policy::splitRectLo(*it, rowEnd));
+ *resultIt++ = Policy::splitRectHi(*it, rowEnd);
+ } else {
+ *resultIt++ = *it;
+ }
+
+ ++it;
+ }
+}
+
}
QVector<QRect>::iterator KisRegion::mergeSparseRects(QVector<QRect>::iterator beginIt, QVector<QRect>::iterator endIt)
{
endIt = detail::mergeRects(beginIt, endIt, detail::HorizontalMergePolicy());
endIt = detail::mergeRects(beginIt, endIt, detail::VerticalMergePolicy());
return endIt;
}
+void KisRegion::approximateOverlappingRects(QVector<QRect> &rects, int gridSize)
+{
+ using namespace detail;
+
+ if (rects.isEmpty()) return;
+
+ QVector<QRect> rowsBuf;
+ QVector<QRect> intermediate;
+ QVector<QRect> tempBuf[2];
+
+ splitRects<VerticalSplitPolicy>(rects.begin(), rects.end(),
+ std::back_inserter(rowsBuf),
+ tempBuf, gridSize, VoidNoOp());
+
+ rects.clear();
+ KIS_SAFE_ASSERT_RECOVER_NOOP(tempBuf[0].isEmpty());
+ KIS_SAFE_ASSERT_RECOVER_NOOP(tempBuf[1].isEmpty());
+
+ auto rowBegin = rowsBuf.begin();
+ while (rowBegin != rowsBuf.end()) {
+ auto rowEnd = std::upper_bound(rowBegin, rowsBuf.end(),
+ QRect(rowBegin->x(),
+ rowBegin->y() + gridSize - 1,
+ 1,1),
+ VerticalSplitPolicy::rowIsLess);
+
+ splitRects<HorizontalSplitPolicy>(rowBegin, rowEnd,
+ std::back_inserter(intermediate),
+ tempBuf, gridSize,
+ MergeRectsOp(intermediate, rects));
+ rowBegin = rowEnd;
+
+ KIS_SAFE_ASSERT_RECOVER_NOOP(intermediate.isEmpty());
+ KIS_SAFE_ASSERT_RECOVER_NOOP(tempBuf[0].isEmpty());
+ KIS_SAFE_ASSERT_RECOVER_NOOP(tempBuf[1].isEmpty());
+ }
+}
+
KisRegion::KisRegion(const QRect &rect)
{
m_rects << rect;
}
KisRegion::KisRegion(std::initializer_list<QRect> rects)
: m_rects(rects)
{
}
KisRegion::KisRegion(const QVector<QRect> &rects)
: m_rects(rects)
{
mergeAllRects();
}
KisRegion::KisRegion(QVector<QRect> &&rects)
: m_rects(rects)
{
mergeAllRects();
}
KisRegion &KisRegion::operator=(const KisRegion &rhs)
{
m_rects = rhs.m_rects;
return *this;
}
KisRegion &KisRegion::operator&=(const QRect &rect)
{
for (auto it = m_rects.begin(); it != m_rects.end(); /* noop */) {
*it &= rect;
if (it->isEmpty()) {
it = m_rects.erase(it);
} else {
++it;
}
}
mergeAllRects();
return *this;
}
QRect KisRegion::boundingRect() const
{
return std::accumulate(m_rects.constBegin(), m_rects.constEnd(), QRect(), std::bit_or<QRect>());
}
QVector<QRect> KisRegion::rects() const
{
return m_rects;
}
int KisRegion::rectCount() const
{
return m_rects.size();
}
bool KisRegion::isEmpty() const
{
return boundingRect().isEmpty();
}
QRegion KisRegion::toQRegion() const
{
// TODO: ustilize QRegion::setRects to make creation of QRegion much
// faster. The only reason why we cannot use it "as is", our m_rects
// do not satisfy the second setRects()'s precondition: "All rectangles with
// a given top coordinate must have the same height". We can implement an
// simple algorithm for cropping m_rects, and it will be much faster than
// constructing QRegion iterationally.
return std::accumulate(m_rects.constBegin(), m_rects.constEnd(), QRegion(), std::bit_or<QRegion>());
}
void KisRegion::translate(int dx, int dy)
{
std::transform(m_rects.begin(), m_rects.end(),
m_rects.begin(),
[dx, dy] (const QRect &rc) { return rc.translated(dx, dy); });
}
KisRegion KisRegion::translated(int dx, int dy) const
{
KisRegion region(*this);
region.translate(dx, dy);
return region;
}
KisRegion KisRegion::fromQRegion(const QRegion &region)
{
KisRegion result;
result.m_rects.clear();
QRegion::const_iterator begin = region.begin();
while (begin != region.end()) {
result.m_rects << *begin;
begin++;
}
return result;
}
+KisRegion KisRegion::fromOverlappingRects(const QVector<QRect> &rects, int gridSize)
+{
+ QVector<QRect> tmp = rects;
+ approximateOverlappingRects(tmp, gridSize);
+ return KisRegion(tmp);
+}
+
void KisRegion::mergeAllRects()
{
auto endIt = mergeSparseRects(m_rects.begin(), m_rects.end());
m_rects.erase(endIt, m_rects.end());
}
bool operator==(const KisRegion &lhs, const KisRegion &rhs)
{
return lhs.m_rects == rhs.m_rects;
}
diff --git a/libs/global/KisRegion.h b/libs/global/KisRegion.h
index 6b21f8b563..b9fa01ce64 100644
--- a/libs/global/KisRegion.h
+++ b/libs/global/KisRegion.h
@@ -1,98 +1,114 @@
/*
* Copyright (c) 2020 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KISREGION_H
#define KISREGION_H
#include "kritaglobal_export.h"
#include <QVector>
#include <QRect>
#include <boost/operators.hpp>
class QRegion;
/**
* An more efficient (and more limited) replacement for QRegion.
*
* Its main purpose it to be able to merge a huge set of rectangles
* into a smalles set of bigger rectangles, the same thing that QRegion
* is supposed to do. The main difference (and limitation) is: all the
* input rects must be non-intersecting. This requirement is perfectly
* fine for Krita's tiles, which do never intersect.
*/
class KRITAGLOBAL_EXPORT KisRegion :
public boost::equality_comparable<KisRegion>,
public boost::andable<KisRegion, QRect>
{
public:
/**
* @brief merge a set of rectanges into a smaller set of bigger rectangles
*
* The algorithm does two passes over the rectanges. First it tries to
* merge all the rectanges horizontally, then vertically. The merge happens
* in-place, that is, all the merged elements will be moved to the front
* of the original range.
*
* The final range is defined by [beginIt, retvalIt)
*
* @param beginIt iterator to the beginning of the source range
* @param endIt iterator to the end of the source range
* @return iteration pointing past the last element of the merged range
*/
static QVector<QRect>::iterator mergeSparseRects(QVector<QRect>::iterator beginIt, QVector<QRect>::iterator endIt);
+
+ /**
+ * Simplifies \p rects in a way that they don't overlap anymore. The actual
+ * resulting area may be larger than original \p rects, but not more than
+ * \p gridSize in any dimension.
+ */
+ static void approximateOverlappingRects(QVector<QRect> &rects, int gridSize);
+
+
public:
KisRegion() = default;
KisRegion(const KisRegion &rhs) = default;
KisRegion(const QRect &rect);
KisRegion(std::initializer_list<QRect> rects);
/**
* @brief creates a region from a set of non-intersecting rectanges
* @param rects rectangles that should be merged. Rectangles must not intersect.
*/
KisRegion(const QVector<QRect> &rects);
KisRegion(QVector<QRect> &&rects);
KisRegion& operator=(const KisRegion &rhs);
friend bool operator==(const KisRegion &lhs, const KisRegion &rhs);
KisRegion& operator&=(const QRect &rect);
QRect boundingRect() const;
QVector<QRect> rects() const;
int rectCount() const;
bool isEmpty() const;
QRegion toQRegion() const;
void translate(int dx, int dy);
KisRegion translated(int x, int y) const;
static KisRegion fromQRegion(const QRegion &region);
+ /**
+ * Approximates a KisRegion from \p rects, which may overlap. The resulting
+ * KisRegion may be larger than the original set of rects, but it is guaranteed
+ * to cover it completely.
+ */
+ static KisRegion fromOverlappingRects(const QVector<QRect> &rects, int gridSize);
+
private:
void mergeAllRects();
private:
QVector<QRect> m_rects;
};
KRITAGLOBAL_EXPORT bool operator==(const KisRegion &lhs, const KisRegion &rhs);
#endif // KISREGION_H
diff --git a/libs/global/KisUsageLogger.cpp b/libs/global/KisUsageLogger.cpp
index 46ef05ce0d..4f6b6a5eea 100644
--- a/libs/global/KisUsageLogger.cpp
+++ b/libs/global/KisUsageLogger.cpp
@@ -1,253 +1,259 @@
/*
* Copyright (c) 2019 Boudewijn Rempt <boud@valdyas.org>
*
* 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 "KisUsageLogger.h"
#include <QScreen>
#include <QGlobalStatic>
#include <QDebug>
#include <QDateTime>
#include <QSysInfo>
#include <QStandardPaths>
#include <QFile>
#include <QFileInfo>
#include <QDesktopWidget>
#include <QClipboard>
#include <QThread>
#include <QApplication>
#include <klocalizedstring.h>
#include <KritaVersionWrapper.h>
#include <QGuiApplication>
+#include <QStyle>
+#include <QStyleFactory>
Q_GLOBAL_STATIC(KisUsageLogger, s_instance)
const QString KisUsageLogger::s_sectionHeader("================================================================================\n");
struct KisUsageLogger::Private {
bool active {false};
QFile logFile;
QFile sysInfoFile;
};
KisUsageLogger::KisUsageLogger()
: d(new Private)
{
d->logFile.setFileName(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/krita.log");
d->sysInfoFile.setFileName(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/krita-sysinfo.log");
rotateLog();
d->logFile.open(QFile::Append | QFile::Text);
d->sysInfoFile.open(QFile::WriteOnly | QFile::Text);
}
KisUsageLogger::~KisUsageLogger()
{
if (d->active) {
close();
}
}
void KisUsageLogger::initialize()
{
s_instance->d->active = true;
QString systemInfo = basicSystemInfo();
s_instance->d->sysInfoFile.write(systemInfo.toUtf8());
}
QString KisUsageLogger::basicSystemInfo()
{
QString systemInfo;
// NOTE: This is intentionally not translated!
// Krita version info
systemInfo.append("Krita\n");
systemInfo.append("\n Version: ").append(KritaVersionWrapper::versionString(true));
systemInfo.append("\n Languages: ").append(KLocalizedString::languages().join(", "));
systemInfo.append("\n Hidpi: ").append(QCoreApplication::testAttribute(Qt::AA_EnableHighDpiScaling) ? "true" : "false");
systemInfo.append("\n\n");
systemInfo.append("Qt\n");
systemInfo.append("\n Version (compiled): ").append(QT_VERSION_STR);
systemInfo.append("\n Version (loaded): ").append(qVersion());
systemInfo.append("\n\n");
// OS information
systemInfo.append("OS Information\n");
systemInfo.append("\n Build ABI: ").append(QSysInfo::buildAbi());
systemInfo.append("\n Build CPU: ").append(QSysInfo::buildCpuArchitecture());
systemInfo.append("\n CPU: ").append(QSysInfo::currentCpuArchitecture());
systemInfo.append("\n Kernel Type: ").append(QSysInfo::kernelType());
systemInfo.append("\n Kernel Version: ").append(QSysInfo::kernelVersion());
systemInfo.append("\n Pretty Productname: ").append(QSysInfo::prettyProductName());
systemInfo.append("\n Product Type: ").append(QSysInfo::productType());
systemInfo.append("\n Product Version: ").append(QSysInfo::productVersion());
#ifdef Q_OS_LINUX
systemInfo.append("\n Desktop: ").append(qgetenv("XDG_CURRENT_DESKTOP"));
#endif
systemInfo.append("\n\n");
return systemInfo;
}
void KisUsageLogger::close()
{
log("CLOSING SESSION");
s_instance->d->active = false;
s_instance->d->logFile.flush();
s_instance->d->logFile.close();
s_instance->d->sysInfoFile.flush();
s_instance->d->sysInfoFile.close();
}
void KisUsageLogger::log(const QString &message)
{
if (!s_instance->d->active) return;
if (!s_instance->d->logFile.isOpen()) return;
s_instance->d->logFile.write(QDateTime::currentDateTime().toString(Qt::RFC2822Date).toUtf8());
s_instance->d->logFile.write(": ");
write(message);
}
void KisUsageLogger::write(const QString &message)
{
if (!s_instance->d->active) return;
if (!s_instance->d->logFile.isOpen()) return;
s_instance->d->logFile.write(message.toUtf8());
s_instance->d->logFile.write("\n");
s_instance->d->logFile.flush();
}
void KisUsageLogger::writeSysInfo(const QString &message)
{
if (!s_instance->d->active) return;
if (!s_instance->d->sysInfoFile.isOpen()) return;
s_instance->d->sysInfoFile.write(message.toUtf8());
s_instance->d->sysInfoFile.write("\n");
s_instance->d->sysInfoFile.flush();
}
void KisUsageLogger::writeHeader()
{
Q_ASSERT(s_instance->d->sysInfoFile.isOpen());
s_instance->d->logFile.write(s_sectionHeader.toUtf8());
QString sessionHeader = QString("SESSION: %1. Executing %2\n\n")
.arg(QDateTime::currentDateTime().toString(Qt::RFC2822Date))
.arg(qApp->arguments().join(' '));
s_instance->d->logFile.write(sessionHeader.toUtf8());
QString KritaAndQtVersion;
KritaAndQtVersion.append("Krita Version: ").append(KritaVersionWrapper::versionString(true))
.append(", Qt version compiled: ").append(QT_VERSION_STR)
.append(", loaded: ").append(qVersion())
.append(". Process ID: ")
.append(QString::number(qApp->applicationPid())).append("\n");
KritaAndQtVersion.append("-- -- -- -- -- -- -- --\n");
s_instance->d->logFile.write(KritaAndQtVersion.toUtf8());
s_instance->d->logFile.flush();
+ log(QString("Style: %1. Available styles: %2")
+ .arg(qApp->style()->objectName(),
+ QStyleFactory::keys().join(", ")));
+
}
QString KisUsageLogger::screenInformation()
{
QList<QScreen*> screens = qApp->screens();
QString info;
info.append("Display Information");
info.append("\nNumber of screens: ").append(QString::number(screens.size()));
for (int i = 0; i < screens.size(); ++i ) {
QScreen *screen = screens[i];
info.append("\n\tScreen: ").append(QString::number(i));
info.append("\n\t\tName: ").append(screen->name());
info.append("\n\t\tDepth: ").append(QString::number(screen->depth()));
info.append("\n\t\tScale: ").append(QString::number(screen->devicePixelRatio()));
info.append("\n\t\tResolution in pixels: ").append(QString::number(screen->geometry().width()))
.append("x")
.append(QString::number(screen->geometry().height()));
info.append("\n\t\tManufacturer: ").append(screen->manufacturer());
info.append("\n\t\tModel: ").append(screen->model());
info.append("\n\t\tRefresh Rate: ").append(QString::number(screen->refreshRate()));
}
info.append("\n");
return info;
}
void KisUsageLogger::rotateLog()
{
if (d->logFile.exists()) {
{
// Check for CLOSING SESSION
d->logFile.open(QFile::ReadOnly);
QString log = QString::fromUtf8(d->logFile.readAll());
if (!log.split(s_sectionHeader).last().contains("CLOSING SESSION")) {
log.append("\nKRITA DID NOT CLOSE CORRECTLY\n");
QString crashLog = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/kritacrash.log");
if (QFileInfo(crashLog).exists()) {
QFile f(crashLog);
f.open(QFile::ReadOnly);
QString crashes = QString::fromUtf8(f.readAll());
f.close();
QStringList crashlist = crashes.split("-------------------");
log.append(QString("\nThere were %1 crashes in total in the crash log.\n").arg(crashlist.size()));
if (crashes.size() > 0) {
log.append(crashlist.last());
}
}
d->logFile.close();
d->logFile.open(QFile::WriteOnly);
d->logFile.write(log.toUtf8());
}
d->logFile.flush();
d->logFile.close();
}
{
// Rotate
d->logFile.open(QFile::ReadOnly);
QString log = QString::fromUtf8(d->logFile.readAll());
int sectionCount = log.count(s_sectionHeader);
int nextSectionIndex = log.indexOf(s_sectionHeader, s_sectionHeader.length());
while(sectionCount >= s_maxLogs) {
log = log.remove(0, log.indexOf(s_sectionHeader, nextSectionIndex));
nextSectionIndex = log.indexOf(s_sectionHeader, s_sectionHeader.length());
sectionCount = log.count(s_sectionHeader);
}
d->logFile.close();
d->logFile.open(QFile::WriteOnly);
d->logFile.write(log.toUtf8());
d->logFile.flush();
d->logFile.close();
}
}
}
diff --git a/libs/odf/KoUnit.cpp b/libs/global/KoUnit.cpp
similarity index 98%
rename from libs/odf/KoUnit.cpp
rename to libs/global/KoUnit.cpp
index 92938cdd3a..966803a973 100644
--- a/libs/odf/KoUnit.cpp
+++ b/libs/global/KoUnit.cpp
@@ -1,423 +1,421 @@
/* This file is part of the KDE project
Copyright (C) 2001 David Faure <faure@kde.org>
Copyright (C) 2004, Nicolas GOUTTE <goutte@kde.org>
Copyright 2012 Friedrich W. H. Kossebau <kossebau@kde.org>
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 "KoUnit.h"
#include <cmath>
#include <QTransform>
#include <klocalizedstring.h>
-#include <OdfDebug.h>
#include <QtGlobal>
// ensure the same order as in KoUnit::Unit
static const char* const unitNameList[KoUnit::TypeCount] =
{
"mm",
"pt",
"in",
"cm",
"dm",
"pi",
"cc",
"px"
};
QString KoUnit::unitDescription(KoUnit::Type type)
{
switch (type) {
case KoUnit::Millimeter:
return i18n("Millimeters (mm)");
case KoUnit::Centimeter:
return i18n("Centimeters (cm)");
case KoUnit::Decimeter:
return i18n("Decimeters (dm)");
case KoUnit::Inch:
return i18n("Inches (in)");
case KoUnit::Pica:
return i18n("Pica (pi)");
case KoUnit::Cicero:
return i18n("Cicero (cc)");
case KoUnit::Point:
return i18n("Points (pt)");
case KoUnit::Pixel:
return i18n("Pixels (px)");
default:
return i18n("Unsupported unit");
}
}
// grouped by units which are similar
static const KoUnit::Type typesInUi[KoUnit::TypeCount] =
{
KoUnit::Millimeter,
KoUnit::Centimeter,
KoUnit::Decimeter,
KoUnit::Inch,
KoUnit::Pica,
KoUnit::Cicero,
KoUnit::Point,
KoUnit::Pixel,
};
QStringList KoUnit::listOfUnitNameForUi(ListOptions listOptions)
{
QStringList lst;
for (int i = 0; i < KoUnit::TypeCount; ++i) {
const Type type = typesInUi[i];
if ((type != Pixel) || ((listOptions & HideMask) == ListAll))
lst.append(unitDescription(type));
}
return lst;
}
KoUnit KoUnit::fromListForUi(int index, ListOptions listOptions, qreal factor)
{
KoUnit::Type type = KoUnit::Point;
if ((0 <= index) && (index < KoUnit::TypeCount)) {
// iterate through all enums and skip the Pixel enum if needed
for (int i = 0; i < KoUnit::TypeCount; ++i) {
if ((listOptions&HidePixel) && (typesInUi[i] == Pixel)) {
++index;
continue;
}
if (i == index) {
type = typesInUi[i];
break;
}
}
}
return KoUnit(type, factor);
}
int KoUnit::indexInListForUi(ListOptions listOptions) const
{
if ((listOptions&HidePixel) && (m_type == Pixel)) {
return -1;
}
int result = -1;
int skipped = 0;
for (int i = 0; i < KoUnit::TypeCount; ++i) {
if ((listOptions&HidePixel) && (typesInUi[i] == Pixel)) {
++skipped;
continue;
}
if (typesInUi[i] == m_type) {
result = i - skipped;
break;
}
}
return result;
}
qreal KoUnit::toUserValueRounded(const qreal value) const
{
qreal userValue = toUserValuePrecise(value);
qreal rounding = 1.0;
switch (m_type) {
case Pixel:
return userValue; // no rounding for Pixel value
case Millimeter:
rounding = MM_ROUNDING;
break;
case Centimeter:
rounding = CM_ROUNDING;
break;
case Decimeter:
rounding = DM_ROUNDING;
break;
case Inch:
rounding = IN_ROUNDING;
break;
case Pica:
rounding = PI_ROUNDING;
break;
case Cicero:
rounding = CC_ROUNDING;
break;
case Point:
default:
rounding = PT_ROUNDING;
}
return floor(userValue * rounding) / rounding;
}
qreal KoUnit::toUserValuePrecise(const qreal ptValue) const
{
switch (m_type) {
case Millimeter:
return POINT_TO_MM(ptValue);
case Centimeter:
return POINT_TO_CM(ptValue);
case Decimeter:
return POINT_TO_DM(ptValue);
case Inch:
return POINT_TO_INCH(ptValue);
case Pica:
return POINT_TO_PI(ptValue);
case Cicero:
return POINT_TO_CC(ptValue);
case Pixel:
return ptValue * m_pixelConversion;
case Point:
default:
return ptValue;
}
}
qreal KoUnit::toUserValue(qreal ptValue, bool rounding) const
{
if (rounding) {
return toUserValueRounded(ptValue);
}
else {
return toUserValuePrecise(ptValue);
}
}
QString KoUnit::toUserStringValue(qreal ptValue) const
{
return QLocale().toString(toUserValue(ptValue));
}
qreal KoUnit::fromUserValue(qreal value) const
{
switch (m_type) {
case Millimeter:
return MM_TO_POINT(value);
case Centimeter:
return CM_TO_POINT(value);
case Decimeter:
return DM_TO_POINT(value);
case Inch:
return INCH_TO_POINT(value);
case Pica:
return PI_TO_POINT(value);
case Cicero:
return CC_TO_POINT(value);
case Pixel:
return value / m_pixelConversion;
case Point:
default:
return value;
}
}
qreal KoUnit::fromUserValue(const QString &value, bool *ok) const
{
return fromUserValue(QLocale().toDouble(value, ok));
}
qreal KoUnit::parseValue(const QString& _value, qreal defaultVal)
{
if (_value.isEmpty())
return defaultVal;
QString value(_value.simplified());
value.remove(QLatin1Char(' '));
int firstLetter = -1;
for (int i = 0; i < value.length(); ++i) {
if (value.at(i).isLetter()) {
if (value.at(i) == QLatin1Char('e'))
continue;
firstLetter = i;
break;
}
}
if (firstLetter == -1)
return value.toDouble();
const QString symbol = value.mid(firstLetter);
value.truncate(firstLetter);
const qreal val = value.toDouble();
if (symbol == QLatin1String("pt"))
return val;
bool ok;
KoUnit u = KoUnit::fromSymbol(symbol, &ok);
if (ok)
return u.fromUserValue(val);
if (symbol == QLatin1String("m"))
return DM_TO_POINT(val * 10.0);
else if (symbol == QLatin1String("km"))
return DM_TO_POINT(val * 10000.0);
- warnOdf << "KoUnit::parseValue: Unit " << symbol << " is not supported, please report.";
// TODO : add support for mi/ft ?
return defaultVal;
}
KoUnit KoUnit::fromSymbol(const QString &symbol, bool *ok)
{
Type result = Point;
if (symbol == QLatin1String("inch") /*compat*/) {
result = Inch;
if (ok)
*ok = true;
} else {
if (ok)
*ok = false;
for (int i = 0; i < TypeCount; ++i) {
if (symbol == QLatin1String(unitNameList[i])) {
result = static_cast<Type>(i);
if (ok)
*ok = true;
}
}
}
return KoUnit(result);
}
qreal KoUnit::convertFromUnitToUnit(const qreal value, const KoUnit &fromUnit, const KoUnit &toUnit, qreal factor)
{
qreal pt;
switch (fromUnit.type()) {
case Millimeter:
pt = MM_TO_POINT(value);
break;
case Centimeter:
pt = CM_TO_POINT(value);
break;
case Decimeter:
pt = DM_TO_POINT(value);
break;
case Inch:
pt = INCH_TO_POINT(value);
break;
case Pica:
pt = PI_TO_POINT(value);
break;
case Cicero:
pt = CC_TO_POINT(value);
break;
case Pixel:
pt = value / factor;
break;
case Point:
default:
pt = value;
}
switch (toUnit.type()) {
case Millimeter:
return POINT_TO_MM(pt);
case Centimeter:
return POINT_TO_CM(pt);
case Decimeter:
return POINT_TO_DM(pt);
case Inch:
return POINT_TO_INCH(pt);
case Pica:
return POINT_TO_PI(pt);
case Cicero:
return POINT_TO_CC(pt);
case Pixel:
return pt * factor;
case Point:
default:
return pt;
}
}
QString KoUnit::symbol() const
{
return QLatin1String(unitNameList[m_type]);
}
qreal KoUnit::parseAngle(const QString& _value, qreal defaultVal)
{
if (_value.isEmpty())
return defaultVal;
QString value(_value.simplified());
value.remove(QLatin1Char(' '));
int firstLetter = -1;
for (int i = 0; i < value.length(); ++i) {
if (value.at(i).isLetter()) {
if (value.at(i) == QLatin1Char('e'))
continue;
firstLetter = i;
break;
}
}
if (firstLetter == -1)
return value.toDouble();
const QString type = value.mid(firstLetter);
value.truncate(firstLetter);
const qreal val = value.toDouble();
if (type == QLatin1String("deg"))
return val;
else if (type == QLatin1String("rad"))
return val * 180 / M_PI;
else if (type == QLatin1String("grad"))
return val * 0.9;
return defaultVal;
}
qreal KoUnit::approxTransformScale(const QTransform &t)
{
return std::sqrt(qAbs(t.determinant()));
}
void KoUnit::adjustByPixelTransform(const QTransform &t)
{
m_pixelConversion *= approxTransformScale(t);
}
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug debug, const KoUnit &unit)
{
#ifndef NDEBUG
debug.nospace() << unit.symbol();
#else
Q_UNUSED(unit);
#endif
return debug.space();
}
#endif
diff --git a/libs/odf/KoUnit.h b/libs/global/KoUnit.h
similarity index 98%
rename from libs/odf/KoUnit.h
rename to libs/global/KoUnit.h
index 60ced5e11c..b6d2c6031d 100644
--- a/libs/odf/KoUnit.h
+++ b/libs/global/KoUnit.h
@@ -1,240 +1,240 @@
/* This file is part of the KDE project
Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
Copyright (C) 2004, Nicolas GOUTTE <goutte@kde.org>
Copyright (C) 2010 Thomas Zander <zander@kde.org>
Copyright 2012 Friedrich W. H. Kossebau <kossebau@kde.org>
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 KOUNIT_H
#define KOUNIT_H
// Calligra
-#include "kritaodf_export.h"
+#include "kritaglobal_export.h"
// Qt
#include <QString>
#include <QDebug>
#include <QMetaType>
// std
#include <math.h> // for floor
class QStringList;
// 1 inch ^= 72 pt
// 1 inch ^= 25.399956 mm (-pedantic ;p)
// 1 pt = 1/12 pi
// 1 pt ^= 0.0077880997 cc
// 1 cc = 12 dd
constexpr qreal POINT_TO_MM(qreal px) {return (px)*0.352777167;}
constexpr qreal MM_TO_POINT(qreal mm) {return mm*2.83465058;}
constexpr qreal POINT_TO_CM(qreal px) {return (px)*0.0352777167;}
constexpr qreal CM_TO_POINT(qreal cm) {return (cm)*28.3465058;}
constexpr qreal POINT_TO_DM(qreal px) {return (px)*0.00352777167;}
constexpr qreal DM_TO_POINT(qreal dm) {return (dm)*283.465058;}
constexpr qreal POINT_TO_INCH(qreal px) {return (px)*0.01388888888889;}
constexpr qreal INCH_TO_POINT(qreal inch) {return (inch)*72.0;}
constexpr qreal MM_TO_INCH(qreal mm) {return (mm)*0.039370147;}
constexpr qreal INCH_TO_MM(qreal inch) {return (inch)*25.399956;}
constexpr qreal POINT_TO_PI(qreal px) {return (px)*0.083333333;}
constexpr qreal POINT_TO_CC(qreal px) {return (px)*0.077880997;}
constexpr qreal PI_TO_POINT(qreal pi) {return (pi)*12;}
constexpr qreal CC_TO_POINT(qreal cc) {return (cc)*12.840103;}
static const qreal PT_ROUNDING {1000.0};
//static const qreal PX_ROUNDING {1000.0}; // pixel value is not to be rounded
static const qreal CM_ROUNDING {10000.0};
static const qreal DM_ROUNDING {10000.0};
static const qreal MM_ROUNDING {10000.0};
static const qreal IN_ROUNDING {100000.0};
static const qreal PI_ROUNDING {100000.0}; // pico
static const qreal CC_ROUNDING {100000.0}; // cicero
/**
* %Calligra stores everything in pt (using "qreal") internally.
* When displaying a value to the user, the value is converted to the user's unit
* of choice, and rounded to a reasonable precision to avoid 0.999999
*
* For implementing the selection of a unit type in the UI use the *ForUi() methods.
* They ensure the same order of the unit types in all places, with the order not
* bound to the order in the enum (so ABI-compatible extension is possible) and
* with the order and scope of listed types controlled by the @c ListOptions parameter.
*/
-class KRITAODF_EXPORT KoUnit
+class KRITAGLOBAL_EXPORT KoUnit
{
public:
/** Length units supported by Calligra. */
enum Type {
Millimeter = 0,
Point, ///< Postscript point, 1/72th of an Inco
Inch,
Centimeter,
Decimeter,
Pica,
Cicero,
Pixel,
TypeCount ///< @internal
};
/// Used to control the scope of the unit types listed in the UI
enum ListOption {
ListAll = 0,
HidePixel = 1,
HideMask = HidePixel
};
Q_DECLARE_FLAGS(ListOptions, ListOption)
/** Returns a KoUnit instance with the type at the @p index of the UI list with the given @p listOptions. */
static KoUnit fromListForUi(int index, ListOptions listOptions = ListAll, qreal factor = 1.0);
/// Convert a unit symbol string into a KoUnit
/// @param symbol symbol to convert
/// @param ok if set, it will be true if the unit was known, false if unknown
static KoUnit fromSymbol(const QString &symbol, bool *ok = 0);
/** Construction requires initialization. The factor is for variable factor units like pixel */
explicit KoUnit(Type unit = Point, qreal factor = 1.0) {
m_type = unit;
m_pixelConversion = factor;
}
KoUnit& operator=(Type unit) {
m_type = unit; m_pixelConversion = 1.0; return *this;
}
bool operator!=(const KoUnit &other) const {
return !operator==(other);
}
bool operator==(const KoUnit &other) const {
return m_type == other.m_type &&
(m_type != Pixel ||
qFuzzyCompare(m_pixelConversion, other.m_pixelConversion));
}
KoUnit::Type type() const {
return m_type;
}
void setFactor(qreal factor) {
m_pixelConversion = factor;
}
/**
* convert the given value directly from one unit to another
*/
static qreal convertFromUnitToUnit(const qreal value, const KoUnit &fromUnit, const KoUnit &toUnit, qreal factor = 1.0);
/**
* Convert the value @p ptValue to the unit and round it.
* This method is meant to be used to display a value in a dialog.
* \return the converted and rounded value
*/
qreal toUserValueRounded(const qreal value) const;
/**
* Convert the value @p ptValue to the unit (without rounding)
* This method is meant to be used in complex calculations.
* \return the converted value
*/
qreal toUserValuePrecise(const qreal ptValue) const;
/**
* Convert the value @p ptValue with or with rounding as indicated by @p rounding.
* This method is a proxy to toUserValuePrecise and toUserValueRounded.
* \return the value @p ptValue converted to unit
*/
qreal toUserValue(qreal ptValue, bool rounding = true) const;
/// This method is the one to use to display a value in a dialog
/// @return the value @p ptValue converted the unit and rounded, ready to be displayed
QString toUserStringValue(qreal ptValue) const;
/// This method is the one to use to read a value from a dialog
/// @return the value converted to points for internal use
qreal fromUserValue(qreal value) const;
/// This method is the one to use to read a value from a dialog
/// @param value value entered by the user
/// @param ok if set, the pointed bool is set to true if the value could be
/// converted to a qreal, and to false otherwise.
/// @return the value converted to points for internal use
qreal fromUserValue(const QString &value, bool *ok = 0) const;
/// Get the description string of the given unit
static QString unitDescription(KoUnit::Type type);
/// Get the symbol string of the unit
QString symbol() const;
/// Returns the list of unit types for the UI, controlled with the given @p listOptions.
static QStringList listOfUnitNameForUi(ListOptions listOptions = ListAll);
/// Get the index of this unit in the list of unit types for the UI,
/// if it is controlled with the given @p listOptions.
int indexInListForUi(ListOptions listOptions = ListAll) const;
/// parse common %Calligra and Odf values, like "10cm", "5mm" to pt
static qreal parseValue(const QString &value, qreal defaultVal = 0.0);
/// parse an angle to its value in degrees
static qreal parseAngle(const QString &value, qreal defaultVal = 0.0);
QString toString() const {
return symbol();
}
/**
* Get an approximate scale of a unit vector that was converted by
* the transformation.
*
* Please note that exact values are guaranteed only for
* combinations of Translate, Rotation and Uniform Scale
* matrices. For combinations having shears and perspective the
* value will be average for the point near CS origin.
*/
static qreal approxTransformScale(const QTransform &t);
/**
* Adjust the unit by pixel transformation applied to the
* describing object. It multiplies the pixel coefficient by the
* average scale of the matrix.
*/
void adjustByPixelTransform(const QTransform &t);
private:
Type m_type;
qreal m_pixelConversion;
};
#ifndef QT_NO_DEBUG_STREAM
-KRITAODF_EXPORT QDebug operator<<(QDebug, const KoUnit &);
+KRITAGLOBAL_EXPORT QDebug operator<<(QDebug, const KoUnit &);
#endif
Q_DECLARE_METATYPE(KoUnit)
Q_DECLARE_OPERATORS_FOR_FLAGS(KoUnit::ListOptions)
#endif
diff --git a/libs/global/kis_algebra_2d.cpp b/libs/global/kis_algebra_2d.cpp
index ac6383bec0..2bfb88edda 100644
--- a/libs/global/kis_algebra_2d.cpp
+++ b/libs/global/kis_algebra_2d.cpp
@@ -1,681 +1,681 @@
/*
* Copyright (c) 2014 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_algebra_2d.h"
#include <QTransform>
#include <QPainterPath>
#include <kis_debug.h>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/min.hpp>
#include <boost/accumulators/statistics/max.hpp>
#include <array>
#include <QVector2D>
#include <QVector3D>
#include <Eigen/Eigenvalues>
#define SANITY_CHECKS
namespace KisAlgebra2D {
void adjustIfOnPolygonBoundary(const QPolygonF &poly, int polygonDirection, QPointF *pt)
{
const int numPoints = poly.size();
for (int i = 0; i < numPoints; i++) {
int nextI = i + 1;
if (nextI >= numPoints) {
nextI = 0;
}
const QPointF &p0 = poly[i];
const QPointF &p1 = poly[nextI];
QPointF edge = p1 - p0;
qreal cross = crossProduct(edge, *pt - p0)
/ (0.5 * edge.manhattanLength());
if (cross < 1.0 &&
isInRange(pt->x(), p0.x(), p1.x()) &&
isInRange(pt->y(), p0.y(), p1.y())) {
QPointF salt = 1.0e-3 * inwardUnitNormal(edge, polygonDirection);
QPointF adjustedPoint = *pt + salt;
// in case the polygon is self-intersecting, polygon direction
// might not help
if (kisDistanceToLine(adjustedPoint, QLineF(p0, p1)) < 1e-4) {
adjustedPoint = *pt - salt;
#ifdef SANITY_CHECKS
if (kisDistanceToLine(adjustedPoint, QLineF(p0, p1)) < 1e-4) {
dbgKrita << ppVar(*pt);
dbgKrita << ppVar(adjustedPoint);
dbgKrita << ppVar(QLineF(p0, p1));
dbgKrita << ppVar(salt);
dbgKrita << ppVar(poly.containsPoint(*pt, Qt::OddEvenFill));
dbgKrita << ppVar(kisDistanceToLine(*pt, QLineF(p0, p1)));
dbgKrita << ppVar(kisDistanceToLine(adjustedPoint, QLineF(p0, p1)));
}
*pt = adjustedPoint;
KIS_ASSERT_RECOVER_NOOP(kisDistanceToLine(*pt, QLineF(p0, p1)) > 1e-4);
#endif /* SANITY_CHECKS */
}
}
}
}
QPointF transformAsBase(const QPointF &pt, const QPointF &base1, const QPointF &base2) {
qreal len1 = norm(base1);
if (len1 < 1e-5) return pt;
qreal sin1 = base1.y() / len1;
qreal cos1 = base1.x() / len1;
qreal len2 = norm(base2);
if (len2 < 1e-5) return QPointF();
qreal sin2 = base2.y() / len2;
qreal cos2 = base2.x() / len2;
qreal sinD = sin2 * cos1 - cos2 * sin1;
qreal cosD = cos1 * cos2 + sin1 * sin2;
qreal scaleD = len2 / len1;
QPointF result;
result.rx() = scaleD * (pt.x() * cosD - pt.y() * sinD);
result.ry() = scaleD * (pt.x() * sinD + pt.y() * cosD);
return result;
}
qreal angleBetweenVectors(const QPointF &v1, const QPointF &v2)
{
qreal a1 = std::atan2(v1.y(), v1.x());
qreal a2 = std::atan2(v2.y(), v2.x());
return a2 - a1;
}
qreal directionBetweenPoints(const QPointF &p1, const QPointF &p2, qreal defaultAngle)
{
if (fuzzyPointCompare(p1, p2)) {
return defaultAngle;
}
const QVector2D diff(p2 - p1);
return std::atan2(diff.y(), diff.x());
}
QPainterPath smallArrow()
{
QPainterPath p;
p.moveTo(5, 2);
p.lineTo(-3, 8);
p.lineTo(-5, 5);
p.lineTo( 2, 0);
p.lineTo(-5,-5);
p.lineTo(-3,-8);
p.lineTo( 5,-2);
p.arcTo(QRectF(3, -2, 4, 4), 90, -180);
return p;
}
template <class Point, class Rect>
inline Point ensureInRectImpl(Point pt, const Rect &bounds)
{
if (pt.x() > bounds.right()) {
pt.rx() = bounds.right();
} else if (pt.x() < bounds.left()) {
pt.rx() = bounds.left();
}
if (pt.y() > bounds.bottom()) {
pt.ry() = bounds.bottom();
} else if (pt.y() < bounds.top()) {
pt.ry() = bounds.top();
}
return pt;
}
QPoint ensureInRect(QPoint pt, const QRect &bounds)
{
return ensureInRectImpl(pt, bounds);
}
QPointF ensureInRect(QPointF pt, const QRectF &bounds)
{
return ensureInRectImpl(pt, bounds);
}
bool intersectLineRect(QLineF &line, const QRect rect)
{
QPointF pt1 = QPointF(), pt2 = QPointF();
QPointF tmp;
if (line.intersect(QLineF(rect.topLeft(), rect.topRight()), &tmp) != QLineF::NoIntersection) {
if (tmp.x() >= rect.left() && tmp.x() <= rect.right()) {
pt1 = tmp;
}
}
if (line.intersect(QLineF(rect.topRight(), rect.bottomRight()), &tmp) != QLineF::NoIntersection) {
if (tmp.y() >= rect.top() && tmp.y() <= rect.bottom()) {
if (pt1.isNull()) pt1 = tmp;
else pt2 = tmp;
}
}
if (line.intersect(QLineF(rect.bottomRight(), rect.bottomLeft()), &tmp) != QLineF::NoIntersection) {
if (tmp.x() >= rect.left() && tmp.x() <= rect.right()) {
if (pt1.isNull()) pt1 = tmp;
else pt2 = tmp;
}
}
if (line.intersect(QLineF(rect.bottomLeft(), rect.topLeft()), &tmp) != QLineF::NoIntersection) {
if (tmp.y() >= rect.top() && tmp.y() <= rect.bottom()) {
if (pt1.isNull()) pt1 = tmp;
else pt2 = tmp;
}
}
if (pt1.isNull() || pt2.isNull()) return false;
// Attempt to retain polarity of end points
if ((line.x1() < line.x2()) != (pt1.x() > pt2.x()) || (line.y1() < line.y2()) != (pt1.y() > pt2.y())) {
tmp = pt1;
pt1 = pt2;
pt2 = tmp;
}
line.setP1(pt1);
line.setP2(pt2);
return true;
}
template <class Rect, class Point>
QVector<Point> sampleRectWithPoints(const Rect &rect)
{
QVector<Point> points;
Point m1 = 0.5 * (rect.topLeft() + rect.topRight());
Point m2 = 0.5 * (rect.bottomLeft() + rect.bottomRight());
points << rect.topLeft();
points << m1;
points << rect.topRight();
points << 0.5 * (rect.topLeft() + rect.bottomLeft());
points << 0.5 * (m1 + m2);
points << 0.5 * (rect.topRight() + rect.bottomRight());
points << rect.bottomLeft();
points << m2;
points << rect.bottomRight();
return points;
}
QVector<QPoint> sampleRectWithPoints(const QRect &rect)
{
return sampleRectWithPoints<QRect, QPoint>(rect);
}
QVector<QPointF> sampleRectWithPoints(const QRectF &rect)
{
return sampleRectWithPoints<QRectF, QPointF>(rect);
}
template <class Rect, class Point, bool alignPixels>
Rect approximateRectFromPointsImpl(const QVector<Point> &points)
{
using namespace boost::accumulators;
accumulator_set<qreal, stats<tag::min, tag::max > > accX;
accumulator_set<qreal, stats<tag::min, tag::max > > accY;
Q_FOREACH (const Point &pt, points) {
accX(pt.x());
accY(pt.y());
}
Rect resultRect;
if (alignPixels) {
resultRect.setCoords(std::floor(min(accX)), std::floor(min(accY)),
std::ceil(max(accX)), std::ceil(max(accY)));
} else {
resultRect.setCoords(min(accX), min(accY),
max(accX), max(accY));
}
return resultRect;
}
QRect approximateRectFromPoints(const QVector<QPoint> &points)
{
return approximateRectFromPointsImpl<QRect, QPoint, true>(points);
}
QRectF approximateRectFromPoints(const QVector<QPointF> &points)
{
return approximateRectFromPointsImpl<QRectF, QPointF, false>(points);
}
QRect approximateRectWithPointTransform(const QRect &rect, std::function<QPointF(QPointF)> func)
{
QVector<QPoint> points = sampleRectWithPoints(rect);
using namespace boost::accumulators;
accumulator_set<qreal, stats<tag::min, tag::max > > accX;
accumulator_set<qreal, stats<tag::min, tag::max > > accY;
Q_FOREACH (const QPoint &pt, points) {
QPointF dstPt = func(pt);
accX(dstPt.x());
accY(dstPt.y());
}
QRect resultRect;
resultRect.setCoords(std::floor(min(accX)), std::floor(min(accY)),
std::ceil(max(accX)), std::ceil(max(accY)));
return resultRect;
}
QRectF cutOffRect(const QRectF &rc, const KisAlgebra2D::RightHalfPlane &p)
{
QVector<QPointF> points;
const QLineF cutLine = p.getLine();
points << rc.topLeft();
points << rc.topRight();
points << rc.bottomRight();
points << rc.bottomLeft();
QPointF p1 = points[3];
bool p1Valid = p.pos(p1) >= 0;
QVector<QPointF> resultPoints;
for (int i = 0; i < 4; i++) {
const QPointF p2 = points[i];
const bool p2Valid = p.pos(p2) >= 0;
if (p1Valid != p2Valid) {
QPointF intersection;
cutLine.intersect(QLineF(p1, p2), &intersection);
resultPoints << intersection;
}
if (p2Valid) {
resultPoints << p2;
}
p1 = p2;
p1Valid = p2Valid;
}
return approximateRectFromPoints(resultPoints);
}
int quadraticEquation(qreal a, qreal b, qreal c, qreal *x1, qreal *x2)
{
int numSolutions = 0;
const qreal D = pow2(b) - 4 * a * c;
const qreal eps = 1e-14;
if (qAbs(D) <= eps) {
*x1 = -b / (2 * a);
numSolutions = 1;
} else if (D < 0) {
return 0;
} else {
const qreal sqrt_D = std::sqrt(D);
*x1 = (-b + sqrt_D) / (2 * a);
*x2 = (-b - sqrt_D) / (2 * a);
numSolutions = 2;
}
return numSolutions;
}
QVector<QPointF> intersectTwoCircles(const QPointF &center1, qreal r1,
const QPointF &center2, qreal r2)
{
QVector<QPointF> points;
const QPointF diff = (center2 - center1);
const QPointF c1;
const QPointF c2 = diff;
const qreal centerDistance = norm(diff);
if (centerDistance > r1 + r2) return points;
if (centerDistance < qAbs(r1 - r2)) return points;
if (centerDistance < qAbs(r1 - r2) + 0.001) {
dbgKrita << "Skipping intersection" << ppVar(center1) << ppVar(center2) << ppVar(r1) << ppVar(r2) << ppVar(centerDistance) << ppVar(qAbs(r1-r2));
return points;
}
const qreal x_kp1 = diff.x();
const qreal y_kp1 = diff.y();
const qreal F2 =
0.5 * (pow2(x_kp1) +
pow2(y_kp1) + pow2(r1) - pow2(r2));
const qreal eps = 1e-6;
if (qAbs(diff.y()) < eps) {
qreal x = F2 / diff.x();
qreal y1, y2;
int result = KisAlgebra2D::quadraticEquation(
1, 0,
pow2(x) - pow2(r2),
&y1, &y2);
KIS_SAFE_ASSERT_RECOVER(result > 0) { return points; }
if (result == 1) {
points << QPointF(x, y1);
} else if (result == 2) {
KisAlgebra2D::RightHalfPlane p(c1, c2);
QPointF p1(x, y1);
QPointF p2(x, y2);
if (p.pos(p1) >= 0) {
points << p1;
points << p2;
} else {
points << p2;
points << p1;
}
}
} else {
const qreal A = diff.x() / diff.y();
const qreal C = F2 / diff.y();
qreal x1, x2;
int result = KisAlgebra2D::quadraticEquation(
1 + pow2(A), -2 * A * C,
pow2(C) - pow2(r1),
&x1, &x2);
KIS_SAFE_ASSERT_RECOVER(result > 0) { return points; }
if (result == 1) {
points << QPointF(x1, C - x1 * A);
} else if (result == 2) {
KisAlgebra2D::RightHalfPlane p(c1, c2);
QPointF p1(x1, C - x1 * A);
QPointF p2(x2, C - x2 * A);
if (p.pos(p1) >= 0) {
points << p1;
points << p2;
} else {
points << p2;
points << p1;
}
}
}
for (int i = 0; i < points.size(); i++) {
points[i] = center1 + points[i];
}
return points;
}
QTransform mapToRect(const QRectF &rect)
{
return
QTransform(rect.width(), 0, 0, rect.height(),
rect.x(), rect.y());
}
QTransform mapToRectInverse(const QRectF &rect)
{
return
QTransform::fromTranslate(-rect.x(), -rect.y()) *
- QTransform::fromScale(rect.width() > 0 ? 1.0 / rect.width() : 0.0,
- rect.height() > 0 ? 1.0 / rect.height() : 0.0);
+ QTransform::fromScale(rect.width() != 0 ? 1.0 / rect.width() : 0.0,
+ rect.height() != 0 ? 1.0 / rect.height() : 0.0);
}
bool fuzzyMatrixCompare(const QTransform &t1, const QTransform &t2, qreal delta) {
return
qAbs(t1.m11() - t2.m11()) < delta &&
qAbs(t1.m12() - t2.m12()) < delta &&
qAbs(t1.m13() - t2.m13()) < delta &&
qAbs(t1.m21() - t2.m21()) < delta &&
qAbs(t1.m22() - t2.m22()) < delta &&
qAbs(t1.m23() - t2.m23()) < delta &&
qAbs(t1.m31() - t2.m31()) < delta &&
qAbs(t1.m32() - t2.m32()) < delta &&
qAbs(t1.m33() - t2.m33()) < delta;
}
bool fuzzyPointCompare(const QPointF &p1, const QPointF &p2)
{
return qFuzzyCompare(p1.x(), p2.x()) && qFuzzyCompare(p1.y(), p2.y());
}
bool fuzzyPointCompare(const QPointF &p1, const QPointF &p2, qreal delta)
{
return qAbs(p1.x() - p2.x()) < delta && qAbs(p1.y() - p2.y()) < delta;
}
/********************************************************/
/* DecomposedMatix */
/********************************************************/
DecomposedMatix::DecomposedMatix()
{
}
DecomposedMatix::DecomposedMatix(const QTransform &t0)
{
QTransform t(t0);
QTransform projMatrix;
if (t.m33() == 0.0 || t0.determinant() == 0.0) {
qWarning() << "Cannot decompose matrix!" << t;
valid = false;
return;
}
if (t.type() == QTransform::TxProject) {
QTransform affineTransform(t.toAffine());
projMatrix = affineTransform.inverted() * t;
t = affineTransform;
proj[0] = projMatrix.m13();
proj[1] = projMatrix.m23();
proj[2] = projMatrix.m33();
}
std::array<QVector3D, 3> rows;
rows[0] = QVector3D(t.m11(), t.m12(), t.m13());
rows[1] = QVector3D(t.m21(), t.m22(), t.m23());
rows[2] = QVector3D(t.m31(), t.m32(), t.m33());
if (!qFuzzyCompare(t.m33(), 1.0)) {
const qreal invM33 = 1.0 / t.m33();
for (auto &row : rows) {
row *= invM33;
}
}
dx = rows[2].x();
dy = rows[2].y();
rows[2] = QVector3D(0,0,1);
scaleX = rows[0].length();
rows[0] *= 1.0 / scaleX;
shearXY = QVector3D::dotProduct(rows[0], rows[1]);
rows[1] = rows[1] - shearXY * rows[0];
scaleY = rows[1].length();
rows[1] *= 1.0 / scaleY;
shearXY *= 1.0 / scaleY;
// If determinant is negative, one axis was flipped.
qreal determinant = rows[0].x() * rows[1].y() - rows[0].y() * rows[1].x();
if (determinant < 0) {
// Flip axis with minimum unit vector dot product.
if (rows[0].x() < rows[1].y()) {
scaleX = -scaleX;
rows[0] = -rows[0];
} else {
scaleY = -scaleY;
rows[1] = -rows[1];
}
shearXY = - shearXY;
}
angle = kisRadiansToDegrees(std::atan2(rows[0].y(), rows[0].x()));
if (angle != 0.0) {
// Rotate(-angle) = [cos(angle), sin(angle), -sin(angle), cos(angle)]
// = [row0x, -row0y, row0y, row0x]
// Thanks to the normalization above.
qreal sn = -rows[0].y();
qreal cs = rows[0].x();
qreal m11 = rows[0].x();
qreal m12 = rows[0].y();
qreal m21 = rows[1].x();
qreal m22 = rows[1].y();
rows[0].setX(cs * m11 + sn * m21);
rows[0].setY(cs * m12 + sn * m22);
rows[1].setX(-sn * m11 + cs * m21);
rows[1].setY(-sn * m12 + cs * m22);
}
QTransform leftOver(
rows[0].x(), rows[0].y(), rows[0].z(),
rows[1].x(), rows[1].y(), rows[1].z(),
rows[2].x(), rows[2].y(), rows[2].z());
KIS_SAFE_ASSERT_RECOVER_NOOP(fuzzyMatrixCompare(leftOver, QTransform(), 1e-4));
}
inline QTransform toQTransformStraight(const Eigen::Matrix3d &m)
{
return QTransform(m(0,0), m(0,1), m(0,2),
m(1,0), m(1,1), m(1,2),
m(2,0), m(2,1), m(2,2));
}
inline Eigen::Matrix3d fromQTransformStraight(const QTransform &t)
{
Eigen::Matrix3d m;
m << t.m11() , t.m12() , t.m13()
,t.m21() , t.m22() , t.m23()
,t.m31() , t.m32() , t.m33();
return m;
}
std::pair<QPointF, QTransform> transformEllipse(const QPointF &axes, const QTransform &fullLocalToGlobal)
{
KisAlgebra2D::DecomposedMatix decomposed(fullLocalToGlobal);
const QTransform localToGlobal =
decomposed.scaleTransform() *
decomposed.shearTransform() *
decomposed.rotateTransform();
const QTransform localEllipse = QTransform(1.0 / pow2(axes.x()), 0.0, 0.0,
0.0, 1.0 / pow2(axes.y()), 0.0,
0.0, 0.0, 1.0);
const QTransform globalToLocal = localToGlobal.inverted();
Eigen::Matrix3d eqM =
fromQTransformStraight(globalToLocal *
localEllipse *
globalToLocal.transposed());
// std::cout << "eqM:" << std::endl << eqM << std::endl;
Eigen::EigenSolver<Eigen::Matrix3d> eigenSolver(eqM);
const Eigen::Matrix3d T = eigenSolver.eigenvalues().real().asDiagonal();
const Eigen::Matrix3d U = eigenSolver.eigenvectors().real();
const Eigen::Matrix3d Ti = eigenSolver.eigenvalues().imag().asDiagonal();
const Eigen::Matrix3d Ui = eigenSolver.eigenvectors().imag();
KIS_SAFE_ASSERT_RECOVER_NOOP(Ti.isZero());
KIS_SAFE_ASSERT_RECOVER_NOOP(Ui.isZero());
KIS_SAFE_ASSERT_RECOVER_NOOP((U * U.transpose()).isIdentity());
// std::cout << "T:" << std::endl << T << std::endl;
// std::cout << "U:" << std::endl << U << std::endl;
// std::cout << "Ti:" << std::endl << Ti << std::endl;
// std::cout << "Ui:" << std::endl << Ui << std::endl;
// std::cout << "UTU':" << std::endl << U * T * U.transpose() << std::endl;
const qreal newA = 1.0 / std::sqrt(T(0,0) * T(2,2));
const qreal newB = 1.0 / std::sqrt(T(1,1) * T(2,2));
const QTransform newGlobalToLocal = toQTransformStraight(U);
const QTransform newLocalToGlobal = QTransform::fromScale(-1,-1) *
newGlobalToLocal.inverted() *
decomposed.translateTransform();
return std::make_pair(QPointF(newA, newB), newLocalToGlobal);
}
QPointF alignForZoom(const QPointF &pt, qreal zoom)
{
return QPointF((pt * zoom).toPoint()) / zoom;
}
}
diff --git a/libs/image/CMakeLists.txt b/libs/image/CMakeLists.txt
index 41f65d37ed..6e1acda047 100644
--- a/libs/image/CMakeLists.txt
+++ b/libs/image/CMakeLists.txt
@@ -1,392 +1,392 @@
add_subdirectory( tests )
add_subdirectory( tiles3 )
include_directories(
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty
${CMAKE_CURRENT_SOURCE_DIR}/brushengine
${CMAKE_CURRENT_SOURCE_DIR}/commands
${CMAKE_CURRENT_SOURCE_DIR}/commands_new
${CMAKE_CURRENT_SOURCE_DIR}/filter
${CMAKE_CURRENT_SOURCE_DIR}/floodfill
${CMAKE_CURRENT_SOURCE_DIR}/generator
${CMAKE_CURRENT_SOURCE_DIR}/layerstyles
${CMAKE_CURRENT_SOURCE_DIR}/processing
${CMAKE_SOURCE_DIR}/sdk/tests
)
include_directories(SYSTEM
${EIGEN3_INCLUDE_DIR}
)
if(FFTW3_FOUND)
include_directories(${FFTW3_INCLUDE_DIR})
endif()
if(HAVE_VC)
include_directories(SYSTEM ${Vc_INCLUDE_DIR} ${Qt5Core_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS})
ko_compile_for_all_implementations(__per_arch_circle_mask_generator_objs kis_brush_mask_applicator_factories.cpp)
else()
set(__per_arch_circle_mask_generator_objs kis_brush_mask_applicator_factories.cpp)
endif()
set(kritaimage_LIB_SRCS
tiles3/kis_tile.cc
tiles3/kis_tile_data.cc
tiles3/kis_tile_data_store.cc
tiles3/kis_tile_data_pooler.cc
tiles3/kis_tiled_data_manager.cc
tiles3/KisTiledExtentManager.cpp
tiles3/kis_memento_manager.cc
tiles3/kis_hline_iterator.cpp
tiles3/kis_vline_iterator.cpp
tiles3/kis_random_accessor.cc
tiles3/swap/kis_abstract_compression.cpp
tiles3/swap/kis_lzf_compression.cpp
tiles3/swap/kis_abstract_tile_compressor.cpp
tiles3/swap/kis_legacy_tile_compressor.cpp
tiles3/swap/kis_tile_compressor_2.cpp
tiles3/swap/kis_chunk_allocator.cpp
tiles3/swap/kis_memory_window.cpp
tiles3/swap/kis_swapped_data_store.cpp
tiles3/swap/kis_tile_data_swapper.cpp
kis_distance_information.cpp
kis_painter.cc
kis_painter_blt_multi_fixed.cpp
kis_marker_painter.cpp
KisPrecisePaintDeviceWrapper.cpp
kis_progress_updater.cpp
brushengine/kis_paint_information.cc
brushengine/kis_random_source.cpp
brushengine/KisPerStrokeRandomSource.cpp
brushengine/kis_stroke_random_source.cpp
brushengine/kis_paintop.cc
brushengine/kis_paintop_factory.cpp
brushengine/kis_paintop_preset.cpp
brushengine/kis_paintop_registry.cc
brushengine/kis_paintop_settings.cpp
brushengine/kis_paintop_settings_update_proxy.cpp
brushengine/kis_paintop_utils.cpp
brushengine/kis_no_size_paintop_settings.cpp
brushengine/kis_locked_properties.cc
brushengine/kis_locked_properties_proxy.cpp
brushengine/kis_locked_properties_server.cpp
brushengine/kis_paintop_config_widget.cpp
brushengine/kis_uniform_paintop_property.cpp
brushengine/kis_combo_based_paintop_property.cpp
brushengine/kis_slider_based_paintop_property.cpp
brushengine/kis_standard_uniform_properties_factory.cpp
brushengine/KisStrokeSpeedMeasurer.cpp
brushengine/KisPaintopSettingsIds.cpp
commands/kis_deselect_global_selection_command.cpp
commands/KisDeselectActiveSelectionCommand.cpp
commands/kis_image_change_layers_command.cpp
commands/kis_image_change_visibility_command.cpp
commands/kis_image_command.cpp
commands/kis_image_layer_add_command.cpp
commands/kis_image_layer_move_command.cpp
commands/kis_image_layer_remove_command.cpp
commands/kis_image_layer_remove_command_impl.cpp
commands/kis_image_lock_command.cpp
commands/kis_node_command.cpp
commands/kis_node_compositeop_command.cpp
commands/kis_node_opacity_command.cpp
commands/kis_node_property_list_command.cpp
commands/kis_reselect_global_selection_command.cpp
commands/KisReselectActiveSelectionCommand.cpp
commands/kis_set_global_selection_command.cpp
commands/KisNodeRenameCommand.cpp
commands_new/kis_saved_commands.cpp
commands_new/kis_processing_command.cpp
commands_new/kis_image_resize_command.cpp
commands_new/kis_image_set_resolution_command.cpp
commands_new/kis_node_move_command2.cpp
commands_new/kis_set_layer_style_command.cpp
commands_new/kis_selection_move_command2.cpp
commands_new/kis_update_command.cpp
commands_new/kis_switch_current_time_command.cpp
commands_new/kis_change_projection_color_command.cpp
commands_new/kis_activate_selection_mask_command.cpp
commands_new/kis_transaction_based_command.cpp
commands_new/KisHoldUIUpdatesCommand.cpp
commands_new/KisChangeChannelFlagsCommand.cpp
commands_new/KisChangeChannelLockFlagsCommand.cpp
commands_new/KisMergeLabeledLayersCommand.cpp
processing/kis_do_nothing_processing_visitor.cpp
processing/kis_simple_processing_visitor.cpp
processing/kis_convert_color_space_processing_visitor.cpp
processing/kis_assign_profile_processing_visitor.cpp
processing/kis_crop_processing_visitor.cpp
processing/kis_crop_selections_processing_visitor.cpp
processing/kis_transform_processing_visitor.cpp
processing/kis_mirror_processing_visitor.cpp
processing/KisSelectionBasedProcessingHelper.cpp
filter/kis_filter.cc
filter/kis_filter_category_ids.cpp
filter/kis_filter_configuration.cc
filter/kis_color_transformation_configuration.cc
filter/kis_filter_registry.cc
filter/kis_color_transformation_filter.cc
generator/kis_generator.cpp
generator/kis_generator_layer.cpp
generator/kis_generator_registry.cpp
floodfill/kis_fill_interval_map.cpp
floodfill/kis_scanline_fill.cpp
lazybrush/kis_min_cut_worker.cpp
lazybrush/kis_lazy_fill_tools.cpp
lazybrush/kis_multiway_cut.cpp
lazybrush/KisWatershedWorker.cpp
lazybrush/kis_colorize_mask.cpp
lazybrush/kis_colorize_stroke_strategy.cpp
KisDelayedUpdateNodeInterface.cpp
KisCroppedOriginalLayerInterface.cpp
KisDecoratedNodeInterface.cpp
kis_adjustment_layer.cc
kis_selection_based_layer.cpp
kis_node_filter_interface.cpp
kis_base_accessor.cpp
kis_base_node.cpp
kis_base_processor.cpp
kis_bookmarked_configuration_manager.cc
KisBusyWaitBroker.cpp
KisSafeBlockingQueueConnectionProxy.cpp
kis_node_uuid_info.cpp
kis_clone_layer.cpp
kis_config_widget.cpp
kis_convolution_kernel.cc
kis_convolution_painter.cc
kis_gaussian_kernel.cpp
kis_edge_detection_kernel.cpp
kis_cubic_curve.cpp
kis_default_bounds.cpp
kis_default_bounds_node_wrapper.cpp
kis_default_bounds_base.cpp
kis_effect_mask.cc
kis_fast_math.cpp
kis_fill_painter.cc
kis_filter_mask.cpp
kis_filter_strategy.cc
kis_transform_mask.cpp
kis_transform_mask_params_interface.cpp
kis_recalculate_transform_mask_job.cpp
kis_recalculate_generator_layer_job.cpp
kis_transform_mask_params_factory_registry.cpp
kis_safe_transform.cpp
kis_gradient_painter.cc
kis_gradient_shape_strategy.cpp
kis_cached_gradient_shape_strategy.cpp
kis_polygonal_gradient_shape_strategy.cpp
kis_iterator_ng.cpp
kis_async_merger.cpp
kis_merge_walker.cc
kis_updater_context.cpp
kis_update_job_item.cpp
kis_stroke_strategy_undo_command_based.cpp
kis_simple_stroke_strategy.cpp
KisRunnableBasedStrokeStrategy.cpp
KisRunnableStrokeJobDataBase.cpp
KisRunnableStrokeJobData.cpp
KisRunnableStrokeJobsInterface.cpp
KisFakeRunnableStrokeJobsExecutor.cpp
kis_stroke_job_strategy.cpp
kis_stroke_strategy.cpp
kis_stroke.cpp
kis_strokes_queue.cpp
KisStrokesQueueMutatedJobInterface.cpp
kis_simple_update_queue.cpp
kis_update_scheduler.cpp
kis_queues_progress_updater.cpp
kis_composite_progress_proxy.cpp
kis_sync_lod_cache_stroke_strategy.cpp
kis_lod_capable_layer_offset.cpp
kis_update_time_monitor.cpp
KisImageConfigNotifier.cpp
kis_group_layer.cc
kis_count_visitor.cpp
kis_histogram.cc
kis_image_interfaces.cpp
kis_image_animation_interface.cpp
kis_time_range.cpp
kis_node_graph_listener.cpp
kis_image.cc
kis_image_signal_router.cpp
KisImageSignals.cpp
kis_image_config.cpp
kis_projection_updates_filter.cpp
kis_suspend_projection_updates_stroke_strategy.cpp
kis_regenerate_frame_stroke_strategy.cpp
kis_switch_time_stroke_strategy.cpp
kis_crop_saved_extra_data.cpp
kis_timed_signal_threshold.cpp
kis_layer.cc
kis_indirect_painting_support.cpp
kis_abstract_projection_plane.cpp
kis_layer_projection_plane.cpp
kis_layer_utils.cpp
kis_mask_projection_plane.cpp
kis_projection_leaf.cpp
KisSafeNodeProjectionStore.cpp
kis_mask.cc
kis_base_mask_generator.cpp
kis_rect_mask_generator.cpp
kis_circle_mask_generator.cpp
kis_gauss_circle_mask_generator.cpp
kis_gauss_rect_mask_generator.cpp
${__per_arch_circle_mask_generator_objs}
kis_curve_circle_mask_generator.cpp
kis_curve_rect_mask_generator.cpp
kis_math_toolbox.cpp
kis_memory_statistics_server.cpp
kis_name_server.cpp
kis_node.cpp
kis_node_facade.cpp
kis_node_progress_proxy.cpp
kis_busy_progress_indicator.cpp
kis_node_visitor.cpp
kis_paint_device.cc
kis_paint_device_debug_utils.cpp
kis_fixed_paint_device.cpp
KisOptimizedByteArray.cpp
kis_paint_layer.cc
kis_perspective_math.cpp
kis_pixel_selection.cpp
kis_processing_information.cpp
kis_properties_configuration.cc
kis_random_accessor_ng.cpp
kis_random_generator.cc
kis_random_sub_accessor.cpp
kis_wrapped_random_accessor.cpp
kis_selection.cc
KisSelectionUpdateCompressor.cpp
kis_selection_mask.cpp
kis_update_outline_job.cpp
kis_update_selection_job.cpp
kis_serializable_configuration.cc
kis_transaction_data.cpp
kis_transform_worker.cc
kis_perspectivetransform_worker.cpp
bsplines/kis_bspline_1d.cpp
bsplines/kis_bspline_2d.cpp
bsplines/kis_nu_bspline_2d.cpp
kis_warptransform_worker.cc
kis_cage_transform_worker.cpp
kis_liquify_transform_worker.cpp
kis_green_coordinates_math.cpp
kis_transparency_mask.cc
kis_undo_adapter.cpp
kis_macro_based_undo_store.cpp
kis_surrogate_undo_adapter.cpp
kis_legacy_undo_adapter.cpp
kis_post_execution_undo_adapter.cpp
kis_processing_visitor.cpp
kis_processing_applicator.cpp
krita_utils.cpp
kis_outline_generator.cpp
kis_layer_composition.cpp
kis_selection_filters.cpp
KisProofingConfiguration.h
KisRecycleProjectionsJob.cpp
kis_keyframe.cpp
kis_keyframe_channel.cpp
kis_keyframe_commands.cpp
kis_scalar_keyframe_channel.cpp
kis_raster_keyframe_channel.cpp
kis_onion_skin_compositor.cpp
kis_onion_skin_cache.cpp
kis_idle_watcher.cpp
kis_layer_properties_icons.cpp
layerstyles/kis_multiple_projection.cpp
layerstyles/kis_layer_style_filter.cpp
layerstyles/kis_layer_style_filter_environment.cpp
layerstyles/kis_layer_style_filter_projection_plane.cpp
layerstyles/kis_layer_style_projection_plane.cpp
layerstyles/kis_ls_drop_shadow_filter.cpp
layerstyles/kis_ls_satin_filter.cpp
layerstyles/kis_ls_stroke_filter.cpp
layerstyles/kis_ls_bevel_emboss_filter.cpp
layerstyles/kis_ls_overlay_filter.cpp
layerstyles/kis_ls_utils.cpp
layerstyles/gimp_bump_map.cpp
layerstyles/KisLayerStyleKnockoutBlower.cpp
KisProofingConfiguration.cpp
kis_node_query_path.cc
kis_asl_layer_style_serializer.cpp
KisAslStorage.cpp
kis_psd_layer_style.cpp
)
set(einspline_SRCS
3rdparty/einspline/bspline_create.cpp
3rdparty/einspline/bspline_data.cpp
3rdparty/einspline/multi_bspline_create.cpp
3rdparty/einspline/nubasis.cpp
3rdparty/einspline/nubspline_create.cpp
3rdparty/einspline/nugrid.cpp
)
add_library(kritaimage SHARED ${kritaimage_LIB_SRCS} ${einspline_SRCS})
generate_export_header(kritaimage BASE_NAME kritaimage)
target_link_libraries(kritaimage
PUBLIC
kritaversion
kritawidgets
kritaglobal
kritapsd
- kritaodf
+
kritapigment
kritacommand
kritawidgetutils
kritametadata
kritaresources
Qt5::Concurrent
)
target_link_libraries(kritaimage PUBLIC ${Boost_SYSTEM_LIBRARY})
if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB)
if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB)
target_link_libraries(kritaimage PUBLIC atomic)
endif()
endif()
if(OPENEXR_FOUND)
target_link_libraries(kritaimage PUBLIC ${OPENEXR_LIBRARIES})
endif()
if(FFTW3_FOUND)
target_link_libraries(kritaimage PRIVATE ${FFTW3_LIBRARIES})
endif()
if(HAVE_VC)
target_link_libraries(kritaimage PUBLIC ${Vc_LIBRARIES})
endif()
if (NOT GSL_FOUND)
message (WARNING "KRITA WARNING! No GNU Scientific Library was found! Krita's Shaped Gradients might be non-normalized! Please install GSL library.")
else ()
target_link_libraries(kritaimage PRIVATE ${GSL_LIBRARIES} ${GSL_CBLAS_LIBRARIES})
endif ()
target_include_directories(kritaimage
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/brushengine>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/filter>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/generator>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/layerstyles>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/processing>
)
set_target_properties(kritaimage PROPERTIES
VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION}
)
install(TARGETS kritaimage ${INSTALL_TARGETS_DEFAULT_ARGS})
diff --git a/libs/image/KisSelectionUpdateCompressor.cpp b/libs/image/KisSelectionUpdateCompressor.cpp
index 129e6d471b..91206c8f9d 100644
--- a/libs/image/KisSelectionUpdateCompressor.cpp
+++ b/libs/image/KisSelectionUpdateCompressor.cpp
@@ -1,75 +1,77 @@
/*
* Copyright (c) 2018 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "KisSelectionUpdateCompressor.h"
#include "kis_image.h"
#include "kis_selection.h"
#include "kis_layer_utils.h"
#include "kis_update_selection_job.h"
KisSelectionUpdateCompressor::KisSelectionUpdateCompressor(KisSelection *selection)
: m_parentSelection(selection)
, m_updateSignalCompressor(new KisThreadSafeSignalCompressor(100, KisSignalCompressor::POSTPONE))
{
connect(m_updateSignalCompressor, SIGNAL(timeout()), this, SLOT(startUpdateJob()));
this->moveToThread(m_updateSignalCompressor->thread());
}
KisSelectionUpdateCompressor::~KisSelectionUpdateCompressor()
{
m_updateSignalCompressor->deleteLater();
}
void KisSelectionUpdateCompressor::requestUpdate(const QRect &updateRect)
{
m_fullUpdateRequested |= updateRect.isEmpty();
m_updateRect = !m_fullUpdateRequested ? m_updateRect | updateRect : QRect();
m_updateSignalCompressor->start();
}
void KisSelectionUpdateCompressor::tryProcessStalledUpdate()
{
if (m_hasStalledUpdate) {
m_updateSignalCompressor->start();
}
}
void KisSelectionUpdateCompressor::startUpdateJob()
{
KisNodeSP parentNode = m_parentSelection->parentNode();
if (!parentNode) {
m_hasStalledUpdate = true;
return;
}
+ // FIXME: we cannot use parentNode->image() here because masks don't
+ // have the pointer initialized for some reason.
KisImageSP image = KisLayerUtils::findImageByHierarchy(parentNode);
if (!image) {
m_hasStalledUpdate = true;
return;
}
if (image) {
image->addSpontaneousJob(new KisUpdateSelectionJob(m_parentSelection, m_updateRect));
}
m_updateRect = QRect();
m_fullUpdateRequested = false;
m_hasStalledUpdate = false;
}
diff --git a/libs/image/kis_base_node.cpp b/libs/image/kis_base_node.cpp
index ffd4f15ea3..4f96a61467 100644
--- a/libs/image/kis_base_node.cpp
+++ b/libs/image/kis_base_node.cpp
@@ -1,501 +1,504 @@
/*
* Copyright (c) 2007 Boudewijn Rempt <boud@valdyas.org>
*
* 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_base_node.h"
#include <klocalizedstring.h>
#include <kis_image.h>
#include <kis_icon.h>
#include <KoProperties.h>
#include <KoColorSpace.h>
#include <KoCompositeOpRegistry.h>
#include "kis_paint_device.h"
#include "kis_layer_properties_icons.h"
#include "kis_scalar_keyframe_channel.h"
struct Q_DECL_HIDDEN KisBaseNode::Private
{
QString compositeOp;
KoProperties properties;
KisBaseNode::Property hack_visible; //HACK
QUuid id;
QMap<QString, KisKeyframeChannel*> keyframeChannels;
QScopedPointer<KisScalarKeyframeChannel> opacityChannel;
bool systemLocked;
bool collapsed;
bool supportsLodMoves;
bool animated;
bool pinnedToTimeline;
KisImageWSP image;
Private(KisImageWSP image)
: id(QUuid::createUuid())
, systemLocked(false)
, collapsed(false)
, supportsLodMoves(false)
, animated(false)
, pinnedToTimeline(false)
, image(image)
{
}
Private(const Private &rhs)
: compositeOp(rhs.compositeOp),
id(QUuid::createUuid()),
systemLocked(false),
collapsed(rhs.collapsed),
supportsLodMoves(rhs.supportsLodMoves),
animated(rhs.animated),
pinnedToTimeline(rhs.pinnedToTimeline),
image(rhs.image)
{
QMapIterator<QString, QVariant> iter = rhs.properties.propertyIterator();
while (iter.hasNext()) {
iter.next();
properties.setProperty(iter.key(), iter.value());
}
}
};
KisBaseNode::KisBaseNode(KisImageWSP image)
: m_d(new Private(image))
{
/**
* Be cautious! These two calls are vital to warm-up KoProperties.
* We use it and its QMap in a threaded environment. This is not
* officially supported by Qt, but our environment guarantees, that
* there will be the only writer and several readers. Whilst the
* value of the QMap is boolean and there are no implicit-sharing
* calls provocated, it is safe to work with it in such an
* environment.
*/
setVisible(true, true);
setUserLocked(false);
setCollapsed(false);
setSupportsLodMoves(true);
m_d->compositeOp = COMPOSITE_OVER;
}
KisBaseNode::KisBaseNode(const KisBaseNode & rhs)
: QObject()
, KisShared()
, m_d(new Private(*rhs.m_d))
{
if (rhs.m_d->keyframeChannels.size() > 0) {
Q_FOREACH(QString key, rhs.m_d->keyframeChannels.keys()) {
KisKeyframeChannel* channel = rhs.m_d->keyframeChannels.value(key);
if (!channel) {
continue;
}
if (channel->inherits("KisScalarKeyframeChannel")) {
KisScalarKeyframeChannel* pchannel = qobject_cast<KisScalarKeyframeChannel*>(channel);
KIS_ASSERT_RECOVER(pchannel) { continue; }
KisScalarKeyframeChannel* channelNew = new KisScalarKeyframeChannel(*pchannel, nullptr);
KIS_ASSERT(channelNew);
m_d->keyframeChannels.insert(channelNew->id(), channelNew);
if (KoID(key) == KisKeyframeChannel::Opacity) {
m_d->opacityChannel.reset(channelNew);
}
}
}
}
}
KisBaseNode::~KisBaseNode()
{
delete m_d;
}
KisPaintDeviceSP KisBaseNode::colorPickSourceDevice() const
{
return projection();
}
quint8 KisBaseNode::opacity() const
{
if (m_d->opacityChannel) {
qreal value = m_d->opacityChannel->currentValue();
if (!qIsNaN(value)) {
return value;
}
}
return nodeProperties().intProperty("opacity", OPACITY_OPAQUE_U8);
}
void KisBaseNode::setOpacity(quint8 val)
{
if (m_d->opacityChannel) {
KisKeyframeSP activeKeyframe = m_d->opacityChannel->currentlyActiveKeyframe();
if (activeKeyframe) {
m_d->opacityChannel->setScalarValue(activeKeyframe, val);
}
}
if (opacity() == val) return;
setNodeProperty("opacity", val);
baseNodeInvalidateAllFramesCallback();
}
quint8 KisBaseNode::percentOpacity() const
{
return int(float(opacity() * 100) / 255 + 0.5);
}
void KisBaseNode::setPercentOpacity(quint8 val)
{
setOpacity(int(float(val * 255) / 100 + 0.5));
}
const QString& KisBaseNode::compositeOpId() const
{
return m_d->compositeOp;
}
void KisBaseNode::setCompositeOpId(const QString& compositeOp)
{
if (m_d->compositeOp == compositeOp) return;
m_d->compositeOp = compositeOp;
baseNodeChangedCallback();
baseNodeInvalidateAllFramesCallback();
}
KisBaseNode::PropertyList KisBaseNode::sectionModelProperties() const
{
KisBaseNode::PropertyList l;
l << KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::visible, visible(), m_d->hack_visible.isInStasis, m_d->hack_visible.stateInStasis);
l << KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::locked, userLocked());
return l;
}
void KisBaseNode::setSectionModelProperties(const KisBaseNode::PropertyList &properties)
{
setVisible(properties.at(0).state.toBool());
m_d->hack_visible = properties.at(0);
setUserLocked(properties.at(1).state.toBool());
}
const KoProperties & KisBaseNode::nodeProperties() const
{
return m_d->properties;
}
void KisBaseNode::setNodeProperty(const QString & name, const QVariant & value)
{
m_d->properties.setProperty(name, value);
baseNodeChangedCallback();
}
void KisBaseNode::mergeNodeProperties(const KoProperties & properties)
{
QMapIterator<QString, QVariant> iter = properties.propertyIterator();
while (iter.hasNext()) {
iter.next();
m_d->properties.setProperty(iter.key(), iter.value());
}
baseNodeChangedCallback();
baseNodeInvalidateAllFramesCallback();
}
bool KisBaseNode::check(const KoProperties & properties) const
{
QMapIterator<QString, QVariant> iter = properties.propertyIterator();
while (iter.hasNext()) {
iter.next();
if (m_d->properties.contains(iter.key())) {
if (m_d->properties.value(iter.key()) != iter.value())
return false;
}
}
return true;
}
-QImage KisBaseNode::createThumbnail(qint32 w, qint32 h)
+QImage KisBaseNode::createThumbnail(qint32 w, qint32 h, Qt::AspectRatioMode aspectRatioMode)
{
+ Q_UNUSED(aspectRatioMode);
+
try {
QImage image(w, h, QImage::Format_ARGB32);
image.fill(0);
return image;
} catch (const std::bad_alloc&) {
return QImage();
}
}
-QImage KisBaseNode::createThumbnailForFrame(qint32 w, qint32 h, int time)
+QImage KisBaseNode::createThumbnailForFrame(qint32 w, qint32 h, int time, Qt::AspectRatioMode aspectRatioMode)
{
Q_UNUSED(time)
+ Q_UNUSED(aspectRatioMode);
return createThumbnail(w, h);
}
bool KisBaseNode::visible(bool recursive) const
{
bool isVisible = m_d->properties.boolProperty(KisLayerPropertiesIcons::visible.id(), true);
KisBaseNodeSP parentNode = parentCallback();
return recursive && isVisible && parentNode ?
parentNode->visible(recursive) : isVisible;
}
void KisBaseNode::setVisible(bool visible, bool loading)
{
const bool isVisible = m_d->properties.boolProperty(KisLayerPropertiesIcons::visible.id(), true);
if (!loading && isVisible == visible) return;
m_d->properties.setProperty(KisLayerPropertiesIcons::visible.id(), visible);
notifyParentVisibilityChanged(visible);
if (!loading) {
baseNodeChangedCallback();
baseNodeInvalidateAllFramesCallback();
}
}
bool KisBaseNode::userLocked() const
{
return m_d->properties.boolProperty(KisLayerPropertiesIcons::locked.id(), false);
}
bool KisBaseNode::belongsToIsolatedGroup() const
{
if (!m_d->image) {
return false;
}
const KisBaseNode* element = this;
while (element) {
if (element->isIsolatedRoot()) {
return true;
} else {
element = element->parentCallback().data();
}
}
return false;
}
bool KisBaseNode::isIsolatedRoot() const
{
if (!m_d->image) {
return false;
}
const KisBaseNode* isolatedRoot = m_d->image->isolatedModeRoot().data();
return (this == isolatedRoot);
}
void KisBaseNode::setUserLocked(bool locked)
{
const bool isLocked = m_d->properties.boolProperty(KisLayerPropertiesIcons::locked.id(), true);
if (isLocked == locked) return;
m_d->properties.setProperty(KisLayerPropertiesIcons::locked.id(), locked);
baseNodeChangedCallback();
}
bool KisBaseNode::isEditable(bool checkVisibility) const
{
bool editable = true;
if (checkVisibility) {
editable = ((visible(false) || belongsToIsolatedGroup()) && !userLocked());
}
else {
editable = (!userLocked());
}
if (editable) {
KisBaseNodeSP parentNode = parentCallback();
if (parentNode && parentNode != this) {
editable = parentNode->isEditable(checkVisibility);
}
}
return editable;
}
bool KisBaseNode::hasEditablePaintDevice() const
{
return paintDevice() && isEditable();
}
void KisBaseNode::setCollapsed(bool collapsed)
{
const bool oldCollapsed = m_d->collapsed;
m_d->collapsed = collapsed;
if (oldCollapsed != collapsed) {
baseNodeCollapsedChangedCallback();
}
}
bool KisBaseNode::collapsed() const
{
return m_d->collapsed;
}
void KisBaseNode::setColorLabelIndex(int index)
{
const int currentLabel = colorLabelIndex();
if (currentLabel == index) return;
m_d->properties.setProperty(KisLayerPropertiesIcons::colorLabelIndex.id(), index);
baseNodeChangedCallback();
}
int KisBaseNode::colorLabelIndex() const
{
return m_d->properties.intProperty(KisLayerPropertiesIcons::colorLabelIndex.id(), 0);
}
QUuid KisBaseNode::uuid() const
{
return m_d->id;
}
void KisBaseNode::setUuid(const QUuid& id)
{
m_d->id = id;
baseNodeChangedCallback();
}
bool KisBaseNode::supportsLodMoves() const
{
return m_d->supportsLodMoves;
}
void KisBaseNode::setImage(KisImageWSP image)
{
m_d->image = image;
}
KisImageWSP KisBaseNode::image() const
{
return m_d->image;
}
bool KisBaseNode::isFakeNode() const
{
return false;
}
void KisBaseNode::setSupportsLodMoves(bool value)
{
m_d->supportsLodMoves = value;
}
QMap<QString, KisKeyframeChannel*> KisBaseNode::keyframeChannels() const
{
return m_d->keyframeChannels;
}
KisKeyframeChannel * KisBaseNode::getKeyframeChannel(const QString &id) const
{
QMap<QString, KisKeyframeChannel*>::const_iterator i = m_d->keyframeChannels.constFind(id);
if (i == m_d->keyframeChannels.constEnd()) {
return 0;
}
return i.value();
}
bool KisBaseNode::isPinnedToTimeline() const
{
return m_d->pinnedToTimeline;
}
void KisBaseNode::setPinnedToTimeline(bool pinned)
{
if (pinned == m_d->pinnedToTimeline) return;
m_d->pinnedToTimeline = pinned;
baseNodeChangedCallback();
}
KisKeyframeChannel * KisBaseNode::getKeyframeChannel(const QString &id, bool create)
{
KisKeyframeChannel *channel = getKeyframeChannel(id);
if (!channel && create) {
channel = requestKeyframeChannel(id);
if (channel) {
addKeyframeChannel(channel);
}
}
return channel;
}
bool KisBaseNode::isAnimated() const
{
return m_d->animated;
}
void KisBaseNode::enableAnimation()
{
m_d->animated = true;
baseNodeChangedCallback();
}
void KisBaseNode::addKeyframeChannel(KisKeyframeChannel *channel)
{
m_d->keyframeChannels.insert(channel->id(), channel);
emit keyframeChannelAdded(channel);
}
KisKeyframeChannel *KisBaseNode::requestKeyframeChannel(const QString &id)
{
if (id == KisKeyframeChannel::Opacity.id()) {
Q_ASSERT(m_d->opacityChannel.isNull());
KisPaintDeviceSP device = original();
if (device) {
KisNode* node = dynamic_cast<KisNode*>(this);
KisScalarKeyframeChannel * channel = new KisScalarKeyframeChannel(
KisKeyframeChannel::Opacity,
0, 255,
KisNodeWSP( node ),
KisKeyframe::Linear
);
m_d->opacityChannel.reset(channel);
return channel;
}
}
return 0;
}
diff --git a/libs/image/kis_base_node.h b/libs/image/kis_base_node.h
index 818804ade7..4213ef73d8 100644
--- a/libs/image/kis_base_node.h
+++ b/libs/image/kis_base_node.h
@@ -1,608 +1,608 @@
/*
* Copyright (c) 2007 Boudewijn Rempt <boud@valdyas.org>
*
* 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_BASE_NODE_H
#define _KIS_BASE_NODE_H
#include <QObject>
#include <QIcon>
#include <QUuid>
#include <QString>
#include <KoID.h>
#include "kis_shared.h"
#include "kis_paint_device.h"
#include "kis_processing_visitor.h" // included, not forward declared for msvc
class KoProperties;
class KoColorSpace;
class KoCompositeOp;
class KisNodeVisitor;
class KisUndoAdapter;
class KisKeyframeChannel;
#include "kritaimage_export.h"
/**
* A KisBaseNode is the base class for all components of an image:
* nodes, layers masks, selections. A node has a number of properties,
* can be represented as a thumbnail and knows what to do when it gets
* a certain paint device to process. A KisBaseNode does not know
* anything about its peers. You should not directly inherit from a
* KisBaseNode; inherit from KisNode instead.
*/
class KRITAIMAGE_EXPORT KisBaseNode : public QObject, public KisShared
{
Q_OBJECT
public:
/**
* Describes a property of a document section.
*
* FIXME: using a QList instead of QMap and not having an untranslated identifier,
* either enum or string, forces applications to rely on the order of properties
* or to compare the translated strings. This makes it hard to robustly extend the
* properties of document section items.
*/
struct Property
{
QString id;
/** i18n-ed name, suitable for displaying */
QString name;
/** Whether the property is a boolean (e.g. locked, visible) which can be toggled directly from the widget itself. */
bool isMutable;
/** Provide these if the property isMutable. */
QIcon onIcon;
QIcon offIcon;
/** If the property isMutable, provide a boolean. Otherwise, a string suitable for displaying. */
QVariant state;
/** If the property is mutable, specifies whether it can be put into stasis. When a property
is in stasis, a new state is created, and the old one is stored in stateInStasis. When
stasis ends, the old value is restored and the new one discarded */
bool canHaveStasis;
/** If the property isMutable and canHaveStasis, indicate whether it is in stasis or not */
bool isInStasis;
/** If the property isMutable and canHaveStasis, provide this value to store the property's
state while in stasis */
bool stateInStasis;
bool operator==(const Property &rhs) const {
return rhs.name == name && rhs.state == state && isInStasis == rhs.isInStasis;
}
Property(): isMutable( false ), isInStasis(false) { }
/// Constructor for a mutable property.
Property( const KoID &n, const QIcon &on, const QIcon &off, bool isOn )
: id(n.id()), name( n.name() ), isMutable( true ), onIcon( on ), offIcon( off ), state( isOn ),
canHaveStasis( false ), isInStasis(false) { }
/** Constructor for a mutable property accepting stasis */
Property( const KoID &n, const QIcon &on, const QIcon &off, bool isOn,
bool _isInStasis, bool _stateInStasis = false )
: id(n.id()), name(n.name()), isMutable( true ), onIcon( on ), offIcon( off ), state( isOn ),
canHaveStasis( true ), isInStasis( _isInStasis ), stateInStasis( _stateInStasis ) { }
/// Constructor for a nonmutable property.
Property( const KoID &n, const QString &s )
: id(n.id()), name(n.name()), isMutable( false ), state( s ), isInStasis(false) { }
};
/** Return this type for PropertiesRole. */
typedef QList<Property> PropertyList;
public:
/**
* Create a new, empty base node. The node is unnamed, unlocked
* visible and unlinked.
*/
KisBaseNode(KisImageWSP image);
/**
* Create a copy of this node.
*/
KisBaseNode(const KisBaseNode & rhs);
/**
* Delete this node
*/
~KisBaseNode() override;
/**
* Return the paintdevice you can use to change pixels on. For a
* paint layer these will be paint pixels, for an adjustment layer or a mask
* the selection paint device.
*
* @return the paint device to paint on. Can be 0 if the actual
* node type does not support painting.
*/
virtual KisPaintDeviceSP paintDevice() const = 0;
/**
* @return the rendered representation of a node
* before the effect masks have had their go at it. Can be 0.
*/
virtual KisPaintDeviceSP original() const = 0;
/**
* @return the fully rendered representation of this layer: its
* rendered original and its effect masks. Can be 0.
*/
virtual KisPaintDeviceSP projection() const = 0;
/**
* @return a special device from where the color picker tool should pick
* color when in layer-only mode. For most of the nodes just shortcuts
* to projection() device. TODO: can it be null?
*/
virtual KisPaintDeviceSP colorPickSourceDevice() const;
virtual const KoColorSpace *colorSpace() const = 0;
/**
* Return the opacity of this layer, scaled to a range between 0
* and 255.
* XXX: Allow true float opacity
*/
quint8 opacity() const; //0-255
/**
* Set the opacity for this layer. The range is between 0 and 255.
* The layer will be marked dirty.
*
* XXX: Allow true float opacity
*/
void setOpacity(quint8 val); //0-255
/**
* return the 8-bit opacity of this layer scaled to the range
* 0-100
*
* XXX: Allow true float opacity
*/
quint8 percentOpacity() const; //0-100
/**
* Set the opacity of this layer with a number between 0 and 100;
* the number will be scaled to between 0 and 255.
* XXX: Allow true float opacity
*/
void setPercentOpacity(quint8 val); //0-100
/**
* Return the composite op associated with this layer.
*/
virtual const KoCompositeOp *compositeOp() const = 0;
const QString& compositeOpId() const;
/**
* Set a new composite op for this layer. The layer will be marked
* dirty.
*/
void setCompositeOpId(const QString& compositeOpId);
/**
* @return unique id, which is now used by clone layers.
*/
QUuid uuid() const;
/**
* Set the uuid of node. This should only be used when loading
* existing node and in constructor.
*/
void setUuid(const QUuid& id);
/**
* return the name of this node. This is the same as the
* QObject::objectName.
*/
QString name() const {
return objectName();
}
/**
* set the QObject::objectName. This is also the user-visible name
* of the layer. The reason for this is that we want to see the
* layer name also when debugging.
*/
void setName(const QString& name) {
setObjectName(name);
baseNodeChangedCallback();
}
/**
* @return the icon used to represent the node type, for instance
* in the layerbox and in the menu.
*/
virtual QIcon icon() const {
return QIcon();
}
/**
* Return a the properties of this base node (locked, visible etc,
* with the right icons for their representation and their state.
*
* Subclasses can extend this list with new properties, like
* opacity for layers or visualized for masks.
*
* The order of properties is, unfortunately, for now, important,
* so take care which properties superclasses of your class
* define.
*
* KisBaseNode defines visible = 0, locked = 1
* KisLayer defines opacity = 2, compositeOp = 3
* KisMask defines active = 2 (KisMask does not inherit kislayer)
*/
virtual PropertyList sectionModelProperties() const;
/**
* Change the section model properties.
*/
virtual void setSectionModelProperties(const PropertyList &properties);
/**
* Return all the properties of this layer as a KoProperties-based
* serializable key-value list.
*/
const KoProperties & nodeProperties() const;
/**
* Set a node property.
* @param name name of the property to be set.
* @param value value to set the property to.
*/
void setNodeProperty(const QString & name, const QVariant & value);
/**
* Merge the specified properties with the properties of this
* layer. Wherever these properties overlap, the value of the
* node properties is changed. No properties on the node are
* deleted. If there are new properties in this list, they will be
* added on the node.
*/
void mergeNodeProperties(const KoProperties & properties);
/**
* Compare the given properties list with the properties of this
* node.
*
* @return false only if the same property exists in both lists
* but with a different value. Properties that are not in both
* lists are disregarded.
*/
bool check(const KoProperties & properties) const;
/**
* Accept the KisNodeVisitor (for the Visitor design pattern),
* should call the correct function on the KisNodeVisitor for this
* node type, so you need to override it for all leaf classes in
* the node inheritance hierarchy.
*
* return false if the visitor could not successfully act on this
* node instance.
*/
virtual bool accept(KisNodeVisitor &) {
return false;
}
/**
* Accept the KisNodeVisitor (for the Visitor design pattern),
* should call the correct function on the KisProcessingVisitor
* for this node type, so you need to override it for all leaf
* classes in the node inheritance hierarchy.
*
* The processing visitor differs from node visitor in the way
* that it accepts undo adapter, that allows the processing to
* be multithreaded
*/
virtual void accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter) {
Q_UNUSED(visitor);
Q_UNUSED(undoAdapter);
}
/**
* @return a thumbnail in requested size. The thumbnail is a rgba
* QImage and may have transparent parts. Returns a fully
* transparent QImage of the requested size if the current node
* type cannot generate a thumbnail. If the requested size is too
* big, return a null QImage.
*/
- virtual QImage createThumbnail(qint32 w, qint32 h);
+ virtual QImage createThumbnail(qint32 w, qint32 h, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio);
/**
* @return a thumbnail in requested size for the defined timestamp.
* The thumbnail is a rgba Image and may have transparent parts.
* Returns a fully transparent QImage of the requested size if the
* current node type cannot generate a thumbnail. If the requested
* size is too big, return a null QImage.
*/
- virtual QImage createThumbnailForFrame(qint32 w, qint32 h, int time);
+ virtual QImage createThumbnailForFrame(qint32 w, qint32 h, int time, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio);
/**
* Ask this node to re-read the pertinent settings from the krita
* configuration.
*/
virtual void updateSettings() {
}
/**
* @return true if this node is visible (i.e, active (except for
* selection masks where visible and active properties are
* different)) in the graph
*
* @param bool recursive if true, check whether all parents of
* this node are visible as well.
*/
virtual bool visible(bool recursive = false) const;
/**
* Set the visible status of this node. Visible nodes are active
* in the graph (except for selections masks which can be active
* while hidden), that is to say, they are taken into account
* when merging. Invisible nodes play no role in the final image
*, but will be modified when modifying all layers, for instance
* when cropping.
*
* Toggling the visibility of a node will not automatically lead
* to recomposition.
*
* @param visible the new visibility state
* @param isLoading if true, the property is set during loading.
*/
virtual void setVisible(bool visible, bool loading = false);
/**
* Return the locked status of this node. Locked nodes cannot be
* edited.
*/
bool userLocked() const;
/**
* Return whether or not the given node is isolated.
*/
bool belongsToIsolatedGroup() const;
/**
* Return whether or not the given node is the root of
* isolation.
*/
bool isIsolatedRoot() const;
/**
* Set the locked status of this node. Locked nodes cannot be
* edited.
*/
virtual void setUserLocked(bool l);
/**
* @return true if the node can be edited:
*
* if checkVisibility is true, then the node is only editable if it is visible and not locked.
* if checkVisibility is false, then the node is editable if it's not locked.
*/
bool isEditable(bool checkVisibility = true) const;
/**
* @return true if the node is editable and has a paintDevice()
* which which can be used for accessing pixels. It is an
* equivalent to (isEditable() && paintDevice())
*/
bool hasEditablePaintDevice() const;
/**
* @return the x-offset of this layer in the image plane.
*/
virtual qint32 x() const {
return 0;
}
/**
* Set the x offset of this layer in the image place.
* Re-implement this where it makes sense, by default it does
* nothing. It should not move child nodes.
*/
virtual void setX(qint32) {
}
/**
* @return the y-offset of this layer in the image plane.
*/
virtual qint32 y() const {
return 0;
}
/**
* Set the y offset of this layer in the image place.
* Re-implement this where it makes sense, by default it does
* nothing. It should not move child nodes.
*/
virtual void setY(qint32) {
}
/**
* Returns an approximation of where the bounds on actual data are
* in this node.
*/
virtual QRect extent() const {
return QRect();
}
/**
* Returns the exact bounds of where the actual data resides in
* this node.
*/
virtual QRect exactBounds() const {
return QRect();
}
/**
* Sets the state of the node to the value of @param collapsed
*/
void setCollapsed(bool collapsed);
/**
* returns the collapsed state of this node
*/
bool collapsed() const;
/**
* Sets a color label index associated to the layer. The actual
* color of the label and the number of available colors is
* defined by Krita GUI configuration.
*/
void setColorLabelIndex(int index);
/**
* \see setColorLabelIndex
*/
int colorLabelIndex() const;
/**
* Returns true if the offset of the node can be changed in a LodN
* stroke. Currently, all the nodes except shape layers support that.
*/
bool supportsLodMoves() const;
/**
* Return the keyframe channels associated with this node
* @return list of keyframe channels
*/
QMap<QString, KisKeyframeChannel*> keyframeChannels() const;
/**
* Get the keyframe channel with given id.
* If the channel does not yet exist and the node supports the requested
* channel, it will be created if create is true.
* @param id internal name for channel
* @param create attempt to create the channel if it does not exist yet
* @return keyframe channel with the id, or null if not found
*/
KisKeyframeChannel *getKeyframeChannel(const QString &id, bool create);
KisKeyframeChannel *getKeyframeChannel(const QString &id) const;
/**
* @return If true, node will be visible on animation timeline even when inactive.
*/
bool isPinnedToTimeline() const;
/**
* Set whether node should be visible on animation timeline even when inactive.
*/
void setPinnedToTimeline(bool pinned);
bool isAnimated() const;
void enableAnimation();
virtual void setImage(KisImageWSP image);
KisImageWSP image() const;
/**
* Fake node is not present in the layer stack and is not used
* for normal projection rendering algorithms.
*/
virtual bool isFakeNode() const;
protected:
void setSupportsLodMoves(bool value);
/**
* FIXME: This method is a workaround for getting parent node
* on a level of KisBaseNode. In fact, KisBaseNode should inherit
* KisNode (in terms of current Krita) to be able to traverse
* the node stack
*/
virtual KisBaseNodeSP parentCallback() const {
return KisBaseNodeSP();
}
virtual void notifyParentVisibilityChanged(bool value) {
Q_UNUSED(value);
}
/**
* This callback is called when some meta state of the base node
* that can be interesting to the UI has changed. E.g. visibility,
* lockness, opacity, compositeOp and etc. This signal is
* forwarded by the KisNode and KisNodeGraphListener to the model
* in KisLayerBox, so it can update its controls when information
* changes.
*/
virtual void baseNodeChangedCallback() {
}
/**
* This callback is called when collapsed state of the base node
* has changed. This signal is forwarded by the KisNode and
* KisNodeGraphListener to the model in KisLayerBox, so it can
* update its controls when information changes.
*/
virtual void baseNodeCollapsedChangedCallback() {
}
virtual void baseNodeInvalidateAllFramesCallback() {
}
/**
* Add a keyframe channel for this node. The channel will be added
* to the common hash table which will be available to the UI.
*
* WARNING: the \p channel object *NOT* become owned by the node!
* The caller must ensure manually that the lifetime of
* the object coincide with the lifetime of the node.
*/
virtual void addKeyframeChannel(KisKeyframeChannel* channel);
/**
* Attempt to create the requested channel. Used internally by getKeyframeChannel.
* Subclasses should implement this method to catch any new channel types they support.
* @param id channel to create
* @return newly created channel or null
*/
virtual KisKeyframeChannel * requestKeyframeChannel(const QString &id);
Q_SIGNALS:
void keyframeChannelAdded(KisKeyframeChannel *channel);
private:
struct Private;
Private * const m_d;
};
Q_DECLARE_METATYPE( KisBaseNode::PropertyList )
#endif
diff --git a/libs/image/kis_gradient_painter.cc b/libs/image/kis_gradient_painter.cc
index fd2ff9e584..973884d056 100644
--- a/libs/image/kis_gradient_painter.cc
+++ b/libs/image/kis_gradient_painter.cc
@@ -1,893 +1,1362 @@
/*
* Copyright (c) 2004 Adrian Page <adrian@pagenet.plus.com>
* Copyright (c) 2019 Miguel Lopez <reptillia39@live.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_gradient_painter.h"
#include <cfloat>
#include <KoColorSpace.h>
#include <resources/KoAbstractGradient.h>
#include <KoUpdater.h>
#include <KoEphemeralResource.h>
#include "kis_global.h"
#include "kis_paint_device.h"
#include <resources/KoPattern.h>
#include "kis_selection.h"
#include <KisSequentialIteratorProgress.h>
#include "kis_image.h"
#include "kis_random_accessor_ng.h"
#include "kis_gradient_shape_strategy.h"
#include "kis_polygonal_gradient_shape_strategy.h"
#include "kis_cached_gradient_shape_strategy.h"
#include "krita_utils.h"
+#include "KoMixColorsOp.h"
class CachedGradient : public KoEphemeralResource<KoAbstractGradient>
{
public:
explicit CachedGradient(const KoAbstractGradientSP gradient, qint32 steps, const KoColorSpace *cs)
: KoEphemeralResource<KoAbstractGradient>(gradient->filename())
, m_subject(gradient)
, m_max(steps - 1)
, m_colorSpace(cs)
, m_black(KoColor(cs))
{
KoColor tmpColor(m_colorSpace);
for(qint32 i = 0; i < steps; i++) {
m_subject->colorAt(tmpColor, qreal(i) / m_max);
m_colors << tmpColor;
}
}
~CachedGradient() override {}
KoResourceSP clone() const override {
return KoResourceSP(new CachedGradient(m_subject, m_max + 1, m_colorSpace));
}
/**
* Creates a QGradient from the gradient.
* The resulting QGradient might differ from original gradient
*/
QGradient* toQGradient() const override
{
return m_subject->toQGradient();
}
QPair<QString, QString> resourceType() const override {
return m_subject->resourceType();
}
/// gets the color data at position 0 <= t <= 1
const quint8 *cachedAt(qreal t) const
{
qint32 tInt = t * m_max + 0.5;
if (m_colors.size() > tInt) {
return m_colors[tInt].data();
}
else {
return m_black.data();
}
}
void setColorSpace(KoColorSpace* colorSpace) { m_colorSpace = colorSpace; }
const KoColorSpace * colorSpace() const { return m_colorSpace; }
QByteArray generateMD5() const override { return QByteArray(); }
private:
const KoAbstractGradientSP m_subject;
qint32 m_max;
const KoColorSpace *m_colorSpace;
QVector<KoColor> m_colors;
KoColor m_black;
};
namespace
{
class LinearGradientStrategy : public KisGradientShapeStrategy
{
public:
LinearGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd);
double valueAt(double x, double y) const override;
protected:
double m_normalisedVectorX;
double m_normalisedVectorY;
double m_vectorLength;
};
LinearGradientStrategy::LinearGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd)
: KisGradientShapeStrategy(gradientVectorStart, gradientVectorEnd)
{
double dx = gradientVectorEnd.x() - gradientVectorStart.x();
double dy = gradientVectorEnd.y() - gradientVectorStart.y();
m_vectorLength = sqrt((dx * dx) + (dy * dy));
if (m_vectorLength < DBL_EPSILON) {
m_normalisedVectorX = 0;
m_normalisedVectorY = 0;
} else {
m_normalisedVectorX = dx / m_vectorLength;
m_normalisedVectorY = dy / m_vectorLength;
}
}
double LinearGradientStrategy::valueAt(double x, double y) const
{
double vx = x - m_gradientVectorStart.x();
double vy = y - m_gradientVectorStart.y();
// Project the vector onto the normalised gradient vector.
double t = vx * m_normalisedVectorX + vy * m_normalisedVectorY;
if (m_vectorLength < DBL_EPSILON) {
t = 0;
} else {
// Scale to 0 to 1 over the gradient vector length.
t /= m_vectorLength;
}
return t;
}
class BiLinearGradientStrategy : public LinearGradientStrategy
{
public:
BiLinearGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd);
double valueAt(double x, double y) const override;
};
BiLinearGradientStrategy::BiLinearGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd)
: LinearGradientStrategy(gradientVectorStart, gradientVectorEnd)
{
}
double BiLinearGradientStrategy::valueAt(double x, double y) const
{
double t = LinearGradientStrategy::valueAt(x, y);
// Reflect
if (t < -DBL_EPSILON) {
t = -t;
}
return t;
}
class RadialGradientStrategy : public KisGradientShapeStrategy
{
public:
RadialGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd);
double valueAt(double x, double y) const override;
protected:
double m_radius;
};
RadialGradientStrategy::RadialGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd)
: KisGradientShapeStrategy(gradientVectorStart, gradientVectorEnd)
{
double dx = gradientVectorEnd.x() - gradientVectorStart.x();
double dy = gradientVectorEnd.y() - gradientVectorStart.y();
m_radius = sqrt((dx * dx) + (dy * dy));
}
double RadialGradientStrategy::valueAt(double x, double y) const
{
double dx = x - m_gradientVectorStart.x();
double dy = y - m_gradientVectorStart.y();
double distance = sqrt((dx * dx) + (dy * dy));
double t;
if (m_radius < DBL_EPSILON) {
t = 0;
} else {
t = distance / m_radius;
}
return t;
}
class SquareGradientStrategy : public KisGradientShapeStrategy
{
public:
SquareGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd);
double valueAt(double x, double y) const override;
protected:
double m_normalisedVectorX;
double m_normalisedVectorY;
double m_vectorLength;
};
SquareGradientStrategy::SquareGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd)
: KisGradientShapeStrategy(gradientVectorStart, gradientVectorEnd)
{
double dx = gradientVectorEnd.x() - gradientVectorStart.x();
double dy = gradientVectorEnd.y() - gradientVectorStart.y();
m_vectorLength = sqrt((dx * dx) + (dy * dy));
if (m_vectorLength < DBL_EPSILON) {
m_normalisedVectorX = 0;
m_normalisedVectorY = 0;
} else {
m_normalisedVectorX = dx / m_vectorLength;
m_normalisedVectorY = dy / m_vectorLength;
}
}
double SquareGradientStrategy::valueAt(double x, double y) const
{
double px = x - m_gradientVectorStart.x();
double py = y - m_gradientVectorStart.y();
double distance1 = 0;
double distance2 = 0;
if (m_vectorLength > DBL_EPSILON) {
// Point to line distance is:
// distance = ((l0.y() - l1.y()) * p.x() + (l1.x() - l0.x()) * p.y() + l0.x() * l1.y() - l1.x() * l0.y()) / m_vectorLength;
//
// Here l0 = (0, 0) and |l1 - l0| = 1
distance1 = -m_normalisedVectorY * px + m_normalisedVectorX * py;
distance1 = fabs(distance1);
// Rotate point by 90 degrees and get the distance to the perpendicular
distance2 = -m_normalisedVectorY * -py + m_normalisedVectorX * px;
distance2 = fabs(distance2);
}
double t = qMax(distance1, distance2) / m_vectorLength;
return t;
}
class ConicalGradientStrategy : public KisGradientShapeStrategy
{
public:
ConicalGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd);
double valueAt(double x, double y) const override;
protected:
double m_vectorAngle;
};
ConicalGradientStrategy::ConicalGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd)
: KisGradientShapeStrategy(gradientVectorStart, gradientVectorEnd)
{
double dx = gradientVectorEnd.x() - gradientVectorStart.x();
double dy = gradientVectorEnd.y() - gradientVectorStart.y();
// Get angle from 0 to 2 PI.
m_vectorAngle = atan2(dy, dx) + M_PI;
}
double ConicalGradientStrategy::valueAt(double x, double y) const
{
double px = x - m_gradientVectorStart.x();
double py = y - m_gradientVectorStart.y();
double angle = atan2(py, px) + M_PI;
angle -= m_vectorAngle;
if (angle < 0) {
angle += 2 * M_PI;
}
double t = angle / (2 * M_PI);
return t;
}
class ConicalSymetricGradientStrategy : public KisGradientShapeStrategy
{
public:
ConicalSymetricGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd);
double valueAt(double x, double y) const override;
protected:
double m_vectorAngle;
};
ConicalSymetricGradientStrategy::ConicalSymetricGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd)
: KisGradientShapeStrategy(gradientVectorStart, gradientVectorEnd)
{
double dx = gradientVectorEnd.x() - gradientVectorStart.x();
double dy = gradientVectorEnd.y() - gradientVectorStart.y();
// Get angle from 0 to 2 PI.
m_vectorAngle = atan2(dy, dx) + M_PI;
}
double ConicalSymetricGradientStrategy::valueAt(double x, double y) const
{
double px = x - m_gradientVectorStart.x();
double py = y - m_gradientVectorStart.y();
double angle = atan2(py, px) + M_PI;
angle -= m_vectorAngle;
if (angle < 0) {
angle += 2 * M_PI;
}
double t;
if (angle < M_PI) {
t = angle / M_PI;
} else {
t = 1 - ((angle - M_PI) / M_PI);
}
return t;
}
class SpiralGradientStrategy : public KisGradientShapeStrategy
{
public:
SpiralGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd);
double valueAt(double x, double y) const override;
protected:
double m_vectorAngle;
double m_radius;
};
SpiralGradientStrategy::SpiralGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd)
: KisGradientShapeStrategy(gradientVectorStart, gradientVectorEnd)
{
double dx = gradientVectorEnd.x() - gradientVectorStart.x();
double dy = gradientVectorEnd.y() - gradientVectorStart.y();
// Get angle from 0 to 2 PI.
m_vectorAngle = atan2(dy, dx) + M_PI;
m_radius = sqrt((dx * dx) + (dy * dy));
};
double SpiralGradientStrategy::valueAt(double x, double y) const
{
double dx = x - m_gradientVectorStart.x();
double dy = y - m_gradientVectorStart.y();
double distance = sqrt((dx * dx) + (dy * dy));
double angle = atan2(dy, dx) + M_PI;
double t;
angle -= m_vectorAngle;
if (m_radius < DBL_EPSILON) {
t = 0;
} else {
t = distance / m_radius;
}
if (angle < 0) {
angle += 2 * M_PI;
}
t += angle / (2 * M_PI);
return t;
};
class ReverseSpiralGradientStrategy : public KisGradientShapeStrategy
{
public:
ReverseSpiralGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd);
double valueAt(double x, double y) const override;
protected:
double m_vectorAngle;
double m_radius;
};
ReverseSpiralGradientStrategy::ReverseSpiralGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd)
: KisGradientShapeStrategy(gradientVectorStart, gradientVectorEnd)
{
double dx = gradientVectorEnd.x() - gradientVectorStart.x();
double dy = gradientVectorEnd.y() - gradientVectorStart.y();
// Get angle from 0 to 2 PI.
m_vectorAngle = atan2(dy, dx) + M_PI;
m_radius = sqrt((dx * dx) + (dy * dy));
};
double ReverseSpiralGradientStrategy::valueAt(double x, double y) const
{
double dx = x - m_gradientVectorStart.x();
double dy = y - m_gradientVectorStart.y();
double distance = sqrt((dx * dx) + (dy * dy));
double angle = atan2(dy, dx) + M_PI;
double t;
angle -= m_vectorAngle;
if (m_radius < DBL_EPSILON) {
t = 0;
} else {
t = distance / m_radius;
}
if (angle < 0) {
angle += 2 * M_PI;
}
//Reverse direction of spiral gradient
t += 1 - (angle / (2 * M_PI));
return t;
};
class GradientRepeatStrategy
{
public:
GradientRepeatStrategy() {}
virtual ~GradientRepeatStrategy() {}
virtual double valueAt(double t) const = 0;
};
class GradientRepeatNoneStrategy : public GradientRepeatStrategy
{
public:
static GradientRepeatNoneStrategy *instance();
double valueAt(double t) const override;
private:
GradientRepeatNoneStrategy() {}
static GradientRepeatNoneStrategy *m_instance;
};
GradientRepeatNoneStrategy *GradientRepeatNoneStrategy::m_instance = 0;
GradientRepeatNoneStrategy *GradientRepeatNoneStrategy::instance()
{
if (m_instance == 0) {
m_instance = new GradientRepeatNoneStrategy();
Q_CHECK_PTR(m_instance);
}
return m_instance;
}
// Output is clamped to 0 to 1.
double GradientRepeatNoneStrategy::valueAt(double t) const
{
double value = t;
if (t < DBL_EPSILON) {
value = 0;
} else if (t > 1 - DBL_EPSILON) {
value = 1;
}
return value;
}
class GradientRepeatForwardsStrategy : public GradientRepeatStrategy
{
public:
static GradientRepeatForwardsStrategy *instance();
double valueAt(double t) const override;
private:
GradientRepeatForwardsStrategy() {}
static GradientRepeatForwardsStrategy *m_instance;
};
GradientRepeatForwardsStrategy *GradientRepeatForwardsStrategy::m_instance = 0;
GradientRepeatForwardsStrategy *GradientRepeatForwardsStrategy::instance()
{
if (m_instance == 0) {
m_instance = new GradientRepeatForwardsStrategy();
Q_CHECK_PTR(m_instance);
}
return m_instance;
}
// Output is 0 to 1, 0 to 1, 0 to 1...
double GradientRepeatForwardsStrategy::valueAt(double t) const
{
int i = static_cast<int>(t);
if (t < DBL_EPSILON) {
i--;
}
double value = t - i;
return value;
}
class GradientRepeatAlternateStrategy : public GradientRepeatStrategy
{
public:
static GradientRepeatAlternateStrategy *instance();
double valueAt(double t) const override;
private:
GradientRepeatAlternateStrategy() {}
static GradientRepeatAlternateStrategy *m_instance;
};
GradientRepeatAlternateStrategy *GradientRepeatAlternateStrategy::m_instance = 0;
GradientRepeatAlternateStrategy *GradientRepeatAlternateStrategy::instance()
{
if (m_instance == 0) {
m_instance = new GradientRepeatAlternateStrategy();
Q_CHECK_PTR(m_instance);
}
return m_instance;
}
// Output is 0 to 1, 1 to 0, 0 to 1, 1 to 0...
double GradientRepeatAlternateStrategy::valueAt(double t) const
{
if (t < 0) {
t = -t;
}
int i = static_cast<int>(t);
double value = t - i;
if (i % 2 == 1) {
value = 1 - value;
}
return value;
}
//Had to create this class to solve alternating mode for cases where values should be repeated for every HalfValues like for example, spirals...
class GradientRepeatModuloDivisiveContinuousHalfStrategy : public GradientRepeatStrategy
{
public:
static GradientRepeatModuloDivisiveContinuousHalfStrategy *instance();
double valueAt(double t) const override;
private:
GradientRepeatModuloDivisiveContinuousHalfStrategy() {}
static GradientRepeatModuloDivisiveContinuousHalfStrategy *m_instance;
};
GradientRepeatModuloDivisiveContinuousHalfStrategy *GradientRepeatModuloDivisiveContinuousHalfStrategy::m_instance = 0;
GradientRepeatModuloDivisiveContinuousHalfStrategy *GradientRepeatModuloDivisiveContinuousHalfStrategy::instance()
{
if (m_instance == 0) {
m_instance = new GradientRepeatModuloDivisiveContinuousHalfStrategy();
Q_CHECK_PTR(m_instance);
}
return m_instance;
}
// Output is 0 to 1, 1 to 0, 0 to 1, 1 to 0 per HalfValues
double GradientRepeatModuloDivisiveContinuousHalfStrategy::valueAt(double t) const
{
if (t < 0) {
t = -t;
}
int i = static_cast<int>(t*2);
int ti = static_cast<int>(t);
double value = t - ti;
if (i % 2 == 1) {
value = 1 - value;
}
return value*2;
}
+
+class RepeatForwardsPaintPolicy
+{
+public:
+ RepeatForwardsPaintPolicy(KisGradientPainter::enumGradientShape shape);
+
+ void setup(const QPointF& gradientVectorStart,
+ const QPointF& gradientVectorEnd,
+ const QSharedPointer<KisGradientShapeStrategy> &shapeStrategy,
+ const GradientRepeatStrategy *repeatStrategy,
+ qreal antiAliasThreshold,
+ bool reverseGradient,
+ const CachedGradient * cachedGradient);
+
+ const quint8 *colorAt(qreal x, qreal y) const;
+
+private:
+ KisGradientPainter::enumGradientShape m_shape;
+ qreal m_antiAliasThresholdNormalized;
+ qreal m_antiAliasThresholdNormalizedRev;
+ qreal m_antiAliasThresholdNormalizedDbl;
+ QSharedPointer<KisGradientShapeStrategy> m_shapeStrategy;
+ const GradientRepeatStrategy *m_repeatStrategy;
+ bool m_reverseGradient;
+ const CachedGradient *m_cachedGradient;
+ const quint8 *m_extremeColors[2];
+ const KoColorSpace *m_colorSpace;
+ mutable QVector<quint8> m_resultColor;
+};
+
+RepeatForwardsPaintPolicy::RepeatForwardsPaintPolicy(KisGradientPainter::enumGradientShape shape)
+ : m_shape(shape)
+{}
+
+void RepeatForwardsPaintPolicy::setup(const QPointF& gradientVectorStart,
+ const QPointF& gradientVectorEnd,
+ const QSharedPointer<KisGradientShapeStrategy> &shapeStrategy,
+ const GradientRepeatStrategy *repeatStrategy,
+ qreal antiAliasThreshold,
+ bool reverseGradient,
+ const CachedGradient * cachedGradient)
+{
+ qreal dx = gradientVectorEnd.x() - gradientVectorStart.x();
+ qreal dy = gradientVectorEnd.y() - gradientVectorStart.y();
+ qreal distanceInPixels = sqrt(dx * dx + dy * dy);
+ // Compute the area to be be smoothed
+ // based on the length of the gradient
+ m_antiAliasThresholdNormalized = antiAliasThreshold / distanceInPixels;
+ m_antiAliasThresholdNormalizedRev = 1. - m_antiAliasThresholdNormalized;
+ m_antiAliasThresholdNormalizedDbl = 2. * m_antiAliasThresholdNormalized;
+
+ m_shapeStrategy = shapeStrategy;
+ m_repeatStrategy = repeatStrategy;
+
+ m_reverseGradient = reverseGradient;
+
+ m_cachedGradient = cachedGradient;
+ m_extremeColors[0] = m_cachedGradient->cachedAt(1.);
+ m_extremeColors[1] = m_cachedGradient->cachedAt(0.);
+
+ m_colorSpace = m_cachedGradient->colorSpace();
+
+ m_resultColor = QVector<quint8>(m_colorSpace->pixelSize());
+}
+
+const quint8 *RepeatForwardsPaintPolicy::colorAt(qreal x, qreal y) const
+{
+ qreal t = m_shapeStrategy->valueAt(x, y);
+ // Early return if the pixel is near the center of the gradient if
+ // the shape is radial or square.
+ // This prevents applying smoothing since there are
+ // no aliasing artifacts in these gradient shapes at the center
+ if (t <= m_antiAliasThresholdNormalized &&
+ (m_shape == KisGradientPainter::GradientShapeBiLinear ||
+ m_shape == KisGradientPainter::GradientShapeRadial ||
+ m_shape == KisGradientPainter::GradientShapeSquare)) {
+ if (m_reverseGradient) {
+ t = 1 - t;
+ }
+ return m_cachedGradient->cachedAt(t);
+ }
+
+ t = m_repeatStrategy->valueAt(t);
+
+ if (m_reverseGradient) {
+ t = 1 - t;
+ }
+
+ // If this pixel is in the area of the smoothing,
+ // then perform bilinear interpolation between the extreme colors.
+ if (t <= m_antiAliasThresholdNormalized || t >= m_antiAliasThresholdNormalizedRev) {
+ qreal s;
+ if (t <= m_antiAliasThresholdNormalized) {
+ s = .5 + t / m_antiAliasThresholdNormalizedDbl;
+ } else {
+ s = (t - m_antiAliasThresholdNormalizedRev) / m_antiAliasThresholdNormalizedDbl;
+ }
+
+ qint16 colorWeights[2];
+ colorWeights[0] = static_cast<quint8>((1.0 - s) * 255 + 0.5);
+ colorWeights[1] = 255 - colorWeights[0];
+
+ m_colorSpace->mixColorsOp()->mixColors(m_extremeColors, colorWeights, 2, m_resultColor.data());
+
+ return m_resultColor.data();
+ }
+
+ return m_cachedGradient->cachedAt(t);
+}
+
+class ConicalGradientPaintPolicy
+{
+public:
+ void setup(const QPointF& gradientVectorStart,
+ const QPointF& gradientVectorEnd,
+ const QSharedPointer<KisGradientShapeStrategy> &shapeStrategy,
+ const GradientRepeatStrategy *repeatStrategy,
+ qreal antiAliasThreshold,
+ bool reverseGradient,
+ const CachedGradient * cachedGradient);
+
+ const quint8 *colorAt(qreal x, qreal y) const;
+
+private:
+ QPointF m_gradientVectorStart;
+ QSharedPointer<KisGradientShapeStrategy> m_shapeStrategy;
+ const GradientRepeatStrategy *m_repeatStrategy;
+ qreal m_singularityThreshold;
+ qreal m_antiAliasThreshold;
+ bool m_reverseGradient;
+ const CachedGradient *m_cachedGradient;
+ const quint8 *m_extremeColors[2];
+ const KoColorSpace *m_colorSpace;
+ mutable QVector<quint8> m_resultColor;
+};
+
+void ConicalGradientPaintPolicy::setup(const QPointF& gradientVectorStart,
+ const QPointF& gradientVectorEnd,
+ const QSharedPointer<KisGradientShapeStrategy> &shapeStrategy,
+ const GradientRepeatStrategy *repeatStrategy,
+ qreal antiAliasThreshold,
+ bool reverseGradient,
+ const CachedGradient * cachedGradient)
+{
+ Q_UNUSED(gradientVectorEnd);
+
+ m_gradientVectorStart = gradientVectorStart;
+
+ m_shapeStrategy = shapeStrategy;
+ m_repeatStrategy = repeatStrategy;
+
+ m_singularityThreshold = 8.;
+ m_antiAliasThreshold = antiAliasThreshold;
+
+ m_reverseGradient = reverseGradient;
+
+ m_cachedGradient = cachedGradient;
+ m_extremeColors[0] = m_cachedGradient->cachedAt(1.);
+ m_extremeColors[1] = m_cachedGradient->cachedAt(0.);
+
+ m_colorSpace = m_cachedGradient->colorSpace();
+
+ m_resultColor = QVector<quint8>(m_colorSpace->pixelSize());
+}
+
+const quint8 *ConicalGradientPaintPolicy::colorAt(qreal x, qreal y) const
+{
+ // Compute the distance from the center of the gradient to thecurrent pixel
+ qreal dx = x - m_gradientVectorStart.x();
+ qreal dy = y - m_gradientVectorStart.y();
+ qreal distanceInPixels = sqrt(dx * dx + dy * dy);
+ // Compute the perimeter for this distance
+ qreal perimeter = 2. * M_PI * distanceInPixels;
+ // The smoothing is applied in the vicinity of the aliased border.
+ // The width of the vicinity is an area antiAliasThreshold pixels wide
+ // to each side of the border, but in this case the area is scaled down
+ // if it is too close to the center
+ qreal antiAliasThresholdNormalized;
+ if (distanceInPixels < m_singularityThreshold){
+ antiAliasThresholdNormalized = distanceInPixels * m_antiAliasThreshold / m_singularityThreshold;
+ } else {
+ antiAliasThresholdNormalized = m_antiAliasThreshold;
+ }
+ antiAliasThresholdNormalized = antiAliasThresholdNormalized / perimeter;
+ qreal antiAliasThresholdNormalizedRev = 1. - antiAliasThresholdNormalized;
+ qreal antiAliasThresholdNormalizedDbl = 2. * antiAliasThresholdNormalized;
+
+ qreal t = m_shapeStrategy->valueAt(x, y);
+ t = m_repeatStrategy->valueAt(t);
+
+ if (m_reverseGradient) {
+ t = 1 - t;
+ }
+
+ // If this pixel is in the area of the smoothing,
+ // then perform bilinear interpolation between the extreme colors.
+ if (t <= antiAliasThresholdNormalized || t >= antiAliasThresholdNormalizedRev) {
+ qreal s;
+ if (t <= antiAliasThresholdNormalized) {
+ s = .5 + t / antiAliasThresholdNormalizedDbl;
+ } else {
+ s = (t - antiAliasThresholdNormalizedRev) / antiAliasThresholdNormalizedDbl;
+ }
+
+ qint16 colorWeights[2];
+ colorWeights[0] = static_cast<quint8>((1.0 - s) * 255 + 0.5);
+ colorWeights[1] = 255 - colorWeights[0];
+
+ m_colorSpace->mixColorsOp()->mixColors(m_extremeColors, colorWeights, 2, m_resultColor.data());
+
+ return m_resultColor.data();
+ }
+
+ return m_cachedGradient->cachedAt(t);
+}
+
+class SpyralGradientRepeatNonePaintPolicy
+{
+public:
+ SpyralGradientRepeatNonePaintPolicy(bool isReverseSpiral = false);
+
+ void setup(const QPointF& gradientVectorStart,
+ const QPointF& gradientVectorEnd,
+ const QSharedPointer<KisGradientShapeStrategy> &shapeStrategy,
+ const GradientRepeatStrategy *repeatStrategy,
+ qreal antiAliasThreshold,
+ bool reverseGradient,
+ const CachedGradient * cachedGradient);
+
+ const quint8 *colorAt(qreal x, qreal y) const;
+
+private:
+ QPointF m_gradientVectorStart;
+ qreal m_distanceInPixels;
+ qreal m_singularityThreshold;
+ qreal m_angle;
+ QSharedPointer<KisGradientShapeStrategy> m_shapeStrategy;
+ const GradientRepeatStrategy *m_repeatStrategy;
+ qreal m_antiAliasThreshold;
+ bool m_reverseGradient;
+ const CachedGradient *m_cachedGradient;
+ mutable const quint8 *m_extremeColors[2];
+ const KoColorSpace *m_colorSpace;
+ mutable QVector<quint8> m_resultColor;
+ bool m_isReverseSpiral;
+};
+
+SpyralGradientRepeatNonePaintPolicy::SpyralGradientRepeatNonePaintPolicy(bool isReverseSpiral)
+ : m_isReverseSpiral(isReverseSpiral)
+{
+}
+
+void SpyralGradientRepeatNonePaintPolicy::setup(const QPointF& gradientVectorStart,
+ const QPointF& gradientVectorEnd,
+ const QSharedPointer<KisGradientShapeStrategy> &shapeStrategy,
+ const GradientRepeatStrategy *repeatStrategy,
+ qreal antiAliasThreshold,
+ bool reverseGradient,
+ const CachedGradient * cachedGradient)
+{
+ m_gradientVectorStart = gradientVectorStart;
+
+ qreal dx = gradientVectorEnd.x() - gradientVectorStart.x();
+ qreal dy = gradientVectorEnd.y() - gradientVectorStart.y();
+ m_distanceInPixels = sqrt(dx * dx + dy * dy);
+ m_singularityThreshold = m_distanceInPixels / 32.;
+ m_angle = atan2(dy, dx) + M_PI;
+
+ m_shapeStrategy = shapeStrategy;
+ m_repeatStrategy = repeatStrategy;
+
+ m_antiAliasThreshold = antiAliasThreshold;
+
+ m_reverseGradient = reverseGradient;
+
+ m_cachedGradient = cachedGradient;
+
+ m_colorSpace = m_cachedGradient->colorSpace();
+
+ m_resultColor = QVector<quint8>(m_colorSpace->pixelSize());
+}
+
+const quint8 *SpyralGradientRepeatNonePaintPolicy::colorAt(qreal x, qreal y) const
+{
+ // Compute the distance from the center of the gradient to thecurrent pixel
+ qreal dx = x - m_gradientVectorStart.x();
+ qreal dy = y - m_gradientVectorStart.y();
+ qreal distanceInPixels = sqrt(dx * dx + dy * dy);
+ // Compute the perimeter for this distance
+ qreal perimeter = 2. * M_PI * distanceInPixels;
+ // The smoothing is applied in the vicinity of the aliased border.
+ // The width of the vicinity is an area antiAliasThreshold pixels wide
+ // to each side of the border, but in this case the area is scaled down
+ // if it is too close to the center
+ qreal antiAliasThresholdNormalized;
+ if (distanceInPixels < m_singularityThreshold) {
+ antiAliasThresholdNormalized = distanceInPixels * m_antiAliasThreshold / m_singularityThreshold;
+ } else {
+ antiAliasThresholdNormalized = m_antiAliasThreshold;
+ }
+ antiAliasThresholdNormalized = antiAliasThresholdNormalized / perimeter;
+ qreal antiAliasThresholdNormalizedRev = 1. - antiAliasThresholdNormalized;
+ qreal antiAliasThresholdNormalizedDbl = 2. * antiAliasThresholdNormalized;
+
+ qreal t = m_shapeStrategy->valueAt(x, y);
+ t = m_repeatStrategy->valueAt(t);
+
+ if (m_reverseGradient) {
+ t = 1 - t;
+ }
+
+ // Compute the area to be be smoothed based on the angle of the gradient
+ // and the angle of the current pixel to the center of the gradient
+ qreal angle = atan2(dy, dx) + M_PI;
+ angle -= m_angle;
+ if (angle < 0.) {
+ angle += 2. * M_PI;
+ }
+ angle /= (2. * M_PI);
+
+ angle = m_repeatStrategy->valueAt(angle);
+
+ // If this pixel is in the area of the smoothing,
+ // then perform bilinear interpolation between the extreme colors.
+ if (distanceInPixels < m_distanceInPixels && (angle <= antiAliasThresholdNormalized || angle >= antiAliasThresholdNormalizedRev)) {
+ qreal s;
+ if (angle <= antiAliasThresholdNormalized) {
+ s = .5 + angle / antiAliasThresholdNormalizedDbl;
+ } else {
+ s = (angle - antiAliasThresholdNormalizedRev) / antiAliasThresholdNormalizedDbl;
+ }
+
+ if (m_reverseGradient) {
+ distanceInPixels = m_distanceInPixels - distanceInPixels;
+ m_extremeColors[0] = m_cachedGradient->cachedAt(0.);
+ } else {
+ m_extremeColors[0] = m_cachedGradient->cachedAt(1.);
+ }
+
+ if (m_isReverseSpiral) {
+ m_extremeColors[1] = m_extremeColors[0];
+ m_extremeColors[0] = (m_cachedGradient->cachedAt(distanceInPixels / m_distanceInPixels));
+ } else {
+ m_extremeColors[1] = (m_cachedGradient->cachedAt(distanceInPixels / m_distanceInPixels));
+ }
+
+ qint16 colorWeights[2];
+ colorWeights[0] = static_cast<quint8>((1.0 - s) * 255 + 0.5);
+ colorWeights[1] = 255 - colorWeights[0];
+
+ m_colorSpace->mixColorsOp()->mixColors(m_extremeColors, colorWeights, 2, m_resultColor.data());
+
+ return m_resultColor.data();
+ }
+
+ return m_cachedGradient->cachedAt(t);
+}
+
+class NoAntialiasPaintPolicy
+{
+public:
+ void setup(const QPointF& gradientVectorStart,
+ const QPointF& gradientVectorEnd,
+ const QSharedPointer<KisGradientShapeStrategy> &shapeStrategy,
+ const GradientRepeatStrategy *repeatStrategy,
+ qreal antiAliasThreshold,
+ bool reverseGradient,
+ const CachedGradient * cachedGradient);
+
+ const quint8 *colorAt(qreal x, qreal y) const;
+
+private:
+ QSharedPointer<KisGradientShapeStrategy> m_shapeStrategy;
+ const GradientRepeatStrategy *m_repeatStrategy;
+ bool m_reverseGradient;
+ const CachedGradient *m_cachedGradient;
+};
+
+void NoAntialiasPaintPolicy::setup(const QPointF& gradientVectorStart,
+ const QPointF& gradientVectorEnd,
+ const QSharedPointer<KisGradientShapeStrategy> &shapeStrategy,
+ const GradientRepeatStrategy *repeatStrategy,
+ qreal antiAliasThreshold,
+ bool reverseGradient,
+ const CachedGradient * cachedGradient)
+{
+ Q_UNUSED(gradientVectorStart);
+ Q_UNUSED(gradientVectorEnd);
+ Q_UNUSED(antiAliasThreshold);
+ m_shapeStrategy = shapeStrategy;
+ m_repeatStrategy = repeatStrategy;
+ m_reverseGradient = reverseGradient;
+ m_cachedGradient = cachedGradient;
+}
+
+const quint8 *NoAntialiasPaintPolicy::colorAt(qreal x, qreal y) const
+{
+ qreal t = m_shapeStrategy->valueAt(x, y);
+ t = m_repeatStrategy->valueAt(t);
+
+ if (m_reverseGradient) {
+ t = 1 - t;
+ }
+
+ return m_cachedGradient->cachedAt(t);
+}
+
}
struct Q_DECL_HIDDEN KisGradientPainter::Private
{
enumGradientShape shape;
struct ProcessRegion {
ProcessRegion() {}
ProcessRegion(QSharedPointer<KisGradientShapeStrategy> _precalculatedShapeStrategy,
const QRect &_processRect)
: precalculatedShapeStrategy(_precalculatedShapeStrategy),
processRect(_processRect) {}
QSharedPointer<KisGradientShapeStrategy> precalculatedShapeStrategy;
QRect processRect;
};
QVector<ProcessRegion> processRegions;
};
KisGradientPainter::KisGradientPainter()
: m_d(new Private())
{
}
KisGradientPainter::KisGradientPainter(KisPaintDeviceSP device)
: KisPainter(device),
m_d(new Private())
{
}
KisGradientPainter::KisGradientPainter(KisPaintDeviceSP device, KisSelectionSP selection)
: KisPainter(device, selection),
m_d(new Private())
{
}
KisGradientPainter::~KisGradientPainter()
{
}
void KisGradientPainter::setGradientShape(enumGradientShape shape)
{
m_d->shape = shape;
}
KisGradientShapeStrategy* createPolygonShapeStrategy(const QPainterPath &path, const QRect &boundingRect)
{
// TODO: implement UI for exponent option
const qreal exponent = 2.0;
KisGradientShapeStrategy *strategy =
new KisPolygonalGradientShapeStrategy(path, exponent);
KIS_ASSERT_RECOVER_NOOP(boundingRect.width() >= 3 &&
boundingRect.height() >= 3);
const qreal step =
qMin(qreal(8.0), KritaUtils::maxDimensionPortion(boundingRect, 0.01, 2));
return new KisCachedGradientShapeStrategy(boundingRect, step, step, strategy);
}
/**
* TODO: make this call happen asynchronously when the user does nothing
*/
void KisGradientPainter::precalculateShape()
{
if (!m_d->processRegions.isEmpty()) return;
QPainterPath path;
if (selection()) {
if (!selection()->outlineCacheValid()) {
selection()->recalculateOutlineCache();
}
KIS_ASSERT_RECOVER_RETURN(selection()->outlineCacheValid());
KIS_ASSERT_RECOVER_RETURN(!selection()->outlineCache().isEmpty());
path = selection()->outlineCache();
} else {
path.addRect(device()->defaultBounds()->bounds());
}
QList<QPainterPath> splitPaths = KritaUtils::splitDisjointPaths(path);
Q_FOREACH (const QPainterPath &subpath, splitPaths) {
QRect boundingRect = subpath.boundingRect().toAlignedRect();
if (boundingRect.width() < 3 || boundingRect.height() < 3) {
boundingRect = kisGrowRect(boundingRect, 2);
}
Private::ProcessRegion r(toQShared(createPolygonShapeStrategy(subpath, boundingRect)),
boundingRect);
m_d->processRegions << r;
}
}
bool KisGradientPainter::paintGradient(const QPointF& gradientVectorStart,
const QPointF& gradientVectorEnd,
enumGradientRepeat repeat,
double antiAliasThreshold,
bool reverseGradient,
qint32 startx,
qint32 starty,
qint32 width,
qint32 height)
{
return paintGradient(gradientVectorStart,
gradientVectorEnd,
repeat,
antiAliasThreshold,
reverseGradient,
QRect(startx, starty, width, height));
}
bool KisGradientPainter::paintGradient(const QPointF& gradientVectorStart,
const QPointF& gradientVectorEnd,
enumGradientRepeat repeat,
double antiAliasThreshold,
bool reverseGradient,
const QRect &applyRect)
{
- Q_UNUSED(antiAliasThreshold);
+ // The following combinations of options have aliasing artifacts
+ // where the first color meets the last color of the gradient.
+ // so antialias threshold is used to compute if the pixel is in
+ // the smothing area. Then linear interpolation is used to blend
+ // between the first and last colors
+ if (antiAliasThreshold > DBL_EPSILON) {
+ if ((m_d->shape == GradientShapeLinear || m_d->shape == GradientShapeBiLinear ||
+ m_d->shape == GradientShapeRadial || m_d->shape == GradientShapeSquare ||
+ m_d->shape == GradientShapeSpiral || m_d->shape == GradientShapeReverseSpiral)
+ && repeat == GradientRepeatForwards) {
+ RepeatForwardsPaintPolicy paintPolicy(m_d->shape);
+ return paintGradient(gradientVectorStart,
+ gradientVectorEnd,
+ repeat,
+ antiAliasThreshold,
+ reverseGradient,
+ applyRect,
+ paintPolicy);
+
+ } else if (m_d->shape == GradientShapeConical) {
+ ConicalGradientPaintPolicy paintPolicy;
+ return paintGradient(gradientVectorStart,
+ gradientVectorEnd,
+ repeat,
+ antiAliasThreshold,
+ reverseGradient,
+ applyRect,
+ paintPolicy);
+
+ } else if ((m_d->shape == GradientShapeSpiral || m_d->shape == GradientShapeReverseSpiral) &&
+ repeat == GradientRepeatNone) {
+ SpyralGradientRepeatNonePaintPolicy paintPolicy(m_d->shape == GradientShapeReverseSpiral);
+ return paintGradient(gradientVectorStart,
+ gradientVectorEnd,
+ repeat,
+ antiAliasThreshold,
+ reverseGradient,
+ applyRect,
+ paintPolicy);
+ }
+ }
+ // Default behavior: no antialiasing required
+ NoAntialiasPaintPolicy paintPolicy;
+ return paintGradient(gradientVectorStart,
+ gradientVectorEnd,
+ repeat,
+ antiAliasThreshold,
+ reverseGradient,
+ applyRect,
+ paintPolicy);
+}
+
+template <class T>
+bool KisGradientPainter::paintGradient(const QPointF& gradientVectorStart,
+ const QPointF& gradientVectorEnd,
+ enumGradientRepeat repeat,
+ double antiAliasThreshold,
+ bool reverseGradient,
+ const QRect &applyRect,
+ T & paintPolicy)
+{
if (!gradient()) return false;
QRect requestedRect = applyRect;
//If the device has a selection only iterate over that selection united with our area of interest
if (selection()) {
requestedRect &= selection()->selectedExactRect();
}
QSharedPointer<KisGradientShapeStrategy> shapeStrategy;
switch (m_d->shape) {
case GradientShapeLinear: {
Private::ProcessRegion r(toQShared(new LinearGradientStrategy(gradientVectorStart, gradientVectorEnd)),
requestedRect);
m_d->processRegions.clear();
m_d->processRegions << r;
break;
}
case GradientShapeBiLinear: {
Private::ProcessRegion r(toQShared(new BiLinearGradientStrategy(gradientVectorStart, gradientVectorEnd)),
requestedRect);
m_d->processRegions.clear();
m_d->processRegions << r;
break;
}
case GradientShapeRadial: {
Private::ProcessRegion r(toQShared(new RadialGradientStrategy(gradientVectorStart, gradientVectorEnd)),
requestedRect);
m_d->processRegions.clear();
m_d->processRegions << r;
break;
}
case GradientShapeSquare: {
Private::ProcessRegion r(toQShared(new SquareGradientStrategy(gradientVectorStart, gradientVectorEnd)),
requestedRect);
m_d->processRegions.clear();
m_d->processRegions << r;
break;
}
case GradientShapeConical: {
Private::ProcessRegion r(toQShared(new ConicalGradientStrategy(gradientVectorStart, gradientVectorEnd)),
requestedRect);
m_d->processRegions.clear();
m_d->processRegions << r;
break;
}
case GradientShapeConicalSymetric: {
Private::ProcessRegion r(toQShared(new ConicalSymetricGradientStrategy(gradientVectorStart, gradientVectorEnd)),
requestedRect);
m_d->processRegions.clear();
m_d->processRegions << r;
break;
}
case GradientShapeSpiral: {
Private::ProcessRegion r(toQShared(new SpiralGradientStrategy(gradientVectorStart, gradientVectorEnd)),
requestedRect);
m_d->processRegions.clear();
m_d->processRegions << r;
break;
}
case GradientShapeReverseSpiral: {
Private::ProcessRegion r(toQShared(new ReverseSpiralGradientStrategy(gradientVectorStart, gradientVectorEnd)),
requestedRect);
m_d->processRegions.clear();
m_d->processRegions << r;
break;
}
case GradientShapePolygonal:
precalculateShape();
repeat = GradientRepeatNone;
break;
}
GradientRepeatStrategy *repeatStrategy = 0;
switch (repeat) {
case GradientRepeatNone:
repeatStrategy = GradientRepeatNoneStrategy::instance();
break;
case GradientRepeatForwards:
repeatStrategy = GradientRepeatForwardsStrategy::instance();
break;
case GradientRepeatAlternate:
if (m_d->shape == GradientShapeSpiral || m_d->shape == GradientShapeReverseSpiral) {repeatStrategy = GradientRepeatModuloDivisiveContinuousHalfStrategy::instance();}
else {repeatStrategy = GradientRepeatAlternateStrategy::instance();}
break;
}
Q_ASSERT(repeatStrategy != 0);
KisPaintDeviceSP dev = device()->createCompositionSourceDevice();
const KoColorSpace * colorSpace = dev->colorSpace();
const qint32 pixelSize = colorSpace->pixelSize();
Q_FOREACH (const Private::ProcessRegion &r, m_d->processRegions) {
QRect processRect = r.processRect;
QSharedPointer<KisGradientShapeStrategy> shapeStrategy = r.precalculatedShapeStrategy;
CachedGradient cachedGradient(gradient(), qMax(processRect.width(), processRect.height()), colorSpace);
KisSequentialIteratorProgress it(dev, processRect, progressUpdater());
- while (it.nextPixel()) {
- double t = shapeStrategy->valueAt(it.x(), it.y());
- t = repeatStrategy->valueAt(t);
-
- if (reverseGradient) {
- t = 1 - t;
- }
+ paintPolicy.setup(gradientVectorStart,
+ gradientVectorEnd,
+ shapeStrategy,
+ repeatStrategy,
+ antiAliasThreshold,
+ reverseGradient,
+ &cachedGradient);
- memcpy(it.rawData(), cachedGradient.cachedAt(t), pixelSize);
+ while (it.nextPixel()) {
+ memcpy(it.rawData(), paintPolicy.colorAt(it.x(), it.y()), pixelSize);
}
bitBlt(processRect.topLeft(), dev, processRect);
}
return true;
}
diff --git a/libs/image/kis_gradient_painter.h b/libs/image/kis_gradient_painter.h
index 8e43ee9030..74398ef4ba 100644
--- a/libs/image/kis_gradient_painter.h
+++ b/libs/image/kis_gradient_painter.h
@@ -1,92 +1,101 @@
/*
* Copyright (c) 2004 Adrian Page <adrian@pagenet.plus.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KIS_GRADIENT_PAINTER_H_
#define KIS_GRADIENT_PAINTER_H_
#include <QScopedPointer>
#include <KoColor.h>
#include "kis_types.h"
#include "kis_painter.h"
#include <kritaimage_export.h>
/**
* XXX: Docs!
*/
class KRITAIMAGE_EXPORT KisGradientPainter : public KisPainter
{
public:
KisGradientPainter();
KisGradientPainter(KisPaintDeviceSP device);
KisGradientPainter(KisPaintDeviceSP device, KisSelectionSP selection);
~KisGradientPainter() override;
enum enumGradientShape {
GradientShapeLinear,
GradientShapeBiLinear,
GradientShapeRadial,
GradientShapeSquare,
GradientShapeConical,
GradientShapeConicalSymetric,
GradientShapeSpiral,
GradientShapeReverseSpiral,
GradientShapePolygonal
};
enum enumGradientRepeat {
GradientRepeatNone,
GradientRepeatForwards,
GradientRepeatAlternate
};
void setGradientShape(enumGradientShape shape);
void precalculateShape();
/**
* Paint a gradient in the rect between startx, starty, width and height.
*/
bool paintGradient(const QPointF& gradientVectorStart,
const QPointF& gradientVectorEnd,
enumGradientRepeat repeat,
double antiAliasThreshold,
bool reverseGradient,
qint32 startx,
qint32 starty,
qint32 width,
qint32 height);
// convenience overload
bool paintGradient(const QPointF& gradientVectorStart,
const QPointF& gradientVectorEnd,
enumGradientRepeat repeat,
double antiAliasThreshold,
bool reverseGradient,
const QRect &applyRect);
+ template <class T>
+ bool paintGradient(const QPointF& gradientVectorStart,
+ const QPointF& gradientVectorEnd,
+ enumGradientRepeat repeat,
+ double antiAliasThreshold,
+ bool reverseGradient,
+ const QRect &applyRect,
+ T & paintPolicy);
+
private:
struct Private;
const QScopedPointer<Private> m_d;
};
#endif //KIS_GRADIENT_PAINTER_H_
diff --git a/libs/image/kis_image.cc b/libs/image/kis_image.cc
index a4bf4ac709..ec37e230be 100644
--- a/libs/image/kis_image.cc
+++ b/libs/image/kis_image.cc
@@ -1,2355 +1,2376 @@
/*
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
* Copyright (c) 2007 Boudewijn Rempt <boud@valdyas.org>
*
* 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_image.h"
#include <KoConfig.h> // WORDS_BIGENDIAN
#include <stdlib.h>
#include <math.h>
#include <QImage>
#include <QPainter>
#include <QSize>
#include <QDateTime>
#include <QRect>
#include <QtConcurrent>
#include <klocalizedstring.h>
#include "KoColorSpaceRegistry.h"
#include "KoColor.h"
#include "KoColorProfile.h"
#include <KoCompositeOpRegistry.h>
#include "KisProofingConfiguration.h"
#include "kis_adjustment_layer.h"
#include "kis_annotation.h"
#include "kis_count_visitor.h"
#include "kis_filter_strategy.h"
#include "kis_group_layer.h"
#include "commands/kis_image_commands.h"
#include "kis_layer.h"
#include "kis_meta_data_merge_strategy_registry.h"
#include "kis_name_server.h"
#include "kis_paint_layer.h"
#include "kis_projection_leaf.h"
#include "kis_painter.h"
#include "kis_selection.h"
#include "kis_transaction.h"
#include "kis_meta_data_merge_strategy.h"
#include "kis_memory_statistics_server.h"
#include "kis_node.h"
#include "kis_types.h"
#include "kis_image_config.h"
#include "kis_update_scheduler.h"
#include "kis_image_signal_router.h"
#include "kis_image_animation_interface.h"
#include "kis_stroke_strategy.h"
#include "kis_simple_stroke_strategy.h"
#include "kis_image_barrier_locker.h"
#include "kis_undo_stores.h"
#include "kis_legacy_undo_adapter.h"
#include "kis_post_execution_undo_adapter.h"
#include "kis_transform_worker.h"
#include "kis_processing_applicator.h"
#include "processing/kis_crop_processing_visitor.h"
#include "processing/kis_crop_selections_processing_visitor.h"
#include "processing/kis_transform_processing_visitor.h"
#include "processing/kis_convert_color_space_processing_visitor.h"
#include "processing/kis_assign_profile_processing_visitor.h"
#include "commands_new/kis_image_resize_command.h"
#include "commands_new/kis_image_set_resolution_command.h"
#include "commands_new/kis_activate_selection_mask_command.h"
#include "kis_do_something_command.h"
#include "kis_composite_progress_proxy.h"
#include "kis_layer_composition.h"
#include "kis_wrapped_rect.h"
#include "kis_crop_saved_extra_data.h"
#include "kis_layer_utils.h"
#include "kis_lod_transform.h"
#include "kis_suspend_projection_updates_stroke_strategy.h"
#include "kis_sync_lod_cache_stroke_strategy.h"
#include "kis_projection_updates_filter.h"
#include "kis_layer_projection_plane.h"
#include "kis_update_time_monitor.h"
#include "tiles3/kis_lockless_stack.h"
#include <QtCore>
#include <functional>
#include "kis_time_range.h"
#include "KisRunnableBasedStrokeStrategy.h"
#include "KisRunnableStrokeJobData.h"
#include "KisRunnableStrokeJobUtils.h"
#include "KisRunnableStrokeJobsInterface.h"
#include "KisBusyWaitBroker.h"
// #define SANITY_CHECKS
#ifdef SANITY_CHECKS
#define SANITY_CHECK_LOCKED(name) \
if (!locked()) warnKrita() << "Locking policy failed:" << name \
<< "has been called without the image" \
"being locked";
#else
#define SANITY_CHECK_LOCKED(name)
#endif
struct KisImageSPStaticRegistrar {
KisImageSPStaticRegistrar() {
qRegisterMetaType<KisImageSP>("KisImageSP");
}
};
static KisImageSPStaticRegistrar __registrar;
class KisImage::KisImagePrivate
{
public:
KisImagePrivate(KisImage *_q, qint32 w, qint32 h,
const KoColorSpace *c,
KisUndoStore *undo,
KisImageAnimationInterface *_animationInterface)
: q(_q)
, lockedForReadOnly(false)
, width(w)
, height(h)
, colorSpace(c ? c : KoColorSpaceRegistry::instance()->rgb8())
, nserver(1)
, undoStore(undo ? undo : new KisDumbUndoStore())
, legacyUndoAdapter(undoStore.data(), _q)
, postExecutionUndoAdapter(undoStore.data(), _q)
, signalRouter(_q)
, animationInterface(_animationInterface)
, scheduler(_q, _q)
, axesCenter(QPointF(0.5, 0.5))
{
{
KisImageConfig cfg(true);
if (cfg.enableProgressReporting()) {
scheduler.setProgressProxy(&compositeProgressProxy);
}
// Each of these lambdas defines a new factory function.
scheduler.setLod0ToNStrokeStrategyFactory(
[=](bool forgettable) {
return KisLodSyncPair(
new KisSyncLodCacheStrokeStrategy(KisImageWSP(q), forgettable),
KisSyncLodCacheStrokeStrategy::createJobsData(KisImageWSP(q)));
});
scheduler.setSuspendResumeUpdatesStrokeStrategyFactory(
[=]() {
KisSuspendProjectionUpdatesStrokeStrategy::SharedDataSP data = KisSuspendProjectionUpdatesStrokeStrategy::createSharedData();
KisSuspendResumePair suspend(new KisSuspendProjectionUpdatesStrokeStrategy(KisImageWSP(q), true, data),
KisSuspendProjectionUpdatesStrokeStrategy::createSuspendJobsData(KisImageWSP(q)));
KisSuspendResumePair resume(new KisSuspendProjectionUpdatesStrokeStrategy(KisImageWSP(q), false, data),
KisSuspendProjectionUpdatesStrokeStrategy::createResumeJobsData(KisImageWSP(q)));
return std::make_pair(suspend, resume);
});
}
connect(q, SIGNAL(sigImageModified()), KisMemoryStatisticsServer::instance(), SLOT(notifyImageChanged()));
}
~KisImagePrivate() {
/**
* Stop animation interface. It may use the rootLayer.
*/
delete animationInterface;
/**
* First delete the nodes, while strokes
* and undo are still alive
*/
rootLayer.clear();
}
KisImage *q;
quint32 lockCount = 0;
bool lockedForReadOnly;
qint32 width;
qint32 height;
double xres = 1.0;
double yres = 1.0;
const KoColorSpace * colorSpace;
KisProofingConfigurationSP proofingConfig;
KisSelectionSP deselectedGlobalSelection;
KisGroupLayerSP rootLayer; // The layers are contained in here
KisSelectionMaskSP targetOverlaySelectionMask; // the overlay switching stroke will try to switch into this mask
KisSelectionMaskSP overlaySelectionMask;
QList<KisLayerCompositionSP> compositions;
KisNodeSP isolatedRootNode;
bool wrapAroundModePermitted = false;
KisNameServer nserver;
QScopedPointer<KisUndoStore> undoStore;
KisLegacyUndoAdapter legacyUndoAdapter;
KisPostExecutionUndoAdapter postExecutionUndoAdapter;
vKisAnnotationSP annotations;
QAtomicInt disableUIUpdateSignals;
KisLocklessStack<QRect> savedDisabledUIUpdates;
// filters are applied in a reversed way, from rbegin() to rend()
QVector<KisProjectionUpdatesFilterSP> projectionUpdatesFilters;
QStack<KisProjectionUpdatesFilterCookie> disabledUpdatesCookies;
KisImageSignalRouter signalRouter;
KisImageAnimationInterface *animationInterface;
KisUpdateScheduler scheduler;
QAtomicInt disableDirtyRequests;
KisCompositeProgressProxy compositeProgressProxy;
bool blockLevelOfDetail = false;
QPointF axesCenter;
bool allowMasksOnRootNode = false;
bool tryCancelCurrentStrokeAsync();
void notifyProjectionUpdatedInPatches(const QRect &rc, QVector<KisRunnableStrokeJobData *> &jobs);
void convertImageColorSpaceImpl(const KoColorSpace *dstColorSpace,
bool convertLayers,
KoColorConversionTransformation::Intent renderingIntent,
KoColorConversionTransformation::ConversionFlags conversionFlags);
struct SetImageProjectionColorSpace;
};
KisImage::KisImage(KisUndoStore *undoStore, qint32 width, qint32 height, const KoColorSpace * colorSpace, const QString& name)
: QObject(0)
, KisShared()
, m_d(new KisImagePrivate(this, width, height,
colorSpace, undoStore,
new KisImageAnimationInterface(this)))
{
// make sure KisImage belongs to the GUI thread
moveToThread(qApp->thread());
connect(this, SIGNAL(sigInternalStopIsolatedModeRequested()), SLOT(stopIsolatedMode()));
setObjectName(name);
setRootLayer(new KisGroupLayer(this, "root", OPACITY_OPAQUE_U8));
}
KisImage::~KisImage()
{
/**
* Request the tools to end currently running strokes
*/
waitForDone();
delete m_d;
disconnect(); // in case Qt gets confused
}
KisImageSP KisImage::fromQImage(const QImage &image, KisUndoStore *undoStore)
{
const KoColorSpace *colorSpace = 0;
switch (image.format()) {
case QImage::Format_Invalid:
case QImage::Format_Mono:
case QImage::Format_MonoLSB:
colorSpace = KoColorSpaceRegistry::instance()->graya8();
break;
case QImage::Format_Indexed8:
case QImage::Format_RGB32:
case QImage::Format_ARGB32:
case QImage::Format_ARGB32_Premultiplied:
colorSpace = KoColorSpaceRegistry::instance()->rgb8();
break;
case QImage::Format_RGB16:
colorSpace = KoColorSpaceRegistry::instance()->rgb16();
break;
case QImage::Format_ARGB8565_Premultiplied:
case QImage::Format_RGB666:
case QImage::Format_ARGB6666_Premultiplied:
case QImage::Format_RGB555:
case QImage::Format_ARGB8555_Premultiplied:
case QImage::Format_RGB888:
case QImage::Format_RGB444:
case QImage::Format_ARGB4444_Premultiplied:
case QImage::Format_RGBX8888:
case QImage::Format_RGBA8888:
case QImage::Format_RGBA8888_Premultiplied:
colorSpace = KoColorSpaceRegistry::instance()->rgb8();
break;
case QImage::Format_BGR30:
case QImage::Format_A2BGR30_Premultiplied:
case QImage::Format_RGB30:
case QImage::Format_A2RGB30_Premultiplied:
colorSpace = KoColorSpaceRegistry::instance()->rgb8();
break;
case QImage::Format_Alpha8:
colorSpace = KoColorSpaceRegistry::instance()->alpha8();
break;
case QImage::Format_Grayscale8:
colorSpace = KoColorSpaceRegistry::instance()->graya8();
break;
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
case QImage::Format_Grayscale16:
colorSpace = KoColorSpaceRegistry::instance()->graya16();
break;
#endif
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
case QImage::Format_RGBX64:
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
colorSpace = KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(), Float32BitsColorDepthID.id(), 0);
break;
#endif
default:
colorSpace = 0;
}
KisImageSP img = new KisImage(undoStore, image.width(), image.height(), colorSpace, i18n("Imported Image"));
KisPaintLayerSP layer = new KisPaintLayer(img, img->nextLayerName(), 255);
layer->paintDevice()->convertFromQImage(image, 0, 0, 0);
img->addNode(layer.data(), img->rootLayer().data());
return img;
}
KisImage *KisImage::clone(bool exactCopy)
{
return new KisImage(*this, 0, exactCopy);
}
void KisImage::copyFromImage(const KisImage &rhs)
{
copyFromImageImpl(rhs, REPLACE);
}
void KisImage::copyFromImageImpl(const KisImage &rhs, int policy)
{
// make sure we choose exactly one from REPLACE and CONSTRUCT
KIS_ASSERT_RECOVER_RETURN((policy & REPLACE) != (policy & CONSTRUCT));
// only when replacing do we need to emit signals
#define EMIT_IF_NEEDED if (!(policy & REPLACE)) {} else emit
if (policy & REPLACE) { // if we are constructing the image, these are already set
if (m_d->width != rhs.width() || m_d->height != rhs.height()) {
m_d->width = rhs.width();
m_d->height = rhs.height();
emit sigSizeChanged(QPointF(), QPointF());
}
if (m_d->colorSpace != rhs.colorSpace()) {
m_d->colorSpace = rhs.colorSpace();
emit sigColorSpaceChanged(m_d->colorSpace);
}
}
// from KisImage::KisImage(const KisImage &, KisUndoStore *, bool)
setObjectName(rhs.objectName());
if (m_d->xres != rhs.m_d->xres || m_d->yres != rhs.m_d->yres) {
m_d->xres = rhs.m_d->xres;
m_d->yres = rhs.m_d->yres;
EMIT_IF_NEEDED sigResolutionChanged(m_d->xres, m_d->yres);
}
m_d->allowMasksOnRootNode = rhs.m_d->allowMasksOnRootNode;
if (rhs.m_d->proofingConfig) {
KisProofingConfigurationSP proofingConfig(new KisProofingConfiguration(*rhs.m_d->proofingConfig));
if (policy & REPLACE) {
setProofingConfiguration(proofingConfig);
} else {
m_d->proofingConfig = proofingConfig;
}
}
KisNodeSP newRoot = rhs.root()->clone();
newRoot->setGraphListener(this);
newRoot->setImage(this);
m_d->rootLayer = dynamic_cast<KisGroupLayer*>(newRoot.data());
setRoot(newRoot);
bool exactCopy = policy & EXACT_COPY;
if (exactCopy || rhs.m_d->isolatedRootNode || rhs.m_d->overlaySelectionMask) {
QQueue<KisNodeSP> linearizedNodes;
KisLayerUtils::recursiveApplyNodes(rhs.root(),
[&linearizedNodes](KisNodeSP node) {
linearizedNodes.enqueue(node);
});
KisLayerUtils::recursiveApplyNodes(newRoot,
[&linearizedNodes, exactCopy, &rhs, this](KisNodeSP node) {
KisNodeSP refNode = linearizedNodes.dequeue();
if (exactCopy) {
node->setUuid(refNode->uuid());
}
if (rhs.m_d->isolatedRootNode &&
rhs.m_d->isolatedRootNode == refNode) {
m_d->isolatedRootNode = node;
}
if (rhs.m_d->overlaySelectionMask &&
KisNodeSP(rhs.m_d->overlaySelectionMask) == refNode) {
m_d->targetOverlaySelectionMask = dynamic_cast<KisSelectionMask*>(node.data());
m_d->overlaySelectionMask = m_d->targetOverlaySelectionMask;
m_d->rootLayer->notifyChildMaskChanged();
}
});
}
KisLayerUtils::recursiveApplyNodes(newRoot,
[](KisNodeSP node) {
dbgImage << "Node: " << (void *)node.data();
});
m_d->compositions.clear();
Q_FOREACH (KisLayerCompositionSP comp, rhs.m_d->compositions) {
m_d->compositions << toQShared(new KisLayerComposition(*comp, this));
}
EMIT_IF_NEEDED sigLayersChangedAsync();
m_d->nserver = rhs.m_d->nserver;
vKisAnnotationSP newAnnotations;
Q_FOREACH (KisAnnotationSP annotation, rhs.m_d->annotations) {
newAnnotations << annotation->clone();
}
m_d->annotations = newAnnotations;
KIS_ASSERT_RECOVER_NOOP(rhs.m_d->projectionUpdatesFilters.isEmpty());
KIS_ASSERT_RECOVER_NOOP(!rhs.m_d->disableUIUpdateSignals);
KIS_ASSERT_RECOVER_NOOP(!rhs.m_d->disableDirtyRequests);
m_d->blockLevelOfDetail = rhs.m_d->blockLevelOfDetail;
#undef EMIT_IF_NEEDED
}
KisImage::KisImage(const KisImage& rhs, KisUndoStore *undoStore, bool exactCopy)
: KisNodeFacade(),
KisNodeGraphListener(),
KisShared(),
m_d(new KisImagePrivate(this,
rhs.width(), rhs.height(),
rhs.colorSpace(),
undoStore ? undoStore : new KisDumbUndoStore(),
new KisImageAnimationInterface(*rhs.animationInterface(), this)))
{
// make sure KisImage belongs to the GUI thread
moveToThread(qApp->thread());
connect(this, SIGNAL(sigInternalStopIsolatedModeRequested()), SLOT(stopIsolatedMode()));
copyFromImageImpl(rhs, CONSTRUCT | (exactCopy ? EXACT_COPY : 0));
}
void KisImage::aboutToAddANode(KisNode *parent, int index)
{
KisNodeGraphListener::aboutToAddANode(parent, index);
SANITY_CHECK_LOCKED("aboutToAddANode");
}
void KisImage::nodeHasBeenAdded(KisNode *parent, int index)
{
KisNodeGraphListener::nodeHasBeenAdded(parent, index);
SANITY_CHECK_LOCKED("nodeHasBeenAdded");
m_d->signalRouter.emitNodeHasBeenAdded(parent, index);
}
void KisImage::aboutToRemoveANode(KisNode *parent, int index)
{
KisNodeSP deletedNode = parent->at(index);
if (!dynamic_cast<KisSelectionMask*>(deletedNode.data()) &&
deletedNode == m_d->isolatedRootNode) {
emit sigInternalStopIsolatedModeRequested();
}
KisNodeGraphListener::aboutToRemoveANode(parent, index);
SANITY_CHECK_LOCKED("aboutToRemoveANode");
m_d->signalRouter.emitAboutToRemoveANode(parent, index);
}
void KisImage::nodeChanged(KisNode* node)
{
KisNodeGraphListener::nodeChanged(node);
requestStrokeEnd();
m_d->signalRouter.emitNodeChanged(node);
}
void KisImage::invalidateAllFrames()
{
invalidateFrames(KisTimeRange::infinite(0), QRect());
}
void KisImage::setOverlaySelectionMask(KisSelectionMaskSP mask)
{
if (m_d->targetOverlaySelectionMask == mask) return;
m_d->targetOverlaySelectionMask = mask;
struct UpdateOverlaySelectionStroke : public KisSimpleStrokeStrategy {
UpdateOverlaySelectionStroke(KisImageSP image)
: KisSimpleStrokeStrategy(QLatin1String("update-overlay-selection-mask"), kundo2_noi18n("update-overlay-selection-mask")),
m_image(image)
{
this->enableJob(JOB_INIT, true, KisStrokeJobData::BARRIER, KisStrokeJobData::EXCLUSIVE);
setClearsRedoOnStart(false);
}
void initStrokeCallback() {
KisSelectionMaskSP oldMask = m_image->m_d->overlaySelectionMask;
KisSelectionMaskSP newMask = m_image->m_d->targetOverlaySelectionMask;
if (oldMask == newMask) return;
KIS_SAFE_ASSERT_RECOVER_RETURN(!newMask || newMask->graphListener() == m_image);
m_image->m_d->overlaySelectionMask = newMask;
if (oldMask || newMask) {
m_image->m_d->rootLayer->notifyChildMaskChanged();
}
if (oldMask) {
m_image->m_d->rootLayer->setDirtyDontResetAnimationCache(oldMask->extent());
}
if (newMask) {
newMask->setDirty();
}
m_image->undoAdapter()->emitSelectionChanged();
}
private:
KisImageSP m_image;
};
KisStrokeId id = startStroke(new UpdateOverlaySelectionStroke(this));
endStroke(id);
}
KisSelectionMaskSP KisImage::overlaySelectionMask() const
{
return m_d->overlaySelectionMask;
}
bool KisImage::hasOverlaySelectionMask() const
{
return m_d->overlaySelectionMask;
}
KisSelectionSP KisImage::globalSelection() const
{
KisSelectionMaskSP selectionMask = m_d->rootLayer->selectionMask();
if (selectionMask) {
return selectionMask->selection();
} else {
return 0;
}
}
void KisImage::setGlobalSelection(KisSelectionSP globalSelection)
{
KisSelectionMaskSP selectionMask = m_d->rootLayer->selectionMask();
if (!globalSelection) {
if (selectionMask) {
removeNode(selectionMask);
}
}
else {
if (!selectionMask) {
selectionMask = new KisSelectionMask(this, i18n("Selection Mask"));
selectionMask->initSelection(m_d->rootLayer);
addNode(selectionMask);
// If we do not set the selection now, the setActive call coming next
// can be very, very expensive, depending on the size of the image.
selectionMask->setSelection(globalSelection);
selectionMask->setActive(true);
}
else {
selectionMask->setSelection(globalSelection);
}
KIS_SAFE_ASSERT_RECOVER_NOOP(m_d->rootLayer->childCount() > 0);
KIS_SAFE_ASSERT_RECOVER_NOOP(m_d->rootLayer->selectionMask());
}
m_d->deselectedGlobalSelection = 0;
m_d->legacyUndoAdapter.emitSelectionChanged();
}
void KisImage::deselectGlobalSelection()
{
KisSelectionSP savedSelection = globalSelection();
setGlobalSelection(0);
m_d->deselectedGlobalSelection = savedSelection;
}
bool KisImage::canReselectGlobalSelection()
{
return m_d->deselectedGlobalSelection;
}
void KisImage::reselectGlobalSelection()
{
if(m_d->deselectedGlobalSelection) {
setGlobalSelection(m_d->deselectedGlobalSelection);
}
}
QString KisImage::nextLayerName(const QString &_baseName) const
{
QString baseName = _baseName;
if (m_d->nserver.currentSeed() == 0) {
m_d->nserver.number();
return i18n("background");
}
if (baseName.isEmpty()) {
baseName = i18n("Layer");
}
return QString("%1 %2").arg(baseName).arg(m_d->nserver.number());
}
void KisImage::rollBackLayerName()
{
m_d->nserver.rollback();
}
KisCompositeProgressProxy* KisImage::compositeProgressProxy()
{
return &m_d->compositeProgressProxy;
}
bool KisImage::locked() const
{
return m_d->lockCount != 0;
}
void KisImage::barrierLock(bool readOnly)
{
if (!locked()) {
requestStrokeEnd();
KisBusyWaitBroker::instance()->notifyWaitOnImageStarted(this);
m_d->scheduler.barrierLock();
KisBusyWaitBroker::instance()->notifyWaitOnImageEnded(this);
m_d->lockedForReadOnly = readOnly;
} else {
m_d->lockedForReadOnly &= readOnly;
}
m_d->lockCount++;
}
bool KisImage::tryBarrierLock(bool readOnly)
{
bool result = true;
if (!locked()) {
result = m_d->scheduler.tryBarrierLock();
m_d->lockedForReadOnly = readOnly;
}
if (result) {
m_d->lockCount++;
m_d->lockedForReadOnly &= readOnly;
}
return result;
}
bool KisImage::isIdle(bool allowLocked)
{
return (allowLocked || !locked()) && m_d->scheduler.isIdle();
}
void KisImage::lock()
{
if (!locked()) {
requestStrokeEnd();
KisBusyWaitBroker::instance()->notifyWaitOnImageStarted(this);
m_d->scheduler.lock();
KisBusyWaitBroker::instance()->notifyWaitOnImageEnded(this);
}
m_d->lockCount++;
m_d->lockedForReadOnly = false;
}
void KisImage::unlock()
{
Q_ASSERT(locked());
if (locked()) {
m_d->lockCount--;
if (m_d->lockCount == 0) {
m_d->scheduler.unlock(!m_d->lockedForReadOnly);
}
}
}
void KisImage::blockUpdates()
{
m_d->scheduler.blockUpdates();
}
void KisImage::unblockUpdates()
{
m_d->scheduler.unblockUpdates();
}
void KisImage::setSize(const QSize& size)
{
m_d->width = size.width();
m_d->height = size.height();
}
void KisImage::resizeImageImpl(const QRect& newRect, bool cropLayers)
{
if (newRect == bounds() && !cropLayers) return;
KUndo2MagicString actionName = cropLayers ?
kundo2_i18n("Crop Image") :
kundo2_i18n("Resize Image");
KisImageSignalVector emitSignals;
emitSignals << ComplexSizeChangedSignal(newRect, newRect.size());
emitSignals << ModifiedSignal;
KisCropSavedExtraData *extraData =
new KisCropSavedExtraData(cropLayers ?
KisCropSavedExtraData::CROP_IMAGE :
KisCropSavedExtraData::RESIZE_IMAGE,
newRect);
KisProcessingApplicator applicator(this, m_d->rootLayer,
KisProcessingApplicator::RECURSIVE |
KisProcessingApplicator::NO_UI_UPDATES,
emitSignals, actionName, extraData);
if (cropLayers || !newRect.topLeft().isNull()) {
KisProcessingVisitorSP visitor =
new KisCropProcessingVisitor(newRect, cropLayers, true);
applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT);
}
applicator.applyCommand(new KisImageResizeCommand(this, newRect.size()));
applicator.end();
}
void KisImage::resizeImage(const QRect& newRect)
{
resizeImageImpl(newRect, false);
}
void KisImage::cropImage(const QRect& newRect)
{
resizeImageImpl(newRect, true);
}
void KisImage::purgeUnusedData(bool isCancellable)
{
/**
* WARNING: don't use this function unless you know what you are doing!
*
* It breaks undo on layers! Therefore, after calling it, KisImage is not
* undo-capable anymore!
*/
struct PurgeUnusedDataStroke : public KisRunnableBasedStrokeStrategy {
PurgeUnusedDataStroke(KisImageSP image, bool isCancellable)
: KisRunnableBasedStrokeStrategy(QLatin1String("purge-unused-data"),
kundo2_noi18n("purge-unused-data")),
m_image(image)
{
this->enableJob(JOB_INIT, true, KisStrokeJobData::BARRIER, KisStrokeJobData::EXCLUSIVE);
this->enableJob(JOB_DOSTROKE, true);
setClearsRedoOnStart(false);
setRequestsOtherStrokesToEnd(!isCancellable);
setCanForgetAboutMe(isCancellable);
}
void initStrokeCallback() {
KisPaintDeviceList deviceList;
QVector<KisStrokeJobData*> jobsData;
KisLayerUtils::recursiveApplyNodes(m_image->root(),
[&deviceList](KisNodeSP node) {
deviceList << node->getLodCapableDevices();
});
Q_FOREACH (KisPaintDeviceSP device, deviceList) {
if (!device) continue;
KritaUtils::addJobConcurrent(jobsData,
[device] () {
const_cast<KisPaintDevice*>(device.data())->purgeDefaultPixels();
});
}
addMutatedJobs(jobsData);
}
private:
KisImageSP m_image;
};
KisStrokeId id = startStroke(new PurgeUnusedDataStroke(this, isCancellable));
endStroke(id);
}
void KisImage::cropNode(KisNodeSP node, const QRect& newRect)
{
bool isLayer = qobject_cast<KisLayer*>(node.data());
KUndo2MagicString actionName = isLayer ?
kundo2_i18n("Crop Layer") :
kundo2_i18n("Crop Mask");
KisImageSignalVector emitSignals;
emitSignals << ModifiedSignal;
KisCropSavedExtraData *extraData =
new KisCropSavedExtraData(KisCropSavedExtraData::CROP_LAYER,
newRect, node);
KisProcessingApplicator applicator(this, node,
KisProcessingApplicator::RECURSIVE,
emitSignals, actionName, extraData);
KisProcessingVisitorSP visitor =
new KisCropProcessingVisitor(newRect, true, false);
applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT);
applicator.end();
}
void KisImage::scaleImage(const QSize &size, qreal xres, qreal yres, KisFilterStrategy *filterStrategy)
{
bool resolutionChanged = xres != xRes() && yres != yRes();
bool sizeChanged = size != this->size();
if (!resolutionChanged && !sizeChanged) return;
KisImageSignalVector emitSignals;
if (resolutionChanged) emitSignals << ResolutionChangedSignal;
if (sizeChanged) emitSignals << ComplexSizeChangedSignal(bounds(), size);
emitSignals << ModifiedSignal;
KUndo2MagicString actionName = sizeChanged ?
kundo2_i18n("Scale Image") :
kundo2_i18n("Change Image Resolution");
KisProcessingApplicator::ProcessingFlags signalFlags =
(resolutionChanged || sizeChanged) ?
KisProcessingApplicator::NO_UI_UPDATES :
KisProcessingApplicator::NONE;
KisProcessingApplicator applicator(this, m_d->rootLayer,
KisProcessingApplicator::RECURSIVE | signalFlags,
emitSignals, actionName);
qreal sx = qreal(size.width()) / this->size().width();
qreal sy = qreal(size.height()) / this->size().height();
QTransform shapesCorrection;
if (resolutionChanged) {
shapesCorrection = QTransform::fromScale(xRes() / xres, yRes() / yres);
}
KisProcessingVisitorSP visitor =
new KisTransformProcessingVisitor(sx, sy,
0, 0,
QPointF(),
0,
0, 0,
filterStrategy,
shapesCorrection);
applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT);
if (resolutionChanged) {
KUndo2Command *parent =
new KisResetShapesCommand(m_d->rootLayer);
new KisImageSetResolutionCommand(this, xres, yres, parent);
applicator.applyCommand(parent);
}
if (sizeChanged) {
applicator.applyCommand(new KisImageResizeCommand(this, size));
}
applicator.end();
}
void KisImage::scaleNode(KisNodeSP node, const QPointF &center, qreal scaleX, qreal scaleY, KisFilterStrategy *filterStrategy, KisSelectionSP selection)
{
KUndo2MagicString actionName(kundo2_i18n("Scale Layer"));
KisImageSignalVector emitSignals;
emitSignals << ModifiedSignal;
QPointF offset;
{
KisTransformWorker worker(0,
scaleX, scaleY,
0, 0, 0, 0,
0.0,
0, 0, 0, 0);
QTransform transform = worker.transform();
offset = center - transform.map(center);
}
KisProcessingApplicator applicator(this, node,
KisProcessingApplicator::RECURSIVE,
emitSignals, actionName);
KisTransformProcessingVisitor *visitor =
new KisTransformProcessingVisitor(scaleX, scaleY,
0, 0,
QPointF(),
0,
offset.x(), offset.y(),
filterStrategy);
visitor->setSelection(selection);
if (selection) {
applicator.applyVisitor(visitor, KisStrokeJobData::CONCURRENT);
} else {
applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT);
}
applicator.end();
}
void KisImage::rotateImpl(const KUndo2MagicString &actionName,
KisNodeSP rootNode,
double radians,
bool resizeImage,
KisSelectionSP selection)
{
// we can either transform (and resize) the whole image or
// transform a selection, we cannot do both at the same time
KIS_SAFE_ASSERT_RECOVER(!(bool(selection) && resizeImage)) {
selection = 0;
}
const QRect baseBounds =
resizeImage ? bounds() :
selection ? selection->selectedExactRect() :
rootNode->exactBounds();
QPointF offset;
QSize newSize;
{
KisTransformWorker worker(0,
1.0, 1.0,
0, 0, 0, 0,
radians,
0, 0, 0, 0);
QTransform transform = worker.transform();
if (resizeImage) {
QRect newRect = transform.mapRect(baseBounds);
newSize = newRect.size();
offset = -newRect.topLeft();
}
else {
QPointF origin = QRectF(baseBounds).center();
newSize = size();
offset = -(transform.map(origin) - origin);
}
}
bool sizeChanged = resizeImage &&
(newSize.width() != baseBounds.width() ||
newSize.height() != baseBounds.height());
// These signals will be emitted after processing is done
KisImageSignalVector emitSignals;
if (sizeChanged) emitSignals << ComplexSizeChangedSignal(baseBounds, newSize);
emitSignals << ModifiedSignal;
// These flags determine whether updates are transferred to the UI during processing
KisProcessingApplicator::ProcessingFlags signalFlags =
sizeChanged ?
KisProcessingApplicator::NO_UI_UPDATES :
KisProcessingApplicator::NONE;
KisProcessingApplicator applicator(this, rootNode,
KisProcessingApplicator::RECURSIVE | signalFlags,
emitSignals, actionName);
KisFilterStrategy *filter = KisFilterStrategyRegistry::instance()->value("Bicubic");
KisTransformProcessingVisitor *visitor =
new KisTransformProcessingVisitor(1.0, 1.0, 0.0, 0.0,
QPointF(),
radians,
offset.x(), offset.y(),
filter);
if (selection) {
visitor->setSelection(selection);
}
if (selection) {
applicator.applyVisitor(visitor, KisStrokeJobData::CONCURRENT);
} else {
applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT);
}
if (sizeChanged) {
applicator.applyCommand(new KisImageResizeCommand(this, newSize));
}
applicator.end();
}
void KisImage::rotateImage(double radians)
{
rotateImpl(kundo2_i18n("Rotate Image"), root(), radians, true, 0);
}
void KisImage::rotateNode(KisNodeSP node, double radians, KisSelectionSP selection)
{
if (node->inherits("KisMask")) {
rotateImpl(kundo2_i18n("Rotate Mask"), node, radians, false, selection);
} else {
rotateImpl(kundo2_i18n("Rotate Layer"), node, radians, false, selection);
}
}
void KisImage::shearImpl(const KUndo2MagicString &actionName,
KisNodeSP rootNode,
bool resizeImage,
double angleX, double angleY,
KisSelectionSP selection)
{
const QRect baseBounds =
resizeImage ? bounds() :
selection ? selection->selectedExactRect() :
rootNode->exactBounds();
const QPointF origin = QRectF(baseBounds).center();
//angleX, angleY are in degrees
const qreal pi = 3.1415926535897932385;
const qreal deg2rad = pi / 180.0;
qreal tanX = tan(angleX * deg2rad);
qreal tanY = tan(angleY * deg2rad);
QPointF offset;
QSize newSize;
{
KisTransformWorker worker(0,
1.0, 1.0,
tanX, tanY, origin.x(), origin.y(),
0,
0, 0, 0, 0);
QRect newRect = worker.transform().mapRect(baseBounds);
newSize = newRect.size();
if (resizeImage) offset = -newRect.topLeft();
}
if (newSize == baseBounds.size()) return;
KisImageSignalVector emitSignals;
if (resizeImage) emitSignals << ComplexSizeChangedSignal(baseBounds, newSize);
emitSignals << ModifiedSignal;
KisProcessingApplicator::ProcessingFlags signalFlags =
KisProcessingApplicator::RECURSIVE;
if (resizeImage) signalFlags |= KisProcessingApplicator::NO_UI_UPDATES;
KisProcessingApplicator applicator(this, rootNode,
signalFlags,
emitSignals, actionName);
KisFilterStrategy *filter = KisFilterStrategyRegistry::instance()->value("Bilinear");
KisTransformProcessingVisitor *visitor =
new KisTransformProcessingVisitor(1.0, 1.0,
tanX, tanY, origin,
0,
offset.x(), offset.y(),
filter);
if (selection) {
visitor->setSelection(selection);
}
if (selection) {
applicator.applyVisitor(visitor, KisStrokeJobData::CONCURRENT);
} else {
applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT);
}
if (resizeImage) {
applicator.applyCommand(new KisImageResizeCommand(this, newSize));
}
applicator.end();
}
void KisImage::shearNode(KisNodeSP node, double angleX, double angleY, KisSelectionSP selection)
{
if (node->inherits("KisMask")) {
shearImpl(kundo2_i18n("Shear Mask"), node, false,
angleX, angleY, selection);
} else {
shearImpl(kundo2_i18n("Shear Layer"), node, false,
angleX, angleY, selection);
}
}
void KisImage::shear(double angleX, double angleY)
{
shearImpl(kundo2_i18n("Shear Image"), m_d->rootLayer, true,
angleX, angleY, 0);
}
void KisImage::convertLayerColorSpace(KisNodeSP node,
const KoColorSpace *dstColorSpace,
KoColorConversionTransformation::Intent renderingIntent,
KoColorConversionTransformation::ConversionFlags conversionFlags)
{
if (!node->projectionLeaf()->isLayer()) return;
const KoColorSpace *srcColorSpace = node->colorSpace();
if (!dstColorSpace || *srcColorSpace == *dstColorSpace) return;
KUndo2MagicString actionName =
kundo2_i18n("Convert Layer Color Space");
KisImageSignalVector emitSignals;
emitSignals << ModifiedSignal;
KisProcessingApplicator applicator(this, node,
KisProcessingApplicator::RECURSIVE,
emitSignals, actionName);
applicator.applyVisitor(
new KisConvertColorSpaceProcessingVisitor(
srcColorSpace, dstColorSpace,
renderingIntent, conversionFlags),
KisStrokeJobData::CONCURRENT);
applicator.end();
}
struct KisImage::KisImagePrivate::SetImageProjectionColorSpace : public KisCommandUtils::FlipFlopCommand
{
SetImageProjectionColorSpace(const KoColorSpace *cs, KisImageWSP image,
State initialState, KUndo2Command *parent = 0)
: KisCommandUtils::FlipFlopCommand(initialState, parent),
m_cs(cs),
m_image(image)
{
}
void partA() override {
KisImageSP image = m_image;
if (image) {
image->setProjectionColorSpace(m_cs);
}
}
private:
const KoColorSpace *m_cs;
KisImageWSP m_image;
};
void KisImage::KisImagePrivate::convertImageColorSpaceImpl(const KoColorSpace *dstColorSpace,
bool convertLayers,
KoColorConversionTransformation::Intent renderingIntent,
KoColorConversionTransformation::ConversionFlags conversionFlags)
{
const KoColorSpace *srcColorSpace = this->colorSpace;
if (!dstColorSpace || *srcColorSpace == *dstColorSpace) return;
const KUndo2MagicString actionName =
convertLayers ?
kundo2_i18n("Convert Image Color Space") :
kundo2_i18n("Convert Projection Color Space");
KisImageSignalVector emitSignals;
emitSignals << ColorSpaceChangedSignal;
emitSignals << ModifiedSignal;
KisProcessingApplicator applicator(q, this->rootLayer,
KisProcessingApplicator::RECURSIVE |
KisProcessingApplicator::NO_UI_UPDATES,
emitSignals, actionName);
applicator.applyCommand(
new KisImagePrivate::SetImageProjectionColorSpace(dstColorSpace,
KisImageWSP(q),
KisCommandUtils::FlipFlopCommand::INITIALIZING),
KisStrokeJobData::BARRIER);
if (convertLayers) {
applicator.applyVisitor(
new KisConvertColorSpaceProcessingVisitor(
srcColorSpace, dstColorSpace,
renderingIntent, conversionFlags),
KisStrokeJobData::CONCURRENT);
} else {
applicator.applyCommand(
new KisDoSomethingCommand<
KisDoSomethingCommandOps::ResetOp, KisGroupLayerSP>
(this->rootLayer, false));
applicator.applyCommand(
new KisDoSomethingCommand<
KisDoSomethingCommandOps::ResetOp, KisGroupLayerSP>
(this->rootLayer, true));
}
applicator.applyCommand(
new KisImagePrivate::SetImageProjectionColorSpace(srcColorSpace,
KisImageWSP(q),
KisCommandUtils::FlipFlopCommand::FINALIZING),
KisStrokeJobData::BARRIER);
applicator.end();
}
void KisImage::convertImageColorSpace(const KoColorSpace *dstColorSpace,
KoColorConversionTransformation::Intent renderingIntent,
KoColorConversionTransformation::ConversionFlags conversionFlags)
{
m_d->convertImageColorSpaceImpl(dstColorSpace, true, renderingIntent, conversionFlags);
}
void KisImage::convertImageProjectionColorSpace(const KoColorSpace *dstColorSpace)
{
m_d->convertImageColorSpaceImpl(dstColorSpace, false,
KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags());
}
bool KisImage::assignLayerProfile(KisNodeSP node, const KoColorProfile *profile)
{
const KoColorSpace *srcColorSpace = node->colorSpace();
if (!node->projectionLeaf()->isLayer()) return false;
if (!profile || *srcColorSpace->profile() == *profile) return false;
KUndo2MagicString actionName = kundo2_i18n("Assign Profile to Layer");
KisImageSignalVector emitSignals;
emitSignals << ModifiedSignal;
const KoColorSpace *dstColorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorSpace()->colorModelId().id(), colorSpace()->colorDepthId().id(), profile);
if (!dstColorSpace) return false;
KisProcessingApplicator applicator(this, node,
KisProcessingApplicator::RECURSIVE |
KisProcessingApplicator::NO_UI_UPDATES,
emitSignals, actionName);
applicator.applyVisitor(
new KisAssignProfileProcessingVisitor(
srcColorSpace, dstColorSpace),
KisStrokeJobData::CONCURRENT);
applicator.end();
return true;
}
bool KisImage::assignImageProfile(const KoColorProfile *profile, bool blockAllUpdates)
{
if (!profile) return false;
const KoColorSpace *srcColorSpace = m_d->colorSpace;
bool imageProfileIsSame = *srcColorSpace->profile() == *profile;
imageProfileIsSame &=
!KisLayerUtils::recursiveFindNode(m_d->rootLayer,
[profile] (KisNodeSP node) {
return *node->colorSpace()->profile() != *profile;
});
if (imageProfileIsSame) {
dbgImage << "Trying to set the same image profile again" << ppVar(srcColorSpace->profile()->name()) << ppVar(profile->name());
return true;
}
KUndo2MagicString actionName = kundo2_i18n("Assign Profile");
KisImageSignalVector emitSignals;
emitSignals << ProfileChangedSignal;
emitSignals << ModifiedSignal;
const KoColorSpace *dstColorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorSpace()->colorModelId().id(), colorSpace()->colorDepthId().id(), profile);
if (!dstColorSpace) return false;
KisProcessingApplicator applicator(this, m_d->rootLayer,
KisProcessingApplicator::RECURSIVE |
(!blockAllUpdates ?
KisProcessingApplicator::NO_UI_UPDATES :
KisProcessingApplicator::NO_IMAGE_UPDATES),
emitSignals, actionName);
applicator.applyCommand(
new KisImagePrivate::SetImageProjectionColorSpace(dstColorSpace,
KisImageWSP(this),
KisCommandUtils::FlipFlopCommand::INITIALIZING),
KisStrokeJobData::BARRIER);
applicator.applyVisitor(
new KisAssignProfileProcessingVisitor(
srcColorSpace, dstColorSpace),
KisStrokeJobData::CONCURRENT);
applicator.applyCommand(
new KisImagePrivate::SetImageProjectionColorSpace(srcColorSpace,
KisImageWSP(this),
KisCommandUtils::FlipFlopCommand::FINALIZING),
KisStrokeJobData::BARRIER);
applicator.end();
return true;
}
void KisImage::setProjectionColorSpace(const KoColorSpace * colorSpace)
{
m_d->colorSpace = colorSpace;
}
const KoColorSpace * KisImage::colorSpace() const
{
return m_d->colorSpace;
}
const KoColorProfile * KisImage::profile() const
{
return colorSpace()->profile();
}
double KisImage::xRes() const
{
return m_d->xres;
}
double KisImage::yRes() const
{
return m_d->yres;
}
void KisImage::setResolution(double xres, double yres)
{
m_d->xres = xres;
m_d->yres = yres;
- m_d->signalRouter.emitNotification(ResolutionChangedSignal);
}
QPointF KisImage::documentToPixel(const QPointF &documentCoord) const
{
return QPointF(documentCoord.x() * xRes(), documentCoord.y() * yRes());
}
QPoint KisImage::documentToImagePixelFloored(const QPointF &documentCoord) const
{
QPointF pixelCoord = documentToPixel(documentCoord);
return QPoint(qFloor(pixelCoord.x()), qFloor(pixelCoord.y()));
}
QRectF KisImage::documentToPixel(const QRectF &documentRect) const
{
return QRectF(documentToPixel(documentRect.topLeft()), documentToPixel(documentRect.bottomRight()));
}
QPointF KisImage::pixelToDocument(const QPointF &pixelCoord) const
{
return QPointF(pixelCoord.x() / xRes(), pixelCoord.y() / yRes());
}
QPointF KisImage::pixelToDocument(const QPoint &pixelCoord) const
{
return QPointF((pixelCoord.x() + 0.5) / xRes(), (pixelCoord.y() + 0.5) / yRes());
}
QRectF KisImage::pixelToDocument(const QRectF &pixelCoord) const
{
return QRectF(pixelToDocument(pixelCoord.topLeft()), pixelToDocument(pixelCoord.bottomRight()));
}
qint32 KisImage::width() const
{
return m_d->width;
}
qint32 KisImage::height() const
{
return m_d->height;
}
KisGroupLayerSP KisImage::rootLayer() const
{
Q_ASSERT(m_d->rootLayer);
return m_d->rootLayer;
}
KisPaintDeviceSP KisImage::projection() const
{
if (m_d->isolatedRootNode) {
return m_d->isolatedRootNode->projection();
}
Q_ASSERT(m_d->rootLayer);
KisPaintDeviceSP projection = m_d->rootLayer->projection();
Q_ASSERT(projection);
return projection;
}
qint32 KisImage::nlayers() const
{
QStringList list;
list << "KisLayer";
KisCountVisitor visitor(list, KoProperties());
m_d->rootLayer->accept(visitor);
return visitor.count();
}
qint32 KisImage::nHiddenLayers() const
{
QStringList list;
list << "KisLayer";
KoProperties properties;
properties.setProperty("visible", false);
KisCountVisitor visitor(list, properties);
m_d->rootLayer->accept(visitor);
return visitor.count();
}
void KisImage::flatten(KisNodeSP activeNode)
{
KisLayerUtils::flattenImage(this, activeNode);
}
void KisImage::mergeMultipleLayers(QList<KisNodeSP> mergedNodes, KisNodeSP putAfter)
{
if (!KisLayerUtils::tryMergeSelectionMasks(this, mergedNodes, putAfter)) {
KisLayerUtils::mergeMultipleLayers(this, mergedNodes, putAfter);
}
}
void KisImage::mergeDown(KisLayerSP layer, const KisMetaData::MergeStrategy* strategy)
{
KisLayerUtils::mergeDown(this, layer, strategy);
}
void KisImage::flattenLayer(KisLayerSP layer)
{
KisLayerUtils::flattenLayer(this, layer);
}
void KisImage::setModified()
{
m_d->signalRouter.emitNotification(ModifiedSignal);
}
QImage KisImage::convertToQImage(QRect imageRect,
const KoColorProfile * profile)
{
qint32 x;
qint32 y;
qint32 w;
qint32 h;
imageRect.getRect(&x, &y, &w, &h);
return convertToQImage(x, y, w, h, profile);
}
QImage KisImage::convertToQImage(qint32 x,
qint32 y,
qint32 w,
qint32 h,
const KoColorProfile * profile)
{
KisPaintDeviceSP dev = projection();
if (!dev) return QImage();
QImage image = dev->convertToQImage(const_cast<KoColorProfile*>(profile), x, y, w, h,
KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags());
return image;
}
QImage KisImage::convertToQImage(const QSize& scaledImageSize, const KoColorProfile *profile)
{
if (scaledImageSize.isEmpty()) {
return QImage();
}
KisPaintDeviceSP dev = new KisPaintDevice(colorSpace());
KisPainter gc;
gc.copyAreaOptimized(QPoint(0, 0), projection(), dev, bounds());
gc.end();
double scaleX = qreal(scaledImageSize.width()) / width();
double scaleY = qreal(scaledImageSize.height()) / height();
QPointer<KoUpdater> updater = new KoDummyUpdater();
KisTransformWorker worker(dev, scaleX, scaleY, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, updater, KisFilterStrategyRegistry::instance()->value("Bicubic"));
worker.run();
delete updater;
return dev->convertToQImage(profile);
}
void KisImage::notifyLayersChanged()
{
m_d->signalRouter.emitNotification(LayersChangedSignal);
}
QRect KisImage::bounds() const
{
return QRect(0, 0, width(), height());
}
QRect KisImage::effectiveLodBounds() const
{
QRect boundRect = bounds();
const int lod = currentLevelOfDetail();
if (lod > 0) {
KisLodTransform t(lod);
boundRect = t.map(boundRect);
}
return boundRect;
}
KisPostExecutionUndoAdapter* KisImage::postExecutionUndoAdapter() const
{
const int lod = currentLevelOfDetail();
return lod > 0 ?
m_d->scheduler.lodNPostExecutionUndoAdapter() :
&m_d->postExecutionUndoAdapter;
}
const KUndo2Command* KisImage::lastExecutedCommand() const
{
return m_d->undoStore->presentCommand();
}
void KisImage::setUndoStore(KisUndoStore *undoStore)
{
m_d->legacyUndoAdapter.setUndoStore(undoStore);
m_d->postExecutionUndoAdapter.setUndoStore(undoStore);
m_d->undoStore.reset(undoStore);
}
KisUndoStore* KisImage::undoStore()
{
return m_d->undoStore.data();
}
KisUndoAdapter* KisImage::undoAdapter() const
{
return &m_d->legacyUndoAdapter;
}
void KisImage::setDefaultProjectionColor(const KoColor &color)
{
KIS_ASSERT_RECOVER_RETURN(m_d->rootLayer);
m_d->rootLayer->setDefaultProjectionColor(color);
}
KoColor KisImage::defaultProjectionColor() const
{
KIS_ASSERT_RECOVER(m_d->rootLayer) {
return KoColor(Qt::transparent, m_d->colorSpace);
}
return m_d->rootLayer->defaultProjectionColor();
}
void KisImage::setRootLayer(KisGroupLayerSP rootLayer)
{
emit sigInternalStopIsolatedModeRequested();
KoColor defaultProjectionColor(Qt::transparent, m_d->colorSpace);
if (m_d->rootLayer) {
m_d->rootLayer->setGraphListener(0);
m_d->rootLayer->disconnect();
KisPaintDeviceSP original = m_d->rootLayer->original();
defaultProjectionColor = original->defaultPixel();
}
m_d->rootLayer = rootLayer;
m_d->rootLayer->disconnect();
m_d->rootLayer->setGraphListener(this);
m_d->rootLayer->setImage(this);
setRoot(m_d->rootLayer.data());
this->setDefaultProjectionColor(defaultProjectionColor);
}
void KisImage::addAnnotation(KisAnnotationSP annotation)
{
// Find the icc annotation, if there is one
vKisAnnotationSP_it it = m_d->annotations.begin();
while (it != m_d->annotations.end()) {
if ((*it)->type() == annotation->type()) {
*it = annotation;
return;
}
++it;
}
m_d->annotations.push_back(annotation);
}
KisAnnotationSP KisImage::annotation(const QString& type)
{
vKisAnnotationSP_it it = m_d->annotations.begin();
while (it != m_d->annotations.end()) {
if ((*it)->type() == type) {
return *it;
}
++it;
}
return KisAnnotationSP(0);
}
void KisImage::removeAnnotation(const QString& type)
{
vKisAnnotationSP_it it = m_d->annotations.begin();
while (it != m_d->annotations.end()) {
if ((*it)->type() == type) {
m_d->annotations.erase(it);
return;
}
++it;
}
}
vKisAnnotationSP_it KisImage::beginAnnotations()
{
return m_d->annotations.begin();
}
vKisAnnotationSP_it KisImage::endAnnotations()
{
return m_d->annotations.end();
}
void KisImage::notifyAboutToBeDeleted()
{
emit sigAboutToBeDeleted();
}
KisImageSignalRouter* KisImage::signalRouter()
{
return &m_d->signalRouter;
}
void KisImage::waitForDone()
{
requestStrokeEnd();
KisBusyWaitBroker::instance()->notifyWaitOnImageStarted(this);
m_d->scheduler.waitForDone();
KisBusyWaitBroker::instance()->notifyWaitOnImageEnded(this);
}
KisStrokeId KisImage::startStroke(KisStrokeStrategy *strokeStrategy)
{
/**
* Ask open strokes to end gracefully. All the strokes clients
* (including the one calling this method right now) will get
* a notification that they should probably end their strokes.
* However this is purely their choice whether to end a stroke
* or not.
*/
if (strokeStrategy->requestsOtherStrokesToEnd()) {
requestStrokeEnd();
}
/**
* Some of the strokes can cancel their work with undoing all the
* changes they did to the paint devices. The problem is that undo
* stack will know nothing about it. Therefore, just notify it
* explicitly
*/
if (strokeStrategy->clearsRedoOnStart()) {
m_d->undoStore->purgeRedoState();
}
return m_d->scheduler.startStroke(strokeStrategy);
}
void KisImage::KisImagePrivate::notifyProjectionUpdatedInPatches(const QRect &rc, QVector<KisRunnableStrokeJobData*> &jobs)
{
KisImageConfig imageConfig(true);
int patchWidth = imageConfig.updatePatchWidth();
int patchHeight = imageConfig.updatePatchHeight();
for (int y = 0; y < rc.height(); y += patchHeight) {
for (int x = 0; x < rc.width(); x += patchWidth) {
QRect patchRect(x, y, patchWidth, patchHeight);
patchRect &= rc;
KritaUtils::addJobConcurrent(jobs, std::bind(&KisImage::notifyProjectionUpdated, q, patchRect));
}
}
}
bool KisImage::startIsolatedMode(KisNodeSP node)
{
struct StartIsolatedModeStroke : public KisRunnableBasedStrokeStrategy {
StartIsolatedModeStroke(KisNodeSP node, KisImageSP image)
: KisRunnableBasedStrokeStrategy(QLatin1String("start-isolated-mode"),
kundo2_noi18n("start-isolated-mode")),
m_node(node),
m_image(image),
m_needsFullRefresh(false)
{
this->enableJob(JOB_INIT, true, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE);
this->enableJob(JOB_DOSTROKE, true);
this->enableJob(JOB_FINISH, true, KisStrokeJobData::BARRIER);
setClearsRedoOnStart(false);
}
void initStrokeCallback() override {
// pass-though node don't have any projection prepared, so we should
// explicitly regenerate it before activating isolated mode.
m_node->projectionLeaf()->explicitlyRegeneratePassThroughProjection();
const bool beforeVisibility = m_node->projectionLeaf()->visible();
m_image->m_d->isolatedRootNode = m_node;
emit m_image->sigIsolatedModeChanged();
const bool afterVisibility = m_node->projectionLeaf()->visible();
m_needsFullRefresh = (beforeVisibility != afterVisibility);
}
void finishStrokeCallback() override {
// the GUI uses our thread to do the color space conversion so we
// need to emit this signal in multiple threads
if (m_needsFullRefresh) {
m_image->refreshGraphAsync(m_node);
} else {
QVector<KisRunnableStrokeJobData*> jobs;
m_image->m_d->notifyProjectionUpdatedInPatches(m_image->bounds(), jobs);
this->runnableJobsInterface()->addRunnableJobs(jobs);
}
m_image->invalidateAllFrames();
}
private:
KisNodeSP m_node;
KisImageSP m_image;
bool m_needsFullRefresh;
};
KisStrokeId id = startStroke(new StartIsolatedModeStroke(node, this));
endStroke(id);
return true;
}
void KisImage::stopIsolatedMode()
{
if (!m_d->isolatedRootNode) return;
struct StopIsolatedModeStroke : public KisRunnableBasedStrokeStrategy {
StopIsolatedModeStroke(KisImageSP image)
: KisRunnableBasedStrokeStrategy(QLatin1String("stop-isolated-mode"), kundo2_noi18n("stop-isolated-mode")),
m_image(image),
m_oldRootNode(nullptr),
m_oldNodeNeedsRefresh(false)
{
this->enableJob(JOB_INIT);
this->enableJob(JOB_DOSTROKE, true);
this->enableJob(JOB_FINISH, true, KisStrokeJobData::BARRIER);
setClearsRedoOnStart(false);
}
void initStrokeCallback() {
if (!m_image->m_d->isolatedRootNode) return;
m_oldRootNode = m_image->m_d->isolatedRootNode;
const bool beforeVisibility = m_oldRootNode->projectionLeaf()->visible();
m_image->m_d->isolatedRootNode = 0;
emit m_image->sigIsolatedModeChanged();
const bool afterVisibility = m_oldRootNode->projectionLeaf()->visible();
m_oldNodeNeedsRefresh = (beforeVisibility != afterVisibility);
}
void finishStrokeCallback() override {
m_image->invalidateAllFrames();
if (m_oldNodeNeedsRefresh){
m_oldRootNode->setDirty(m_image->bounds());
} else {
// TODO: Substitute notifyProjectionUpdated() with this code
// when update optimization is implemented
//
// QRect updateRect = bounds() | oldRootNode->extent();
//oldRootNode->setDirty(updateRect);
QVector<KisRunnableStrokeJobData*> jobs;
m_image->m_d->notifyProjectionUpdatedInPatches(m_image->bounds(), jobs);
this->runnableJobsInterface()->addRunnableJobs(jobs);
}
}
private:
KisImageSP m_image;
KisNodeSP m_oldRootNode;
bool m_oldNodeNeedsRefresh;
};
KisStrokeId id = startStroke(new StopIsolatedModeStroke(this));
endStroke(id);
}
KisNodeSP KisImage::isolatedModeRoot() const
{
return m_d->isolatedRootNode;
}
void KisImage::addJob(KisStrokeId id, KisStrokeJobData *data)
{
KisUpdateTimeMonitor::instance()->reportJobStarted(data);
m_d->scheduler.addJob(id, data);
}
void KisImage::endStroke(KisStrokeId id)
{
m_d->scheduler.endStroke(id);
}
bool KisImage::cancelStroke(KisStrokeId id)
{
return m_d->scheduler.cancelStroke(id);
}
bool KisImage::KisImagePrivate::tryCancelCurrentStrokeAsync()
{
return scheduler.tryCancelCurrentStrokeAsync();
}
void KisImage::requestUndoDuringStroke()
{
emit sigUndoDuringStrokeRequested();
}
void KisImage::requestStrokeCancellation()
{
if (!m_d->tryCancelCurrentStrokeAsync()) {
emit sigStrokeCancellationRequested();
}
}
UndoResult KisImage::tryUndoUnfinishedLod0Stroke()
{
return m_d->scheduler.tryUndoLastStrokeAsync();
}
void KisImage::requestStrokeEnd()
{
emit sigStrokeEndRequested();
emit sigStrokeEndRequestedActiveNodeFiltered();
}
void KisImage::requestStrokeEndActiveNode()
{
emit sigStrokeEndRequested();
}
void KisImage::refreshGraph(KisNodeSP root)
{
refreshGraph(root, bounds(), bounds());
}
void KisImage::refreshGraph(KisNodeSP root, const QRect &rc, const QRect &cropRect)
{
if (!root) root = m_d->rootLayer;
m_d->animationInterface->notifyNodeChanged(root.data(), rc, true);
m_d->scheduler.fullRefresh(root, rc, cropRect);
}
void KisImage::initialRefreshGraph()
{
/**
* NOTE: Tricky part. We set crop rect to null, so the clones
* will not rely on precalculated projections of their sources
*/
refreshGraphAsync(0, bounds(), QRect());
waitForDone();
}
void KisImage::refreshGraphAsync(KisNodeSP root)
{
refreshGraphAsync(root, bounds(), bounds());
}
void KisImage::refreshGraphAsync(KisNodeSP root, const QRect &rc)
{
refreshGraphAsync(root, rc, bounds());
}
void KisImage::refreshGraphAsync(KisNodeSP root, const QRect &rc, const QRect &cropRect)
+{
+ refreshGraphAsync(root, QVector<QRect>({rc}), cropRect);
+}
+
+void KisImage::refreshGraphAsync(KisNodeSP root, const QVector<QRect> &rects, const QRect &cropRect)
{
if (!root) root = m_d->rootLayer;
- m_d->animationInterface->notifyNodeChanged(root.data(), rc, true);
- m_d->scheduler.fullRefreshAsync(root, rc, cropRect);
+ /**
+ * We iterate through the filters in a reversed way. It makes the most nested filters
+ * to execute first.
+ */
+ for (auto it = m_d->projectionUpdatesFilters.rbegin();
+ it != m_d->projectionUpdatesFilters.rend();
+ ++it) {
+
+ KIS_SAFE_ASSERT_RECOVER(*it) { continue; }
+
+ if ((*it)->filterRefreshGraph(this, root.data(), rects, cropRect)) {
+ return;
+ }
+ }
+
+
+ m_d->animationInterface->notifyNodeChanged(root.data(), rects, true);
+ m_d->scheduler.fullRefreshAsync(root, rects, cropRect);
}
+
void KisImage::requestProjectionUpdateNoFilthy(KisNodeSP pseudoFilthy, const QRect &rc, const QRect &cropRect)
{
requestProjectionUpdateNoFilthy(pseudoFilthy, rc, cropRect, true);
}
void KisImage::requestProjectionUpdateNoFilthy(KisNodeSP pseudoFilthy, const QRect &rc, const QRect &cropRect, const bool resetAnimationCache)
{
KIS_ASSERT_RECOVER_RETURN(pseudoFilthy);
if (resetAnimationCache) {
m_d->animationInterface->notifyNodeChanged(pseudoFilthy.data(), rc, false);
}
m_d->scheduler.updateProjectionNoFilthy(pseudoFilthy, rc, cropRect);
}
void KisImage::addSpontaneousJob(KisSpontaneousJob *spontaneousJob)
{
m_d->scheduler.addSpontaneousJob(spontaneousJob);
}
bool KisImage::hasUpdatesRunning() const
{
return m_d->scheduler.hasUpdatesRunning();
}
KisProjectionUpdatesFilterCookie KisImage::addProjectionUpdatesFilter(KisProjectionUpdatesFilterSP filter)
{
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(filter, KisProjectionUpdatesFilterCookie());
m_d->projectionUpdatesFilters.append(filter);
return KisProjectionUpdatesFilterCookie(filter.data());
}
KisProjectionUpdatesFilterSP KisImage::removeProjectionUpdatesFilter(KisProjectionUpdatesFilterCookie cookie)
{
KIS_SAFE_ASSERT_RECOVER_NOOP(cookie);
KIS_SAFE_ASSERT_RECOVER_NOOP(m_d->projectionUpdatesFilters.last() == cookie);
auto it = std::find(m_d->projectionUpdatesFilters.begin(), m_d->projectionUpdatesFilters.end(), cookie);
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(it != m_d->projectionUpdatesFilters.end(), KisProjectionUpdatesFilterSP());
KisProjectionUpdatesFilterSP filter = *it;
m_d->projectionUpdatesFilters.erase(it);
return filter;
}
KisProjectionUpdatesFilterCookie KisImage::currentProjectionUpdatesFilter() const
{
return !m_d->projectionUpdatesFilters.isEmpty() ?
m_d->projectionUpdatesFilters.last().data() :
KisProjectionUpdatesFilterCookie();
}
void KisImage::disableDirtyRequests()
{
m_d->disabledUpdatesCookies.push(
addProjectionUpdatesFilter(toQShared(new KisDropAllProjectionUpdatesFilter())));
}
void KisImage::enableDirtyRequests()
{
KIS_SAFE_ASSERT_RECOVER_RETURN(!m_d->disabledUpdatesCookies.isEmpty());
removeProjectionUpdatesFilter(m_d->disabledUpdatesCookies.pop());
}
void KisImage::disableUIUpdates()
{
m_d->disableUIUpdateSignals.ref();
}
void KisImage::notifyBatchUpdateStarted()
{
m_d->signalRouter.emitNotifyBatchUpdateStarted();
}
void KisImage::notifyBatchUpdateEnded()
{
m_d->signalRouter.emitNotifyBatchUpdateEnded();
}
void KisImage::notifyUIUpdateCompleted(const QRect &rc)
{
notifyProjectionUpdated(rc);
}
QVector<QRect> KisImage::enableUIUpdates()
{
m_d->disableUIUpdateSignals.deref();
QRect rect;
QVector<QRect> postponedUpdates;
while (m_d->savedDisabledUIUpdates.pop(rect)) {
postponedUpdates.append(rect);
}
return postponedUpdates;
}
void KisImage::notifyProjectionUpdated(const QRect &rc)
{
KisUpdateTimeMonitor::instance()->reportUpdateFinished(rc);
if (!m_d->disableUIUpdateSignals) {
int lod = currentLevelOfDetail();
QRect dirtyRect = !lod ? rc : KisLodTransform::upscaledRect(rc, lod);
if (dirtyRect.isEmpty()) return;
emit sigImageUpdated(dirtyRect);
} else {
m_d->savedDisabledUIUpdates.push(rc);
}
}
void KisImage::setWorkingThreadsLimit(int value)
{
m_d->scheduler.setThreadsLimit(value);
}
int KisImage::workingThreadsLimit() const
{
return m_d->scheduler.threadsLimit();
}
void KisImage::notifySelectionChanged()
{
/**
* The selection is calculated asynchronously, so it is not
* handled by disableUIUpdates() and other special signals of
* KisImageSignalRouter
*/
m_d->legacyUndoAdapter.emitSelectionChanged();
/**
* Editing of selection masks doesn't necessary produce a
* setDirty() call, so in the end of the stroke we need to request
* direct update of the UI's cache.
*/
if (m_d->isolatedRootNode &&
dynamic_cast<KisSelectionMask*>(m_d->isolatedRootNode.data())) {
notifyProjectionUpdated(bounds());
}
}
void KisImage::requestProjectionUpdateImpl(KisNode *node,
const QVector<QRect> &rects,
const QRect &cropRect)
{
if (rects.isEmpty()) return;
m_d->scheduler.updateProjection(node, rects, cropRect);
}
void KisImage::requestProjectionUpdate(KisNode *node, const QVector<QRect> &rects, bool resetAnimationCache)
{
/**
* We iterate through the filters in a reversed way. It makes the most nested filters
* to execute first.
*/
for (auto it = m_d->projectionUpdatesFilters.rbegin();
it != m_d->projectionUpdatesFilters.rend();
++it) {
KIS_SAFE_ASSERT_RECOVER(*it) { continue; }
if ((*it)->filter(this, node, rects, resetAnimationCache)) {
return;
}
}
if (resetAnimationCache) {
m_d->animationInterface->notifyNodeChanged(node, rects, false);
}
/**
* Here we use 'permitted' instead of 'active' intentively,
* because the updates may come after the actual stroke has been
* finished. And having some more updates for the stroke not
* supporting the wrap-around mode will not make much harm.
*/
if (m_d->wrapAroundModePermitted) {
QVector<QRect> allSplitRects;
const QRect boundRect = effectiveLodBounds();
Q_FOREACH (const QRect &rc, rects) {
KisWrappedRect splitRect(rc, boundRect);
allSplitRects.append(splitRect);
}
requestProjectionUpdateImpl(node, allSplitRects, boundRect);
} else {
requestProjectionUpdateImpl(node, rects, bounds());
}
KisNodeGraphListener::requestProjectionUpdate(node, rects, resetAnimationCache);
}
void KisImage::invalidateFrames(const KisTimeRange &range, const QRect &rect)
{
m_d->animationInterface->invalidateFrames(range, rect);
}
void KisImage::requestTimeSwitch(int time)
{
m_d->animationInterface->requestTimeSwitchNonGUI(time);
}
KisNode *KisImage::graphOverlayNode() const
{
return m_d->overlaySelectionMask.data();
}
QList<KisLayerCompositionSP> KisImage::compositions()
{
return m_d->compositions;
}
void KisImage::addComposition(KisLayerCompositionSP composition)
{
m_d->compositions.append(composition);
}
void KisImage::removeComposition(KisLayerCompositionSP composition)
{
m_d->compositions.removeAll(composition);
}
bool checkMasksNeedConversion(KisNodeSP root, const QRect &bounds)
{
KisSelectionMask *mask = dynamic_cast<KisSelectionMask*>(root.data());
if (mask &&
(!bounds.contains(mask->paintDevice()->exactBounds()) ||
mask->selection()->hasShapeSelection())) {
return true;
}
KisNodeSP node = root->firstChild();
while (node) {
if (checkMasksNeedConversion(node, bounds)) {
return true;
}
node = node->nextSibling();
}
return false;
}
void KisImage::setWrapAroundModePermitted(bool value)
{
if (m_d->wrapAroundModePermitted != value) {
requestStrokeEnd();
}
m_d->wrapAroundModePermitted = value;
if (m_d->wrapAroundModePermitted &&
checkMasksNeedConversion(root(), bounds())) {
KisProcessingApplicator applicator(this, root(),
KisProcessingApplicator::RECURSIVE,
KisImageSignalVector() << ModifiedSignal,
kundo2_i18n("Crop Selections"));
KisProcessingVisitorSP visitor =
new KisCropSelectionsProcessingVisitor(bounds());
applicator.applyVisitor(visitor, KisStrokeJobData::CONCURRENT);
applicator.end();
}
}
bool KisImage::wrapAroundModePermitted() const
{
return m_d->wrapAroundModePermitted;
}
bool KisImage::wrapAroundModeActive() const
{
return m_d->wrapAroundModePermitted &&
m_d->scheduler.wrapAroundModeSupported();
}
void KisImage::setDesiredLevelOfDetail(int lod)
{
if (m_d->blockLevelOfDetail) {
qWarning() << "WARNING: KisImage::setDesiredLevelOfDetail()"
<< "was called while LoD functionality was being blocked!";
return;
}
m_d->scheduler.setDesiredLevelOfDetail(lod);
}
int KisImage::currentLevelOfDetail() const
{
if (m_d->blockLevelOfDetail) {
return 0;
}
return m_d->scheduler.currentLevelOfDetail();
}
void KisImage::setLevelOfDetailBlocked(bool value)
{
KisImageBarrierLockerRaw l(this);
if (value && !m_d->blockLevelOfDetail) {
m_d->scheduler.setDesiredLevelOfDetail(0);
}
m_d->blockLevelOfDetail = value;
}
void KisImage::explicitRegenerateLevelOfDetail()
{
if (!m_d->blockLevelOfDetail) {
m_d->scheduler.explicitRegenerateLevelOfDetail();
}
}
bool KisImage::levelOfDetailBlocked() const
{
return m_d->blockLevelOfDetail;
}
void KisImage::nodeCollapsedChanged(KisNode * node)
{
Q_UNUSED(node);
emit sigNodeCollapsedChanged();
}
KisImageAnimationInterface* KisImage::animationInterface() const
{
return m_d->animationInterface;
}
void KisImage::setProofingConfiguration(KisProofingConfigurationSP proofingConfig)
{
m_d->proofingConfig = proofingConfig;
emit sigProofingConfigChanged();
}
KisProofingConfigurationSP KisImage::proofingConfiguration() const
{
if (m_d->proofingConfig) {
return m_d->proofingConfig;
}
return KisProofingConfigurationSP();
}
QPointF KisImage::mirrorAxesCenter() const
{
return m_d->axesCenter;
}
void KisImage::setMirrorAxesCenter(const QPointF &value) const
{
m_d->axesCenter = value;
}
void KisImage::setAllowMasksOnRootNode(bool value)
{
m_d->allowMasksOnRootNode = value;
}
bool KisImage::allowMasksOnRootNode() const
{
return m_d->allowMasksOnRootNode;
}
diff --git a/libs/image/kis_image.h b/libs/image/kis_image.h
index 1e3b5e75fa..0e9a5798ba 100644
--- a/libs/image/kis_image.h
+++ b/libs/image/kis_image.h
@@ -1,1247 +1,1248 @@
/*
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
* Copyright (c) 2007 Boudewijn Rempt <boud@valdyas.org>
*
* 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_IMAGE_H_
#define KIS_IMAGE_H_
#include <QObject>
#include <QString>
#include <QPainter>
#include <QRect>
#include <QBitArray>
#include <KoColorConversionTransformation.h>
#include "kis_types.h"
#include "kis_shared.h"
#include "kis_node_graph_listener.h"
#include "kis_node_facade.h"
#include "kis_image_interfaces.h"
#include "kis_strokes_queue_undo_result.h"
#include <kritaimage_export.h>
class KoColorSpace;
class KoColor;
class KisCompositeProgressProxy;
class KisUndoStore;
class KisUndoAdapter;
class KisImageSignalRouter;
class KisPostExecutionUndoAdapter;
class KisFilterStrategy;
class KoColorProfile;
class KisLayerComposition;
class KisSpontaneousJob;
class KisImageAnimationInterface;
class KUndo2MagicString;
class KisProofingConfiguration;
class KisPaintDevice;
namespace KisMetaData
{
class MergeStrategy;
}
/**
* This is the image class, it contains a tree of KisLayer stack and
* meta information about the image. And it also provides some
* functions to manipulate the whole image.
*/
class KRITAIMAGE_EXPORT KisImage : public QObject,
public KisStrokesFacade,
public KisStrokeUndoFacade,
public KisUpdatesFacade,
public KisProjectionUpdateListener,
public KisNodeFacade,
public KisNodeGraphListener,
public KisShared
{
Q_OBJECT
public:
/// @p colorSpace can be null. In that case, it will be initialised to a default color space.
KisImage(KisUndoStore *undoStore, qint32 width, qint32 height, const KoColorSpace *colorSpace, const QString& name);
~KisImage() override;
static KisImageSP fromQImage(const QImage &image, KisUndoStore *undoStore);
public: // KisNodeGraphListener implementation
void aboutToAddANode(KisNode *parent, int index) override;
void nodeHasBeenAdded(KisNode *parent, int index) override;
void aboutToRemoveANode(KisNode *parent, int index) override;
void nodeChanged(KisNode * node) override;
void nodeCollapsedChanged(KisNode *node) override;
void invalidateAllFrames() override;
void notifySelectionChanged() override;
void requestProjectionUpdate(KisNode *node, const QVector<QRect> &rects, bool resetAnimationCache) override;
void invalidateFrames(const KisTimeRange &range, const QRect &rect) override;
void requestTimeSwitch(int time) override;
KisNode* graphOverlayNode() const override;
public: // KisProjectionUpdateListener implementation
void notifyProjectionUpdated(const QRect &rc) override;
public:
/**
* Set the number of threads used by the image's working threads
*/
void setWorkingThreadsLimit(int value);
/**
* Return the number of threads available to the image's working threads
*/
int workingThreadsLimit() const;
/**
* Makes a copy of the image with all the layers. If possible, shallow
* copies of the layers are made.
*
* \p exactCopy shows if the copied image should look *exactly* the same as
* the other one (according to it's .kra xml representation). It means that
* the layers will have the same UUID keys and, therefore, you are not
* expected to use the copied image anywhere except for saving. Don't use
* this option if you plan to work with the copied image later.
*/
KisImage *clone(bool exactCopy = false);
void copyFromImage(const KisImage &rhs);
private:
// must specify exactly one from CONSTRUCT or REPLACE.
enum CopyPolicy {
CONSTRUCT = 1, ///< we are copy-constructing a new KisImage
REPLACE = 2, ///< we are replacing the current KisImage with another
EXACT_COPY = 4, /// we need an exact copy of the original image
};
void copyFromImageImpl(const KisImage &rhs, int policy);
public:
/**
* Render the projection onto a QImage.
*/
QImage convertToQImage(qint32 x1,
qint32 y1,
qint32 width,
qint32 height,
const KoColorProfile * profile);
/**
* Render the projection onto a QImage.
* (this is an overloaded function)
*/
QImage convertToQImage(QRect imageRect,
const KoColorProfile * profile);
/**
* Render a thumbnail of the projection onto a QImage.
*/
QImage convertToQImage(const QSize& scaledImageSize, const KoColorProfile *profile);
/**
* [low-level] Lock the image without waiting for all the internal job queues are processed
*
* WARNING: Don't use it unless you really know what you are doing! Use barrierLock() instead!
*
* Waits for all the **currently running** internal jobs to complete and locks the image
* for writing. Please note that this function does **not** wait for all the internal
* queues to process, so there might be some non-finished actions pending. It means that
* you just postpone these actions until you unlock() the image back. Until then, then image
* might easily be frozen in some inconsistent state.
*
* The only sane usage for this function is to lock the image for **emergency**
* processing, when some internal action or scheduler got hung up, and you just want
* to fetch some data from the image without races.
*
* In all other cases, please use barrierLock() instead!
*/
void lock();
/**
* Unlocks the image and starts/resumes all the pending internal jobs. If the image
* has been locked for a non-readOnly access, then all the internal caches of the image
* (e.g. lod-planes) are reset and regeneration jobs are scheduled.
*/
void unlock();
/**
* @return return true if the image is in a locked state, i.e. all the internal
* jobs are blocked from execution by calling wither lock() or barrierLock().
*
* When the image is locked, the user can do some modifications to the image
* contents safely without a perspective having race conditions with internal
* image jobs.
*/
bool locked() const;
/**
* Sets the mask (it must be a part of the node hierarchy already) to be paited on
* the top of all layers. This method does all the locking and syncing for you. It
* is executed asynchronously.
*/
void setOverlaySelectionMask(KisSelectionMaskSP mask);
/**
* \see setOverlaySelectionMask
*/
KisSelectionMaskSP overlaySelectionMask() const;
/**
* \see setOverlaySelectionMask
*/
bool hasOverlaySelectionMask() const;
/**
* @return the global selection object or 0 if there is none. The
* global selection is always read-write.
*/
KisSelectionSP globalSelection() const;
/**
* Retrieve the next automatic layername (XXX: fix to add option to return Mask X)
*/
QString nextLayerName(const QString &baseName = "") const;
/**
* Set the automatic layer name counter one back.
*/
void rollBackLayerName();
/**
* @brief start asynchronous operation on resizing the image
*
* The method will resize the image to fit the new size without
* dropping any pixel data. The GUI will get correct
* notification with old and new sizes, so it adjust canvas origin
* accordingly and avoid jumping of the canvas on screen
*
* @param newRect the rectangle of the image which will be visible
* after operation is completed
*
* Please note that the actual operation starts asynchronously in
* a background, so you cannot expect the image having new size
* right after this call.
*/
void resizeImage(const QRect& newRect);
/**
* @brief start asynchronous operation on cropping the image
*
* The method will **drop** all the image data outside \p newRect
* and resize the image to fit the new size. The GUI will get correct
* notification with old and new sizes, so it adjust canvas origin
* accordingly and avoid jumping of the canvas on screen
*
* @param newRect the rectangle of the image which will be cut-out
*
* Please note that the actual operation starts asynchronously in
* a background, so you cannot expect the image having new size
* right after this call.
*/
void cropImage(const QRect& newRect);
/**
* @brief purge all pixels that have default pixel to free up memory
* @param isCancellable if true, the scheduler is allower to stop and
* cancel purging operation as soon as the user starts any action.
* If \p isCancellable is false, then the user will not be allowed to do
* anything until purging operation is completed.
*/
void purgeUnusedData(bool isCancellable);
/**
* @brief start asynchronous operation on cropping a subtree of nodes starting at \p node
*
* The method will **drop** all the layer data outside \p newRect. Neither
* image nor a layer will be moved anywhere
*
* @param node node to crop
* @param newRect the rectangle of the layer which will be cut-out
*
* Please note that the actual operation starts asynchronously in
* a background, so you cannot expect the image having new size
* right after this call.
*/
void cropNode(KisNodeSP node, const QRect& newRect);
/**
* @brief start asynchronous operation on scaling the image
* @param size new image size in pixels
* @param xres new image x-resolution pixels-per-pt
* @param yres new image y-resolution pixels-per-pt
* @param filterStrategy filtering strategy
*
* Please note that the actual operation starts asynchronously in
* a background, so you cannot expect the image having new size
* right after this call.
*/
void scaleImage(const QSize &size, qreal xres, qreal yres, KisFilterStrategy *filterStrategy);
/**
* @brief start asynchronous operation on scaling a subtree of nodes starting at \p node
* @param node node to scale
* @param center the center of the scaling
* @param scaleX x-scale coefficient to be applied to the node
* @param scaleY y-scale coefficient to be applied to the node
* @param filterStrategy filtering strategy
* @param selection the selection we based on
*
* Please note that the actual operation starts asynchronously in
* a background, so you cannot expect the image having new size
* right after this call.
*/
void scaleNode(KisNodeSP node, const QPointF &center, qreal scaleX, qreal scaleY, KisFilterStrategy *filterStrategy, KisSelectionSP selection);
/**
* @brief start asynchronous operation on rotating the image
*
* The image is resized to fit the rotated rectangle
*
* @param radians rotation angle in radians
*
* Please note that the actual operation starts asynchronously in
* a background, so you cannot expect the operation being completed
* right after the call
*/
void rotateImage(double radians);
/**
* @brief start asynchronous operation on rotating a subtree of nodes starting at \p node
*
* The image is not resized!
*
* @param node the root of the subtree to rotate
* @param radians rotation angle in radians
* @param selection the selection we based on
*
* Please note that the actual operation starts asynchronously in
* a background, so you cannot expect the operation being completed
* right after the call
*/
void rotateNode(KisNodeSP node, double radians, KisSelectionSP selection);
/**
* @brief start asynchronous operation on shearing the image
*
* The image is resized to fit the sheared polygon
*
* @p angleX, @p angleY are given in degrees.
*
* Please note that the actual operation starts asynchronously in
* a background, so you cannot expect the operation being completed
* right after the call
*/
void shear(double angleX, double angleY);
/**
* @brief start asynchronous operation on shearing a subtree of nodes starting at \p node
*
* The image is not resized!
*
* @param node the root of the subtree to rotate
* @param angleX x-shear given in degrees.
* @param angleY y-shear given in degrees.
* @param selection the selection we based on
*
* Please note that the actual operation starts asynchronously in
* a background, so you cannot expect the operation being completed
* right after the call
*/
void shearNode(KisNodeSP node, double angleX, double angleY, KisSelectionSP selection);
/**
* Convert image projection to \p dstColorSpace, keeping all the layers intouched.
*/
void convertImageProjectionColorSpace(const KoColorSpace *dstColorSpace);
/**
* Convert the image and all its layers to the dstColorSpace
*/
void convertImageColorSpace(const KoColorSpace *dstColorSpace,
KoColorConversionTransformation::Intent renderingIntent,
KoColorConversionTransformation::ConversionFlags conversionFlags);
/**
* Convert layer and all its child layers to dstColorSpace
*/
void convertLayerColorSpace(KisNodeSP node,
const KoColorSpace *dstColorSpace,
KoColorConversionTransformation::Intent renderingIntent,
KoColorConversionTransformation::ConversionFlags conversionFlags);
// Get the profile associated with this image
const KoColorProfile * profile() const;
/**
* Set the profile of the layer and all its children to the new profile.
* It doesn't do any pixel conversion.
*
* This is essential if you have loaded an image that didn't
* have an embedded profile to which you want to attach the right profile.
*
* @returns false if the profile could not be assigned
*/
bool assignLayerProfile(KisNodeSP node, const KoColorProfile *profile);
/**
* Set the profile of the image to the new profile and do the same for
* all layers that have the same colorspace and profile of the image.
* It doesn't do any pixel conversion.
*
* This is essential if you have loaded an image that didn't
* have an embedded profile to which you want to attach the right profile.
*
* @returns false if the profile could not be assigned
*/
bool assignImageProfile(const KoColorProfile *profile, bool blockAllUpdates = false);
/**
* Returns the current undo adapter. You can add new commands to the
* undo stack using the adapter. This adapter is used for a backward
* compatibility for old commands created before strokes. It blocks
* all the porcessing at the scheduler, waits until it's finished
* and executes commands exclusively.
*/
KisUndoAdapter* undoAdapter() const;
/**
* This adapter is used by the strokes system. The commands are added
* to it *after* redo() is done (in the scheduler context). They are
* wrapped into a special command and added to the undo stack. redo()
* in not called.
*/
KisPostExecutionUndoAdapter* postExecutionUndoAdapter() const override;
/**
* Return the lastly executed LoD0 command. It is effectively the same
* as to call undoAdapter()->presentCommand();
*/
const KUndo2Command* lastExecutedCommand() const override;
/**
* Replace current undo store with the new one. The old store
* will be deleted.
* This method is used by KisDocument for dropping all the commands
* during file loading.
*/
void setUndoStore(KisUndoStore *undoStore);
/**
* Return current undo store of the image
*/
KisUndoStore* undoStore();
/**
* Tell the image it's modified; this emits the sigImageModified
* signal. This happens when the image needs to be saved
*/
void setModified();
/**
* The default colorspace of this image: new layers will have this
* colorspace and the projection will have this colorspace.
*/
const KoColorSpace * colorSpace() const;
/**
* X resolution in pixels per pt
*/
double xRes() const;
/**
* Y resolution in pixels per pt
*/
double yRes() const;
/**
* Set the resolution in pixels per pt.
*/
void setResolution(double xres, double yres);
/**
* Convert a document coordinate to a pixel coordinate.
*
* @param documentCoord PostScript Pt coordinate to convert.
*/
QPointF documentToPixel(const QPointF &documentCoord) const;
/**
* Convert a document coordinate to an integer pixel coordinate rounded down.
*
* @param documentCoord PostScript Pt coordinate to convert.
*/
QPoint documentToImagePixelFloored(const QPointF &documentCoord) const;
/**
* Convert a document rectangle to a pixel rectangle.
*
* @param documentRect PostScript Pt rectangle to convert.
*/
QRectF documentToPixel(const QRectF &documentRect) const;
/**
* Convert a pixel coordinate to a document coordinate.
*
* @param pixelCoord pixel coordinate to convert.
*/
QPointF pixelToDocument(const QPointF &pixelCoord) const;
/**
* Convert an integer pixel coordinate to a document coordinate.
* The document coordinate is at the centre of the pixel.
*
* @param pixelCoord pixel coordinate to convert.
*/
QPointF pixelToDocument(const QPoint &pixelCoord) const;
/**
* Convert a document rectangle to an integer pixel rectangle.
*
* @param pixelCoord pixel coordinate to convert.
*/
QRectF pixelToDocument(const QRectF &pixelCoord) const;
/**
* Return the width of the image
*/
qint32 width() const;
/**
* Return the height of the image
*/
qint32 height() const;
/**
* Return the size of the image
*/
QSize size() const {
return QSize(width(), height());
}
/**
* @return the root node of the image node graph
*/
KisGroupLayerSP rootLayer() const;
/**
* Return the projection; that is, the complete, composited
* representation of this image.
*/
KisPaintDeviceSP projection() const;
/**
* Return the number of layers (not other nodes) that are in this
* image.
*/
qint32 nlayers() const;
/**
* Return the number of layers (not other node types) that are in
* this image and that are hidden.
*/
qint32 nHiddenLayers() const;
/**
* Merge all visible layers and discard hidden ones.
*/
void flatten(KisNodeSP activeNode);
/**
* Merge the specified layer with the layer
* below this layer, remove the specified layer.
*/
void mergeDown(KisLayerSP l, const KisMetaData::MergeStrategy* strategy);
/**
* flatten the layer: that is, the projection becomes the layer
* and all subnodes are removed. If this is not a paint layer, it will morph
* into a paint layer.
*/
void flattenLayer(KisLayerSP layer);
/**
* Merges layers in \p mergedLayers and creates a new layer above
* \p putAfter
*/
void mergeMultipleLayers(QList<KisNodeSP> mergedLayers, KisNodeSP putAfter);
/// @return the exact bounds of the image in pixel coordinates.
QRect bounds() const override;
/**
* Returns the actual bounds of the image, taking LevelOfDetail
* into account. This value is used as a bounds() value of
* KisDefaultBounds object.
*/
QRect effectiveLodBounds() const;
/// use if the layers have changed _completely_ (eg. when flattening)
void notifyLayersChanged();
/**
* Sets the default color of the root layer projection. All the layers
* will be merged on top of this very color
*/
void setDefaultProjectionColor(const KoColor &color);
/**
* \see setDefaultProjectionColor()
*/
KoColor defaultProjectionColor() const;
void setRootLayer(KisGroupLayerSP rootLayer);
/**
* Add an annotation for this image. This can be anything: Gamma, EXIF, etc.
* Note that the "icc" annotation is reserved for the color strategies.
* If the annotation already exists, overwrite it with this one.
*/
void addAnnotation(KisAnnotationSP annotation);
/** get the annotation with the given type, can return 0 */
KisAnnotationSP annotation(const QString& type);
/** delete the annotation, if the image contains it */
void removeAnnotation(const QString& type);
/**
* Start of an iteration over the annotations of this image (including the ICC Profile)
*/
vKisAnnotationSP_it beginAnnotations();
/** end of an iteration over the annotations of this image */
vKisAnnotationSP_it endAnnotations();
/**
* Called before the image is deleted and sends the sigAboutToBeDeleted signal
*/
void notifyAboutToBeDeleted();
KisImageSignalRouter* signalRouter();
/**
* Returns whether we can reselect current global selection
*
* \see reselectGlobalSelection()
*/
bool canReselectGlobalSelection();
/**
* Returns the layer compositions for the image
*/
QList<KisLayerCompositionSP> compositions();
/**
* Adds a new layer composition, will be saved with the image
*/
void addComposition(KisLayerCompositionSP composition);
/**
* Remove the layer compostion
*/
void removeComposition(KisLayerCompositionSP composition);
/**
* Permit or deny the wrap-around mode for all the paint devices
* of the image. Note that permitting the wraparound mode will not
* necessarily activate it right now. To be activated the wrap
* around mode should be 1) permitted; 2) supported by the
* currently running stroke.
*/
void setWrapAroundModePermitted(bool value);
/**
* \return whether the wrap-around mode is permitted for this
* image. If the wrap around mode is permitted and the
* currently running stroke supports it, the mode will be
* activated for all paint devices of the image.
*
* \see setWrapAroundMode
*/
bool wrapAroundModePermitted() const;
/**
* \return whether the wraparound mode is activated for all the
* devices of the image. The mode is activated when both
* factors are true: the user permitted it and the stroke
* supports it
*/
bool wrapAroundModeActive() const;
/**
* \return current level of detail which is used when processing the image.
* Current working zoom = 2 ^ (- currentLevelOfDetail()). Default value is
* null, which means we work on the original image.
*/
int currentLevelOfDetail() const;
/**
* Notify KisImage which level of detail should be used in the
* lod-mode. Setting the mode does not guarantee the LOD to be
* used. It will be activated only when the stokes supports it.
*/
void setDesiredLevelOfDetail(int lod);
/**
* Relative position of the mirror axis center
* 0,0 - topleft corner of the image
* 1,1 - bottomright corner of the image
*/
QPointF mirrorAxesCenter() const;
/**
* Sets the relative position of the axes center
* \see mirrorAxesCenter() for details
*/
void setMirrorAxesCenter(const QPointF &value) const;
/**
* Configure the image to allow masks on the root not (as reported by
* root()->allowAsChild()). By default it is not allowed (because it
* looks weird from GUI point of view)
*/
void setAllowMasksOnRootNode(bool value);
/**
* \see setAllowMasksOnRootNode()
*/
bool allowMasksOnRootNode() const;
public Q_SLOTS:
/**
* Explicitly start regeneration of LoD planes of all the devices
* in the image. This call should be performed when the user is idle,
* just to make the quality of image updates better.
*/
void explicitRegenerateLevelOfDetail();
public:
/**
* Blocks usage of level of detail functionality. After this method
* has been called, no new strokes will use LoD.
*/
void setLevelOfDetailBlocked(bool value);
/**
* \see setLevelOfDetailBlocked()
*/
bool levelOfDetailBlocked() const;
KisImageAnimationInterface *animationInterface() const;
/**
* @brief setProofingConfiguration, this sets the image's proofing configuration, and signals
* the proofingConfiguration has changed.
* @param proofingConfig - the kis proofing config that will be used instead.
*/
void setProofingConfiguration(KisProofingConfigurationSP proofingConfig);
/**
* @brief proofingConfiguration
* @return the proofing configuration of the image.
*/
KisProofingConfigurationSP proofingConfiguration() const;
public Q_SLOTS:
bool startIsolatedMode(KisNodeSP node);
void stopIsolatedMode();
public:
KisNodeSP isolatedModeRoot() const;
Q_SIGNALS:
/**
* Emitted whenever an action has caused the image to be
* recomposited. Parameter is the rect that has been recomposited.
*/
void sigImageUpdated(const QRect &);
/**
Emitted whenever the image has been modified, so that it
doesn't match with the version saved on disk.
*/
void sigImageModified();
/**
* The signal is emitted when the size of the image is changed.
* \p oldStillPoint and \p newStillPoint give the receiver the
* hint about how the new and old rect of the image correspond to
* each other. They specify the point of the image around which
* the conversion was done. This point will stay still on the
* user's screen. That is the \p newStillPoint of the new image
* will be painted at the same screen position, where \p
* oldStillPoint of the old image was painted.
*
* \param oldStillPoint is a still point represented in *old*
* image coordinates
*
* \param newStillPoint is a still point represented in *new*
* image coordinates
*/
void sigSizeChanged(const QPointF &oldStillPoint, const QPointF &newStillPoint);
void sigProfileChanged(const KoColorProfile * profile);
void sigColorSpaceChanged(const KoColorSpace* cs);
void sigResolutionChanged(double xRes, double yRes);
void sigRequestNodeReselection(KisNodeSP activeNode, const KisNodeList &selectedNodes);
/**
* Inform the model that a node was changed
*/
void sigNodeChanged(KisNodeSP node);
/**
* Inform that the image is going to be deleted
*/
void sigAboutToBeDeleted();
/**
* The signal is emitted right after a node has been connected
* to the graph of the nodes.
*
* WARNING: you must not request any graph-related information
* about the node being run in a not-scheduler thread. If you need
* information about the parent/siblings of the node connect
* with Qt::DirectConnection, get needed information and then
* emit another Qt::AutoConnection signal to pass this information
* to your thread. See details of the implementation
* in KisDummiesfacadeBase.
*/
void sigNodeAddedAsync(KisNodeSP node);
/**
* This signal is emitted right before a node is going to removed
* from the graph of the nodes.
*
* WARNING: you must not request any graph-related information
* about the node being run in a not-scheduler thread.
*
* \see comment in sigNodeAddedAsync()
*/
void sigRemoveNodeAsync(KisNodeSP node);
/**
* Emitted when the root node of the image has changed.
* It happens, e.g. when we flatten the image. When
* this happens the receiver should reload information
* about the image
*/
void sigLayersChangedAsync();
/**
* Emitted when the UI has requested the undo of the last stroke's
* operation. The point is, we cannot deal with the internals of
* the stroke without its creator knowing about it (which most
* probably cause a crash), so we just forward this request from
* the UI to the creator of the stroke.
*
* If your tool supports undoing part of its work, just listen to
* this signal and undo when it comes
*/
void sigUndoDuringStrokeRequested();
/**
* Emitted when the UI has requested the cancellation of
* the stroke. The point is, we cannot cancel the stroke
* without its creator knowing about it (which most probably
* cause a crash), so we just forward this request from the UI
* to the creator of the stroke.
*
* If your tool supports cancelling of its work in the middle
* of operation, just listen to this signal and cancel
* the stroke when it comes
*/
void sigStrokeCancellationRequested();
/**
* Emitted when the image decides that the stroke should better
* be ended. The point is, we cannot just end the stroke
* without its creator knowing about it (which most probably
* cause a crash), so we just forward this request from the UI
* to the creator of the stroke.
*
* If your tool supports long strokes that may involve multiple
* mouse actions in one stroke, just listen to this signal and
* end the stroke when it comes.
*/
void sigStrokeEndRequested();
/**
* Same as sigStrokeEndRequested() but is not emitted when the active node
* is changed.
*/
void sigStrokeEndRequestedActiveNodeFiltered();
/**
* Emitted when the isolated mode status has changed.
*
* Can be used by the receivers to catch a fact of forcefully
* stopping the isolated mode by the image when some complex
* action was requested
*/
void sigIsolatedModeChanged();
/**
* Emitted when one or more nodes changed the collapsed state
*
*/
void sigNodeCollapsedChanged();
/**
* Emitted when the proofing configuration of the image is being changed.
*
*/
void sigProofingConfigChanged();
/**
* Internal signal for asynchronously requesting isolated mode to stop. Don't use it
* outside KisImage, use sigIsolatedModeChanged() instead.
*/
void sigInternalStopIsolatedModeRequested();
public Q_SLOTS:
KisCompositeProgressProxy* compositeProgressProxy();
bool isIdle(bool allowLocked = false);
/**
* @brief Wait until all the queued background jobs are completed and lock the image.
*
* KisImage object has a local scheduler that executes long-running image
* rendering/modifying jobs (we call them "strokes") in a background. Basically,
* one should either access the image from the scope of such jobs (strokes) or
* just lock the image before using.
*
* Calling barrierLock() will wait until all the queued operations are finished
* and lock the image, so you can start accessing it in a safe way.
*
* @p readOnly tells the image if the caller is going to modify the image during
* holding the lock. Locking with non-readOnly access will reset all
* the internal caches of the image (lod-planes) when the lock status
* will be lifted.
*/
void barrierLock(bool readOnly = false);
/**
* @brief Tries to lock the image without waiting for the jobs to finish
*
* Same as barrierLock(), but doesn't block execution of the calling thread
* until all the background jobs are finished. Instead, in case of presence of
* unfinished jobs in the queue, it just returns false
*
* @return whether the lock has been acquired
* @see barrierLock
*/
bool tryBarrierLock(bool readOnly = false);
/**
* Wait for all the internal image jobs to complete and return without locking
* the image. This function is handly for tests or other synchronous actions,
* when one needs to wait for the result of his actions.
*/
void waitForDone();
KisStrokeId startStroke(KisStrokeStrategy *strokeStrategy) override;
void addJob(KisStrokeId id, KisStrokeJobData *data) override;
void endStroke(KisStrokeId id) override;
bool cancelStroke(KisStrokeId id) override;
/**
* @brief blockUpdates block updating the image projection
*/
void blockUpdates() override;
/**
* @brief unblockUpdates unblock updating the image project. This
* only restarts the scheduler and does not schedule a full refresh.
*/
void unblockUpdates() override;
/**
* Disables notification of the UI about the changes in the image.
* This feature is used by KisProcessingApplicator. It is needed
* when we change the size of the image. In this case, the whole
* image will be reloaded into UI by sigSizeChanged(), so there is
* no need to inform the UI about individual dirty rects.
*
* The last call to enableUIUpdates() will return the list of updates
* that were requested while they were blocked.
*/
void disableUIUpdates() override;
/**
* Notify GUI about a bunch of updates planned. GUI is expected to wait
* until all the updates are completed, and render them on screen only
* in the very and of the batch.
*/
void notifyBatchUpdateStarted() override;
/**
* Notify GUI that batch update has been completed. Now GUI can start
* showing all of them on screen.
*/
void notifyBatchUpdateEnded() override;
/**
* Notify GUI that rect \p rc is now prepared in the image and
* GUI can read data from it.
*
* WARNING: GUI will read the data right in the handler of this
* signal, so exclusive access to the area must be guaranteed
* by the caller.
*/
void notifyUIUpdateCompleted(const QRect &rc) override;
/**
* \see disableUIUpdates
*/
QVector<QRect> enableUIUpdates() override;
/**
* Disables the processing of all the setDirty() requests that
* come to the image. The incoming requests are effectively
* *dropped*.
*
* This feature is used by KisProcessingApplicator. For many cases
* it provides its own updates interface, which recalculates the
* whole subtree of nodes. But while we change any particular
* node, it can ask for an update itself. This method is a way of
* blocking such intermediate (and excessive) requests.
*
* NOTE: this is a convenience function for addProjectionUpdatesFilter()
* that installs a predefined filter that eats everything. Please
* note that these calls are *not* recursive.
*
* WARNING: The calls to enable/disable must be balanced.
*/
void disableDirtyRequests() override;
/**
* \see disableDirtyRequests()
*/
void enableDirtyRequests() override;
/**
* Installs a filter object that will filter all the incoming projection update
* requests. If the filter return true, the incoming update is dropped.
*
* NOTE: you can add multiple filters to the image, **but** the calls to add/remove
* must be nested and balanced. E.g.
*
* \code{.cpp}
*
* auto cookie1 = image->addProjectionUpdatesFilter(filter1);
* auto cookie2 = image->addProjectionUpdatesFilter(filter2);
*
* /// ...do something...
*
* /// correct:
* image->removeProjectionUpdatesFilter(cookie2)
* image->removeProjectionUpdatesFilter(cookie1)
*
* /// incorrect:
* // image->removeProjectionUpdatesFilter(cookie1)
* // image->removeProjectionUpdatesFilter(cookie2)
* \endcode
*/
KisProjectionUpdatesFilterCookie addProjectionUpdatesFilter(KisProjectionUpdatesFilterSP filter) override;
/**
* @brief removes already installed filter from the stack of updates filers
* @param cookie a cookie object returned by addProjectionUpdatesFilter() on intallation
* @return the installed filter. If the cookie is invalid, or nesting rule has been
* broken, then removeProjectionUpdatesFilter() may safe-assert and return nullptr.
*
* NOTE: some weird code (e.g. KisRegenerateFrameStrokeStrategy) needs to temporary remove
* all the filters and then install them back. Current implementation ensures that after removal
* and the following installation, cookies will be preserved. So this operation is considered
* safe.
*
* \see addProjectionUpdatesFilter()
*/
KisProjectionUpdatesFilterSP removeProjectionUpdatesFilter(KisProjectionUpdatesFilterCookie cookie) override;
/**
* Return the cookie of the lastly-installed filter
*
* \see addProjectionUpdatesFilter()
*/
KisProjectionUpdatesFilterCookie currentProjectionUpdatesFilter() const override;
void refreshGraphAsync(KisNodeSP root = KisNodeSP()) override;
void refreshGraphAsync(KisNodeSP root, const QRect &rc) override;
void refreshGraphAsync(KisNodeSP root, const QRect &rc, const QRect &cropRect) override;
+ void refreshGraphAsync(KisNodeSP root, const QVector<QRect> &rects, const QRect &cropRect) override;
/**
* Triggers synchronous recomposition of the projection
*/
void refreshGraph(KisNodeSP root = KisNodeSP());
void refreshGraph(KisNodeSP root, const QRect& rc, const QRect &cropRect);
void initialRefreshGraph();
/**
* Initiate a stack regeneration skipping the recalculation of the
* filthy node's projection.
*
* Works exactly as pseudoFilthy->setDirty() with the only
* exception that pseudoFilthy::updateProjection() will not be
* called. That is used by KisRecalculateTransformMaskJob to avoid
* cyclic dependencies.
*/
void requestProjectionUpdateNoFilthy(KisNodeSP pseudoFilthy, const QRect &rc, const QRect &cropRect);
void requestProjectionUpdateNoFilthy(KisNodeSP pseudoFilthy, const QRect &rc, const QRect &cropRect, const bool notifyFrameChange );
/**
* Adds a spontaneous job to the updates queue.
*
* A spontaneous job may do some trivial tasks in the background,
* like updating the outline of selection or purging unused tiles
* from the existing paint devices.
*/
void addSpontaneousJob(KisSpontaneousJob *spontaneousJob);
/**
* \return true if there are some updates in the updates queue
* Please note, that is doesn't guarantee that there are no updates
* running in in the updater context at the very moment. To guarantee that
* there are no updates left at all, please use barrier jobs instead.
*/
bool hasUpdatesRunning() const override;
/**
* This method is called by the UI (*not* by the creator of the
* stroke) when it thinks the current stroke should undo its last
* action, for example, when the user presses Ctrl+Z while some
* stroke is active.
*
* If the creator of the stroke supports undoing of intermediate
* actions, it will be notified about this request and can undo
* its last action.
*/
void requestUndoDuringStroke();
/**
* This method is called by the UI (*not* by the creator of the
* stroke) when it thinks current stroke should be cancelled. If
* there is a running stroke that has already been detached from
* its creator (ended or cancelled), it will be forcefully
* cancelled and reverted. If there is an open stroke present, and
* if its creator supports cancelling, it will be notified about
* the request and the stroke will be cancelled
*/
void requestStrokeCancellation();
/**
* This method requests the last stroke executed on the image to become undone.
* If the stroke is not ended, or if all the Lod0 strokes are completed, the method
* returns UNDO_FAIL. If the last Lod0 is going to be finished soon, then UNDO_WAIT
* is returned and the caller should just wait for its completion and call global undo
* instead. UNDO_OK means one unfinished stroke has been undone.
*/
UndoResult tryUndoUnfinishedLod0Stroke();
/**
* This method is called when image or some other part of Krita
* (*not* the creator of the stroke) decides that the stroke
* should be ended. If the creator of the stroke supports it, it
* will be notified and the stroke will be cancelled
*/
void requestStrokeEnd();
/**
* Same as requestStrokeEnd() but is called by view manager when
* the current node is changed. Use to distinguish
* sigStrokeEndRequested() and
* sigStrokeEndRequestedActiveNodeFiltered() which are used by
* KisNodeJugglerCompressed
*/
void requestStrokeEndActiveNode();
private:
KisImage(const KisImage& rhs, KisUndoStore *undoStore, bool exactCopy);
KisImage& operator=(const KisImage& rhs);
void emitSizeChanged();
void resizeImageImpl(const QRect& newRect, bool cropLayers);
void rotateImpl(const KUndo2MagicString &actionName, KisNodeSP rootNode, double radians,
bool resizeImage, KisSelectionSP selection);
void shearImpl(const KUndo2MagicString &actionName, KisNodeSP rootNode,
bool resizeImage, double angleX, double angleY, KisSelectionSP selection);
void safeRemoveTwoNodes(KisNodeSP node1, KisNodeSP node2);
void refreshHiddenArea(KisNodeSP rootNode, const QRect &preparedArea);
void requestProjectionUpdateImpl(KisNode *node,
const QVector<QRect> &rects,
const QRect &cropRect);
friend class KisImageResizeCommand;
void setSize(const QSize& size);
void setProjectionColorSpace(const KoColorSpace * colorSpace);
friend class KisDeselectGlobalSelectionCommand;
friend class KisReselectGlobalSelectionCommand;
friend class KisSetGlobalSelectionCommand;
friend class KisImageTest;
friend class Document; // For libkis
/**
* Replaces the current global selection with globalSelection. If
* \p globalSelection is empty, removes the selection object, so that
* \ref globalSelection() will return 0 after that.
*/
void setGlobalSelection(KisSelectionSP globalSelection);
/**
* Deselects current global selection.
* \ref globalSelection() will return 0 after that.
*/
void deselectGlobalSelection();
/**
* Reselects current deselected selection
*
* \see deselectGlobalSelection()
*/
void reselectGlobalSelection();
private:
class KisImagePrivate;
KisImagePrivate * m_d;
};
#endif // KIS_IMAGE_H_
diff --git a/libs/image/kis_image_interfaces.h b/libs/image/kis_image_interfaces.h
index 7eecf627f2..a44341c8e6 100644
--- a/libs/image/kis_image_interfaces.h
+++ b/libs/image/kis_image_interfaces.h
@@ -1,88 +1,89 @@
/*
* Copyright (c) 2011 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_IMAGE_INTERFACES_H
#define __KIS_IMAGE_INTERFACES_H
#include "kis_types.h"
#include <kritaimage_export.h>
class QRect;
class KisStrokeStrategy;
class KisStrokeJobData;
class KisPostExecutionUndoAdapter;
class KRITAIMAGE_EXPORT KisStrokesFacade
{
public:
virtual ~KisStrokesFacade();
virtual KisStrokeId startStroke(KisStrokeStrategy *strokeStrategy) = 0;
virtual void addJob(KisStrokeId id, KisStrokeJobData *data) = 0;
virtual void endStroke(KisStrokeId id) = 0;
virtual bool cancelStroke(KisStrokeId id) = 0;
};
class KRITAIMAGE_EXPORT KisUpdatesFacade
{
public:
virtual ~KisUpdatesFacade();
virtual void blockUpdates() = 0;
virtual void unblockUpdates() = 0;
virtual void disableUIUpdates() = 0;
virtual QVector<QRect> enableUIUpdates() = 0;
virtual bool hasUpdatesRunning() const = 0;
virtual void notifyBatchUpdateStarted() = 0;
virtual void notifyBatchUpdateEnded() = 0;
virtual void notifyUIUpdateCompleted(const QRect &rc) = 0;
virtual QRect bounds() const = 0;
virtual void disableDirtyRequests() = 0;
virtual void enableDirtyRequests() = 0;
virtual void refreshGraphAsync(KisNodeSP root) = 0;
virtual void refreshGraphAsync(KisNodeSP root, const QRect &rc) = 0;
virtual void refreshGraphAsync(KisNodeSP root, const QRect &rc, const QRect &cropRect) = 0;
+ virtual void refreshGraphAsync(KisNodeSP root, const QVector<QRect> &rc, const QRect &cropRect) = 0;
virtual KisProjectionUpdatesFilterCookie addProjectionUpdatesFilter(KisProjectionUpdatesFilterSP filter) = 0;
virtual KisProjectionUpdatesFilterSP removeProjectionUpdatesFilter(KisProjectionUpdatesFilterCookie cookie) = 0;
virtual KisProjectionUpdatesFilterCookie currentProjectionUpdatesFilter() const = 0;
};
class KRITAIMAGE_EXPORT KisProjectionUpdateListener
{
public:
virtual ~KisProjectionUpdateListener();
virtual void notifyProjectionUpdated(const QRect &rc) = 0;
};
class KRITAIMAGE_EXPORT KisStrokeUndoFacade
{
public:
virtual ~KisStrokeUndoFacade();
virtual KisPostExecutionUndoAdapter* postExecutionUndoAdapter() const = 0;
virtual const KUndo2Command* lastExecutedCommand() const = 0;
};
#endif /* __KIS_IMAGE_INTERFACES_H */
diff --git a/libs/image/kis_indirect_painting_support.cpp b/libs/image/kis_indirect_painting_support.cpp
index 2e01fee657..4c8d79a7ee 100644
--- a/libs/image/kis_indirect_painting_support.cpp
+++ b/libs/image/kis_indirect_painting_support.cpp
@@ -1,179 +1,179 @@
/*
* Copyright (c) 2004 Bart Coppens <kde@bartcoppens.be>
* Copyright (c) 2010 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <compositeops/KoVcMultiArchBuildSupport.h> //MSVC requires that Vc come first
#include "kis_indirect_painting_support.h"
#include <QMutex>
#include <QMutexLocker>
#include <QReadWriteLock>
#include <KoCompositeOp.h>
#include "kis_layer.h"
#include "kis_paint_layer.h"
#include "kis_paint_device.h"
#include "kis_selection.h"
#include "kis_painter.h"
struct Q_DECL_HIDDEN KisIndirectPaintingSupport::Private {
// To simulate the indirect painting
KisPaintDeviceSP temporaryTarget;
QString compositeOp;
quint8 compositeOpacity;
QBitArray channelFlags;
KisSelectionSP selection;
QReadWriteLock lock;
};
KisIndirectPaintingSupport::KisIndirectPaintingSupport()
: d(new Private)
{
}
KisIndirectPaintingSupport::~KisIndirectPaintingSupport()
{
delete d;
}
void KisIndirectPaintingSupport::setCurrentColor(const KoColor &color)
{
Q_UNUSED(color);
}
void KisIndirectPaintingSupport::setTemporaryTarget(KisPaintDeviceSP t)
{
d->temporaryTarget = t;
}
void KisIndirectPaintingSupport::setTemporaryCompositeOp(const QString &id)
{
d->compositeOp = id;
}
void KisIndirectPaintingSupport::setTemporaryOpacity(quint8 o)
{
d->compositeOpacity = o;
}
void KisIndirectPaintingSupport::setTemporaryChannelFlags(const QBitArray& channelFlags)
{
d->channelFlags = channelFlags;
}
void KisIndirectPaintingSupport::setTemporarySelection(KisSelectionSP selection)
{
d->selection = selection;
}
void KisIndirectPaintingSupport::lockTemporaryTarget() const
{
d->lock.lockForRead();
}
void KisIndirectPaintingSupport::lockTemporaryTargetForWrite() const
{
d->lock.lockForWrite();
}
void KisIndirectPaintingSupport::unlockTemporaryTarget() const
{
d->lock.unlock();
}
KisPaintDeviceSP KisIndirectPaintingSupport::temporaryTarget() const
{
return d->temporaryTarget;
}
bool KisIndirectPaintingSupport::supportsNonIndirectPainting() const
{
return true;
}
QString KisIndirectPaintingSupport::temporaryCompositeOp() const
{
return d->compositeOp;
}
KisSelectionSP KisIndirectPaintingSupport::temporarySelection() const
{
return d->selection;
}
bool KisIndirectPaintingSupport::hasTemporaryTarget() const
{
return d->temporaryTarget;
}
void KisIndirectPaintingSupport::setupTemporaryPainter(KisPainter *painter) const
{
painter->setOpacity(d->compositeOpacity);
painter->setCompositeOp(d->compositeOp);
painter->setChannelFlags(d->channelFlags);
painter->setSelection(d->selection);
}
void KisIndirectPaintingSupport::mergeToLayer(KisNodeSP layer, KisPostExecutionUndoAdapter *undoAdapter, const KUndo2MagicString &transactionText,int timedID)
{
QWriteLocker l(&d->lock);
mergeToLayerImpl(layer->paintDevice(), undoAdapter, transactionText, timedID);
}
void KisIndirectPaintingSupport::mergeToLayerImpl(KisPaintDeviceSP dst, KisPostExecutionUndoAdapter *undoAdapter, const KUndo2MagicString &transactionText, int timedID, bool cleanResources)
{
/**
- * We do not apply selection here, because it has already
- * been taken into account in a tool code
+ * Brushes don't apply the selection, we apply that during the indirect
+ * painting merge operation. It is cheaper calculation-wise.
*/
KisPainter gc(dst);
setupTemporaryPainter(&gc);
/**
* Scratchpad may not have an undo adapter
*/
if(undoAdapter) {
gc.beginTransaction(transactionText,timedID);
}
writeMergeData(&gc, d->temporaryTarget);
if (cleanResources) {
releaseResources();
}
if(undoAdapter) {
gc.endTransaction(undoAdapter);
}
}
void KisIndirectPaintingSupport::writeMergeData(KisPainter *painter, KisPaintDeviceSP src)
{
Q_FOREACH (const QRect &rc, src->region().rects()) {
painter->bitBlt(rc.topLeft(), src, rc);
}
}
void KisIndirectPaintingSupport::releaseResources()
{
d->temporaryTarget = 0;
d->selection = 0;
}
diff --git a/libs/image/kis_layer.cc b/libs/image/kis_layer.cc
index 1c326b894b..d4a0766823 100644
--- a/libs/image/kis_layer.cc
+++ b/libs/image/kis_layer.cc
@@ -1,1006 +1,1006 @@
/*
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
* Copyright (c) 2005 C. Boemann <cbo@boemann.dk>
* Copyright (c) 2009 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_layer.h"
#include <klocalizedstring.h>
#include <QImage>
#include <QBitArray>
#include <QStack>
#include <QMutex>
#include <QMutexLocker>
#include <QReadWriteLock>
#include <QReadLocker>
#include <QWriteLocker>
#include <KoIcon.h>
#include <kis_icon.h>
#include <KoProperties.h>
#include <KoCompositeOpRegistry.h>
#include <KoColorSpace.h>
#include "kis_debug.h"
#include "kis_image.h"
#include "kis_painter.h"
#include "kis_mask.h"
#include "kis_effect_mask.h"
#include "kis_selection_mask.h"
#include "kis_meta_data_store.h"
#include "kis_selection.h"
#include "kis_paint_layer.h"
#include "kis_raster_keyframe_channel.h"
#include "kis_clone_layer.h"
#include "kis_psd_layer_style.h"
#include "kis_layer_projection_plane.h"
#include "layerstyles/kis_layer_style_projection_plane.h"
#include "krita_utils.h"
#include "kis_layer_properties_icons.h"
#include "kis_layer_utils.h"
#include "kis_projection_leaf.h"
#include "KisSafeNodeProjectionStore.h"
class KisCloneLayersList {
public:
void addClone(KisCloneLayerWSP cloneLayer) {
m_clonesList.append(cloneLayer);
}
void removeClone(KisCloneLayerWSP cloneLayer) {
m_clonesList.removeOne(cloneLayer);
}
void setDirty(const QRect &rect) {
Q_FOREACH (KisCloneLayerSP clone, m_clonesList) {
if (clone) {
clone->setDirtyOriginal(rect);
}
}
}
const QList<KisCloneLayerWSP> registeredClones() const {
return m_clonesList;
}
bool hasClones() const {
return !m_clonesList.isEmpty();
}
private:
QList<KisCloneLayerWSP> m_clonesList;
};
class KisLayerMasksCache {
public:
KisLayerMasksCache(KisLayer *parent)
: m_parent(parent)
{
}
KisSelectionMaskSP selectionMask() {
QReadLocker readLock(&m_lock);
if (!m_isSelectionMaskValid) {
readLock.unlock();
QWriteLocker writeLock(&m_lock);
if (!m_isSelectionMaskValid) {
KoProperties properties;
properties.setProperty("active", true);
properties.setProperty("visible", true);
QList<KisNodeSP> masks = m_parent->childNodes(QStringList("KisSelectionMask"), properties);
// return the first visible mask
Q_FOREACH (KisNodeSP mask, masks) {
if (mask) {
m_selectionMask = dynamic_cast<KisSelectionMask*>(mask.data());
break;
}
}
m_isSelectionMaskValid = true;
}
// return under write lock
return m_selectionMask;
}
// return under read lock
return m_selectionMask;
}
QList<KisEffectMaskSP> effectMasks() {
QReadLocker readLock(&m_lock);
if (!m_isEffectMasksValid) {
readLock.unlock();
QWriteLocker writeLock(&m_lock);
if (!m_isEffectMasksValid) {
m_effectMasks = m_parent->searchEffectMasks(0);
m_isEffectMasksValid = true;
}
// return under write lock
return m_effectMasks;
}
// return under read lock
return m_effectMasks;
}
void setDirty()
{
QWriteLocker l(&m_lock);
m_isSelectionMaskValid = false;
m_isEffectMasksValid = false;
m_selectionMask = 0;
m_effectMasks.clear();
}
private:
KisLayer *m_parent;
QReadWriteLock m_lock;
bool m_isSelectionMaskValid = false;
bool m_isEffectMasksValid = false;
KisSelectionMaskSP m_selectionMask;
QList<KisEffectMaskSP> m_effectMasks;
};
struct Q_DECL_HIDDEN KisLayer::Private
{
Private(KisLayer *q)
: masksCache(q)
{
}
QBitArray channelFlags;
KisMetaData::Store* metaDataStore;
KisCloneLayersList clonesList;
KisPSDLayerStyleSP layerStyle;
KisLayerStyleProjectionPlaneSP layerStyleProjectionPlane;
KisLayerProjectionPlaneSP projectionPlane;
KisSafeNodeProjectionStoreSP safeProjection;
KisLayerMasksCache masksCache;
};
KisLayer::KisLayer(KisImageWSP image, const QString &name, quint8 opacity)
: KisNode(image)
, m_d(new Private(this))
{
setName(name);
setOpacity(opacity);
m_d->metaDataStore = new KisMetaData::Store();
m_d->projectionPlane = toQShared(new KisLayerProjectionPlane(this));
m_d->safeProjection = new KisSafeNodeProjectionStore();
m_d->safeProjection->setImage(image);
}
KisLayer::KisLayer(const KisLayer& rhs)
: KisNode(rhs)
, m_d(new Private(this))
{
if (this != &rhs) {
m_d->metaDataStore = new KisMetaData::Store(*rhs.m_d->metaDataStore);
m_d->channelFlags = rhs.m_d->channelFlags;
setName(rhs.name());
m_d->projectionPlane = toQShared(new KisLayerProjectionPlane(this));
m_d->safeProjection = new KisSafeNodeProjectionStore(*rhs.m_d->safeProjection);
m_d->safeProjection->setImage(image());
if (rhs.m_d->layerStyle) {
m_d->layerStyle = rhs.m_d->layerStyle->clone().dynamicCast<KisPSDLayerStyle>();
if (rhs.m_d->layerStyleProjectionPlane) {
m_d->layerStyleProjectionPlane = toQShared(
new KisLayerStyleProjectionPlane(*rhs.m_d->layerStyleProjectionPlane,
this,
m_d->layerStyle));
}
}
}
}
KisLayer::~KisLayer()
{
delete m_d->metaDataStore;
delete m_d;
}
const KoColorSpace * KisLayer::colorSpace() const
{
KisImageSP image = this->image();
if (!image) {
return nullptr;
}
return image->colorSpace();
}
const KoCompositeOp * KisLayer::compositeOp() const
{
/**
* FIXME: This function duplicates the same function from
* KisMask. We can't move it to KisBaseNode as it doesn't
* know anything about parent() method of KisNode
* Please think it over...
*/
KisNodeSP parentNode = parent();
if (!parentNode) return 0;
if (!parentNode->colorSpace()) return 0;
const KoCompositeOp* op = parentNode->colorSpace()->compositeOp(compositeOpId());
return op ? op : parentNode->colorSpace()->compositeOp(COMPOSITE_OVER);
}
KisPSDLayerStyleSP KisLayer::layerStyle() const
{
return m_d->layerStyle;
}
void KisLayer::setLayerStyle(KisPSDLayerStyleSP layerStyle)
{
if (layerStyle) {
m_d->layerStyle = layerStyle;
KisLayerStyleProjectionPlaneSP plane = !layerStyle->isEmpty() ?
KisLayerStyleProjectionPlaneSP(new KisLayerStyleProjectionPlane(this)) :
KisLayerStyleProjectionPlaneSP(0);
m_d->layerStyleProjectionPlane = plane;
} else {
m_d->layerStyleProjectionPlane.clear();
m_d->layerStyle.clear();
}
}
KisBaseNode::PropertyList KisLayer::sectionModelProperties() const
{
KisBaseNode::PropertyList l = KisBaseNode::sectionModelProperties();
l << KisBaseNode::Property(KoID("opacity", i18n("Opacity")), i18n("%1%", percentOpacity()));
const KoCompositeOp * compositeOp = this->compositeOp();
if (compositeOp) {
l << KisBaseNode::Property(KoID("compositeop", i18n("Blending Mode")), compositeOp->description());
}
if (m_d->layerStyle && !m_d->layerStyle->isEmpty()) {
l << KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::layerStyle, m_d->layerStyle->isEnabled());
}
l << KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::inheritAlpha, alphaChannelDisabled());
return l;
}
void KisLayer::setSectionModelProperties(const KisBaseNode::PropertyList &properties)
{
KisBaseNode::setSectionModelProperties(properties);
Q_FOREACH (const KisBaseNode::Property &property, properties) {
if (property.id == KisLayerPropertiesIcons::inheritAlpha.id()) {
disableAlphaChannel(property.state.toBool());
}
if (property.id == KisLayerPropertiesIcons::layerStyle.id()) {
if (m_d->layerStyle &&
m_d->layerStyle->isEnabled() != property.state.toBool()) {
m_d->layerStyle->setEnabled(property.state.toBool());
baseNodeChangedCallback();
baseNodeInvalidateAllFramesCallback();
}
}
}
}
void KisLayer::disableAlphaChannel(bool disable)
{
QBitArray newChannelFlags = m_d->channelFlags;
if(newChannelFlags.isEmpty())
newChannelFlags = colorSpace()->channelFlags(true, true);
if(disable)
newChannelFlags &= colorSpace()->channelFlags(true, false);
else
newChannelFlags |= colorSpace()->channelFlags(false, true);
setChannelFlags(newChannelFlags);
}
bool KisLayer::alphaChannelDisabled() const
{
QBitArray flags = colorSpace()->channelFlags(false, true) & m_d->channelFlags;
return flags.count(true) == 0 && !m_d->channelFlags.isEmpty();
}
void KisLayer::setChannelFlags(const QBitArray & channelFlags)
{
Q_ASSERT(channelFlags.isEmpty() ||((quint32)channelFlags.count() == colorSpace()->channelCount()));
if (KritaUtils::compareChannelFlags(channelFlags,
this->channelFlags())) {
return;
}
if (!channelFlags.isEmpty() &&
channelFlags == QBitArray(channelFlags.size(), true)) {
m_d->channelFlags.clear();
} else {
m_d->channelFlags = channelFlags;
}
baseNodeChangedCallback();
baseNodeInvalidateAllFramesCallback();
}
QBitArray & KisLayer::channelFlags() const
{
return m_d->channelFlags;
}
bool KisLayer::temporary() const
{
return nodeProperties().boolProperty("temporary", false);
}
void KisLayer::setTemporary(bool t)
{
setNodeProperty("temporary", t);
}
void KisLayer::setImage(KisImageWSP image)
{
// we own the projection device, so we should take care about it
KisPaintDeviceSP projection = this->projection();
if (projection && projection != original()) {
projection->setDefaultBounds(new KisDefaultBounds(image));
}
m_d->safeProjection->setImage(image);
KisNode::setImage(image);
}
bool KisLayer::canMergeAndKeepBlendOptions(KisLayerSP otherLayer)
{
return
this->compositeOpId() == otherLayer->compositeOpId() &&
this->opacity() == otherLayer->opacity() &&
this->channelFlags() == otherLayer->channelFlags() &&
!this->layerStyle() && !otherLayer->layerStyle() &&
(this->colorSpace() == otherLayer->colorSpace() ||
*this->colorSpace() == *otherLayer->colorSpace());
}
KisLayerSP KisLayer::createMergedLayerTemplate(KisLayerSP prevLayer)
{
const bool keepBlendingOptions = canMergeAndKeepBlendOptions(prevLayer);
KisLayerSP newLayer = new KisPaintLayer(image(), prevLayer->name(), OPACITY_OPAQUE_U8);
if (keepBlendingOptions) {
newLayer->setCompositeOpId(compositeOpId());
newLayer->setOpacity(opacity());
newLayer->setChannelFlags(channelFlags());
}
return newLayer;
}
void KisLayer::fillMergedLayerTemplate(KisLayerSP dstLayer, KisLayerSP prevLayer)
{
const bool keepBlendingOptions = canMergeAndKeepBlendOptions(prevLayer);
QRect layerProjectionExtent = this->projection()->extent();
QRect prevLayerProjectionExtent = prevLayer->projection()->extent();
bool alphaDisabled = this->alphaChannelDisabled();
bool prevAlphaDisabled = prevLayer->alphaChannelDisabled();
KisPaintDeviceSP mergedDevice = dstLayer->paintDevice();
if (!keepBlendingOptions) {
KisPainter gc(mergedDevice);
KisImageSP imageSP = image().toStrongRef();
if (!imageSP) {
return;
}
//Copy the pixels of previous layer with their actual alpha value
prevLayer->disableAlphaChannel(false);
prevLayer->projectionPlane()->apply(&gc, prevLayerProjectionExtent | imageSP->bounds());
//Restore the previous prevLayer disableAlpha status for correct undo/redo
prevLayer->disableAlphaChannel(prevAlphaDisabled);
//Paint the pixels of the current layer, using their actual alpha value
if (alphaDisabled == prevAlphaDisabled) {
this->disableAlphaChannel(false);
}
this->projectionPlane()->apply(&gc, layerProjectionExtent | imageSP->bounds());
//Restore the layer disableAlpha status for correct undo/redo
this->disableAlphaChannel(alphaDisabled);
}
else {
//Copy prevLayer
KisPaintDeviceSP srcDev = prevLayer->projection();
mergedDevice->makeCloneFrom(srcDev, srcDev->extent());
//Paint layer on the copy
KisPainter gc(mergedDevice);
gc.bitBlt(layerProjectionExtent.topLeft(), this->projection(), layerProjectionExtent);
}
}
void KisLayer::registerClone(KisCloneLayerWSP clone)
{
m_d->clonesList.addClone(clone);
}
void KisLayer::unregisterClone(KisCloneLayerWSP clone)
{
m_d->clonesList.removeClone(clone);
}
const QList<KisCloneLayerWSP> KisLayer::registeredClones() const
{
return m_d->clonesList.registeredClones();
}
bool KisLayer::hasClones() const
{
return m_d->clonesList.hasClones();
}
void KisLayer::updateClones(const QRect &rect)
{
m_d->clonesList.setDirty(rect);
}
void KisLayer::notifyChildMaskChanged()
{
m_d->masksCache.setDirty();
}
KisSelectionMaskSP KisLayer::selectionMask() const
{
return m_d->masksCache.selectionMask();
}
KisSelectionSP KisLayer::selection() const
{
KisSelectionMaskSP mask = selectionMask();
if (mask) {
return mask->selection();
}
KisImageSP image = this->image();
if (image) {
return image->globalSelection();
}
return KisSelectionSP();
}
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
QList<KisEffectMaskSP> KisLayer::effectMasks() const
{
return m_d->masksCache.effectMasks();
}
QList<KisEffectMaskSP> KisLayer::effectMasks(KisNodeSP lastNode) const
{
if (lastNode.isNull()) {
return effectMasks();
} else {
// happens rarely.
return searchEffectMasks(lastNode);
}
}
QList<KisEffectMaskSP> KisLayer::searchEffectMasks(KisNodeSP lastNode) const
{
QList<KisEffectMaskSP> masks;
KIS_SAFE_ASSERT_RECOVER_NOOP(projectionLeaf());
KisProjectionLeafSP child = projectionLeaf()->firstChild();
while (child) {
if (child->node() == lastNode) break;
KIS_SAFE_ASSERT_RECOVER_NOOP(child);
KIS_SAFE_ASSERT_RECOVER_NOOP(child->node());
if (child->visible()) {
KisEffectMaskSP mask = dynamic_cast<KisEffectMask*>(const_cast<KisNode*>(child->node().data()));
if (mask) {
masks.append(mask);
}
}
child = child->nextSibling();
}
return masks;
}
bool KisLayer::hasEffectMasks() const
{
return !m_d->masksCache.effectMasks().isEmpty();
}
QRect KisLayer::masksChangeRect(const QList<KisEffectMaskSP> &masks,
const QRect &requestedRect,
bool &rectVariesFlag) const
{
rectVariesFlag = false;
QRect prevChangeRect = requestedRect;
/**
* We set default value of the change rect for the case
* when there is no mask at all
*/
QRect changeRect = requestedRect;
Q_FOREACH (const KisEffectMaskSP& mask, masks) {
changeRect = mask->changeRect(prevChangeRect);
if (changeRect != prevChangeRect)
rectVariesFlag = true;
prevChangeRect = changeRect;
}
return changeRect;
}
QRect KisLayer::masksNeedRect(const QList<KisEffectMaskSP> &masks,
const QRect &changeRect,
QStack<QRect> &applyRects,
bool &rectVariesFlag) const
{
rectVariesFlag = false;
QRect prevNeedRect = changeRect;
QRect needRect;
for (qint32 i = masks.size() - 1; i >= 0; i--) {
applyRects.push(prevNeedRect);
needRect = masks[i]->needRect(prevNeedRect);
if (prevNeedRect != needRect)
rectVariesFlag = true;
prevNeedRect = needRect;
}
return needRect;
}
KisNode::PositionToFilthy calculatePositionToFilthy(KisNodeSP nodeInQuestion,
KisNodeSP filthy,
KisNodeSP parent)
{
if (parent == filthy || parent != filthy->parent()) {
return KisNode::N_ABOVE_FILTHY;
}
if (nodeInQuestion == filthy) {
return KisNode::N_FILTHY;
}
KisNodeSP node = nodeInQuestion->prevSibling();
while (node) {
if (node == filthy) {
return KisNode::N_ABOVE_FILTHY;
}
node = node->prevSibling();
}
return KisNode::N_BELOW_FILTHY;
}
QRect KisLayer::applyMasks(const KisPaintDeviceSP source,
KisPaintDeviceSP destination,
const QRect &requestedRect,
KisNodeSP filthyNode,
KisNodeSP lastNode) const
{
Q_ASSERT(source);
Q_ASSERT(destination);
QList<KisEffectMaskSP> masks = effectMasks(lastNode);
QRect changeRect;
QRect needRect;
if (masks.isEmpty()) {
changeRect = requestedRect;
if (source != destination) {
copyOriginalToProjection(source, destination, requestedRect);
}
} else {
QStack<QRect> applyRects;
bool changeRectVaries;
bool needRectVaries;
/**
* FIXME: Assume that varying of the changeRect has already
* been taken into account while preparing walkers
*/
changeRectVaries = false;
changeRect = requestedRect;
//changeRect = masksChangeRect(masks, requestedRect,
// changeRectVaries);
needRect = masksNeedRect(masks, changeRect,
applyRects, needRectVaries);
if (!changeRectVaries && !needRectVaries) {
/**
* A bit of optimization:
* All filters will read/write exactly from/to the requested
* rect so we needn't create temporary paint device,
* just apply it onto destination
*/
Q_ASSERT(needRect == requestedRect);
if (source != destination) {
copyOriginalToProjection(source, destination, needRect);
}
Q_FOREACH (const KisEffectMaskSP& mask, masks) {
const QRect maskApplyRect = applyRects.pop();
const QRect maskNeedRect =
applyRects.isEmpty() ? needRect : applyRects.top();
PositionToFilthy maskPosition = calculatePositionToFilthy(mask, filthyNode, const_cast<KisLayer*>(this));
mask->apply(destination, maskApplyRect, maskNeedRect, maskPosition);
}
Q_ASSERT(applyRects.isEmpty());
} else {
/**
* We can't eliminate additional copy-op
* as filters' behaviour may be quite insane here,
* so let them work on their own paintDevice =)
*/
KisPaintDeviceSP tempDevice = new KisPaintDevice(colorSpace());
tempDevice->prepareClone(source);
copyOriginalToProjection(source, tempDevice, needRect);
QRect maskApplyRect = applyRects.pop();
QRect maskNeedRect = needRect;
Q_FOREACH (const KisEffectMaskSP& mask, masks) {
PositionToFilthy maskPosition = calculatePositionToFilthy(mask, filthyNode, const_cast<KisLayer*>(this));
mask->apply(tempDevice, maskApplyRect, maskNeedRect, maskPosition);
if (!applyRects.isEmpty()) {
maskNeedRect = maskApplyRect;
maskApplyRect = applyRects.pop();
}
}
Q_ASSERT(applyRects.isEmpty());
KisPainter::copyAreaOptimized(changeRect.topLeft(), tempDevice, destination, changeRect);
}
}
return changeRect;
}
QRect KisLayer::updateProjection(const QRect& rect, KisNodeSP filthyNode)
{
QRect updatedRect = rect;
KisPaintDeviceSP originalDevice = original();
if (!rect.isValid() ||
(!visible() && !isIsolatedRoot() && !hasClones()) ||
!originalDevice) return QRect();
if (!needProjection() && !hasEffectMasks()) {
m_d->safeProjection->releaseDevice();
} else {
if (!updatedRect.isEmpty()) {
KisPaintDeviceSP projection = m_d->safeProjection->getDeviceLazy(originalDevice);
updatedRect = applyMasks(originalDevice, projection,
updatedRect, filthyNode, 0);
}
}
return updatedRect;
}
QRect KisLayer::partialChangeRect(KisNodeSP lastNode, const QRect& rect)
{
bool changeRectVaries = false;
QRect changeRect = outgoingChangeRect(rect);
changeRect = masksChangeRect(effectMasks(lastNode), changeRect,
changeRectVaries);
return changeRect;
}
/**
* \p rect is a dirty rect in layer's original() coordinates!
*/
void KisLayer::buildProjectionUpToNode(KisPaintDeviceSP projection, KisNodeSP lastNode, const QRect& rect)
{
QRect changeRect = partialChangeRect(lastNode, rect);
KisPaintDeviceSP originalDevice = original();
KIS_ASSERT_RECOVER_RETURN(needProjection() || hasEffectMasks());
if (!changeRect.isEmpty()) {
applyMasks(originalDevice, projection,
changeRect, this, lastNode);
}
}
bool KisLayer::needProjection() const
{
return false;
}
void KisLayer::copyOriginalToProjection(const KisPaintDeviceSP original,
KisPaintDeviceSP projection,
const QRect& rect) const
{
KisPainter::copyAreaOptimized(rect.topLeft(), original, projection, rect);
}
KisAbstractProjectionPlaneSP KisLayer::projectionPlane() const
{
return m_d->layerStyleProjectionPlane ?
KisAbstractProjectionPlaneSP(m_d->layerStyleProjectionPlane) :
KisAbstractProjectionPlaneSP(m_d->projectionPlane);
}
KisLayerProjectionPlaneSP KisLayer::internalProjectionPlane() const
{
return m_d->projectionPlane;
}
KisPaintDeviceSP KisLayer::projection() const
{
KisPaintDeviceSP originalDevice = original();
return needProjection() || hasEffectMasks() ?
m_d->safeProjection->getDeviceLazy(originalDevice) : originalDevice;
}
QRect KisLayer::tightUserVisibleBounds() const
{
QRect changeRect = exactBounds();
/// we do not use incomingChangeRect() here, because
/// exactBounds() already takes it into account (it
/// was used while preparing original())
bool changeRectVaries;
changeRect = outgoingChangeRect(changeRect);
changeRect = masksChangeRect(effectMasks(), changeRect, changeRectVaries);
return changeRect;
}
QRect KisLayer::changeRect(const QRect &rect, PositionToFilthy pos) const
{
QRect changeRect = rect;
changeRect = incomingChangeRect(changeRect);
if(pos == KisNode::N_FILTHY) {
QRect projectionToBeUpdated = projection()->exactBoundsAmortized() & changeRect;
bool changeRectVaries;
changeRect = outgoingChangeRect(changeRect);
changeRect = masksChangeRect(effectMasks(), changeRect, changeRectVaries);
/**
* If the projection contains some dirty areas we should also
* add them to the change rect, because they might have
* changed. E.g. when a visibility of the mask has chnaged
* while the parent layer was invinisble.
*/
if (!projectionToBeUpdated.isEmpty() &&
!changeRect.contains(projectionToBeUpdated)) {
changeRect |= projectionToBeUpdated;
}
}
// TODO: string comparizon: optimize!
if (pos != KisNode::N_FILTHY &&
pos != KisNode::N_FILTHY_PROJECTION &&
compositeOpId() != COMPOSITE_COPY) {
changeRect |= rect;
}
return changeRect;
}
void KisLayer::childNodeChanged(KisNodeSP changedChildNode)
{
if (dynamic_cast<KisMask*>(changedChildNode.data())) {
notifyChildMaskChanged();
}
}
QRect KisLayer::incomingChangeRect(const QRect &rect) const
{
return rect;
}
QRect KisLayer::outgoingChangeRect(const QRect &rect) const
{
return rect;
}
QRect KisLayer::needRectForOriginal(const QRect &rect) const
{
QRect needRect = rect;
const QList<KisEffectMaskSP> masks = effectMasks();
if (!masks.isEmpty()) {
QStack<QRect> applyRects;
bool needRectVaries;
needRect = masksNeedRect(masks, rect,
applyRects, needRectVaries);
}
return needRect;
}
-QImage KisLayer::createThumbnail(qint32 w, qint32 h)
+QImage KisLayer::createThumbnail(qint32 w, qint32 h, Qt::AspectRatioMode aspectRatioMode)
{
if (w == 0 || h == 0) {
return QImage();
}
KisPaintDeviceSP originalDevice = original();
return originalDevice ?
- originalDevice->createThumbnail(w, h, 1,
+ originalDevice->createThumbnail(w, h, aspectRatioMode, 1,
KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags()) : QImage();
}
-QImage KisLayer::createThumbnailForFrame(qint32 w, qint32 h, int time)
+QImage KisLayer::createThumbnailForFrame(qint32 w, qint32 h, int time, Qt::AspectRatioMode aspectRatioMode)
{
if (w == 0 || h == 0) {
return QImage();
}
KisPaintDeviceSP originalDevice = original();
if (originalDevice ) {
KisRasterKeyframeChannel *channel = originalDevice->keyframeChannel();
if (channel) {
KisPaintDeviceSP targetDevice = new KisPaintDevice(colorSpace());
KisKeyframeSP keyframe = channel->activeKeyframeAt(time);
channel->fetchFrame(keyframe, targetDevice);
- return targetDevice->createThumbnail(w, h, 1,
+ return targetDevice->createThumbnail(w, h, aspectRatioMode, 1,
KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags());
}
}
return createThumbnail(w, h);
}
qint32 KisLayer::x() const
{
KisPaintDeviceSP originalDevice = original();
return originalDevice ? originalDevice->x() : 0;
}
qint32 KisLayer::y() const
{
KisPaintDeviceSP originalDevice = original();
return originalDevice ? originalDevice->y() : 0;
}
void KisLayer::setX(qint32 x)
{
KisPaintDeviceSP originalDevice = original();
if (originalDevice)
originalDevice->setX(x);
}
void KisLayer::setY(qint32 y)
{
KisPaintDeviceSP originalDevice = original();
if (originalDevice)
originalDevice->setY(y);
}
QRect KisLayer::layerExtentImpl(bool needExactBounds) const
{
QRect additionalMaskExtent = QRect();
QList<KisEffectMaskSP> effectMasks = this->effectMasks();
Q_FOREACH(KisEffectMaskSP mask, effectMasks) {
additionalMaskExtent |= mask->nonDependentExtent();
}
KisPaintDeviceSP originalDevice = original();
QRect layerExtent;
if (originalDevice) {
layerExtent = needExactBounds ?
originalDevice->exactBounds() :
originalDevice->extent();
}
QRect additionalCompositeOpExtent;
if (compositeOpId() == COMPOSITE_DESTINATION_IN ||
compositeOpId() == COMPOSITE_DESTINATION_ATOP) {
additionalCompositeOpExtent = originalDevice->defaultBounds()->bounds();
}
return layerExtent | additionalMaskExtent | additionalCompositeOpExtent;
}
QRect KisLayer::extent() const
{
return layerExtentImpl(false);
}
QRect KisLayer::exactBounds() const
{
return layerExtentImpl(true);
}
KisLayerSP KisLayer::parentLayer() const
{
return qobject_cast<KisLayer*>(parent().data());
}
KisMetaData::Store* KisLayer::metaData()
{
return m_d->metaDataStore;
}
diff --git a/libs/image/kis_layer.h b/libs/image/kis_layer.h
index 0590aa6be5..7418f11ebe 100644
--- a/libs/image/kis_layer.h
+++ b/libs/image/kis_layer.h
@@ -1,426 +1,426 @@
/*
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
* Copyright (c) 2005 C. Boemann <cbo@boemann.dk>
* Copyright (c) 2007 Boudewijn Rempt <boud@valdyas.org>
* Copyright (c) 2009 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KIS_LAYER_H_
#define KIS_LAYER_H_
#include <QRect>
#include <QMetaType>
#include <QObject>
#include "kritaimage_export.h"
#include "kis_base_node.h"
#include "kis_types.h"
#include "kis_node.h"
#include "kis_psd_layer_style.h"
template <class T>
class QStack;
class QBitArray;
class KisCloneLayer;
class KisPSDLayerStyle;
class KisAbstractProjectionPlane;
class KisLayerProjectionPlane;
typedef QSharedPointer<KisLayerProjectionPlane> KisLayerProjectionPlaneSP;
namespace KisMetaData
{
class Store;
}
/**
* Abstract class that represents the concept of a Layer in Krita. This is not related
* to the paint devices: this is merely an abstraction of how layers can be stacked and
* rendered differently.
* Regarding the previous-, first-, next- and lastChild() calls, first means that it the layer
* is at the top of the group in the layerlist, using next will iterate to the bottom to last,
* whereas previous will go up to first again.
*
*
* TODO: Add a layer mode whereby the projection of the layer is used
* as a clipping path?
**/
class KRITAIMAGE_EXPORT KisLayer : public KisNode
{
Q_OBJECT
public:
/**
* @param image is the pointer of the image or null
* @param opacity is a value between OPACITY_TRANSPARENT_U8 and OPACITY_OPAQUE_U8
**/
KisLayer(KisImageWSP image, const QString &name, quint8 opacity);
KisLayer(const KisLayer& rhs);
~KisLayer() override;
/// returns the image's colorSpace or null, if there is no image
const KoColorSpace * colorSpace() const override;
/// returns the layer's composite op for the colorspace of the layer's parent.
const KoCompositeOp * compositeOp() const override;
KisPSDLayerStyleSP layerStyle() const;
void setLayerStyle(KisPSDLayerStyleSP layerStyle);
/**
* \see a comment in KisNode::projectionPlane()
*/
KisAbstractProjectionPlaneSP projectionPlane() const override;
/**
* The projection plane representing the layer itself without any
* styles or anything else. It is used by the layer styles projection
* plane to stack up the planes.
*/
virtual KisLayerProjectionPlaneSP internalProjectionPlane() const;
QRect partialChangeRect(KisNodeSP lastNode, const QRect& rect);
void buildProjectionUpToNode(KisPaintDeviceSP projection, KisNodeSP lastNode, const QRect& rect);
virtual bool needProjection() const;
/**
* Return the fully rendered representation of this layer: its
* data and its effect masks
*/
KisPaintDeviceSP projection() const override;
/**
* Return the layer data before the effect masks have had their go
* at it.
*/
KisPaintDeviceSP original() const override = 0;
/**
* @return the selection associated with this layer, if there is
* one. Otherwise, return 0;
*/
virtual KisSelectionMaskSP selectionMask() const;
/**
* @return the selection contained in the first KisSelectionMask associated
* with this layer or the image, if either exists, otherwise, return 0.
*/
virtual KisSelectionSP selection() const;
KisBaseNode::PropertyList sectionModelProperties() const override;
void setSectionModelProperties(const KisBaseNode::PropertyList &properties) override;
/**
* set/unset the channel flag for the alpha channel of this layer
*/
void disableAlphaChannel(bool disable);
/**
* returns true if the channel flag for the alpha channel
* of this layer is not set.
* returns false otherwise.
*/
bool alphaChannelDisabled() const;
/**
* set the channelflags for this layer to the specified bit array.
* The bit array must have exactly the same number of channels as
* the colorspace this layer is in, or be empty, in which case all
* channels are active.
*/
virtual void setChannelFlags(const QBitArray & channelFlags);
/**
* Return a bit array where each bit indicates whether a
* particular channel is active or not. If the channelflags bit
* array is empty, all channels are active.
*/
QBitArray & channelFlags() const;
/**
* Returns true if this layer is temporary: i.e., it should not
* appear in the layerbox, even though it is temporarily in the
* layer stack and taken into account on recomposition.
*/
bool temporary() const;
/**
* Set to true if this layer should not appear in the layerbox,
* even though it is temporarily in the layer stack and taken into
* account on recomposition.
*/
void setTemporary(bool t);
/**
* Set the image this layer belongs to.
*/
void setImage(KisImageWSP image) override;
/**
* Create and return a layer that is the result of merging
* this with layer.
*
* This method is designed to be called only within KisImage::mergeLayerDown().
*
* Decendands override this to create specific merged types when possible.
* The KisLayer one creates a KisPaintLayerSP via a bitBlt, and can work on all layer types.
*
* Descendants that perform their own version do NOT call KisLayer::createMergedLayer
*/
virtual KisLayerSP createMergedLayerTemplate(KisLayerSP prevLayer);
virtual void fillMergedLayerTemplate(KisLayerSP dstLayer, KisLayerSP prevLayer);
/**
* Clones should be informed about updates of the original
* layer, so this is a way to register them
*/
void registerClone(KisCloneLayerWSP clone);
/**
* Deregisters the clone from the update list
*
* \see registerClone()
*/
void unregisterClone(KisCloneLayerWSP clone);
/**
* Return the list of the clones of this node. Be careful
* with the list, because it is not thread safe.
*/
const QList<KisCloneLayerWSP> registeredClones() const;
/**
* Returns whether we have a clone.
*
* Be careful with it. It is not thread safe to add/remove
* clone while checking hasClones(). So there should be no updates.
*/
bool hasClones() const;
/**
* It is calles by the async merger after projection update is done
*/
void updateClones(const QRect &rect);
/**
* Informs this layers that its masks might have changed.
*/
void notifyChildMaskChanged();
public:
qint32 x() const override;
qint32 y() const override;
void setX(qint32 x) override;
void setY(qint32 y) override;
/**
* Returns an approximation of where the bounds
* of actual data of this layer are
*/
QRect extent() const override;
/**
* Returns the exact bounds of where the actual data
* of this layer resides
*/
QRect exactBounds() const override;
- QImage createThumbnail(qint32 w, qint32 h) override;
+ QImage createThumbnail(qint32 w, qint32 h, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio) override;
- QImage createThumbnailForFrame(qint32 w, qint32 h, int time) override;
+ QImage createThumbnailForFrame(qint32 w, qint32 h, int time, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio) override;
/**
* Return a tight rectange, where the contents of the layer
* is placed from user's point of view. This rectangle includes
* all the masks and effects the layer has (excluding layer
* styles, they report their bounds via projection plane).
*/
QRect tightUserVisibleBounds() const;
public:
/**
* Returns true if there are any effect masks present
*/
bool hasEffectMasks() const;
/**
* @return the list of effect masks
*/
QList<KisEffectMaskSP> effectMasks() const;
/**
* @return the list of effect masks up to a certain node
*/
QList<KisEffectMaskSP> effectMasks(KisNodeSP lastNode) const;
/**
* Get the group layer that contains this layer.
*/
KisLayerSP parentLayer() const;
/**
* @return the metadata object associated with this object.
*/
KisMetaData::Store* metaData();
protected:
// override from KisNode
QRect changeRect(const QRect &rect, PositionToFilthy pos = N_FILTHY) const override;
void childNodeChanged(KisNodeSP changedChildNode) override;
protected:
/**
* Ask the layer to assemble its data & apply all the effect masks
* to it.
*/
QRect updateProjection(const QRect& rect, KisNodeSP filthyNode);
/**
* Layers can override this method to get some special behavior
* when copying data from \p original to \p projection, e.g. blend
* in indirect painting device. If you need to modify data
* outside \p rect, please also override outgoingChangeRect()
* method.
*/
virtual void copyOriginalToProjection(const KisPaintDeviceSP original,
KisPaintDeviceSP projection,
const QRect& rect) const;
/**
* For KisLayer classes change rect transformation consists of two
* parts: incoming and outgoing.
*
* 1) incomingChangeRect(rect) chande rect transformation
* performed by the transformations done basing on global
* projection. It is performed in KisAsyncMerger +
* KisUpdateOriginalVisitor classes. It happens before data
* coming to KisLayer::original() therefore it is
* 'incoming'. See KisAdjustmentLayer for example of usage.
*
* 2) outgoingChangeRect(rect) change rect transformation that
* happens in KisLayer::copyOriginalToProjection(). It applies
* *only* when the layer is 'filthy', that is was the cause of
* the merge process. See KisCloneLayer for example of usage.
*
* The flow of changed areas can be illustrated in the
* following way:
*
* 1. Current projection of size R1 is stored in KisAsyncMerger::m_currentProjection
* |
* | <-- KisUpdateOriginalVisitor writes data into layer's original() device.
* | The changed area on KisLayer::original() is
* | R2 = KisLayer::incomingChangeRect(R1)
* |
* 2. KisLayer::original() / changed rect: R2
* |
* | <-- KisLayer::updateProjection() starts composing a layer
* | It calls KisLayer::copyOriginalToProjection() which copies some area
* | to a temporaty device. The temporary device now stores
* | R3 = KisLayer::outgoingChangeRect(R2)
* |
* 3. Temporary device / changed rect: R3
* |
* | <-- KisLayer::updateProjection() continues composing a layer. It merges a mask.
* | R4 = KisMask::changeRect(R3)
* |
* 4. KisLayer::original() / changed rect: R4
*
* So in the end rect R4 will be passed up to the next layers in the stack.
*/
virtual QRect incomingChangeRect(const QRect &rect) const;
/**
* \see incomingChangeRect()
*/
virtual QRect outgoingChangeRect(const QRect &rect) const;
/**
* Return need rect that should be prepared on original()
* device of the layer to get \p rect on its projection.
*
* This method is used either for layers that can have other
* layers as children (yes, KisGroupLayer, I'm looking at you!),
* or for layers that depend on the lower nodes (it's you,
* KisAdjustmentLayer!).
*
* These layers may have some filter masks that need a bit
* more pixels than requested, therefore child nodes should do
* a bit more work to prepare them.
*/
QRect needRectForOriginal(const QRect &rect) const;
/**
* @param rectVariesFlag (out param) a flag, showing whether
* a rect varies from mask to mask
* @return an area that should be updated because of
* the change of @requestedRect of the layer
*/
QRect masksChangeRect(const QList<KisEffectMaskSP> &masks,
const QRect &requestedRect,
bool &rectVariesFlag) const;
/**
* Get needRects for all masks
* @param changeRect requested rect to be updated on final
* projection. Should be a return value
* of @ref masksChangedRect()
* @param applyRects (out param) a stack of the rects where filters
* should be applied
* @param rectVariesFlag (out param) a flag, showing whether
* a rect varies from mask to mask
* @return a needRect that should be prepared on the layer's
* paintDevice for all masks to succeed
*/
QRect masksNeedRect(const QList<KisEffectMaskSP> &masks,
const QRect &changeRect,
QStack<QRect> &applyRects,
bool &rectVariesFlag) const;
QRect applyMasks(const KisPaintDeviceSP source,
KisPaintDeviceSP destination,
const QRect &requestedRect,
KisNodeSP filthyNode, KisNodeSP lastNode) const;
bool canMergeAndKeepBlendOptions(KisLayerSP otherLayer);
QList<KisEffectMaskSP> searchEffectMasks(KisNodeSP lastNode) const;
private:
friend class KisLayerMasksCache;
friend class KisLayerProjectionPlane;
friend class KisTransformMask;
friend class KisLayerTest;
private:
QRect layerExtentImpl(bool exactBounds) const;
private:
struct Private;
Private * const m_d;
};
Q_DECLARE_METATYPE(KisLayerSP)
#endif // KIS_LAYER_H_
diff --git a/libs/image/kis_layer_utils.cpp b/libs/image/kis_layer_utils.cpp
index da511bd0f1..6071dd030b 100644
--- a/libs/image/kis_layer_utils.cpp
+++ b/libs/image/kis_layer_utils.cpp
@@ -1,1649 +1,1659 @@
/*
* Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_layer_utils.h"
#include <algorithm>
#include <QUuid>
#include <KoColorSpaceConstants.h>
#include <KoProperties.h>
#include "kis_painter.h"
#include "kis_image.h"
#include "kis_node.h"
#include "kis_layer.h"
#include "kis_paint_layer.h"
#include "kis_clone_layer.h"
#include "kis_group_layer.h"
#include "kis_selection.h"
#include "kis_selection_mask.h"
#include "kis_meta_data_merge_strategy.h"
#include <kundo2command.h>
#include "commands/kis_image_layer_add_command.h"
#include "commands/kis_image_layer_remove_command.h"
#include "commands/kis_image_layer_move_command.h"
#include "commands/kis_image_change_layers_command.h"
#include "commands_new/kis_activate_selection_mask_command.h"
#include "commands/kis_image_change_visibility_command.h"
#include "kis_abstract_projection_plane.h"
#include "kis_processing_applicator.h"
#include "kis_image_animation_interface.h"
#include "kis_keyframe_channel.h"
#include "kis_command_utils.h"
#include "commands_new/kis_change_projection_color_command.h"
#include "kis_layer_properties_icons.h"
#include "lazybrush/kis_colorize_mask.h"
#include "commands/kis_node_property_list_command.h"
#include "commands/kis_node_compositeop_command.h"
#include <KisDelayedUpdateNodeInterface.h>
#include <KisCroppedOriginalLayerInterface.h>
#include "krita_utils.h"
#include "kis_image_signal_router.h"
namespace KisLayerUtils {
void fetchSelectionMasks(KisNodeList mergedNodes, QVector<KisSelectionMaskSP> &selectionMasks)
{
foreach (KisNodeSP node, mergedNodes) {
Q_FOREACH(KisNodeSP child, node->childNodes(QStringList("KisSelectionMask"), KoProperties())) {
KisSelectionMaskSP mask = qobject_cast<KisSelectionMask*>(child.data());
if (mask) {
selectionMasks.append(mask);
}
}
}
}
struct MergeDownInfoBase {
MergeDownInfoBase(KisImageSP _image)
: image(_image),
storage(new SwitchFrameCommand::SharedStorage())
{
}
virtual ~MergeDownInfoBase() {}
KisImageWSP image;
QVector<KisSelectionMaskSP> selectionMasks;
KisNodeSP dstNode;
SwitchFrameCommand::SharedStorageSP storage;
QSet<int> frames;
bool pinnedToTimeline = false;
bool enableOnionSkins = false;
virtual KisNodeList allSrcNodes() = 0;
KisLayerSP dstLayer() {
return qobject_cast<KisLayer*>(dstNode.data());
}
};
struct MergeDownInfo : public MergeDownInfoBase {
MergeDownInfo(KisImageSP _image,
KisLayerSP _prevLayer,
KisLayerSP _currLayer)
: MergeDownInfoBase(_image),
prevLayer(_prevLayer),
currLayer(_currLayer)
{
frames =
fetchLayerFramesRecursive(prevLayer) |
fetchLayerFramesRecursive(currLayer);
pinnedToTimeline = prevLayer->isPinnedToTimeline() || currLayer->isPinnedToTimeline();
const KisPaintLayer *paintLayer = qobject_cast<KisPaintLayer*>(currLayer.data());
if (paintLayer) enableOnionSkins |= paintLayer->onionSkinEnabled();
paintLayer = qobject_cast<KisPaintLayer*>(prevLayer.data());
if (paintLayer) enableOnionSkins |= paintLayer->onionSkinEnabled();
}
KisLayerSP prevLayer;
KisLayerSP currLayer;
KisNodeList allSrcNodes() override {
KisNodeList mergedNodes;
mergedNodes << currLayer;
mergedNodes << prevLayer;
return mergedNodes;
}
};
struct MergeMultipleInfo : public MergeDownInfoBase {
MergeMultipleInfo(KisImageSP _image,
KisNodeList _mergedNodes)
: MergeDownInfoBase(_image),
mergedNodes(_mergedNodes)
{
foreach (KisNodeSP node, mergedNodes) {
frames |= fetchLayerFramesRecursive(node);
pinnedToTimeline |= node->isPinnedToTimeline();
const KisPaintLayer *paintLayer = qobject_cast<KisPaintLayer*>(node.data());
if (paintLayer) {
enableOnionSkins |= paintLayer->onionSkinEnabled();
}
}
}
KisNodeList mergedNodes;
bool nodesCompositingVaries = false;
KisNodeList allSrcNodes() override {
return mergedNodes;
}
};
typedef QSharedPointer<MergeDownInfoBase> MergeDownInfoBaseSP;
typedef QSharedPointer<MergeDownInfo> MergeDownInfoSP;
typedef QSharedPointer<MergeMultipleInfo> MergeMultipleInfoSP;
struct FillSelectionMasks : public KUndo2Command {
FillSelectionMasks(MergeDownInfoBaseSP info) : m_info(info) {}
void redo() override {
fetchSelectionMasks(m_info->allSrcNodes(), m_info->selectionMasks);
}
private:
MergeDownInfoBaseSP m_info;
};
struct DisableColorizeKeyStrokes : public KisCommandUtils::AggregateCommand {
DisableColorizeKeyStrokes(MergeDownInfoBaseSP info) : m_info(info) {}
void populateChildCommands() override {
Q_FOREACH (KisNodeSP node, m_info->allSrcNodes()) {
recursiveApplyNodes(node,
[this] (KisNodeSP node) {
if (dynamic_cast<KisColorizeMask*>(node.data()) &&
KisLayerPropertiesIcons::nodeProperty(node, KisLayerPropertiesIcons::colorizeEditKeyStrokes, true).toBool()) {
KisBaseNode::PropertyList props = node->sectionModelProperties();
KisLayerPropertiesIcons::setNodeProperty(&props,
KisLayerPropertiesIcons::colorizeEditKeyStrokes,
false);
addCommand(new KisNodePropertyListCommand(node, props));
}
});
}
}
private:
MergeDownInfoBaseSP m_info;
};
struct DisableOnionSkins : public KisCommandUtils::AggregateCommand {
DisableOnionSkins(MergeDownInfoBaseSP info) : m_info(info) {}
void populateChildCommands() override {
Q_FOREACH (KisNodeSP node, m_info->allSrcNodes()) {
recursiveApplyNodes(node,
[this] (KisNodeSP node) {
if (KisLayerPropertiesIcons::nodeProperty(node, KisLayerPropertiesIcons::onionSkins, false).toBool()) {
KisBaseNode::PropertyList props = node->sectionModelProperties();
KisLayerPropertiesIcons::setNodeProperty(&props,
KisLayerPropertiesIcons::onionSkins,
false);
addCommand(new KisNodePropertyListCommand(node, props));
}
});
}
}
private:
MergeDownInfoBaseSP m_info;
};
struct DisableExtraCompositing : public KisCommandUtils::AggregateCommand {
DisableExtraCompositing(MergeMultipleInfoSP info) : m_info(info) {}
void populateChildCommands() override {
/**
* We disable extra compositing only in case all the layers have
* the same compositing properties, therefore, we can just sum them using
* Normal blend mode
*/
if (m_info->nodesCompositingVaries) return;
// we should disable dirty requests on **redo only**, otherwise
// the state of the layers will not be recovered on undo
m_info->image->disableDirtyRequests();
Q_FOREACH (KisNodeSP node, m_info->allSrcNodes()) {
if (node->compositeOpId() != COMPOSITE_OVER) {
addCommand(new KisNodeCompositeOpCommand(node, node->compositeOpId(), COMPOSITE_OVER));
}
if (KisLayerPropertiesIcons::nodeProperty(node, KisLayerPropertiesIcons::inheritAlpha, false).toBool()) {
KisBaseNode::PropertyList props = node->sectionModelProperties();
KisLayerPropertiesIcons::setNodeProperty(&props,
KisLayerPropertiesIcons::inheritAlpha,
false);
addCommand(new KisNodePropertyListCommand(node, props));
}
}
m_info->image->enableDirtyRequests();
}
private:
MergeMultipleInfoSP m_info;
};
struct DisablePassThroughForHeadsOnly : public KisCommandUtils::AggregateCommand {
DisablePassThroughForHeadsOnly(MergeDownInfoBaseSP info, bool skipIfDstIsGroup = false)
: m_info(info),
m_skipIfDstIsGroup(skipIfDstIsGroup)
{
}
void populateChildCommands() override {
if (m_skipIfDstIsGroup &&
m_info->dstLayer() &&
m_info->dstLayer()->inherits("KisGroupLayer")) {
return;
}
Q_FOREACH (KisNodeSP node, m_info->allSrcNodes()) {
if (KisLayerPropertiesIcons::nodeProperty(node, KisLayerPropertiesIcons::passThrough, false).toBool()) {
KisBaseNode::PropertyList props = node->sectionModelProperties();
KisLayerPropertiesIcons::setNodeProperty(&props,
KisLayerPropertiesIcons::passThrough,
false);
addCommand(new KisNodePropertyListCommand(node, props));
}
}
}
private:
MergeDownInfoBaseSP m_info;
bool m_skipIfDstIsGroup;
};
struct RefreshHiddenAreas : public KUndo2Command {
RefreshHiddenAreas(MergeDownInfoBaseSP info) : m_info(info) {}
void redo() override {
KisImageAnimationInterface *interface = m_info->image->animationInterface();
const QRect preparedRect = !interface->externalFrameActive() ?
m_info->image->bounds() : QRect();
foreach (KisNodeSP node, m_info->allSrcNodes()) {
refreshHiddenAreaAsync(m_info->image, node, preparedRect);
}
}
private:
MergeDownInfoBaseSP m_info;
};
struct RefreshDelayedUpdateLayers : public KUndo2Command {
RefreshDelayedUpdateLayers(MergeDownInfoBaseSP info) : m_info(info) {}
void redo() override {
foreach (KisNodeSP node, m_info->allSrcNodes()) {
forceAllDelayedNodesUpdate(node);
}
}
private:
MergeDownInfoBaseSP m_info;
};
struct KeepMergedNodesSelected : public KisCommandUtils::AggregateCommand {
KeepMergedNodesSelected(MergeDownInfoSP info, bool finalizing)
: m_singleInfo(info),
m_finalizing(finalizing) {}
KeepMergedNodesSelected(MergeMultipleInfoSP info, KisNodeSP putAfter, bool finalizing)
: m_multipleInfo(info),
m_finalizing(finalizing),
m_putAfter(putAfter) {}
void populateChildCommands() override {
KisNodeSP prevNode;
KisNodeSP nextNode;
KisNodeList prevSelection;
KisNodeList nextSelection;
KisImageSP image;
if (m_singleInfo) {
prevNode = m_singleInfo->currLayer;
nextNode = m_singleInfo->dstNode;
image = m_singleInfo->image;
} else if (m_multipleInfo) {
prevNode = m_putAfter;
nextNode = m_multipleInfo->dstNode;
prevSelection = m_multipleInfo->allSrcNodes();
image = m_multipleInfo->image;
}
if (!m_finalizing) {
addCommand(new KeepNodesSelectedCommand(prevSelection, KisNodeList(),
prevNode, KisNodeSP(),
image, false));
} else {
addCommand(new KeepNodesSelectedCommand(KisNodeList(), nextSelection,
KisNodeSP(), nextNode,
image, true));
}
}
private:
MergeDownInfoSP m_singleInfo;
MergeMultipleInfoSP m_multipleInfo;
bool m_finalizing;
KisNodeSP m_putAfter;
};
struct CreateMergedLayer : public KisCommandUtils::AggregateCommand {
CreateMergedLayer(MergeDownInfoSP info) : m_info(info) {}
void populateChildCommands() override {
// actual merging done by KisLayer::createMergedLayer (or specialized descendant)
m_info->dstNode = m_info->currLayer->createMergedLayerTemplate(m_info->prevLayer);
if (m_info->frames.size() > 0) {
m_info->dstNode->enableAnimation();
m_info->dstNode->getKeyframeChannel(KisKeyframeChannel::Content.id(), true);
}
m_info->dstNode->setPinnedToTimeline(m_info->pinnedToTimeline);
KisPaintLayer *dstPaintLayer = qobject_cast<KisPaintLayer*>(m_info->dstNode.data());
if (dstPaintLayer) {
dstPaintLayer->setOnionSkinEnabled(m_info->enableOnionSkins);
}
}
private:
MergeDownInfoSP m_info;
};
struct CreateMergedLayerMultiple : public KisCommandUtils::AggregateCommand {
CreateMergedLayerMultiple(MergeMultipleInfoSP info, const QString name = QString() )
: m_info(info),
m_name(name) {}
void populateChildCommands() override {
QString mergedLayerName;
if (m_name.isEmpty()){
const QString mergedLayerSuffix = i18n("Merged");
mergedLayerName = m_info->mergedNodes.first()->name();
if (!mergedLayerName.endsWith(mergedLayerSuffix)) {
mergedLayerName = QString("%1 %2")
.arg(mergedLayerName).arg(mergedLayerSuffix);
}
} else {
mergedLayerName = m_name;
}
KisPaintLayer *dstPaintLayer = new KisPaintLayer(m_info->image, mergedLayerName, OPACITY_OPAQUE_U8);
m_info->dstNode = dstPaintLayer;
if (m_info->frames.size() > 0) {
m_info->dstNode->enableAnimation();
m_info->dstNode->getKeyframeChannel(KisKeyframeChannel::Content.id(), true);
}
auto channelFlagsLazy = [](KisNodeSP node) {
KisLayer *layer = dynamic_cast<KisLayer*>(node.data());
return layer ? layer->channelFlags() : QBitArray();
};
QString compositeOpId;
QBitArray channelFlags;
bool compositionVaries = false;
bool isFirstCycle = true;
foreach (KisNodeSP node, m_info->allSrcNodes()) {
if (isFirstCycle) {
compositeOpId = node->compositeOpId();
channelFlags = channelFlagsLazy(node);
isFirstCycle = false;
} else if (compositeOpId != node->compositeOpId() ||
channelFlags != channelFlagsLazy(node)) {
compositionVaries = true;
break;
}
KisLayerSP layer = qobject_cast<KisLayer*>(node.data());
if (layer && layer->layerStyle()) {
compositionVaries = true;
break;
}
}
if (!compositionVaries) {
if (!compositeOpId.isEmpty()) {
m_info->dstNode->setCompositeOpId(compositeOpId);
}
if (m_info->dstLayer() && !channelFlags.isEmpty()) {
m_info->dstLayer()->setChannelFlags(channelFlags);
}
}
m_info->nodesCompositingVaries = compositionVaries;
m_info->dstNode->setPinnedToTimeline(m_info->pinnedToTimeline);
dstPaintLayer->setOnionSkinEnabled(m_info->enableOnionSkins);
}
private:
MergeMultipleInfoSP m_info;
QString m_name;
};
struct MergeLayers : public KisCommandUtils::AggregateCommand {
MergeLayers(MergeDownInfoSP info) : m_info(info) {}
void populateChildCommands() override {
// actual merging done by KisLayer::createMergedLayer (or specialized descendant)
m_info->currLayer->fillMergedLayerTemplate(m_info->dstLayer(), m_info->prevLayer);
}
private:
MergeDownInfoSP m_info;
};
struct MergeLayersMultiple : public KisCommandUtils::AggregateCommand {
MergeLayersMultiple(MergeMultipleInfoSP info) : m_info(info) {}
void populateChildCommands() override {
KisPainter gc(m_info->dstNode->paintDevice());
foreach (KisNodeSP node, m_info->allSrcNodes()) {
QRect rc = node->exactBounds() | m_info->image->bounds();
node->projectionPlane()->apply(&gc, rc);
}
}
private:
MergeMultipleInfoSP m_info;
};
struct MergeMetaData : public KUndo2Command {
MergeMetaData(MergeDownInfoSP info, const KisMetaData::MergeStrategy* strategy)
: m_info(info),
m_strategy(strategy) {}
void redo() override {
QRect layerProjectionExtent = m_info->currLayer->projection()->extent();
QRect prevLayerProjectionExtent = m_info->prevLayer->projection()->extent();
int prevLayerArea = prevLayerProjectionExtent.width() * prevLayerProjectionExtent.height();
int layerArea = layerProjectionExtent.width() * layerProjectionExtent.height();
QList<double> scores;
double norm = qMax(prevLayerArea, layerArea);
scores.append(prevLayerArea / norm);
scores.append(layerArea / norm);
QList<const KisMetaData::Store*> srcs;
srcs.append(m_info->prevLayer->metaData());
srcs.append(m_info->currLayer->metaData());
m_strategy->merge(m_info->dstLayer()->metaData(), srcs, scores);
}
private:
MergeDownInfoSP m_info;
const KisMetaData::MergeStrategy *m_strategy;
};
KeepNodesSelectedCommand::KeepNodesSelectedCommand(const KisNodeList &selectedBefore,
const KisNodeList &selectedAfter,
KisNodeSP activeBefore,
KisNodeSP activeAfter,
KisImageSP image,
bool finalize, KUndo2Command *parent)
: FlipFlopCommand(finalize, parent),
m_selectedBefore(selectedBefore),
m_selectedAfter(selectedAfter),
m_activeBefore(activeBefore),
m_activeAfter(activeAfter),
m_image(image)
{
}
void KeepNodesSelectedCommand::partB() {
KisImageSignalType type;
if (getState() == State::FINALIZING) {
type = ComplexNodeReselectionSignal(m_activeAfter, m_selectedAfter);
} else {
type = ComplexNodeReselectionSignal(m_activeBefore, m_selectedBefore);
}
m_image->signalRouter()->emitNotification(type);
}
SelectGlobalSelectionMask::SelectGlobalSelectionMask(KisImageSP image)
: m_image(image)
{
}
void SelectGlobalSelectionMask::redo() {
KisImageSignalType type =
ComplexNodeReselectionSignal(m_image->rootLayer()->selectionMask(), KisNodeList());
m_image->signalRouter()->emitNotification(type);
}
RemoveNodeHelper::~RemoveNodeHelper()
{
}
/**
* The removal of two nodes in one go may be a bit tricky, because one
* of them may be the clone of another. If we remove the source of a
* clone layer, it will reincarnate into a paint layer. In this case
* the pointer to the second layer will be lost.
*
* That's why we need to care about the order of the nodes removal:
* the clone --- first, the source --- last.
*/
void RemoveNodeHelper::safeRemoveMultipleNodes(KisNodeList nodes, KisImageSP image) {
const bool lastLayer = scanForLastLayer(image, nodes);
auto isNodeWeird = [] (KisNodeSP node) {
const bool normalCompositeMode = node->compositeOpId() == COMPOSITE_OVER;
KisLayer *layer = dynamic_cast<KisLayer*>(node.data());
const bool hasInheritAlpha = layer && layer->alphaChannelDisabled();
return !normalCompositeMode && !hasInheritAlpha;
};
while (!nodes.isEmpty()) {
KisNodeList::iterator it = nodes.begin();
while (it != nodes.end()) {
if (!checkIsSourceForClone(*it, nodes)) {
KisNodeSP node = *it;
addCommandImpl(new KisImageLayerRemoveCommand(image, node, !isNodeWeird(node), true));
it = nodes.erase(it);
} else {
++it;
}
}
}
if (lastLayer) {
KisLayerSP newLayer = new KisPaintLayer(image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8, image->colorSpace());
addCommandImpl(new KisImageLayerAddCommand(image, newLayer,
image->root(),
KisNodeSP(),
false, false));
}
}
bool RemoveNodeHelper::checkIsSourceForClone(KisNodeSP src, const KisNodeList &nodes) {
foreach (KisNodeSP node, nodes) {
if (node == src) continue;
KisCloneLayer *clone = dynamic_cast<KisCloneLayer*>(node.data());
if (clone && KisNodeSP(clone->copyFrom()) == src) {
return true;
}
}
return false;
}
bool RemoveNodeHelper::scanForLastLayer(KisImageWSP image, KisNodeList nodesToRemove) {
bool removeLayers = false;
Q_FOREACH(KisNodeSP nodeToRemove, nodesToRemove) {
if (qobject_cast<KisLayer*>(nodeToRemove.data())) {
removeLayers = true;
break;
}
}
if (!removeLayers) return false;
bool lastLayer = true;
KisNodeSP node = image->root()->firstChild();
while (node) {
if (!nodesToRemove.contains(node) &&
qobject_cast<KisLayer*>(node.data()) &&
!node->isFakeNode()) {
lastLayer = false;
break;
}
node = node->nextSibling();
}
return lastLayer;
}
SimpleRemoveLayers::SimpleRemoveLayers(const KisNodeList &nodes,
KisImageSP image)
: m_nodes(nodes),
m_image(image)
{
}
void SimpleRemoveLayers::populateChildCommands() {
if (m_nodes.isEmpty()) return;
safeRemoveMultipleNodes(m_nodes, m_image);
}
void SimpleRemoveLayers::addCommandImpl(KUndo2Command *cmd) {
addCommand(cmd);
}
struct InsertNode : public KisCommandUtils::AggregateCommand {
InsertNode(MergeDownInfoBaseSP info, KisNodeSP putAfter)
: m_info(info), m_putAfter(putAfter) {}
void populateChildCommands() override {
addCommand(new KisImageLayerAddCommand(m_info->image,
m_info->dstNode,
m_putAfter->parent(),
m_putAfter,
true, false));
}
private:
virtual void addCommandImpl(KUndo2Command *cmd) {
addCommand(cmd);
}
private:
MergeDownInfoBaseSP m_info;
KisNodeSP m_putAfter;
};
struct CleanUpNodes : private RemoveNodeHelper, public KisCommandUtils::AggregateCommand {
CleanUpNodes(MergeDownInfoBaseSP info, KisNodeSP putAfter)
: m_info(info), m_putAfter(putAfter) {}
static void findPerfectParent(KisNodeList nodesToDelete, KisNodeSP &putAfter, KisNodeSP &parent) {
if (!putAfter) {
putAfter = nodesToDelete.last();
}
// Add the new merged node on top of the active node
// -- checking all parents if they are included in nodesToDelete
// Not every descendant is included in nodesToDelete even if in fact
// they are going to be deleted, so we need to check it.
// If we consider the path from root to the putAfter node,
// if there are any nodes marked for deletion, any node afterwards
// is going to be deleted, too.
// example: root . . . . . ! ! . . ! ! ! ! . . . . putAfter
// it should be: root . . . . . ! ! ! ! ! ! ! ! ! ! ! ! !putAfter
// and here: root . . . . X ! ! . . ! ! ! ! . . . . putAfter
// you can see which node is "the perfect ancestor"
// (marked X; called "parent" in the function arguments).
// and here: root . . . . . O ! . . ! ! ! ! . . . . putAfter
// you can see which node is "the topmost deleted ancestor" (marked 'O')
KisNodeSP node = putAfter->parent();
bool foundDeletedAncestor = false;
KisNodeSP topmostAncestorToDelete = nullptr;
while (node) {
if (nodesToDelete.contains(node)
&& !nodesToDelete.contains(node->parent())) {
foundDeletedAncestor = true;
topmostAncestorToDelete = node;
// Here node is to be deleted and its parent is not,
// so its parent is the one of the first not deleted (="perfect") ancestors.
// We need the one that is closest to the top (root)
}
node = node->parent();
}
if (foundDeletedAncestor) {
parent = topmostAncestorToDelete->parent();
putAfter = topmostAncestorToDelete;
}
else {
parent = putAfter->parent(); // putAfter (and none of its ancestors) is to be deleted, so its parent is the first not deleted ancestor
}
}
void populateChildCommands() override {
KisNodeList nodesToDelete = m_info->allSrcNodes();
KisNodeSP parent;
findPerfectParent(nodesToDelete, m_putAfter, parent);
if (!parent) {
KisNodeSP oldRoot = m_info->image->root();
KisNodeSP newRoot(new KisGroupLayer(m_info->image, "root", OPACITY_OPAQUE_U8));
// copy all fake nodes into the new image
KisLayerUtils::recursiveApplyNodes(oldRoot, [this, oldRoot, newRoot] (KisNodeSP node) {
if (node->isFakeNode() && node->parent() == oldRoot) {
addCommand(new KisImageLayerAddCommand(m_info->image,
node->clone(),
newRoot,
KisNodeSP(),
false, false));
}
});
addCommand(new KisImageLayerAddCommand(m_info->image,
m_info->dstNode,
newRoot,
KisNodeSP(),
true, false));
addCommand(new KisImageChangeLayersCommand(m_info->image, oldRoot, newRoot));
}
else {
addCommand(new KisImageLayerAddCommand(m_info->image,
m_info->dstNode,
parent,
m_putAfter,
true, false));
/**
* We can merge selection masks, in this case dstLayer is not defined!
*/
if (m_info->dstLayer()) {
reparentSelectionMasks(m_info->image,
m_info->dstLayer(),
m_info->selectionMasks);
}
KisNodeList safeNodesToDelete = m_info->allSrcNodes();
for (KisNodeList::iterator it = safeNodesToDelete.begin(); it != safeNodesToDelete.end(); ++it) {
KisNodeSP node = *it;
if (node->userLocked() && node->visible()) {
addCommand(new KisImageChangeVisibilityCommand(false, node));
}
}
KritaUtils::filterContainer<KisNodeList>(safeNodesToDelete, [](KisNodeSP node) {
return !node->userLocked();
});
safeRemoveMultipleNodes(safeNodesToDelete, m_info->image);
}
}
private:
void addCommandImpl(KUndo2Command *cmd) override {
addCommand(cmd);
}
void reparentSelectionMasks(KisImageSP image,
KisLayerSP newLayer,
const QVector<KisSelectionMaskSP> &selectionMasks) {
KIS_SAFE_ASSERT_RECOVER_RETURN(newLayer);
foreach (KisSelectionMaskSP mask, selectionMasks) {
addCommand(new KisImageLayerMoveCommand(image, mask, newLayer, newLayer->lastChild()));
addCommand(new KisActivateSelectionMaskCommand(mask, false));
}
}
private:
MergeDownInfoBaseSP m_info;
KisNodeSP m_putAfter;
};
SwitchFrameCommand::SharedStorage::~SharedStorage() {
}
SwitchFrameCommand::SwitchFrameCommand(KisImageSP image, int time, bool finalize, SharedStorageSP storage)
: FlipFlopCommand(finalize),
m_image(image),
m_newTime(time),
m_storage(storage) {}
SwitchFrameCommand::~SwitchFrameCommand() {}
void SwitchFrameCommand::partA() {
KisImageAnimationInterface *interface = m_image->animationInterface();
const int currentTime = interface->currentTime();
if (currentTime == m_newTime) {
m_storage->value = m_newTime;
return;
}
interface->image()->disableUIUpdates();
interface->saveAndResetCurrentTime(m_newTime, &m_storage->value);
}
void SwitchFrameCommand::partB() {
KisImageAnimationInterface *interface = m_image->animationInterface();
const int currentTime = interface->currentTime();
if (currentTime == m_storage->value) {
return;
}
interface->restoreCurrentTime(&m_storage->value);
interface->image()->enableUIUpdates();
}
struct AddNewFrame : public KisCommandUtils::AggregateCommand {
AddNewFrame(MergeDownInfoBaseSP info, int frame) : m_info(info), m_frame(frame) {}
void populateChildCommands() override {
KUndo2Command *cmd = new KisCommandUtils::SkipFirstRedoWrapper();
KisKeyframeChannel *channel = m_info->dstNode->getKeyframeChannel(KisKeyframeChannel::Content.id());
KisKeyframeSP keyframe = channel->addKeyframe(m_frame, cmd);
applyKeyframeColorLabel(keyframe);
addCommand(cmd);
}
void applyKeyframeColorLabel(KisKeyframeSP dstKeyframe) {
Q_FOREACH(KisNodeSP srcNode, m_info->allSrcNodes()) {
Q_FOREACH(KisKeyframeChannel *channel, srcNode->keyframeChannels().values()) {
KisKeyframeSP keyframe = channel->keyframeAt(m_frame);
if (!keyframe.isNull() && keyframe->colorLabel() != 0) {
dstKeyframe->setColorLabel(keyframe->colorLabel());
return;
}
}
}
dstKeyframe->setColorLabel(0);
}
private:
MergeDownInfoBaseSP m_info;
int m_frame;
};
QSet<int> fetchLayerFrames(KisNodeSP node) {
KisKeyframeChannel *channel = node->getKeyframeChannel(KisKeyframeChannel::Content.id());
if (!channel) return QSet<int>();
return channel->allKeyframeIds();
}
QSet<int> fetchLayerFramesRecursive(KisNodeSP rootNode) {
QSet<int> frames = fetchLayerFrames(rootNode);
KisNodeSP node = rootNode->firstChild();
while(node) {
frames |= fetchLayerFramesRecursive(node);
node = node->nextSibling();
}
return frames;
}
void updateFrameJobs(FrameJobs *jobs, KisNodeSP node) {
QSet<int> frames = fetchLayerFrames(node);
if (frames.isEmpty()) {
(*jobs)[0].insert(node);
} else {
foreach (int frame, frames) {
(*jobs)[frame].insert(node);
}
}
}
void updateFrameJobsRecursive(FrameJobs *jobs, KisNodeSP rootNode) {
updateFrameJobs(jobs, rootNode);
KisNodeSP node = rootNode->firstChild();
while(node) {
updateFrameJobsRecursive(jobs, node);
node = node->nextSibling();
}
}
/**
* \see a comment in mergeMultipleLayersImpl()
*/
void mergeDown(KisImageSP image, KisLayerSP layer, const KisMetaData::MergeStrategy* strategy)
{
if (!layer->prevSibling()) return;
// XXX: this breaks if we allow free mixing of masks and layers
KisLayerSP prevLayer = qobject_cast<KisLayer*>(layer->prevSibling().data());
if (!prevLayer) return;
if (!layer->visible() && !prevLayer->visible()) {
return;
}
KisImageSignalVector emitSignals;
emitSignals << ModifiedSignal;
KisProcessingApplicator applicator(image, 0,
KisProcessingApplicator::NONE,
emitSignals,
kundo2_i18n("Merge Down"));
if (layer->visible() && prevLayer->visible()) {
MergeDownInfoSP info(new MergeDownInfo(image, prevLayer, layer));
// disable key strokes on all colorize masks, all onion skins on
// paint layers and wait until update is finished with a barrier
applicator.applyCommand(new DisableColorizeKeyStrokes(info));
applicator.applyCommand(new DisableOnionSkins(info));
applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
applicator.applyCommand(new KeepMergedNodesSelected(info, false));
applicator.applyCommand(new FillSelectionMasks(info));
applicator.applyCommand(new CreateMergedLayer(info), KisStrokeJobData::BARRIER);
// NOTE: shape layer may have emitted spontaneous jobs during layer creation,
// wait for them to complete!
applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
// in two-layer mode we disable pass through only when the destination layer
// is not a group layer
applicator.applyCommand(new DisablePassThroughForHeadsOnly(info, true));
applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
if (info->frames.size() > 0) {
foreach (int frame, info->frames) {
applicator.applyCommand(new SwitchFrameCommand(info->image, frame, false, info->storage));
applicator.applyCommand(new AddNewFrame(info, frame));
applicator.applyCommand(new RefreshHiddenAreas(info));
applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
applicator.applyCommand(new MergeLayers(info), KisStrokeJobData::BARRIER);
applicator.applyCommand(new SwitchFrameCommand(info->image, frame, true, info->storage));
}
} else {
applicator.applyCommand(new RefreshHiddenAreas(info));
applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
applicator.applyCommand(new MergeLayers(info), KisStrokeJobData::BARRIER);
}
applicator.applyCommand(new MergeMetaData(info, strategy), KisStrokeJobData::BARRIER);
applicator.applyCommand(new CleanUpNodes(info, layer),
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::EXCLUSIVE);
applicator.applyCommand(new KeepMergedNodesSelected(info, true));
} else if (layer->visible()) {
applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
layer, KisNodeSP(),
image, false));
applicator.applyCommand(
new SimpleRemoveLayers(KisNodeList() << prevLayer,
image),
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::EXCLUSIVE);
applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
KisNodeSP(), layer,
image, true));
} else if (prevLayer->visible()) {
applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
layer, KisNodeSP(),
image, false));
applicator.applyCommand(
new SimpleRemoveLayers(KisNodeList() << layer,
image),
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::EXCLUSIVE);
applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
KisNodeSP(), prevLayer,
image, true));
}
applicator.end();
}
bool checkIsChildOf(KisNodeSP node, const KisNodeList &parents)
{
KisNodeList nodeParents;
KisNodeSP parent = node->parent();
while (parent) {
nodeParents << parent;
parent = parent->parent();
}
foreach(KisNodeSP perspectiveParent, parents) {
if (nodeParents.contains(perspectiveParent)) {
return true;
}
}
return false;
}
bool checkIsCloneOf(KisNodeSP node, const KisNodeList &nodes)
{
bool result = false;
KisCloneLayer *clone = dynamic_cast<KisCloneLayer*>(node.data());
if (clone) {
KisNodeSP cloneSource = KisNodeSP(clone->copyFrom());
Q_FOREACH(KisNodeSP subtree, nodes) {
result =
recursiveFindNode(subtree,
[cloneSource](KisNodeSP node) -> bool
{
return node == cloneSource;
});
if (!result) {
result = checkIsCloneOf(cloneSource, nodes);
}
if (result) {
break;
}
}
}
return result;
}
void filterMergableNodes(KisNodeList &nodes, bool allowMasks)
{
KisNodeList::iterator it = nodes.begin();
while (it != nodes.end()) {
if ((!allowMasks && !qobject_cast<KisLayer*>(it->data())) ||
checkIsChildOf(*it, nodes)) {
//qDebug() << "Skipping node" << ppVar((*it)->name());
it = nodes.erase(it);
} else {
++it;
}
}
}
void sortMergableNodes(KisNodeSP root, KisNodeList &inputNodes, KisNodeList &outputNodes)
{
KisNodeList::iterator it = std::find(inputNodes.begin(), inputNodes.end(), root);
if (it != inputNodes.end()) {
outputNodes << *it;
inputNodes.erase(it);
}
if (inputNodes.isEmpty()) {
return;
}
KisNodeSP child = root->firstChild();
while (child) {
sortMergableNodes(child, inputNodes, outputNodes);
child = child->nextSibling();
}
/**
* By the end of recursion \p inputNodes must be empty
*/
KIS_ASSERT_RECOVER_NOOP(root->parent() || inputNodes.isEmpty());
}
KisNodeList sortMergableNodes(KisNodeSP root, KisNodeList nodes)
{
KisNodeList result;
sortMergableNodes(root, nodes, result);
return result;
}
KisNodeList sortAndFilterMergableInternalNodes(KisNodeList nodes, bool allowMasks)
{
KIS_ASSERT_RECOVER(!nodes.isEmpty()) { return nodes; }
KisNodeSP root;
Q_FOREACH(KisNodeSP node, nodes) {
KisNodeSP localRoot = node;
while (localRoot->parent()) {
localRoot = localRoot->parent();
}
if (!root) {
root = localRoot;
}
KIS_ASSERT_RECOVER(root == localRoot) { return nodes; }
}
KisNodeList result;
sortMergableNodes(root, nodes, result);
filterMergableNodes(result, allowMasks);
return result;
}
KisNodeList sortAndFilterAnyMergableNodesSafe(const KisNodeList &nodes, KisImageSP image) {
KisNodeList filteredNodes = nodes;
KisNodeList sortedNodes;
KisLayerUtils::filterMergableNodes(filteredNodes, true);
bool haveExternalNodes = false;
Q_FOREACH (KisNodeSP node, nodes) {
if (node->graphListener() != image->root()->graphListener()) {
haveExternalNodes = true;
break;
}
}
if (!haveExternalNodes) {
KisLayerUtils::sortMergableNodes(image->root(), filteredNodes, sortedNodes);
} else {
sortedNodes = filteredNodes;
}
return sortedNodes;
}
void addCopyOfNameTag(KisNodeSP node)
{
const QString prefix = i18n("Copy of");
QString newName = node->name();
if (!newName.startsWith(prefix)) {
newName = QString("%1 %2").arg(prefix).arg(newName);
node->setName(newName);
}
}
KisNodeList findNodesWithProps(KisNodeSP root, const KoProperties &props, bool excludeRoot)
{
KisNodeList nodes;
if ((!excludeRoot || root->parent()) && root->check(props)) {
nodes << root;
}
KisNodeSP node = root->firstChild();
while (node) {
nodes += findNodesWithProps(node, props, excludeRoot);
node = node->nextSibling();
}
return nodes;
}
KisNodeList filterInvisibleNodes(const KisNodeList &nodes, KisNodeList *invisibleNodes, KisNodeSP *putAfter)
{
KIS_ASSERT_RECOVER(invisibleNodes) { return nodes; }
KIS_ASSERT_RECOVER(putAfter) { return nodes; }
KisNodeList visibleNodes;
int putAfterIndex = -1;
Q_FOREACH(KisNodeSP node, nodes) {
if (node->visible() || node->userLocked()) {
visibleNodes << node;
} else {
*invisibleNodes << node;
if (node == *putAfter) {
putAfterIndex = visibleNodes.size() - 1;
}
}
}
if (!visibleNodes.isEmpty() && putAfterIndex >= 0) {
putAfterIndex = qBound(0, putAfterIndex, visibleNodes.size() - 1);
*putAfter = visibleNodes[putAfterIndex];
}
return visibleNodes;
}
void filterUnlockedNodes(KisNodeList &nodes)
{
KisNodeList::iterator it = nodes.begin();
while (it != nodes.end()) {
if ((*it)->userLocked()) {
it = nodes.erase(it);
} else {
++it;
}
}
}
void changeImageDefaultProjectionColor(KisImageSP image, const KoColor &color)
{
KisImageSignalVector emitSignals;
emitSignals << ModifiedSignal;
KisProcessingApplicator applicator(image,
image->root(),
KisProcessingApplicator::RECURSIVE,
emitSignals,
kundo2_i18n("Change projection color"),
0,
142857 + 1);
applicator.applyCommand(new KisChangeProjectionColorCommand(image, color), KisStrokeJobData::BARRIER, KisStrokeJobData::EXCLUSIVE);
applicator.end();
}
/**
* There might be two approaches for merging multiple layers:
*
* 1) Consider the selected nodes as a distinct "group" and merge them
* as if they were isolated from the rest of the image. The key point
* of this approach is that the look of the image will change, when
* merging "weird" layers, like adjustment layers or layers with
* non-normal blending mode.
*
* 2) Merge layers in a way to keep the look of the image as unchanged as
* possible. With this approach one uses a few heuristics:
*
* * when merging multiple layers with non-normal (but equal) blending
* mode, first merge these layers together using Normal blending mode,
* then set blending mode of the result to the original blending mode
*
* * when merging multiple layers with different blending modes or
* layer styles, they are first rasterized, and then laid over each
* other with their own composite op. The blending mode of the final
* layer is set to Normal, so the user could clearly see that he should
* choose the correct blending mode.
*
* Krita uses the second approach: after merge operation, the image should look
* as if nothing has happened (if it is technically possible).
*/
void mergeMultipleLayersImpl(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter,
bool flattenSingleLayer, const KUndo2MagicString &actionName,
bool cleanupNodes = true, const QString layerName = QString())
{
if (!putAfter) {
putAfter = mergedNodes.first();
}
filterMergableNodes(mergedNodes);
{
KisNodeList tempNodes;
std::swap(mergedNodes, tempNodes);
sortMergableNodes(image->root(), tempNodes, mergedNodes);
}
if (mergedNodes.size() <= 1 &&
(!flattenSingleLayer && mergedNodes.size() == 1)) return;
KisImageSignalVector emitSignals;
emitSignals << ModifiedSignal;
emitSignals << ComplexNodeReselectionSignal(KisNodeSP(), KisNodeList(), KisNodeSP(), mergedNodes);
KisProcessingApplicator applicator(image, 0,
KisProcessingApplicator::NONE,
emitSignals,
actionName);
KisNodeList originalNodes = mergedNodes;
KisNodeList invisibleNodes;
mergedNodes = filterInvisibleNodes(originalNodes, &invisibleNodes, &putAfter);
if (!invisibleNodes.isEmpty() && !mergedNodes.isEmpty()) {
/* If the putAfter node is invisible,
* we should instead pick one of the nodes
* to be merged to avoid a null putAfter.
*/
if (!putAfter->visible()){
putAfter = mergedNodes.first();
}
applicator.applyCommand(
new SimpleRemoveLayers(invisibleNodes,
image),
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::EXCLUSIVE);
}
if (mergedNodes.size() > 1 || invisibleNodes.isEmpty()) {
MergeMultipleInfoSP info(new MergeMultipleInfo(image, mergedNodes));
// disable key strokes on all colorize masks, all onion skins on
// paint layers and wait until update is finished with a barrier
applicator.applyCommand(new DisableColorizeKeyStrokes(info));
applicator.applyCommand(new DisableOnionSkins(info));
applicator.applyCommand(new DisablePassThroughForHeadsOnly(info));
applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
applicator.applyCommand(new KeepMergedNodesSelected(info, putAfter, false));
applicator.applyCommand(new FillSelectionMasks(info));
applicator.applyCommand(new CreateMergedLayerMultiple(info, layerName), KisStrokeJobData::BARRIER);
applicator.applyCommand(new DisableExtraCompositing(info));
applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
if (!info->frames.isEmpty()) {
foreach (int frame, info->frames) {
applicator.applyCommand(new SwitchFrameCommand(info->image, frame, false, info->storage));
applicator.applyCommand(new AddNewFrame(info, frame));
applicator.applyCommand(new RefreshHiddenAreas(info));
applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
applicator.applyCommand(new MergeLayersMultiple(info), KisStrokeJobData::BARRIER);
applicator.applyCommand(new SwitchFrameCommand(info->image, frame, true, info->storage));
}
} else {
applicator.applyCommand(new RefreshHiddenAreas(info));
applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
applicator.applyCommand(new MergeLayersMultiple(info), KisStrokeJobData::BARRIER);
}
//applicator.applyCommand(new MergeMetaData(info, strategy), KisStrokeJobData::BARRIER);
if (cleanupNodes){
applicator.applyCommand(new CleanUpNodes(info, putAfter),
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::EXCLUSIVE);
} else {
applicator.applyCommand(new InsertNode(info, putAfter),
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::EXCLUSIVE);
}
applicator.applyCommand(new KeepMergedNodesSelected(info, putAfter, true));
}
applicator.end();
}
void mergeMultipleLayers(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter)
{
mergeMultipleLayersImpl(image, mergedNodes, putAfter, false, kundo2_i18n("Merge Selected Nodes"));
}
void newLayerFromVisible(KisImageSP image, KisNodeSP putAfter)
{
KisNodeList mergedNodes;
mergedNodes << image->root();
mergeMultipleLayersImpl(image, mergedNodes, putAfter, true, kundo2_i18n("New From Visible"), false, i18nc("New layer created from all the visible layers", "Visible"));
}
struct MergeSelectionMasks : public KisCommandUtils::AggregateCommand {
MergeSelectionMasks(MergeDownInfoBaseSP info, KisNodeSP putAfter)
: m_info(info),
m_putAfter(putAfter){}
void populateChildCommands() override {
KisNodeSP parent;
CleanUpNodes::findPerfectParent(m_info->allSrcNodes(), m_putAfter, parent);
KisLayerSP parentLayer;
do {
parentLayer = qobject_cast<KisLayer*>(parent.data());
parent = parent->parent();
} while(!parentLayer && parent);
KisSelectionSP selection = new KisSelection();
foreach (KisNodeSP node, m_info->allSrcNodes()) {
KisMaskSP mask = dynamic_cast<KisMask*>(node.data());
if (!mask) continue;
selection->pixelSelection()->applySelection(
mask->selection()->pixelSelection(), SELECTION_ADD);
}
KisSelectionMaskSP mergedMask = new KisSelectionMask(m_info->image, i18n("Selection Mask"));
mergedMask->initSelection(parentLayer);
mergedMask->setSelection(selection);
m_info->dstNode = mergedMask;
}
private:
MergeDownInfoBaseSP m_info;
KisNodeSP m_putAfter;
};
struct ActivateSelectionMask : public KisCommandUtils::AggregateCommand {
ActivateSelectionMask(MergeDownInfoBaseSP info)
: m_info(info) {}
void populateChildCommands() override {
KisSelectionMaskSP mergedMask = dynamic_cast<KisSelectionMask*>(m_info->dstNode.data());
addCommand(new KisActivateSelectionMaskCommand(mergedMask, true));
}
private:
MergeDownInfoBaseSP m_info;
};
bool tryMergeSelectionMasks(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter)
{
QList<KisSelectionMaskSP> selectionMasks;
for (auto it = mergedNodes.begin(); it != mergedNodes.end(); /*noop*/) {
KisSelectionMaskSP mask = dynamic_cast<KisSelectionMask*>(it->data());
if (!mask) {
it = mergedNodes.erase(it);
} else {
selectionMasks.append(mask);
++it;
}
}
if (mergedNodes.isEmpty()) return false;
KisLayerSP parentLayer = qobject_cast<KisLayer*>(selectionMasks.first()->parent().data());
KIS_ASSERT_RECOVER(parentLayer) { return 0; }
KisImageSignalVector emitSignals;
emitSignals << ModifiedSignal;
KisProcessingApplicator applicator(image, 0,
KisProcessingApplicator::NONE,
emitSignals,
kundo2_i18n("Merge Selection Masks"));
MergeMultipleInfoSP info(new MergeMultipleInfo(image, mergedNodes));
applicator.applyCommand(new MergeSelectionMasks(info, putAfter));
applicator.applyCommand(new CleanUpNodes(info, putAfter),
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::EXCLUSIVE);
applicator.applyCommand(new ActivateSelectionMask(info));
applicator.end();
return true;
}
void flattenLayer(KisImageSP image, KisLayerSP layer)
{
if (!layer->childCount() && !layer->layerStyle())
return;
KisNodeList mergedNodes;
mergedNodes << layer;
mergeMultipleLayersImpl(image, mergedNodes, layer, true, kundo2_i18n("Flatten Layer"));
}
void flattenImage(KisImageSP image, KisNodeSP activeNode)
{
if (!activeNode) {
activeNode = image->root()->lastChild();
}
KisNodeList mergedNodes;
mergedNodes << image->root();
mergeMultipleLayersImpl(image, mergedNodes, activeNode, true, kundo2_i18n("Flatten Image"));
}
KisSimpleUpdateCommand::KisSimpleUpdateCommand(KisNodeList nodes, bool finalize, KUndo2Command *parent)
: FlipFlopCommand(finalize, parent),
m_nodes(nodes)
{
}
void KisSimpleUpdateCommand::partB()
{
updateNodes(m_nodes);
}
void KisSimpleUpdateCommand::updateNodes(const KisNodeList &nodes)
{
Q_FOREACH(KisNodeSP node, nodes) {
node->setDirty(node->extent());
}
}
KisNodeSP recursiveFindNode(KisNodeSP node, std::function<bool(KisNodeSP)> func)
{
if (func(node)) {
return node;
}
node = node->firstChild();
while (node) {
KisNodeSP resultNode = recursiveFindNode(node, func);
if (resultNode) {
return resultNode;
}
node = node->nextSibling();
}
return 0;
}
KisNodeSP findNodeByUuid(KisNodeSP root, const QUuid &uuid)
{
return recursiveFindNode(root,
[uuid] (KisNodeSP node) {
return node->uuid() == uuid;
});
}
void forceAllDelayedNodesUpdate(KisNodeSP root)
{
KisLayerUtils::recursiveApplyNodes(root,
[] (KisNodeSP node) {
KisDelayedUpdateNodeInterface *delayedUpdate =
dynamic_cast<KisDelayedUpdateNodeInterface*>(node.data());
if (delayedUpdate) {
delayedUpdate->forceUpdateTimedNode();
}
});
}
bool hasDelayedNodeWithUpdates(KisNodeSP root)
{
return recursiveFindNode(root,
[] (KisNodeSP node) {
KisDelayedUpdateNodeInterface *delayedUpdate =
dynamic_cast<KisDelayedUpdateNodeInterface*>(node.data());
return delayedUpdate ? delayedUpdate->hasPendingTimedUpdates() : false;
});
}
void forceAllHiddenOriginalsUpdate(KisNodeSP root)
{
KisLayerUtils::recursiveApplyNodes(root,
[] (KisNodeSP node) {
KisCroppedOriginalLayerInterface *croppedUpdate =
dynamic_cast<KisCroppedOriginalLayerInterface*>(node.data());
if (croppedUpdate) {
croppedUpdate->forceUpdateHiddenAreaOnOriginal();
}
});
}
KisImageSP findImageByHierarchy(KisNodeSP node)
{
while (node) {
const KisLayer *layer = dynamic_cast<const KisLayer*>(node.data());
if (layer) {
return layer->image();
}
node = node->parent();
}
return 0;
}
namespace Private {
QRect realNodeChangeRect(KisNodeSP rootNode, QRect currentRect = QRect()) {
KisNodeSP node = rootNode->firstChild();
while(node) {
currentRect |= realNodeChangeRect(node, currentRect);
node = node->nextSibling();
}
if (!rootNode->isFakeNode()) {
// TODO: it would be better to count up changeRect inside
// node's extent() method
currentRect |= rootNode->projectionPlane()->changeRect(rootNode->exactBounds());
}
return currentRect;
}
}
void refreshHiddenAreaAsync(KisImageSP image, KisNodeSP rootNode, const QRect &preparedArea) {
QRect realNodeRect = Private::realNodeChangeRect(rootNode);
if (!preparedArea.contains(realNodeRect)) {
QRegion dirtyRegion = realNodeRect;
dirtyRegion -= preparedArea;
auto rc = dirtyRegion.begin();
while (rc != dirtyRegion.end()) {
image->refreshGraphAsync(rootNode, *rc, realNodeRect);
rc++;
}
}
}
QRect recursiveTightNodeVisibleBounds(KisNodeSP rootNode)
{
QRect exactBounds;
recursiveApplyNodes(rootNode, [&exactBounds] (KisNodeSP node) {
exactBounds |= node->projectionPlane()->tightUserVisibleBounds();
});
return exactBounds;
}
+ KisNodeSP findRoot(KisNodeSP node)
+ {
+ if (!node) return node;
+
+ while (node->parent()) {
+ node = node->parent();
+ }
+ return node;
+ }
+
}
diff --git a/libs/image/kis_layer_utils.h b/libs/image/kis_layer_utils.h
index 7a7f33a41d..665e15db07 100644
--- a/libs/image/kis_layer_utils.h
+++ b/libs/image/kis_layer_utils.h
@@ -1,239 +1,241 @@
/*
* Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, 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 <functional>
#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<KisNodeSP> &inputNodes, QList<KisNodeSP> &outputNodes);
KRITAIMAGE_EXPORT KisNodeList sortMergableNodes(KisNodeSP root, KisNodeList nodes);
KRITAIMAGE_EXPORT void filterMergableNodes(KisNodeList &nodes, bool allowMasks = false);
KRITAIMAGE_EXPORT KisNodeList sortAndFilterAnyMergableNodesSafe(const KisNodeList &nodes, KisImageSP image);
KRITAIMAGE_EXPORT bool checkIsChildOf(KisNodeSP node, const KisNodeList &parents);
KRITAIMAGE_EXPORT void filterUnlockedNodes(KisNodeList &nodes);
KRITAIMAGE_EXPORT void refreshHiddenAreaAsync(KisImageSP image, KisNodeSP rootNode, const QRect &preparedArea);
KRITAIMAGE_EXPORT QRect recursiveTightNodeVisibleBounds(KisNodeSP rootNode);
/**
* 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 bool hasDelayedNodeWithUpdates(KisNodeSP root);
KRITAIMAGE_EXPORT void forceAllHiddenOriginalsUpdate(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<int> fetchLayerFrames(KisNodeSP node);
KRITAIMAGE_EXPORT QSet<int> 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<int, QSet<KisNodeSP> > 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<SharedStorage> 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 <typename T>
bool checkNodesDiffer(KisNodeList nodes, std::function<T(KisNodeSP)> 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 <typename NodePointer, typename Functor>
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<bool(KisNodeSP)> func);
/**
* Recursively searches for a node with specified Uuid
*/
KisNodeSP KRITAIMAGE_EXPORT findNodeByUuid(KisNodeSP root, const QUuid &uuid);
KisImageSP KRITAIMAGE_EXPORT findImageByHierarchy(KisNodeSP node);
template <class T>
T* findNodeByType(KisNodeSP root) {
return dynamic_cast<T*>(recursiveFindNode(root, [] (KisNodeSP node) {
return bool(dynamic_cast<T*>(node.data()));
}).data());
}
+
+ KisNodeSP KRITAIMAGE_EXPORT findRoot(KisNodeSP node);
}
#endif /* __KIS_LAYER_UTILS_H */
diff --git a/libs/image/kis_lod_transform.h b/libs/image/kis_lod_transform.h
index 8e2aa570ed..c0b33c56c7 100644
--- a/libs/image/kis_lod_transform.h
+++ b/libs/image/kis_lod_transform.h
@@ -1,193 +1,201 @@
/*
* Copyright (c) 2014 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_LOD_TRANSFORM_H
#define __KIS_LOD_TRANSFORM_H
#include <QtCore/qmath.h>
#include <QTransform>
#include <brushengine/kis_paint_information.h>
#include <kritaimage_export.h>
class KRITAIMAGE_EXPORT KisLodTransform {
public:
KisLodTransform(int levelOfDetail) {
qreal scale = lodToScale(levelOfDetail);
m_transform = QTransform::fromScale(scale, scale);
m_levelOfDetail = levelOfDetail;
}
template <class PaintDeviceTypeSP>
KisLodTransform(PaintDeviceTypeSP device) {
int levelOfDetail = device->defaultBounds()->currentLevelOfDetail();
qreal scale = lodToScale(levelOfDetail);
m_transform = QTransform::fromScale(scale, scale);
m_levelOfDetail = levelOfDetail;
}
static int scaleToLod(qreal scale, int maxLod) {
return qMin(maxLod, qMax(0, qFloor(std::log2(1.0 / scale))));
}
static qreal lodToScale(int levelOfDetail) {
return levelOfDetail > 0 ? 1.0 / (1 << qMax(0, levelOfDetail)) : 1.0;
}
static qreal lodToInvScale(int levelOfDetail) {
return 1 << qMax(0, levelOfDetail);
}
template <class PaintDeviceTypeSP>
static qreal lodToScale(PaintDeviceTypeSP device) {
return lodToScale(device->defaultBounds()->currentLevelOfDetail());
}
QRectF map(const QRectF &rc) const {
return m_transform.mapRect(rc);
}
QRect map(const QRect &rc) const {
return m_transform.mapRect(rc);
}
+ QRectF mapInverted(const QRectF &rc) const {
+ return m_transform.inverted().mapRect(rc);
+ }
+
+ QRect mapInverted(const QRect &rc) const {
+ return m_transform.inverted().mapRect(rc);
+ }
+
KisPaintInformation map(KisPaintInformation pi) const {
QPointF pos = pi.pos();
pi.setPos(m_transform.map(pos));
pi.setLevelOfDetail(m_levelOfDetail);
return pi;
}
template <class T>
T map(const T &object) const {
return m_transform.map(object);
}
static inline QRect alignedRect(const QRect &srcRect, int lod)
{
qint32 alignment = 1 << lod;
qint32 x1, y1, x2, y2;
srcRect.getCoords(&x1, &y1, &x2, &y2);
alignByPow2Lo(x1, alignment);
alignByPow2Lo(y1, alignment);
/**
* Here is a workaround of Qt's QRect::right()/bottom()
* "historical reasons". It should be one pixel smaller
* than actual right/bottom position
*/
alignByPow2ButOneHi(x2, alignment);
alignByPow2ButOneHi(y2, alignment);
QRect rect;
rect.setCoords(x1, y1, x2, y2);
return rect;
}
static inline QRect scaledRect(const QRect &srcRect, int lod) {
qint32 x1, y1, x2, y2;
srcRect.getCoords(&x1, &y1, &x2, &y2);
KIS_ASSERT_RECOVER_NOOP(!(x1 & 1));
KIS_ASSERT_RECOVER_NOOP(!(y1 & 1));
KIS_ASSERT_RECOVER_NOOP(!((x2 + 1) & 1));
KIS_ASSERT_RECOVER_NOOP(!((y2 + 1) & 1));
x1 = divideSafe(x1, lod);
y1 = divideSafe(y1, lod);
x2 = divideSafe(x2 + 1, lod) - 1;
y2 = divideSafe(y2 + 1, lod) - 1;
QRect rect;
rect.setCoords(x1, y1, x2, y2);
return rect;
}
static QRect upscaledRect(const QRect &srcRect, int lod) {
qint32 x1, y1, x2, y2;
srcRect.getCoords(&x1, &y1, &x2, &y2);
x1 <<= lod;
y1 <<= lod;
x2 <<= lod;
y2 <<= lod;
QRect rect;
rect.setCoords(x1, y1, x2, y2);
return rect;
}
static inline int coordToLodCoord(int x, int lod) {
return divideSafe(x, lod);
}
private:
/**
* Aligns @value to the lowest integer not smaller than @value and
* that is, increased by one, a divident of alignment
*/
static inline void alignByPow2ButOneHi(qint32 &value, qint32 alignment)
{
qint32 mask = alignment - 1;
value |= mask;
}
/**
* Aligns @value to the highest integer not exceeding @value and
* that is a divident of @alignment
*/
static inline void alignByPow2Lo(qint32 &value, qint32 alignment)
{
qint32 mask = alignment - 1;
value &= ~mask;
}
static inline int divideSafe(int x, int lod) {
return x > 0 ? x >> lod : -( -x >> lod);
}
private:
QTransform m_transform;
int m_levelOfDetail;
};
class KisLodTransformScalar {
public:
KisLodTransformScalar(int lod) {
m_scale = KisLodTransform::lodToScale(lod);
}
template <class PaintDeviceTypeSP>
KisLodTransformScalar(PaintDeviceTypeSP device) {
m_scale = KisLodTransform::lodToScale(device->defaultBounds()->currentLevelOfDetail());
}
qreal scale(qreal value) const {
return m_scale * value;
}
private:
qreal m_scale;
};
#endif /* __KIS_LOD_TRANSFORM_H */
diff --git a/libs/image/kis_mask.cc b/libs/image/kis_mask.cc
index 71743c2c7b..5983bd2d95 100644
--- a/libs/image/kis_mask.cc
+++ b/libs/image/kis_mask.cc
@@ -1,513 +1,510 @@
/*
* Copyright (c) 2006 Boudewijn Rempt <boud@valdyas.org>
* (c) 2009 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_mask.h"
#include <kis_debug.h>
// to prevent incomplete class types on "delete selection->flatten();"
#include <kundo2command.h>
#include <QScopedPointer>
#include <KoColor.h>
#include <KoColorSpace.h>
#include <KoCompositeOpRegistry.h>
#include "kis_paint_device.h"
#include "kis_selection.h"
#include "kis_pixel_selection.h"
#include "kis_painter.h"
#include "kis_image.h"
#include "kis_layer.h"
#include "kis_cached_paint_device.h"
#include "kis_mask_projection_plane.h"
#include "kis_raster_keyframe_channel.h"
#include "KisSafeNodeProjectionStore.h"
struct Q_DECL_HIDDEN KisMask::Private {
Private(KisMask *_q)
: q(_q),
projectionPlane(new KisMaskProjectionPlane(q))
{
}
mutable KisSelectionSP selection;
KisCachedPaintDevice paintDeviceCache;
KisMask *q;
/**
* Due to the design of the Kra format the X,Y offset of the paint
* device belongs to the node, but not to the device itself. So
* the offset is set when the node is created, but not when the
* selection is initialized. This causes the X,Y values to be
* lost, since the selection doen not exist at the moment. That is
* why we save it separately.
*/
QScopedPointer<QPoint> deferredSelectionOffset;
KisAbstractProjectionPlaneSP projectionPlane;
KisSafeSelectionNodeProjectionStoreSP safeProjection;
void initSelectionImpl(KisSelectionSP copyFrom, KisLayerSP parentLayer, KisPaintDeviceSP copyFromDevice);
};
KisMask::KisMask(const QString & name)
: KisNode(nullptr)
, m_d(new Private(this))
{
setName(name);
m_d->safeProjection = new KisSafeSelectionNodeProjectionStore();
m_d->safeProjection->setImage(image());
}
KisMask::KisMask(const KisMask& rhs)
: KisNode(rhs)
, KisIndirectPaintingSupport()
, m_d(new Private(this))
{
setName(rhs.name());
m_d->safeProjection = new KisSafeSelectionNodeProjectionStore(*rhs.m_d->safeProjection);
if (rhs.m_d->selection) {
m_d->selection = new KisSelection(*rhs.m_d->selection.data());
m_d->selection->setParentNode(this);
KisPixelSelectionSP pixelSelection = m_d->selection->pixelSelection();
if (pixelSelection->framesInterface()) {
addKeyframeChannel(pixelSelection->keyframeChannel());
enableAnimation();
}
}
}
KisMask::~KisMask()
{
if (m_d->selection) {
m_d->selection->setParentNode(0);
}
delete m_d;
}
void KisMask::setImage(KisImageWSP image)
{
KisPaintDeviceSP parentPaintDevice = parent() ? parent()->original() : 0;
KisDefaultBoundsBaseSP defaultBounds = new KisSelectionDefaultBounds(parentPaintDevice);
if (m_d->selection) {
m_d->selection->setDefaultBounds(defaultBounds);
}
m_d->safeProjection->setImage(image);
KisNode::setImage(image);
}
bool KisMask::allowAsChild(KisNodeSP node) const
{
Q_UNUSED(node);
return false;
}
const KoColorSpace * KisMask::colorSpace() const
{
KisNodeSP parentNode = parent();
return parentNode ? parentNode->colorSpace() : 0;
}
const KoCompositeOp * KisMask::compositeOp() const
{
/**
* FIXME: This function duplicates the same function from
* KisLayer. We can't move it to KisBaseNode as it doesn't
* know anything about parent() method of KisNode
* Please think it over...
*/
const KoColorSpace *colorSpace = this->colorSpace();
if (!colorSpace) return 0;
const KoCompositeOp* op = colorSpace->compositeOp(compositeOpId());
return op ? op : colorSpace->compositeOp(COMPOSITE_OVER);
}
void KisMask::initSelection(KisSelectionSP copyFrom, KisLayerSP parentLayer)
{
m_d->initSelectionImpl(copyFrom, parentLayer, 0);
}
void KisMask::initSelection(KisPaintDeviceSP copyFromDevice, KisLayerSP parentLayer)
{
m_d->initSelectionImpl(0, parentLayer, copyFromDevice);
}
void KisMask::initSelection(KisLayerSP parentLayer)
{
m_d->initSelectionImpl(0, parentLayer, 0);
}
void KisMask::Private::initSelectionImpl(KisSelectionSP copyFrom, KisLayerSP parentLayer, KisPaintDeviceSP copyFromDevice)
{
Q_ASSERT(parentLayer);
KisPaintDeviceSP parentPaintDevice = parentLayer->original();
if (copyFrom) {
/**
* We can't use setSelection as we may not have parent() yet
*/
selection = new KisSelection(*copyFrom);
selection->setDefaultBounds(new KisSelectionDefaultBounds(parentPaintDevice));
- if (copyFrom->hasShapeSelection()) {
- delete selection->flatten();
- }
} else if (copyFromDevice) {
KritaUtils::DeviceCopyMode copyMode =
q->inherits("KisFilterMask") || q->inherits("KisTransparencyMask") ?
KritaUtils::CopyAllFrames : KritaUtils::CopySnapshot;
selection = new KisSelection(copyFromDevice, copyMode, new KisSelectionDefaultBounds(parentPaintDevice));
KisPixelSelectionSP pixelSelection = selection->pixelSelection();
if (pixelSelection->framesInterface()) {
KisRasterKeyframeChannel *keyframeChannel = pixelSelection->keyframeChannel();
keyframeChannel->setFilenameSuffix(".pixelselection");
q->addKeyframeChannel(keyframeChannel);
q->enableAnimation();
}
} else {
selection = new KisSelection(new KisSelectionDefaultBounds(parentPaintDevice));
selection->pixelSelection()->setDefaultPixel(KoColor(Qt::white, selection->pixelSelection()->colorSpace()));
if (deferredSelectionOffset) {
selection->setX(deferredSelectionOffset->x());
selection->setY(deferredSelectionOffset->y());
deferredSelectionOffset.reset();
}
}
selection->setParentNode(q);
selection->updateProjection();
}
KisSelectionSP KisMask::selection() const
{
return m_d->selection;
}
KisPaintDeviceSP KisMask::paintDevice() const
{
KisSelectionSP selection = this->selection();
return selection ? selection->pixelSelection() : 0;
}
KisPaintDeviceSP KisMask::original() const
{
return paintDevice();
}
KisPaintDeviceSP KisMask::projection() const
{
KisPaintDeviceSP originalDevice = original();
KisPaintDeviceSP result = originalDevice;
KisSelectionSP selection = this->selection();
if (selection && hasTemporaryTarget()) {
result = m_d->safeProjection->getDeviceLazy(selection)->pixelSelection();
}
return result;
}
KisAbstractProjectionPlaneSP KisMask::projectionPlane() const
{
return m_d->projectionPlane;
}
void KisMask::setSelection(KisSelectionSP selection)
{
m_d->selection = selection;
if (parent()) {
const KisLayer *parentLayer = qobject_cast<const KisLayer*>(parent());
m_d->selection->setDefaultBounds(new KisDefaultBounds(parentLayer->image()));
}
m_d->selection->setParentNode(this);
}
void KisMask::select(const QRect & rc, quint8 selectedness)
{
KisSelectionSP sel = selection();
KisPixelSelectionSP psel = sel->pixelSelection();
psel->select(rc, selectedness);
sel->updateProjection(rc);
}
QRect KisMask::decorateRect(KisPaintDeviceSP &src,
KisPaintDeviceSP &dst,
const QRect & rc,
PositionToFilthy maskPos) const
{
Q_UNUSED(src);
Q_UNUSED(dst);
Q_UNUSED(maskPos);
Q_ASSERT_X(0, "KisMask::decorateRect", "Should be overridden by successors");
return rc;
}
bool KisMask::paintsOutsideSelection() const
{
return false;
}
void KisMask::apply(KisPaintDeviceSP projection, const QRect &applyRect, const QRect &needRect, PositionToFilthy maskPos) const
{
if (selection()) {
flattenSelectionProjection(m_d->selection, applyRect);
KisSelectionSP effectiveSelection = m_d->selection;
{
// Access temporary target under the lock held
KisIndirectPaintingSupport::ReadLocker l(this);
if (!paintsOutsideSelection()) {
// extent of m_d->selection should also be accessed under a lock,
// because it might be being merged in by the temporary target atm
QRect effectiveExtent = m_d->selection->selectedRect();
if (hasTemporaryTarget()) {
effectiveExtent |= temporaryTarget()->extent();
}
if(!effectiveExtent.intersects(applyRect)) {
return;
}
}
if (hasTemporaryTarget()) {
effectiveSelection = m_d->safeProjection->getDeviceLazy(m_d->selection);
KisPainter::copyAreaOptimized(applyRect.topLeft(),
m_d->selection->pixelSelection(),
effectiveSelection->pixelSelection(), applyRect);
KisPainter gc(effectiveSelection->pixelSelection());
setupTemporaryPainter(&gc);
gc.bitBlt(applyRect.topLeft(), temporaryTarget(), applyRect);
} else {
m_d->safeProjection->releaseDevice();
}
mergeInMaskInternal(projection, effectiveSelection, applyRect, needRect, maskPos);
}
} else {
mergeInMaskInternal(projection, 0, applyRect, needRect, maskPos);
}
}
void KisMask::mergeInMaskInternal(KisPaintDeviceSP projection,
KisSelectionSP effectiveSelection,
const QRect &applyRect,
const QRect &preparedNeedRect,
KisNode::PositionToFilthy maskPos) const
{
KisCachedPaintDevice::Guard d1(projection, m_d->paintDeviceCache);
KisPaintDeviceSP cacheDevice = d1.device();
if (effectiveSelection) {
QRect updatedRect = decorateRect(projection, cacheDevice, applyRect, maskPos);
// masks don't have any compositioning
KisPainter::copyAreaOptimized(updatedRect.topLeft(), cacheDevice, projection, updatedRect, effectiveSelection);
} else {
cacheDevice->makeCloneFromRough(projection, preparedNeedRect);
projection->clear(preparedNeedRect);
decorateRect(cacheDevice, projection, applyRect, maskPos);
}
}
void KisMask::flattenSelectionProjection(KisSelectionSP selection, const QRect &dirtyRect) const
{
selection->updateProjection(dirtyRect);
}
QRect KisMask::needRect(const QRect &rect, PositionToFilthy pos) const
{
Q_UNUSED(pos);
QRect resultRect = rect;
if (m_d->selection) {
QRect selectionExtent = m_d->selection->selectedRect();
// copy for thread safety!
KisPaintDeviceSP temporaryTarget = this->temporaryTarget();
if (temporaryTarget) {
selectionExtent |= temporaryTarget->extent();
}
resultRect &= selectionExtent;
}
return resultRect;
}
QRect KisMask::changeRect(const QRect &rect, PositionToFilthy pos) const
{
return KisMask::needRect(rect, pos);
}
QRect KisMask::extent() const
{
QRect resultRect;
if (m_d->selection) {
resultRect = m_d->selection->selectedRect();
// copy for thread safety!
KisPaintDeviceSP temporaryTarget = this->temporaryTarget();
if (temporaryTarget) {
resultRect |= temporaryTarget->extent();
}
} else if (KisNodeSP parent = this->parent()) {
resultRect = parent->extent();
}
return resultRect;
}
QRect KisMask::exactBounds() const
{
QRect resultRect;
if (m_d->selection) {
resultRect = m_d->selection->selectedExactRect();
// copy for thread safety!
KisPaintDeviceSP temporaryTarget = this->temporaryTarget();
if (temporaryTarget) {
resultRect |= temporaryTarget->exactBounds();
}
} else if (KisNodeSP parent = this->parent()) {
resultRect = parent->exactBounds();
}
return resultRect;
}
qint32 KisMask::x() const
{
return m_d->selection ? m_d->selection->x() :
m_d->deferredSelectionOffset ? m_d->deferredSelectionOffset->x() :
parent() ? parent()->x() : 0;
}
qint32 KisMask::y() const
{
return m_d->selection ? m_d->selection->y() :
m_d->deferredSelectionOffset ? m_d->deferredSelectionOffset->y() :
parent() ? parent()->y() : 0;
}
void KisMask::setX(qint32 x)
{
if (m_d->selection) {
m_d->selection->setX(x);
} else if (!m_d->deferredSelectionOffset) {
m_d->deferredSelectionOffset.reset(new QPoint(x, 0));
} else {
m_d->deferredSelectionOffset->rx() = x;
}
}
void KisMask::setY(qint32 y)
{
if (m_d->selection) {
m_d->selection->setY(y);
} else if (!m_d->deferredSelectionOffset) {
m_d->deferredSelectionOffset.reset(new QPoint(0, y));
} else {
m_d->deferredSelectionOffset->ry() = y;
}
}
QRect KisMask::nonDependentExtent() const
{
return QRect();
}
-QImage KisMask::createThumbnail(qint32 w, qint32 h)
+QImage KisMask::createThumbnail(qint32 w, qint32 h, Qt::AspectRatioMode aspectRatioMode)
{
KisPaintDeviceSP originalDevice =
selection() ? selection()->projection() : 0;
return originalDevice ?
- originalDevice->createThumbnail(w, h, 1,
+ originalDevice->createThumbnail(w, h, aspectRatioMode, 1,
KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags()) : QImage();
}
void KisMask::testingInitSelection(const QRect &rect, KisLayerSP parentLayer)
{
if (parentLayer) {
m_d->selection = new KisSelection(new KisSelectionDefaultBounds(parentLayer->paintDevice()));
} else {
m_d->selection = new KisSelection();
}
m_d->selection->pixelSelection()->select(rect, OPACITY_OPAQUE_U8);
m_d->selection->updateProjection(rect);
m_d->selection->setParentNode(this);
}
KisKeyframeChannel *KisMask::requestKeyframeChannel(const QString &id)
{
if (id == KisKeyframeChannel::Content.id()) {
KisPaintDeviceSP device = paintDevice();
if (device) {
KisRasterKeyframeChannel *contentChannel = device->createKeyframeChannel(KisKeyframeChannel::Content);
contentChannel->setFilenameSuffix(".pixelselection");
return contentChannel;
}
}
return KisNode::requestKeyframeChannel(id);
}
void KisMask::baseNodeChangedCallback()
{
KisNodeSP up = parent();
KisLayer *layer = dynamic_cast<KisLayer*>(up.data());
if (layer) {
layer->notifyChildMaskChanged();
}
KisNode::baseNodeChangedCallback();
}
diff --git a/libs/image/kis_mask.h b/libs/image/kis_mask.h
index 2c11ed079c..862f65b3b4 100644
--- a/libs/image/kis_mask.h
+++ b/libs/image/kis_mask.h
@@ -1,236 +1,236 @@
/*
* Copyright (c) 2006 Boudewijn Rempt <boud@valdyas.org>
* (c) 2009 Dmitry Kazakov <dimula73@gmail.com>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.b
*/
#ifndef _KIS_MASK_
#define _KIS_MASK_
#include <QRect>
#include "kis_types.h"
#include "kis_global.h"
#include "kis_node.h"
#include "kis_indirect_painting_support.h"
#include <kritaimage_export.h>
/**
KisMask is the base class for all single channel
mask-like paint devices in Krita. Masks can be rendered in different
ways at different moments during the rendering stack. Masks are
"owned" by layers (of any type), and cannot occur by themselves on
themselves.
The properties that masks implement are made available through the
iterators created on their parent layer, or through iterators that
can be created on the paint device that holds the mask data: masks
are just paint devices, too.
Masks should show up in the layerbox as sub-layers for the layer they
are associated with and be ccp'able and draggable to other layers.
Examples of masks are:
- filter masks: like the alpha filter mask that is the most common
type of mask and is simply known as "mask" in the
gui. Other filter masks use any of krita's filters to
filter the pixels of their parent. (In this they
differ from adjustment layers, which filter all
layers under them in their group stack).
- selections: the selection mask is rendered after composition and
zooming and determines the selectedness of the pixels of the parent
layer.
- painterly overlays: painterly overlays indicate a particular
property of the pixel in the parent paint device they are associated
with, like wetness, height or gravity.
XXX: For now, all masks are 8 bit. Make the channel depth settable.
*/
class KRITAIMAGE_EXPORT KisMask : public KisNode, public KisIndirectPaintingSupport
{
Q_OBJECT
public:
/**
* Create a new KisMask.
*/
KisMask(const QString & name);
/**
* Copy the mask
*/
KisMask(const KisMask& rhs);
~KisMask() override;
void setImage(KisImageWSP image) override;
bool allowAsChild(KisNodeSP node) const override;
/**
* @brief initSelection initializes the selection for the mask from
* the given selection's projection.
* @param copyFrom the selection we base the mask on
* @param parentLayer the parent of this mask; it determines the default bounds of the mask.
*/
void initSelection(KisSelectionSP copyFrom, KisLayerSP parentLayer);
/**
* @brief initSelection initializes the selection for the mask from
* the given paint device.
* @param copyFromDevice the paint device we base the mask on
* @param parentLayer the parent of this mask; it determines the default bounds of the mask.
*/
void initSelection(KisPaintDeviceSP copyFromDevice, KisLayerSP parentLayer);
/**
* @brief initSelection initializes an empty selection
* @param parentLayer the parent of this mask; it determines the default bounds of the mask.
*/
void initSelection(KisLayerSP parentLayer);
const KoColorSpace * colorSpace() const override;
const KoCompositeOp * compositeOp() const override;
/**
* Return the selection associated with this mask. A selection can
* contain both a paint device and shapes.
*/
KisSelectionSP selection() const;
/**
* @return the selection: if you paint on mask, you paint on the selections
*/
KisPaintDeviceSP paintDevice() const override;
/**
* @return the same as paintDevice()
*/
KisPaintDeviceSP original() const override;
/**
* @return the same as paintDevice()
*/
KisPaintDeviceSP projection() const override;
KisAbstractProjectionPlaneSP projectionPlane() const override;
/**
* Change the selection to the specified selection object. The
* selection is deep copied.
*/
void setSelection(KisSelectionSP selection);
/**
* Selected the specified rect with the specified amount of selectedness.
*/
void select(const QRect & rc, quint8 selectedness = MAX_SELECTED);
/**
* The extent and bounds of the mask are those of the selection inside
*/
QRect extent() const override;
QRect exactBounds() const override;
/**
* overridden from KisBaseNode
*/
qint32 x() const override;
/**
* overridden from KisBaseNode
*/
void setX(qint32 x) override;
/**
* overridden from KisBaseNode
*/
qint32 y() const override;
/**
* overridden from KisBaseNode
*/
void setY(qint32 y) override;
/**
* Usually masks themselves do not have any paint device and
* all their final effect on the layer stack is computed using
* the changeRect() of the dirty rect of the parent layer. Their
* extent() and exectBounds() methods work the same way: by taking
* the extent of the parent layer and computing the rect basing
* on it. But some of the masks like Colorize Mask may have their
* own "projection", which is painted independently from the changed
* area of the parent layer. This additional "non-dependent" extent
* is added to the extent of the parent layer.
*/
virtual QRect nonDependentExtent() const;
QRect needRect(const QRect &rect, PositionToFilthy pos = N_FILTHY) const override;
QRect changeRect(const QRect &rect, PositionToFilthy pos = N_FILTHY) const override;
- QImage createThumbnail(qint32 w, qint32 h) override;
+ QImage createThumbnail(qint32 w, qint32 h, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio) override;
void testingInitSelection(const QRect &rect, KisLayerSP parentLayer);
protected:
/**
* Apply the effect the projection using the mask as a selection.
* Made public in KisEffectMask
*/
void apply(KisPaintDeviceSP projection, const QRect & applyRect, const QRect & needRect, PositionToFilthy maskPos) const;
virtual void mergeInMaskInternal(KisPaintDeviceSP projection,
KisSelectionSP effectiveSelection,
const QRect &applyRect, const QRect &preparedNeedRect,
PositionToFilthy maskPos) const;
/**
* A special callback for calling selection->updateProjection() during
* the projection calculation process. Some masks (e.g. selection masks)
* don't need it, because they do it separately.
*/
virtual void flattenSelectionProjection(KisSelectionSP selection, const QRect &dirtyRect) const;
virtual QRect decorateRect(KisPaintDeviceSP &src,
KisPaintDeviceSP &dst,
const QRect & rc,
PositionToFilthy maskPos) const;
virtual bool paintsOutsideSelection() const;
KisKeyframeChannel *requestKeyframeChannel(const QString &id) override;
void baseNodeChangedCallback() override;
private:
friend class KisMaskProjectionPlane;
private:
struct Private;
Private * const m_d;
};
#endif
diff --git a/libs/image/kis_paint_device.cc b/libs/image/kis_paint_device.cc
index cd96946f37..9580ea884d 100644
--- a/libs/image/kis_paint_device.cc
+++ b/libs/image/kis_paint_device.cc
@@ -1,2250 +1,2276 @@
/*
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
* Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
*
* 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_paint_device.h"
#include <QRect>
#include <QTransform>
#include <QImage>
#include <QList>
#include <QHash>
#include <QIODevice>
#include <qmath.h>
#include <KisRegion.h>
#include <klocalizedstring.h>
#include <KoChannelInfo.h>
#include <KoColorProfile.h>
#include <KoColor.h>
#include <KoColorSpace.h>
#include <KoColorSpaceRegistry.h>
#include <KoColorModelStandardIds.h>
#include <KoIntegerMaths.h>
#include <KoMixColorsOp.h>
#include <KoUpdater.h>
#include "kis_image.h"
#include "kis_random_sub_accessor.h"
#include "kis_selection.h"
#include "kis_node.h"
#include "kis_datamanager.h"
#include "kis_paint_device_writer.h"
#include "kis_selection_component.h"
#include "kis_pixel_selection.h"
#include "kis_repeat_iterators_pixel.h"
#include "kis_fixed_paint_device.h"
#include "tiles3/kis_hline_iterator.h"
#include "tiles3/kis_vline_iterator.h"
#include "tiles3/kis_random_accessor.h"
#include "kis_default_bounds.h"
#include "kis_lod_transform.h"
#include "kis_raster_keyframe_channel.h"
#include "kis_paint_device_cache.h"
#include "kis_paint_device_data.h"
#include "kis_paint_device_frames_interface.h"
#include "kis_transform_worker.h"
#include "kis_filter_strategy.h"
#include "krita_utils.h"
struct KisPaintDeviceSPStaticRegistrar {
KisPaintDeviceSPStaticRegistrar() {
qRegisterMetaType<KisPaintDeviceSP>("KisPaintDeviceSP");
}
};
static KisPaintDeviceSPStaticRegistrar __registrar;
struct KisPaintDevice::Private
{
/**
* Used when the paint device is loading to ensure no lod/animation
* interferes the process.
*/
static const KisDefaultBoundsSP transitionalDefaultBounds;
public:
class KisPaintDeviceStrategy;
class KisPaintDeviceWrappedStrategy;
class DeviceChangeProfileCommand;
class DeviceChangeColorSpaceCommand;
Private(KisPaintDevice *paintDevice);
~Private();
KisPaintDevice *q;
KisNodeWSP parent;
QScopedPointer<KisRasterKeyframeChannel> contentChannel;
KisDefaultBoundsBaseSP defaultBounds;
QScopedPointer<KisPaintDeviceStrategy> basicStrategy;
QScopedPointer<KisPaintDeviceWrappedStrategy> wrappedStrategy;
QMutex m_wrappedStrategyMutex;
QScopedPointer<KisPaintDeviceFramesInterface> framesInterface;
bool isProjectionDevice;
KisPaintDeviceStrategy* currentStrategy();
void init(const KoColorSpace *cs, const quint8 *defaultPixel);
void convertColorSpace(const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags, KUndo2Command *parentCommand);
bool assignProfile(const KoColorProfile * profile, KUndo2Command *parentCommand);
+ KUndo2Command* reincarnateWithDetachedHistory(bool copyContent);
+
+
inline const KoColorSpace* colorSpace() const
{
return currentData()->colorSpace();
}
inline KisDataManagerSP dataManager() const
{
return currentData()->dataManager();
}
inline qint32 x() const
{
return currentData()->x();
}
inline qint32 y() const
{
return currentData()->y();
}
inline void setX(qint32 x)
{
currentData()->setX(x);
}
inline void setY(qint32 y)
{
currentData()->setY(y);
}
inline KisPaintDeviceCache* cache()
{
return currentData()->cache();
}
inline KisIteratorCompleteListener* cacheInvalidator() {
return currentData()->cacheInvalidator();
}
void cloneAllDataObjects(Private *rhs, bool copyFrames)
{
m_lodData.reset();
m_externalFrameData.reset();
if (!m_frames.isEmpty()) {
m_frames.clear();
}
if (!copyFrames) {
if (m_data) {
m_data->prepareClone(rhs->currentNonLodData(), true);
} else {
m_data = toQShared(new KisPaintDeviceData(q, rhs->currentNonLodData(), true));
}
} else {
if (m_data && !rhs->m_data) {
m_data.clear();
} else if (!m_data && rhs->m_data) {
m_data = toQShared(new KisPaintDeviceData(q, rhs->m_data.data(), true));
} else if (m_data && rhs->m_data) {
m_data->prepareClone(rhs->m_data.data(), true);
}
if (!rhs->m_frames.isEmpty()) {
FramesHash::const_iterator it = rhs->m_frames.constBegin();
FramesHash::const_iterator end = rhs->m_frames.constEnd();
for (; it != end; ++it) {
DataSP data = toQShared(new KisPaintDeviceData(q, it.value().data(), true));
m_frames.insert(it.key(), data);
}
}
m_nextFreeFrameId = rhs->m_nextFreeFrameId;
}
if (rhs->m_lodData) {
m_lodData.reset(new KisPaintDeviceData(q, rhs->m_lodData.data(), true));
}
}
void prepareClone(KisPaintDeviceSP src)
{
prepareCloneImpl(src, src->m_d->currentData());
KIS_SAFE_ASSERT_RECOVER_NOOP(fastBitBltPossible(src));
}
bool fastBitBltPossible(KisPaintDeviceSP src)
{
return fastBitBltPossibleImpl(src->m_d->currentData());
}
int currentFrameId() const
{
KIS_ASSERT_RECOVER(contentChannel) {
return -1;
}
return !defaultBounds->currentLevelOfDetail() ?
contentChannel->frameIdAt(defaultBounds->currentTime()) :
-1;
}
KisDataManagerSP frameDataManager(int frameId) const
{
DataSP data = m_frames[frameId];
return data->dataManager();
}
void invalidateFrameCache(int frameId)
{
DataSP data = m_frames[frameId];
return data->cache()->invalidate();
}
private:
typedef KisPaintDeviceData Data;
typedef QSharedPointer<Data> DataSP;
typedef QHash<int, DataSP> FramesHash;
class FrameInsertionCommand : public KUndo2Command
{
public:
FrameInsertionCommand(FramesHash *hash, DataSP data, int frameId, bool insert, KUndo2Command *parentCommand)
: KUndo2Command(parentCommand),
m_hash(hash),
m_data(data),
m_frameId(frameId),
m_insert(insert)
{
}
void redo() override
{
doSwap(m_insert);
}
void undo() override
{
doSwap(!m_insert);
}
private:
void doSwap(bool insert)
{
if (insert) {
m_hash->insert(m_frameId, m_data);
} else {
DataSP deletedData = m_hash->take(m_frameId);
}
}
private:
FramesHash *m_hash;
DataSP m_data;
int m_frameId;
bool m_insert;
};
public:
int getNextFrameId() {
int frameId = 0;
while (m_frames.contains(frameId = m_nextFreeFrameId++));
KIS_SAFE_ASSERT_RECOVER_NOOP(!m_frames.contains(frameId));
return frameId;
}
int createFrame(bool copy, int copySrc, const QPoint &offset, KUndo2Command *parentCommand)
{
KIS_ASSERT_RECOVER(parentCommand) {
return -1;
}
DataSP data;
bool initialFrame = false;
if (m_frames.isEmpty()) {
/**
* Here we move the contents of the paint device to the
* new frame and clear m_data to make the "background" for
* the areas where there is no frame at all.
*/
data = toQShared(new Data(q, m_data.data(), true));
m_data->dataManager()->clear();
m_data->cache()->invalidate();
initialFrame = true;
} else if (copy) {
DataSP srcData = m_frames[copySrc];
data = toQShared(new Data(q, srcData.data(), true));
} else {
DataSP srcData = m_frames.begin().value();
data = toQShared(new Data(q, srcData.data(), false));
}
if (!initialFrame && !copy) {
data->setX(offset.x());
data->setY(offset.y());
}
int frameId = getNextFrameId();
KUndo2Command *cmd =
new FrameInsertionCommand(&m_frames,
data,
frameId, true,
parentCommand);
cmd->redo();
return frameId;
}
void deleteFrame(int frame, KUndo2Command *parentCommand)
{
KIS_ASSERT_RECOVER_RETURN(m_frames.contains(frame));
KIS_ASSERT_RECOVER_RETURN(parentCommand);
DataSP deletedData = m_frames[frame];
KUndo2Command *cmd =
new FrameInsertionCommand(&m_frames,
deletedData,
frame, false,
parentCommand);
cmd->redo();
}
QRect frameBounds(int frameId)
{
DataSP data = m_frames[frameId];
QRect extent = data->dataManager()->extent();
extent.translate(data->x(), data->y());
return extent;
}
QPoint frameOffset(int frameId) const
{
DataSP data = m_frames[frameId];
return QPoint(data->x(), data->y());
}
void setFrameOffset(int frameId, const QPoint &offset)
{
DataSP data = m_frames[frameId];
data->setX(offset.x());
data->setY(offset.y());
}
const QList<int> frameIds() const
{
return m_frames.keys();
}
bool readFrame(QIODevice *stream, int frameId)
{
bool retval = false;
DataSP data = m_frames[frameId];
retval = data->dataManager()->read(stream);
data->cache()->invalidate();
return retval;
}
bool writeFrame(KisPaintDeviceWriter &store, int frameId)
{
DataSP data = m_frames[frameId];
return data->dataManager()->write(store);
}
void setFrameDefaultPixel(const KoColor &defPixel, int frameId)
{
DataSP data = m_frames[frameId];
KoColor color(defPixel);
color.convertTo(data->colorSpace());
data->dataManager()->setDefaultPixel(color.data());
}
KoColor frameDefaultPixel(int frameId) const
{
DataSP data = m_frames[frameId];
return KoColor(data->dataManager()->defaultPixel(),
data->colorSpace());
}
void fetchFrame(int frameId, KisPaintDeviceSP targetDevice);
void uploadFrame(int srcFrameId, int dstFrameId, KisPaintDeviceSP srcDevice);
void uploadFrame(int dstFrameId, KisPaintDeviceSP srcDevice);
void uploadFrameData(DataSP srcData, DataSP dstData);
struct LodDataStructImpl;
LodDataStruct* createLodDataStruct(int lod);
void updateLodDataStruct(LodDataStruct *dst, const QRect &srcRect);
void uploadLodDataStruct(LodDataStruct *dst);
KisRegion regionForLodSyncing() const;
void updateLodDataManager(KisDataManager *srcDataManager,
KisDataManager *dstDataManager, const QPoint &srcOffset, const QPoint &dstOffset,
const QRect &originalRect, int lod);
void generateLodCloneDevice(KisPaintDeviceSP dst, const QRect &originalRect, int lod);
void tesingFetchLodDevice(KisPaintDeviceSP targetDevice);
private:
qint64 estimateDataSize(Data *data) const {
const QRect &rc = data->dataManager()->extent();
return rc.width() * rc.height() * data->colorSpace()->pixelSize();
}
public:
void estimateMemoryStats(qint64 &imageData, qint64 &temporaryData, qint64 &lodData) const {
imageData = 0;
temporaryData = 0;
lodData = 0;
if (m_data) {
imageData += estimateDataSize(m_data.data());
}
if (m_lodData) {
lodData += estimateDataSize(m_lodData.data());
}
if (m_externalFrameData) {
temporaryData += estimateDataSize(m_externalFrameData.data());
}
Q_FOREACH (DataSP value, m_frames.values()) {
imageData += estimateDataSize(value.data());
}
}
private:
inline DataSP currentFrameData() const
{
DataSP data;
const int numberOfFrames = contentChannel->keyframeCount();
if (numberOfFrames > 1) {
int frameId = contentChannel->frameIdAt(defaultBounds->currentTime());
if (frameId == -1) {
data = m_data;
} else {
KIS_ASSERT_RECOVER(m_frames.contains(frameId)) {
return m_frames.begin().value();
}
data = m_frames[frameId];
}
} else if (numberOfFrames == 1) {
data = m_frames.begin().value();
} else {
data = m_data;
}
return data;
}
inline Data* currentNonLodData() const
{
Data *data = m_data.data();
if (contentChannel) {
data = currentFrameData().data();
} else if (isProjectionDevice && defaultBounds->externalFrameActive()) {
if (!m_externalFrameData) {
QMutexLocker l(&m_dataSwitchLock);
if (!m_externalFrameData) {
m_externalFrameData.reset(new Data(q, m_data.data(), false));
}
}
data = m_externalFrameData.data();
}
return data;
}
inline void ensureLodDataPresent() const
{
if (!m_lodData) {
Data *srcData = currentNonLodData();
QMutexLocker l(&m_dataSwitchLock);
if (!m_lodData) {
m_lodData.reset(new Data(q, srcData, false));
}
}
}
inline Data* currentData() const
{
Data *data;
if (defaultBounds->currentLevelOfDetail()) {
ensureLodDataPresent();
data = m_lodData.data();
} else {
data = currentNonLodData();
}
return data;
}
void prepareCloneImpl(KisPaintDeviceSP src, Data *srcData)
{
/**
* The result of currentData() depends on the current
* level of detail and animation frame index. So we
* should first connect the device to the new
* default bounds object, and only after that ask
* currentData() to start cloning.
*/
q->setDefaultPixel(KoColor(srcData->dataManager()->defaultPixel(), colorSpace()));
q->setDefaultBounds(src->defaultBounds());
currentData()->prepareClone(srcData);
}
bool fastBitBltPossibleImpl(Data *srcData)
{
return x() == srcData->x() && y() == srcData->y() &&
*colorSpace() == *srcData->colorSpace();
}
QList<Data*> allDataObjects() const
{
QList<Data*> dataObjects;
if (m_frames.isEmpty()) {
dataObjects << m_data.data();
}
dataObjects << m_lodData.data();
dataObjects << m_externalFrameData.data();
Q_FOREACH (DataSP value, m_frames.values()) {
dataObjects << value.data();
}
return dataObjects;
}
void transferFromData(Data *data, KisPaintDeviceSP targetDevice);
struct Q_DECL_HIDDEN StrategyPolicy;
typedef KisSequentialIteratorBase<ReadOnlyIteratorPolicy<StrategyPolicy>, StrategyPolicy> InternalSequentialConstIterator;
typedef KisSequentialIteratorBase<WritableIteratorPolicy<StrategyPolicy>, StrategyPolicy> InternalSequentialIterator;
private:
friend class KisPaintDeviceFramesInterface;
private:
DataSP m_data;
mutable QScopedPointer<Data> m_lodData;
mutable QScopedPointer<Data> m_externalFrameData;
mutable QMutex m_dataSwitchLock;
FramesHash m_frames;
int m_nextFreeFrameId;
};
const KisDefaultBoundsSP KisPaintDevice::Private::transitionalDefaultBounds = new KisDefaultBounds();
#include "kis_paint_device_strategies.h"
KisPaintDevice::Private::Private(KisPaintDevice *paintDevice)
: q(paintDevice),
basicStrategy(new KisPaintDeviceStrategy(paintDevice, this)),
isProjectionDevice(false),
m_data(new Data(paintDevice)),
m_nextFreeFrameId(0)
{
}
KisPaintDevice::Private::~Private()
{
m_frames.clear();
}
KisPaintDevice::Private::KisPaintDeviceStrategy* KisPaintDevice::Private::currentStrategy()
{
if (!defaultBounds->wrapAroundMode()) {
return basicStrategy.data();
}
const QRect wrapRect = defaultBounds->bounds();
if (!wrappedStrategy || wrappedStrategy->wrapRect() != wrapRect) {
QMutexLocker locker(&m_wrappedStrategyMutex);
if (!wrappedStrategy) {
wrappedStrategy.reset(new KisPaintDeviceWrappedStrategy(wrapRect, q, this));
} else if (wrappedStrategy->wrapRect() != wrapRect) {
wrappedStrategy->setWrapRect(wrapRect);
}
}
return wrappedStrategy.data();
}
struct KisPaintDevice::Private::StrategyPolicy {
StrategyPolicy(KisPaintDevice::Private::KisPaintDeviceStrategy *strategy,
KisDataManager *dataManager, qint32 offsetX, qint32 offsetY)
: m_strategy(strategy),
m_dataManager(dataManager),
m_offsetX(offsetX),
m_offsetY(offsetY)
{
}
KisHLineConstIteratorSP createConstIterator(const QRect &rect)
{
return m_strategy->createHLineConstIteratorNG(m_dataManager, rect.x(), rect.y(), rect.width(), m_offsetX, m_offsetY);
}
KisHLineIteratorSP createIterator(const QRect &rect)
{
return m_strategy->createHLineIteratorNG(m_dataManager, rect.x(), rect.y(), rect.width(), m_offsetX, m_offsetY);
}
int pixelSize() const
{
return m_dataManager->pixelSize();
}
KisPaintDeviceStrategy *m_strategy;
KisDataManager *m_dataManager;
int m_offsetX;
int m_offsetY;
};
struct KisPaintDevice::Private::LodDataStructImpl : public KisPaintDevice::LodDataStruct {
LodDataStructImpl(Data *_lodData) : lodData(_lodData) {}
QScopedPointer<Data> lodData;
};
KisRegion KisPaintDevice::Private::regionForLodSyncing() const
{
Data *srcData = currentNonLodData();
return srcData->dataManager()->region().translated(srcData->x(), srcData->y());
}
KisPaintDevice::LodDataStruct* KisPaintDevice::Private::createLodDataStruct(int newLod)
{
KIS_SAFE_ASSERT_RECOVER_NOOP(newLod > 0);
Data *srcData = currentNonLodData();
Data *lodData = new Data(q, srcData, false);
LodDataStruct *lodStruct = new LodDataStructImpl(lodData);
int expectedX = KisLodTransform::coordToLodCoord(srcData->x(), newLod);
int expectedY = KisLodTransform::coordToLodCoord(srcData->y(), newLod);
/**
* We compare color spaces as pure pointers, because they must be
* exactly the same, since they come from the common source.
*/
if (lodData->levelOfDetail() != newLod ||
lodData->colorSpace() != srcData->colorSpace() ||
lodData->x() != expectedX ||
lodData->y() != expectedY) {
lodData->prepareClone(srcData);
lodData->setLevelOfDetail(newLod);
lodData->setX(expectedX);
lodData->setY(expectedY);
// FIXME: different kind of synchronization
}
lodData->cache()->invalidate();
return lodStruct;
}
void KisPaintDevice::Private::updateLodDataManager(KisDataManager *srcDataManager,
KisDataManager *dstDataManager,
const QPoint &srcOffset,
const QPoint &dstOffset,
const QRect &originalRect,
int lod)
{
if (originalRect.isEmpty()) return;
const int srcStepSize = 1 << lod;
KIS_ASSERT_RECOVER_RETURN(lod > 0);
const QRect srcRect = KisLodTransform::alignedRect(originalRect, lod);
const QRect dstRect = KisLodTransform::scaledRect(srcRect, lod);
if (!srcRect.isValid() || !dstRect.isValid()) return;
KIS_ASSERT_RECOVER_NOOP(srcRect.width() / srcStepSize == dstRect.width());
const int pixelSize = srcDataManager->pixelSize();
int rowsAccumulated = 0;
int columnsAccumulated = 0;
KoMixColorsOp *mixOp = colorSpace()->mixColorsOp();
QScopedArrayPointer<quint8> blendData(new quint8[srcStepSize * srcRect.width() * pixelSize]);
quint8 *blendDataPtr = blendData.data();
int blendDataOffset = 0;
const int srcCellSize = srcStepSize * srcStepSize;
const int srcCellStride = srcCellSize * pixelSize;
const int srcStepStride = srcStepSize * pixelSize;
const int srcColumnStride = (srcStepSize - 1) * srcStepStride;
QScopedArrayPointer<qint16> weights(new qint16[srcCellSize]);
{
const qint16 averageWeight = qCeil(255.0 / srcCellSize);
const qint16 extraWeight = averageWeight * srcCellSize - 255;
KIS_ASSERT_RECOVER_NOOP(extraWeight == 1);
for (int i = 0; i < srcCellSize - 1; i++) {
weights[i] = averageWeight;
}
weights[srcCellSize - 1] = averageWeight - extraWeight;
}
InternalSequentialConstIterator srcIntIt(StrategyPolicy(currentStrategy(), srcDataManager, srcOffset.x(), srcOffset.y()), srcRect);
InternalSequentialIterator dstIntIt(StrategyPolicy(currentStrategy(), dstDataManager, dstOffset.x(), dstOffset.y()), dstRect);
int rowsRemaining = srcRect.height();
while (rowsRemaining > 0) {
int colsRemaining = srcRect.width();
while (colsRemaining > 0 && srcIntIt.nextPixel()) {
memcpy(blendDataPtr, srcIntIt.rawDataConst(), pixelSize);
blendDataPtr += pixelSize;
columnsAccumulated++;
if (columnsAccumulated >= srcStepSize) {
blendDataPtr += srcColumnStride;
columnsAccumulated = 0;
}
colsRemaining--;
}
rowsAccumulated++;
if (rowsAccumulated >= srcStepSize) {
// blend and write the final data
blendDataPtr = blendData.data();
int colsRemaining = dstRect.width();
while (colsRemaining > 0 && dstIntIt.nextPixel()) {
mixOp->mixColors(blendDataPtr, weights.data(), srcCellSize, dstIntIt.rawData());
blendDataPtr += srcCellStride;
colsRemaining--;
}
// reset counters
rowsAccumulated = 0;
blendDataPtr = blendData.data();
blendDataOffset = 0;
} else {
blendDataOffset += srcStepStride;
blendDataPtr = blendData.data() + blendDataOffset;
}
rowsRemaining--;
}
}
void KisPaintDevice::Private::updateLodDataStruct(LodDataStruct *_dst, const QRect &originalRect)
{
LodDataStructImpl *dst = dynamic_cast<LodDataStructImpl*>(_dst);
KIS_SAFE_ASSERT_RECOVER_RETURN(dst);
Data *lodData = dst->lodData.data();
Data *srcData = currentNonLodData();
const int lod = lodData->levelOfDetail();
updateLodDataManager(srcData->dataManager().data(), lodData->dataManager().data(),
QPoint(srcData->x(), srcData->y()),
QPoint(lodData->x(), lodData->y()),
originalRect, lod);
}
void KisPaintDevice::Private::generateLodCloneDevice(KisPaintDeviceSP dst, const QRect &originalRect, int lod)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(fastBitBltPossible(dst));
Data *srcData = currentNonLodData();
updateLodDataManager(srcData->dataManager().data(), dst->dataManager().data(),
QPoint(srcData->x(), srcData->y()),
QPoint(dst->x(), dst->y()),
originalRect, lod);
}
void KisPaintDevice::Private::uploadLodDataStruct(LodDataStruct *_dst)
{
LodDataStructImpl *dst = dynamic_cast<LodDataStructImpl*>(_dst);
KIS_SAFE_ASSERT_RECOVER_RETURN(dst);
KIS_SAFE_ASSERT_RECOVER_RETURN(
dst->lodData->levelOfDetail() == defaultBounds->currentLevelOfDetail());
ensureLodDataPresent();
m_lodData->prepareClone(dst->lodData.data());
m_lodData->dataManager()->bitBltRough(dst->lodData->dataManager(), dst->lodData->dataManager()->extent());
}
void KisPaintDevice::Private::transferFromData(Data *data, KisPaintDeviceSP targetDevice)
{
QRect extent = data->dataManager()->extent();
extent.translate(data->x(), data->y());
targetDevice->m_d->prepareCloneImpl(q, data);
targetDevice->m_d->currentStrategy()->fastBitBltRough(data->dataManager(), extent);
}
void KisPaintDevice::Private::fetchFrame(int frameId, KisPaintDeviceSP targetDevice)
{
DataSP data = m_frames[frameId];
transferFromData(data.data(), targetDevice);
}
void KisPaintDevice::Private::uploadFrame(int srcFrameId, int dstFrameId, KisPaintDeviceSP srcDevice)
{
DataSP dstData = m_frames[dstFrameId];
KIS_ASSERT_RECOVER_RETURN(dstData);
DataSP srcData = srcDevice->m_d->m_frames[srcFrameId];
KIS_ASSERT_RECOVER_RETURN(srcData);
uploadFrameData(srcData, dstData);
}
void KisPaintDevice::Private::uploadFrame(int dstFrameId, KisPaintDeviceSP srcDevice)
{
DataSP dstData = m_frames[dstFrameId];
KIS_ASSERT_RECOVER_RETURN(dstData);
DataSP srcData = srcDevice->m_d->m_data;
KIS_ASSERT_RECOVER_RETURN(srcData);
uploadFrameData(srcData, dstData);
}
void KisPaintDevice::Private::uploadFrameData(DataSP srcData, DataSP dstData)
{
if (srcData->colorSpace() != dstData->colorSpace() &&
*srcData->colorSpace() != *dstData->colorSpace()) {
KUndo2Command tempCommand;
srcData = toQShared(new Data(q, srcData.data(), true));
srcData->convertDataColorSpace(dstData->colorSpace(),
KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags(),
&tempCommand);
}
dstData->dataManager()->clear();
dstData->cache()->invalidate();
const QRect rect = srcData->dataManager()->extent();
dstData->dataManager()->bitBltRough(srcData->dataManager(), rect);
dstData->setX(srcData->x());
dstData->setY(srcData->y());
}
void KisPaintDevice::Private::tesingFetchLodDevice(KisPaintDeviceSP targetDevice)
{
Data *data = m_lodData.data();
Q_ASSERT(data);
transferFromData(data, targetDevice);
}
class KisPaintDevice::Private::DeviceChangeProfileCommand : public KUndo2Command
{
public:
DeviceChangeProfileCommand(KisPaintDeviceSP device, KUndo2Command *parent = 0)
: KUndo2Command(parent),
m_device(device)
{
}
virtual void emitNotifications()
{
m_device->emitProfileChanged();
}
void redo() override
{
if (m_firstRun) {
m_firstRun = false;
return;
}
KUndo2Command::redo();
emitNotifications();
}
void undo() override
{
KUndo2Command::undo();
emitNotifications();
}
protected:
KisPaintDeviceSP m_device;
private:
bool m_firstRun {true};
};
class KisPaintDevice::Private::DeviceChangeColorSpaceCommand : public DeviceChangeProfileCommand
{
public:
DeviceChangeColorSpaceCommand(KisPaintDeviceSP device, KUndo2Command *parent = 0)
: DeviceChangeProfileCommand(device, parent)
{
}
void emitNotifications() override
{
m_device->emitColorSpaceChanged();
}
};
void KisPaintDevice::Private::convertColorSpace(const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags, KUndo2Command *parentCommand)
{
QList<Data*> dataObjects = allDataObjects();
if (dataObjects.isEmpty()) return;
KUndo2Command *mainCommand =
parentCommand ? new DeviceChangeColorSpaceCommand(q, parentCommand) : 0;
Q_FOREACH (Data *data, dataObjects) {
if (!data) continue;
data->convertDataColorSpace(dstColorSpace, renderingIntent, conversionFlags, mainCommand);
}
q->emitColorSpaceChanged();
}
bool KisPaintDevice::Private::assignProfile(const KoColorProfile * profile, KUndo2Command *parentCommand)
{
if (!profile) return false;
const KoColorSpace *dstColorSpace =
KoColorSpaceRegistry::instance()->colorSpace(colorSpace()->colorModelId().id(), colorSpace()->colorDepthId().id(), profile);
if (!dstColorSpace) return false;
KUndo2Command *mainCommand =
parentCommand ? new DeviceChangeColorSpaceCommand(q, parentCommand) : 0;
QList<Data*> dataObjects = allDataObjects();
Q_FOREACH (Data *data, dataObjects) {
if (!data) continue;
data->assignColorSpace(dstColorSpace, mainCommand);
}
q->emitProfileChanged();
// no undo information is provided here
return true;
}
+KUndo2Command *KisPaintDevice::Private::reincarnateWithDetachedHistory(bool copyContent)
+{
+ KUndo2Command *mainCommand = new KUndo2Command();
+ currentData()->reincarnateWithDetachedHistory(copyContent, mainCommand);
+ return mainCommand;
+}
+
void KisPaintDevice::Private::init(const KoColorSpace *cs, const quint8 *defaultPixel)
{
QList<Data*> dataObjects = allDataObjects();
Q_FOREACH (Data *data, dataObjects) {
if (!data) continue;
KisDataManagerSP dataManager = new KisDataManager(cs->pixelSize(), defaultPixel);
data->init(cs, dataManager);
}
}
KisPaintDevice::KisPaintDevice(const KoColorSpace * colorSpace, const QString& name)
: QObject(0)
, m_d(new Private(this))
{
init(colorSpace, new KisDefaultBounds(), 0, name);
}
KisPaintDevice::KisPaintDevice(KisNodeWSP parent, const KoColorSpace * colorSpace, KisDefaultBoundsBaseSP defaultBounds, const QString& name)
: QObject(0)
, m_d(new Private(this))
{
init(colorSpace, defaultBounds, parent, name);
}
void KisPaintDevice::init(const KoColorSpace *colorSpace,
KisDefaultBoundsBaseSP defaultBounds,
KisNodeWSP parent, const QString& name)
{
Q_ASSERT(colorSpace);
setObjectName(name);
// temporary def. bounds object for the initialization phase only
m_d->defaultBounds = m_d->transitionalDefaultBounds;
if (!defaultBounds) {
// Reuse transitionalDefaultBounds here. Change if you change
// semantics of transitionalDefaultBounds
defaultBounds = m_d->transitionalDefaultBounds;
}
QScopedArrayPointer<quint8> defaultPixel(new quint8[colorSpace->pixelSize()]);
colorSpace->fromQColor(Qt::transparent, defaultPixel.data());
m_d->init(colorSpace, defaultPixel.data());
Q_ASSERT(m_d->colorSpace());
setDefaultBounds(defaultBounds);
setParentNode(parent);
}
KisPaintDevice::KisPaintDevice(const KisPaintDevice& rhs, KritaUtils::DeviceCopyMode copyMode, KisNode *newParentNode)
: QObject()
, KisShared()
, m_d(new Private(this))
{
if (this != &rhs) {
makeFullCopyFrom(rhs, copyMode, newParentNode);
}
}
void KisPaintDevice::makeFullCopyFrom(const KisPaintDevice &rhs, KritaUtils::DeviceCopyMode copyMode, KisNode *newParentNode)
{
// temporary def. bounds object for the initialization phase only
m_d->defaultBounds = m_d->transitionalDefaultBounds;
// copy data objects with or without frames
m_d->cloneAllDataObjects(rhs.m_d, copyMode == KritaUtils::CopyAllFrames);
if (copyMode == KritaUtils::CopyAllFrames && rhs.m_d->framesInterface) {
KIS_ASSERT_RECOVER_RETURN(rhs.m_d->framesInterface);
KIS_ASSERT_RECOVER_RETURN(rhs.m_d->contentChannel);
m_d->framesInterface.reset(new KisPaintDeviceFramesInterface(this));
m_d->contentChannel.reset(new KisRasterKeyframeChannel(*rhs.m_d->contentChannel.data(), newParentNode, this));
}
setDefaultBounds(rhs.m_d->defaultBounds);
setParentNode(newParentNode);
}
KisPaintDevice::~KisPaintDevice()
{
delete m_d;
}
void KisPaintDevice::setProjectionDevice(bool value)
{
m_d->isProjectionDevice = value;
}
void KisPaintDevice::prepareClone(KisPaintDeviceSP src)
{
m_d->prepareClone(src);
}
void KisPaintDevice::makeCloneFrom(KisPaintDeviceSP src, const QRect &rect)
{
prepareClone(src);
// we guarantee that *this is totally empty, so copy pixels that
// are areally present on the source image only
const QRect optimizedRect = rect & src->extent();
fastBitBlt(src, optimizedRect);
}
void KisPaintDevice::makeCloneFromRough(KisPaintDeviceSP src, const QRect &minimalRect)
{
prepareClone(src);
// we guarantee that *this is totally empty, so copy pixels that
// are areally present on the source image only
const QRect optimizedRect = minimalRect & src->extent();
fastBitBltRough(src, optimizedRect);
}
void KisPaintDevice::setDirty()
{
m_d->cache()->invalidate();
if (m_d->parent.isValid())
m_d->parent->setDirty();
}
void KisPaintDevice::setDirty(const QRect & rc)
{
m_d->cache()->invalidate();
if (m_d->parent.isValid())
m_d->parent->setDirty(rc);
}
void KisPaintDevice::setDirty(const KisRegion &region)
{
m_d->cache()->invalidate();
if (m_d->parent.isValid())
m_d->parent->setDirty(region);
}
void KisPaintDevice::setDirty(const QVector<QRect> &rects)
{
m_d->cache()->invalidate();
if (m_d->parent.isValid())
m_d->parent->setDirty(rects);
}
void KisPaintDevice::requestTimeSwitch(int time)
{
if (m_d->parent.isValid()) {
m_d->parent->requestTimeSwitch(time);
}
}
int KisPaintDevice::sequenceNumber() const
{
return m_d->cache()->sequenceNumber();
}
void KisPaintDevice::estimateMemoryStats(qint64 &imageData, qint64 &temporaryData, qint64 &lodData) const
{
m_d->estimateMemoryStats(imageData, temporaryData, lodData);
}
void KisPaintDevice::setParentNode(KisNodeWSP parent)
{
m_d->parent = parent;
}
// for testing purposes only
KisNodeWSP KisPaintDevice::parentNode() const
{
return m_d->parent;
}
void KisPaintDevice::setDefaultBounds(KisDefaultBoundsBaseSP defaultBounds)
{
m_d->defaultBounds = defaultBounds;
m_d->cache()->invalidate();
}
KisDefaultBoundsBaseSP KisPaintDevice::defaultBounds() const
{
return m_d->defaultBounds;
}
void KisPaintDevice::moveTo(const QPoint &pt)
{
m_d->currentStrategy()->move(pt);
m_d->cache()->invalidate();
}
QPoint KisPaintDevice::offset() const
{
return QPoint(x(), y());
}
void KisPaintDevice::moveTo(qint32 x, qint32 y)
{
moveTo(QPoint(x, y));
}
void KisPaintDevice::setX(qint32 x)
{
moveTo(QPoint(x, m_d->y()));
}
void KisPaintDevice::setY(qint32 y)
{
moveTo(QPoint(m_d->x(), y));
}
qint32 KisPaintDevice::x() const
{
return m_d->x();
}
qint32 KisPaintDevice::y() const
{
return m_d->y();
}
void KisPaintDevice::extent(qint32 &x, qint32 &y, qint32 &w, qint32 &h) const
{
QRect rc = extent();
x = rc.x();
y = rc.y();
w = rc.width();
h = rc.height();
}
QRect KisPaintDevice::extent() const
{
return m_d->currentStrategy()->extent();
}
KisRegion KisPaintDevice::region() const
{
return m_d->currentStrategy()->region();
}
QRect KisPaintDevice::nonDefaultPixelArea() const
{
return m_d->cache()->nonDefaultPixelArea();
}
QRect KisPaintDevice::exactBounds() const
{
return m_d->cache()->exactBounds();
}
QRect KisPaintDevice::exactBoundsAmortized() const
{
return m_d->cache()->exactBoundsAmortized();
}
namespace Impl
{
struct CheckFullyTransparent {
CheckFullyTransparent(const KoColorSpace *colorSpace)
: m_colorSpace(colorSpace)
{
}
bool isPixelEmpty(const quint8 *pixelData)
{
return m_colorSpace->opacityU8(pixelData) == OPACITY_TRANSPARENT_U8;
}
private:
const KoColorSpace *m_colorSpace;
};
struct CheckNonDefault {
CheckNonDefault(int pixelSize, const quint8 *defaultPixel)
: m_pixelSize(pixelSize),
m_defaultPixel(defaultPixel)
{
}
bool isPixelEmpty(const quint8 *pixelData)
{
return memcmp(m_defaultPixel, pixelData, m_pixelSize) == 0;
}
private:
int m_pixelSize;
const quint8 *m_defaultPixel;
};
template <class ComparePixelOp>
QRect calculateExactBoundsImpl(const KisPaintDevice *device, const QRect &startRect, const QRect &endRect, ComparePixelOp compareOp)
{
if (startRect == endRect) return startRect;
// the passed extent might have weird invalid structure that
// can overflow integer precision when calling startRect.right()
if (!startRect.isValid()) return QRect();
// Solution n°2
int x, y, w, h;
int boundLeft, boundTop, boundRight, boundBottom;
int endDirN, endDirE, endDirS, endDirW;
startRect.getRect(&x, &y, &w, &h);
if (endRect.isEmpty()) {
endDirS = startRect.bottom();
endDirN = startRect.top();
endDirE = startRect.right();
endDirW = startRect.left();
startRect.getCoords(&boundLeft, &boundTop, &boundRight, &boundBottom);
} else {
endDirS = endRect.top() - 1;
endDirN = endRect.bottom() + 1;
endDirE = endRect.left() - 1;
endDirW = endRect.right() + 1;
endRect.getCoords(&boundLeft, &boundTop, &boundRight, &boundBottom);
}
// XXX: a small optimization is possible by using H/V line iterators in the first
// and third cases, at the cost of making the code a bit more complex
KisRandomConstAccessorSP accessor = device->createRandomConstAccessorNG();
bool found = false;
{
for (qint32 y2 = y; y2 <= endDirS; ++y2) {
for (qint32 x2 = x; x2 < x + w || found; ++ x2) {
accessor->moveTo(x2, y2);
if (!compareOp.isPixelEmpty(accessor->rawDataConst())) {
boundTop = y2;
found = true;
break;
}
}
if (found) break;
}
}
/**
* If the first pass hasn't found any opaque pixel, there is no
* reason to check that 3 more times. They will not appear in the
* meantime. Just return an empty bounding rect.
*/
if (!found && endRect.isEmpty()) {
return QRect();
}
found = false;
for (qint32 y2 = y + h - 1; y2 >= endDirN ; --y2) {
for (qint32 x2 = x + w - 1; x2 >= x || found; --x2) {
accessor->moveTo(x2, y2);
if (!compareOp.isPixelEmpty(accessor->rawDataConst())) {
boundBottom = y2;
found = true;
break;
}
}
if (found) break;
}
found = false;
{
for (qint32 x2 = x; x2 <= endDirE ; ++x2) {
for (qint32 y2 = y; y2 < y + h || found; ++y2) {
accessor->moveTo(x2, y2);
if (!compareOp.isPixelEmpty(accessor->rawDataConst())) {
boundLeft = x2;
found = true;
break;
}
}
if (found) break;
}
}
found = false;
// Look for right edge )
{
for (qint32 x2 = x + w - 1; x2 >= endDirW; --x2) {
for (qint32 y2 = y + h - 1; y2 >= y || found; --y2) {
accessor->moveTo(x2, y2);
if (!compareOp.isPixelEmpty(accessor->rawDataConst())) {
boundRight = x2;
found = true;
break;
}
}
if (found) break;
}
}
return QRect(boundLeft, boundTop,
boundRight - boundLeft + 1,
boundBottom - boundTop + 1);
}
}
QRect KisPaintDevice::calculateExactBounds(bool nonDefaultOnly) const
{
QRect startRect = extent();
QRect endRect;
quint8 defaultOpacity = defaultPixel().opacityU8();
if (defaultOpacity != OPACITY_TRANSPARENT_U8) {
if (!nonDefaultOnly) {
/**
* We will calculate exact bounds only outside of the
* image bounds, and that'll be nondefault area only.
*/
endRect = defaultBounds()->bounds();
nonDefaultOnly = true;
} else {
startRect = region().boundingRect();
}
}
if (nonDefaultOnly) {
const KoColor defaultPixel = this->defaultPixel();
Impl::CheckNonDefault compareOp(pixelSize(), defaultPixel.data());
endRect = Impl::calculateExactBoundsImpl(this, startRect, endRect, compareOp);
} else {
Impl::CheckFullyTransparent compareOp(m_d->colorSpace());
endRect = Impl::calculateExactBoundsImpl(this, startRect, endRect, compareOp);
}
return endRect;
}
KisRegion KisPaintDevice::regionExact() const
{
QVector<QRect> sourceRects = region().rects();
QVector<QRect> resultRects;
const KoColor defaultPixel = this->defaultPixel();
Impl::CheckNonDefault compareOp(pixelSize(), defaultPixel.data());
Q_FOREACH (const QRect &rc1, sourceRects) {
const int patchSize = 64;
QVector<QRect> smallerRects = KritaUtils::splitRectIntoPatches(rc1, QSize(patchSize, patchSize));
Q_FOREACH (const QRect &rc2, smallerRects) {
const QRect result =
Impl::calculateExactBoundsImpl(this, rc2, QRect(), compareOp);
if (!result.isEmpty()) {
resultRects << result;
}
}
}
return KisRegion(std::move(resultRects));
}
void KisPaintDevice::crop(qint32 x, qint32 y, qint32 w, qint32 h)
{
crop(QRect(x, y, w, h));
}
void KisPaintDevice::crop(const QRect &rect)
{
m_d->currentStrategy()->crop(rect);
}
void KisPaintDevice::purgeDefaultPixels()
{
KisDataManagerSP dm = m_d->dataManager();
dm->purge(dm->extent());
}
void KisPaintDevice::setDefaultPixel(const KoColor &defPixel)
{
KoColor color(defPixel);
color.convertTo(colorSpace());
m_d->dataManager()->setDefaultPixel(color.data());
m_d->cache()->invalidate();
}
KoColor KisPaintDevice::defaultPixel() const
{
return KoColor(m_d->dataManager()->defaultPixel(), colorSpace());
}
void KisPaintDevice::clear()
{
m_d->dataManager()->clear();
m_d->cache()->invalidate();
}
void KisPaintDevice::clear(const QRect & rc)
{
m_d->currentStrategy()->clear(rc);
}
void KisPaintDevice::fill(const QRect & rc, const KoColor &color)
{
KIS_ASSERT_RECOVER_RETURN(*color.colorSpace() == *colorSpace());
m_d->currentStrategy()->fill(rc, color.data());
}
void KisPaintDevice::fill(qint32 x, qint32 y, qint32 w, qint32 h, const quint8 *fillPixel)
{
m_d->currentStrategy()->fill(QRect(x, y, w, h), fillPixel);
}
bool KisPaintDevice::write(KisPaintDeviceWriter &store)
{
return m_d->dataManager()->write(store);
}
bool KisPaintDevice::read(QIODevice *stream)
{
bool retval;
retval = m_d->dataManager()->read(stream);
m_d->cache()->invalidate();
return retval;
}
void KisPaintDevice::emitColorSpaceChanged()
{
emit colorSpaceChanged(m_d->colorSpace());
}
void KisPaintDevice::emitProfileChanged()
{
emit profileChanged(m_d->colorSpace()->profile());
}
void KisPaintDevice::convertTo(const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags, KUndo2Command *parentCommand)
{
m_d->convertColorSpace(dstColorSpace, renderingIntent, conversionFlags, parentCommand);
}
bool KisPaintDevice::setProfile(const KoColorProfile * profile, KUndo2Command *parentCommand)
{
return m_d->assignProfile(profile, parentCommand);
}
+KUndo2Command *KisPaintDevice::reincarnateWithDetachedHistory(bool copyContent)
+{
+ return m_d->reincarnateWithDetachedHistory(copyContent);
+}
+
KisDataManagerSP KisPaintDevice::dataManager() const
{
return m_d->dataManager();
}
void KisPaintDevice::convertFromQImage(const QImage& _image, const KoColorProfile *profile,
qint32 offsetX, qint32 offsetY)
{
QImage image = _image;
if (image.format() != QImage::Format_ARGB32) {
image = image.convertToFormat(QImage::Format_ARGB32);
}
// Don't convert if not no profile is given and both paint dev and qimage are rgba.
if (!profile && colorSpace()->id() == "RGBA") {
writeBytes(image.constBits(), offsetX, offsetY, image.width(), image.height());
} else {
try {
quint8 * dstData = new quint8[image.width() * image.height() * pixelSize()];
KoColorSpaceRegistry::instance()
->colorSpace(RGBAColorModelID.id(), Integer8BitsColorDepthID.id(), profile)
->convertPixelsTo(image.constBits(), dstData, colorSpace(), image.width() * image.height(),
KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags());
writeBytes(dstData, offsetX, offsetY, image.width(), image.height());
delete[] dstData;
} catch (const std::bad_alloc&) {
warnKrita << "KisPaintDevice::convertFromQImage: Could not allocate" << image.width() * image.height() * pixelSize() << "bytes";
return;
}
}
m_d->cache()->invalidate();
}
QImage KisPaintDevice::convertToQImage(const KoColorProfile *dstProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
{
qint32 x1;
qint32 y1;
qint32 w;
qint32 h;
QRect rc = exactBounds();
x1 = rc.x();
y1 = rc.y();
w = rc.width();
h = rc.height();
return convertToQImage(dstProfile, x1, y1, w, h, renderingIntent, conversionFlags);
}
QImage KisPaintDevice::convertToQImage(const KoColorProfile *dstProfile,
const QRect &rc,
KoColorConversionTransformation::Intent renderingIntent,
KoColorConversionTransformation::ConversionFlags conversionFlags) const
{
return convertToQImage(dstProfile,
rc.x(), rc.y(), rc.width(), rc.height(),
renderingIntent, conversionFlags);
}
QImage KisPaintDevice::convertToQImage(const KoColorProfile *dstProfile, qint32 x1, qint32 y1, qint32 w, qint32 h, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
{
if (w < 0)
return QImage();
if (h < 0)
return QImage();
quint8 *data = 0;
try {
data = new quint8 [w * h * pixelSize()];
} catch (const std::bad_alloc&) {
warnKrita << "KisPaintDevice::convertToQImage std::bad_alloc for " << w << " * " << h << " * " << pixelSize();
//delete[] data; // data is not allocated, so don't free it
return QImage();
}
Q_CHECK_PTR(data);
// XXX: Is this really faster than converting line by line and building the QImage directly?
// This copies potentially a lot of data.
readBytes(data, x1, y1, w, h);
QImage image = colorSpace()->convertToQImage(data, w, h, dstProfile, renderingIntent, conversionFlags);
delete[] data;
return image;
}
inline bool moveBy(KisSequentialConstIterator& iter, int numPixels)
{
int pos = 0;
while (pos < numPixels) {
int step = std::min(iter.nConseqPixels(), numPixels - pos);
if (!iter.nextPixels(step))
return false;
pos += step;
}
return true;
}
static KisPaintDeviceSP createThumbnailDeviceInternal(const KisPaintDevice* srcDev, qint32 srcX0, qint32 srcY0, qint32 srcWidth, qint32 srcHeight, qint32 w, qint32 h, QRect outputRect)
{
KisPaintDeviceSP thumbnail = new KisPaintDevice(srcDev->colorSpace());
qint32 pixelSize = srcDev->pixelSize();
KisRandomConstAccessorSP srcIter = srcDev->createRandomConstAccessorNG();
KisRandomAccessorSP dstIter = thumbnail->createRandomAccessorNG();
for (qint32 y = outputRect.y(); y < outputRect.y() + outputRect.height(); ++y) {
qint32 iY = srcY0 + (y * srcHeight) / h;
for (qint32 x = outputRect.x(); x < outputRect.x() + outputRect.width(); ++x) {
qint32 iX = srcX0 + (x * srcWidth) / w;
srcIter->moveTo(iX, iY);
dstIter->moveTo(x, y);
memcpy(dstIter->rawData(), srcIter->rawDataConst(), pixelSize);
}
}
return thumbnail;
}
QSize fixThumbnailSize(QSize size)
{
if (!size.width() && size.height()) {
size.setWidth(1);
}
if (size.width() && !size.height()) {
size.setHeight(1);
}
return size;
}
KisPaintDeviceSP KisPaintDevice::createThumbnailDevice(qint32 w, qint32 h, QRect rect, QRect outputRect) const
{
QSize thumbnailSize(w, h);
QRect imageRect = rect.isValid() ? rect : extent();
if ((thumbnailSize.width() > imageRect.width()) || (thumbnailSize.height() > imageRect.height())) {
thumbnailSize.scale(imageRect.size(), Qt::KeepAspectRatio);
}
thumbnailSize = fixThumbnailSize(thumbnailSize);
//can't create thumbnail for an empty device, e.g. layer thumbnail for empty image
if (imageRect.isEmpty() || thumbnailSize.isEmpty()) {
return new KisPaintDevice(colorSpace());
}
int srcWidth, srcHeight;
int srcX0, srcY0;
imageRect.getRect(&srcX0, &srcY0, &srcWidth, &srcHeight);
if (!outputRect.isValid()) {
outputRect = QRect(0, 0, w, h);
}
KisPaintDeviceSP thumbnail = createThumbnailDeviceInternal(this, imageRect.x(), imageRect.y(), imageRect.width(), imageRect.height(),
thumbnailSize.width(), thumbnailSize.height(), outputRect);
return thumbnail;
}
KisPaintDeviceSP KisPaintDevice::createThumbnailDeviceOversampled(qint32 w, qint32 h, qreal oversample, QRect rect, QRect outputTileRect) const
{
QSize thumbnailSize(w, h);
qreal oversampleAdjusted = qMax(oversample, 1.);
QSize thumbnailOversampledSize = oversampleAdjusted * thumbnailSize;
QRect outputRect;
QRect imageRect = rect.isValid() ? rect : extent();
qint32 hstart = thumbnailOversampledSize.height();
if ((thumbnailOversampledSize.width() > imageRect.width()) || (thumbnailOversampledSize.height() > imageRect.height())) {
thumbnailOversampledSize.scale(imageRect.size(), Qt::KeepAspectRatio);
}
thumbnailOversampledSize = fixThumbnailSize(thumbnailOversampledSize);
//can't create thumbnail for an empty device, e.g. layer thumbnail for empty image
if (imageRect.isEmpty() || thumbnailSize.isEmpty() || thumbnailOversampledSize.isEmpty()) {
return new KisPaintDevice(colorSpace());
}
oversampleAdjusted *= (hstart > 0) ? ((qreal)thumbnailOversampledSize.height() / hstart) : 1.; //readjusting oversample ratio, given that we had to adjust thumbnail size
outputRect = QRect(0, 0, thumbnailOversampledSize.width(), thumbnailOversampledSize.height());
if (outputTileRect.isValid()) {
//compensating output rectangle for oversampling
outputTileRect = QRect(oversampleAdjusted * outputTileRect.topLeft(), oversampleAdjusted * outputTileRect.bottomRight());
outputRect = outputRect.intersected(outputTileRect);
}
KisPaintDeviceSP thumbnail = createThumbnailDeviceInternal(this, imageRect.x(), imageRect.y(), imageRect.width(), imageRect.height(),
thumbnailOversampledSize.width(), thumbnailOversampledSize.height(), outputRect);
if (oversample != 1. && oversampleAdjusted != 1.) {
KoDummyUpdater updater;
KisTransformWorker worker(thumbnail, 1 / oversampleAdjusted, 1 / oversampleAdjusted, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
&updater, KisFilterStrategyRegistry::instance()->value("Bilinear"));
worker.run();
}
return thumbnail;
}
QImage KisPaintDevice::createThumbnail(qint32 w, qint32 h, QRect rect, qreal oversample, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
{
QSize size = fixThumbnailSize(QSize(w, h));
KisPaintDeviceSP dev = createThumbnailDeviceOversampled(size.width(), size.height(), oversample, rect);
QImage thumbnail = dev->convertToQImage(KoColorSpaceRegistry::instance()->rgb8()->profile(), 0, 0, w, h, renderingIntent, conversionFlags);
return thumbnail;
}
QImage KisPaintDevice::createThumbnail(qint32 w, qint32 h, qreal oversample, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
{
QSize size = fixThumbnailSize(QSize(w, h));
return m_d->cache()->createThumbnail(size.width(), size.height(), oversample, renderingIntent, conversionFlags);
}
+QImage KisPaintDevice::createThumbnail(qint32 maxw, qint32 maxh,
+ Qt::AspectRatioMode aspectRatioMode,
+ qreal oversample, KoColorConversionTransformation::Intent renderingIntent,
+ KoColorConversionTransformation::ConversionFlags conversionFlags)
+{
+ const QRect deviceExtent = extent();
+ const QSize thumbnailSize = deviceExtent.size().scaled(maxw, maxh, aspectRatioMode);
+ return createThumbnail(thumbnailSize.width(), thumbnailSize.height(),
+ oversample, renderingIntent, conversionFlags);
+}
+
KisHLineIteratorSP KisPaintDevice::createHLineIteratorNG(qint32 x, qint32 y, qint32 w)
{
m_d->cache()->invalidate();
return m_d->currentStrategy()->createHLineIteratorNG(m_d->dataManager().data(), x, y, w, m_d->x(), m_d->y());
}
KisHLineConstIteratorSP KisPaintDevice::createHLineConstIteratorNG(qint32 x, qint32 y, qint32 w) const
{
return m_d->currentStrategy()->createHLineConstIteratorNG(m_d->dataManager().data(), x, y, w, m_d->x(), m_d->y());
}
KisVLineIteratorSP KisPaintDevice::createVLineIteratorNG(qint32 x, qint32 y, qint32 w)
{
m_d->cache()->invalidate();
return m_d->currentStrategy()->createVLineIteratorNG(x, y, w);
}
KisVLineConstIteratorSP KisPaintDevice::createVLineConstIteratorNG(qint32 x, qint32 y, qint32 w) const
{
return m_d->currentStrategy()->createVLineConstIteratorNG(x, y, w);
}
KisRepeatHLineConstIteratorSP KisPaintDevice::createRepeatHLineConstIterator(qint32 x, qint32 y, qint32 w, const QRect& _dataWidth) const
{
return new KisRepeatHLineConstIteratorNG(m_d->dataManager().data(), x, y, w, m_d->x(), m_d->y(), _dataWidth, m_d->cacheInvalidator());
}
KisRepeatVLineConstIteratorSP KisPaintDevice::createRepeatVLineConstIterator(qint32 x, qint32 y, qint32 h, const QRect& _dataWidth) const
{
return new KisRepeatVLineConstIteratorNG(m_d->dataManager().data(), x, y, h, m_d->x(), m_d->y(), _dataWidth, m_d->cacheInvalidator());
}
KisRandomAccessorSP KisPaintDevice::createRandomAccessorNG()
{
m_d->cache()->invalidate();
return m_d->currentStrategy()->createRandomAccessorNG();
}
KisRandomConstAccessorSP KisPaintDevice::createRandomConstAccessorNG() const
{
return m_d->currentStrategy()->createRandomConstAccessorNG();
}
KisRandomSubAccessorSP KisPaintDevice::createRandomSubAccessor() const
{
KisPaintDevice* pd = const_cast<KisPaintDevice*>(this);
return new KisRandomSubAccessor(pd);
}
void KisPaintDevice::clearSelection(KisSelectionSP selection)
{
const KoColorSpace *colorSpace = m_d->colorSpace();
const QRect r = selection->selectedExactRect();
if (r.isValid()) {
{
KisHLineIteratorSP devIt = createHLineIteratorNG(r.x(), r.y(), r.width());
KisHLineConstIteratorSP selectionIt = selection->projection()->createHLineConstIteratorNG(r.x(), r.y(), r.width());
const KoColor defaultPixel = this->defaultPixel();
bool transparentDefault = (defaultPixel.opacityU8() == OPACITY_TRANSPARENT_U8);
for (qint32 y = 0; y < r.height(); y++) {
do {
// XXX: Optimize by using stretches
colorSpace->applyInverseAlphaU8Mask(devIt->rawData(), selectionIt->rawDataConst(), 1);
if (transparentDefault && colorSpace->opacityU8(devIt->rawData()) == OPACITY_TRANSPARENT_U8) {
memcpy(devIt->rawData(), defaultPixel.data(), colorSpace->pixelSize());
}
} while (devIt->nextPixel() && selectionIt->nextPixel());
devIt->nextRow();
selectionIt->nextRow();
}
}
// purge() must be executed **after** all iterators have been destroyed!
m_d->dataManager()->purge(r.translated(-m_d->x(), -m_d->y()));
setDirty(r);
}
}
bool KisPaintDevice::pixel(qint32 x, qint32 y, QColor *c) const
{
KisHLineConstIteratorSP iter = createHLineConstIteratorNG(x, y, 1);
const quint8 *pix = iter->rawDataConst();
if (!pix) return false;
colorSpace()->toQColor(pix, c);
return true;
}
bool KisPaintDevice::pixel(qint32 x, qint32 y, KoColor * kc) const
{
KisHLineConstIteratorSP iter = createHLineConstIteratorNG(x, y, 1);
const quint8 *pix = iter->rawDataConst();
if (!pix) return false;
kc->setColor(pix, m_d->colorSpace());
return true;
}
KoColor KisPaintDevice::pixel(const QPoint &pos) const
{
KisHLineConstIteratorSP iter = createHLineConstIteratorNG(pos.x(), pos.y(), 1);
return KoColor(iter->rawDataConst(), m_d->colorSpace());
}
bool KisPaintDevice::setPixel(qint32 x, qint32 y, const QColor& c)
{
KisHLineIteratorSP iter = createHLineIteratorNG(x, y, 1);
colorSpace()->fromQColor(c, iter->rawData());
m_d->cache()->invalidate();
return true;
}
bool KisPaintDevice::setPixel(qint32 x, qint32 y, const KoColor& kc)
{
const quint8 * pix;
KisHLineIteratorSP iter = createHLineIteratorNG(x, y, 1);
if (kc.colorSpace() != m_d->colorSpace()) {
KoColor kc2(kc, m_d->colorSpace());
pix = kc2.data();
memcpy(iter->rawData(), pix, m_d->colorSpace()->pixelSize());
} else {
pix = kc.data();
memcpy(iter->rawData(), pix, m_d->colorSpace()->pixelSize());
}
m_d->cache()->invalidate();
return true;
}
bool KisPaintDevice::fastBitBltPossible(KisPaintDeviceSP src)
{
return m_d->fastBitBltPossible(src);
}
void KisPaintDevice::fastBitBlt(KisPaintDeviceSP src, const QRect &rect)
{
m_d->currentStrategy()->fastBitBlt(src, rect);
}
void KisPaintDevice::fastBitBltOldData(KisPaintDeviceSP src, const QRect &rect)
{
m_d->currentStrategy()->fastBitBltOldData(src, rect);
}
void KisPaintDevice::fastBitBltRough(KisPaintDeviceSP src, const QRect &rect)
{
m_d->currentStrategy()->fastBitBltRough(src, rect);
}
void KisPaintDevice::fastBitBltRoughOldData(KisPaintDeviceSP src, const QRect &rect)
{
m_d->currentStrategy()->fastBitBltRoughOldData(src, rect);
}
void KisPaintDevice::readBytes(quint8 * data, qint32 x, qint32 y, qint32 w, qint32 h) const
{
readBytes(data, QRect(x, y, w, h));
}
void KisPaintDevice::readBytes(quint8 *data, const QRect &rect) const
{
m_d->currentStrategy()->readBytes(data, rect);
}
void KisPaintDevice::writeBytes(const quint8 *data, qint32 x, qint32 y, qint32 w, qint32 h)
{
writeBytes(data, QRect(x, y, w, h));
}
void KisPaintDevice::writeBytes(const quint8 *data, const QRect &rect)
{
m_d->currentStrategy()->writeBytes(data, rect);
}
QVector<quint8*> KisPaintDevice::readPlanarBytes(qint32 x, qint32 y, qint32 w, qint32 h) const
{
return m_d->currentStrategy()->readPlanarBytes(x, y, w, h);
}
void KisPaintDevice::writePlanarBytes(QVector<quint8*> planes, qint32 x, qint32 y, qint32 w, qint32 h)
{
m_d->currentStrategy()->writePlanarBytes(planes, x, y, w, h);
}
quint32 KisPaintDevice::pixelSize() const
{
quint32 _pixelSize = m_d->colorSpace()->pixelSize();
Q_ASSERT(_pixelSize > 0);
return _pixelSize;
}
quint32 KisPaintDevice::channelCount() const
{
quint32 _channelCount = m_d->colorSpace()->channelCount();
Q_ASSERT(_channelCount > 0);
return _channelCount;
}
KisRasterKeyframeChannel *KisPaintDevice::createKeyframeChannel(const KoID &id)
{
Q_ASSERT(!m_d->framesInterface);
m_d->framesInterface.reset(new KisPaintDeviceFramesInterface(this));
Q_ASSERT(!m_d->contentChannel);
if (m_d->parent.isValid()) {
m_d->contentChannel.reset(new KisRasterKeyframeChannel(id, this, m_d->parent));
} else {
//fallback when paint device is isolated / does not belong to a node.
ENTER_FUNCTION() << ppVar(this) << ppVar(m_d->defaultBounds);
m_d->contentChannel.reset(new KisRasterKeyframeChannel(id, this, m_d->defaultBounds));
}
// Raster channels always have at least one frame (representing a static image)
KUndo2Command tempParentCommand;
m_d->contentChannel->addKeyframe(0, &tempParentCommand);
return m_d->contentChannel.data();
}
KisRasterKeyframeChannel* KisPaintDevice::keyframeChannel() const
{
if (m_d->contentChannel) {
return m_d->contentChannel.data();
}
return 0;
}
const KoColorSpace* KisPaintDevice::colorSpace() const
{
Q_ASSERT(m_d->colorSpace() != 0);
return m_d->colorSpace();
}
KisPaintDeviceSP KisPaintDevice::createCompositionSourceDevice() const
{
KisPaintDeviceSP device = new KisPaintDevice(compositionSourceColorSpace());
device->setDefaultBounds(defaultBounds());
return device;
}
KisPaintDeviceSP KisPaintDevice::createCompositionSourceDevice(KisPaintDeviceSP cloneSource) const
{
KisPaintDeviceSP clone = new KisPaintDevice(*cloneSource);
clone->setDefaultBounds(defaultBounds());
clone->convertTo(compositionSourceColorSpace(),
KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags());
return clone;
}
KisPaintDeviceSP KisPaintDevice::createCompositionSourceDevice(KisPaintDeviceSP cloneSource, const QRect roughRect) const
{
KisPaintDeviceSP clone = new KisPaintDevice(colorSpace());
clone->setDefaultBounds(defaultBounds());
clone->makeCloneFromRough(cloneSource, roughRect);
clone->convertTo(compositionSourceColorSpace(),
KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags());
return clone;
}
KisFixedPaintDeviceSP KisPaintDevice::createCompositionSourceDeviceFixed() const
{
return new KisFixedPaintDevice(compositionSourceColorSpace());
}
const KoColorSpace* KisPaintDevice::compositionSourceColorSpace() const
{
return colorSpace();
}
QVector<qint32> KisPaintDevice::channelSizes() const
{
QVector<qint32> sizes;
QList<KoChannelInfo*> channels = colorSpace()->channels();
std::sort(channels.begin(), channels.end());
Q_FOREACH (KoChannelInfo * channelInfo, channels) {
sizes.append(channelInfo->size());
}
return sizes;
}
KisPaintDevice::MemoryReleaseObject::~MemoryReleaseObject()
{
KisDataManager::releaseInternalPools();
}
KisPaintDevice::MemoryReleaseObject* KisPaintDevice::createMemoryReleaseObject()
{
return new MemoryReleaseObject();
}
KisPaintDevice::LodDataStruct::~LodDataStruct()
{
}
KisRegion KisPaintDevice::regionForLodSyncing() const
{
return m_d->regionForLodSyncing();
}
KisPaintDevice::LodDataStruct* KisPaintDevice::createLodDataStruct(int lod)
{
return m_d->createLodDataStruct(lod);
}
void KisPaintDevice::updateLodDataStruct(LodDataStruct *dst, const QRect &srcRect)
{
m_d->updateLodDataStruct(dst, srcRect);
}
void KisPaintDevice::uploadLodDataStruct(LodDataStruct *dst)
{
m_d->uploadLodDataStruct(dst);
}
void KisPaintDevice::generateLodCloneDevice(KisPaintDeviceSP dst, const QRect &originalRect, int lod)
{
m_d->generateLodCloneDevice(dst, originalRect, lod);
}
KisPaintDeviceFramesInterface* KisPaintDevice::framesInterface()
{
return m_d->framesInterface.data();
}
/******************************************************************/
/* KisPaintDeviceFramesInterface */
/******************************************************************/
KisPaintDeviceFramesInterface::KisPaintDeviceFramesInterface(KisPaintDevice *parentDevice)
: q(parentDevice)
{
}
QList<int> KisPaintDeviceFramesInterface::frames()
{
return q->m_d->frameIds();
}
int KisPaintDeviceFramesInterface::createFrame(bool copy, int copySrc, const QPoint &offset, KUndo2Command *parentCommand)
{
return q->m_d->createFrame(copy, copySrc, offset, parentCommand);
}
void KisPaintDeviceFramesInterface::deleteFrame(int frame, KUndo2Command *parentCommand)
{
return q->m_d->deleteFrame(frame, parentCommand);
}
void KisPaintDeviceFramesInterface::fetchFrame(int frameId, KisPaintDeviceSP targetDevice)
{
q->m_d->fetchFrame(frameId, targetDevice);
}
void KisPaintDeviceFramesInterface::uploadFrame(int srcFrameId, int dstFrameId, KisPaintDeviceSP srcDevice)
{
q->m_d->uploadFrame(srcFrameId, dstFrameId, srcDevice);
}
void KisPaintDeviceFramesInterface::uploadFrame(int dstFrameId, KisPaintDeviceSP srcDevice)
{
q->m_d->uploadFrame(dstFrameId, srcDevice);
}
QRect KisPaintDeviceFramesInterface::frameBounds(int frameId)
{
return q->m_d->frameBounds(frameId);
}
QPoint KisPaintDeviceFramesInterface::frameOffset(int frameId) const
{
return q->m_d->frameOffset(frameId);
}
void KisPaintDeviceFramesInterface::setFrameDefaultPixel(const KoColor &defPixel, int frameId)
{
KIS_ASSERT_RECOVER_RETURN(frameId >= 0);
q->m_d->setFrameDefaultPixel(defPixel, frameId);
}
KoColor KisPaintDeviceFramesInterface::frameDefaultPixel(int frameId) const
{
KIS_ASSERT_RECOVER(frameId >= 0) {
return KoColor(Qt::red, q->m_d->colorSpace());
}
return q->m_d->frameDefaultPixel(frameId);
}
bool KisPaintDeviceFramesInterface::writeFrame(KisPaintDeviceWriter &store, int frameId)
{
KIS_ASSERT_RECOVER(frameId >= 0) {
return false;
}
return q->m_d->writeFrame(store, frameId);
}
bool KisPaintDeviceFramesInterface::readFrame(QIODevice *stream, int frameId)
{
KIS_ASSERT_RECOVER(frameId >= 0) {
return false;
}
return q->m_d->readFrame(stream, frameId);
}
int KisPaintDeviceFramesInterface::currentFrameId() const
{
return q->m_d->currentFrameId();
}
KisDataManagerSP KisPaintDeviceFramesInterface::frameDataManager(int frameId) const
{
KIS_ASSERT_RECOVER(frameId >= 0) {
return q->m_d->dataManager();
}
return q->m_d->frameDataManager(frameId);
}
void KisPaintDeviceFramesInterface::invalidateFrameCache(int frameId)
{
KIS_ASSERT_RECOVER_RETURN(frameId >= 0);
return q->m_d->invalidateFrameCache(frameId);
}
void KisPaintDeviceFramesInterface::setFrameOffset(int frameId, const QPoint &offset)
{
KIS_ASSERT_RECOVER_RETURN(frameId >= 0);
return q->m_d->setFrameOffset(frameId, offset);
}
KisPaintDeviceFramesInterface::TestingDataObjects
KisPaintDeviceFramesInterface::testingGetDataObjects() const
{
TestingDataObjects objects;
objects.m_data = q->m_d->m_data.data();
objects.m_lodData = q->m_d->m_lodData.data();
objects.m_externalFrameData = q->m_d->m_externalFrameData.data();
typedef KisPaintDevice::Private::FramesHash FramesHash;
FramesHash::const_iterator it = q->m_d->m_frames.constBegin();
FramesHash::const_iterator end = q->m_d->m_frames.constEnd();
for (; it != end; ++it) {
objects.m_frames.insert(it.key(), it.value().data());
}
objects.m_currentData = q->m_d->currentData();
return objects;
}
QList<KisPaintDeviceData*> KisPaintDeviceFramesInterface::testingGetDataObjectsList() const
{
return q->m_d->allDataObjects();
}
void KisPaintDevice::tesingFetchLodDevice(KisPaintDeviceSP targetDevice)
{
m_d->tesingFetchLodDevice(targetDevice);
}
diff --git a/libs/image/kis_paint_device.h b/libs/image/kis_paint_device.h
index f2ea29725b..709ada1969 100644
--- a/libs/image/kis_paint_device.h
+++ b/libs/image/kis_paint_device.h
@@ -1,898 +1,927 @@
/*
* Copyright (c) 2002 patrick julien <freak@codepimps.org>
* Copyright (c) 2006 Boudewijn Rempt <boud@valdyas.org>
*
* 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_PAINT_DEVICE_IMPL_H_
#define KIS_PAINT_DEVICE_IMPL_H_
#include <QObject>
#include <QRect>
#include <QVector>
#include "kis_debug.h"
#include <KoColorConversionTransformation.h>
#include "kis_types.h"
#include "kis_shared.h"
#include "kis_default_bounds_base.h"
#include <kritaimage_export.h>
class KUndo2Command;
class QRect;
class QImage;
class QPoint;
class QString;
class QColor;
class QIODevice;
class KoColor;
class KoColorSpace;
class KoColorProfile;
class KisRegion;
class KisDataManager;
class KisPaintDeviceWriter;
class KisKeyframe;
class KisRasterKeyframeChannel;
class KisPaintDeviceFramesInterface;
typedef KisSharedPtr<KisDataManager> KisDataManagerSP;
namespace KritaUtils {
enum DeviceCopyMode {
CopySnapshot = 0,
CopyAllFrames
};
}
/**
* A paint device contains the actual pixel data and offers methods
* to read and write pixels. A paint device has an integer x, y position
* (it is not positioned on the image with sub-pixel accuracy).
* A KisPaintDevice doesn't have any fixed size, the size changes dynamically
* when pixels are accessed by an iterator.
*/
class KRITAIMAGE_EXPORT KisPaintDevice
: public QObject
, public KisShared
{
Q_OBJECT
public:
/**
* Create a new paint device with the specified colorspace.
*
* @param colorSpace the colorspace of this paint device
* @param name for debugging purposes
*/
explicit KisPaintDevice(const KoColorSpace * colorSpace, const QString& name = QString());
/**
* Create a new paint device with the specified colorspace. The
* parent node will be notified of changes to this paint device.
*
* @param parent the node that contains this paint device
* @param colorSpace the colorspace of this paint device
* @param defaultBounds boundaries of the device in case it is empty
* @param name for debugging purposes
*/
KisPaintDevice(KisNodeWSP parent, const KoColorSpace * colorSpace, KisDefaultBoundsBaseSP defaultBounds = KisDefaultBoundsBaseSP(), const QString& name = QString());
/**
* Creates a copy of this device.
*
* If \p copyMode is CopySnapshot, the newly created device clones the
* current frame of \p rhs only (default and efficient
* behavior). If \p copyFrames is CopyAllFrames, the new device is a deep
* copy of the source with all the frames included.
*/
KisPaintDevice(const KisPaintDevice& rhs, KritaUtils::DeviceCopyMode copyMode = KritaUtils::CopySnapshot, KisNode *newParentNode = 0);
~KisPaintDevice() override;
void makeFullCopyFrom(const KisPaintDevice& rhs, KritaUtils::DeviceCopyMode copyMode = KritaUtils::CopySnapshot, KisNode *newParentNode = 0);
protected:
/**
* A special constructor for usage in KisPixelSelection. It allows
* two paint devices to share a data manager.
*
* @param explicitDataManager data manager to use inside paint device
* @param src source paint device to copy parameters from
* @param name for debugging purposes
*/
KisPaintDevice(KisDataManagerSP explicitDataManager,
KisPaintDeviceSP src, const QString& name = QString());
public:
/**
* Write the pixels of this paint device into the specified file store.
*/
bool write(KisPaintDeviceWriter &store);
/**
* Fill this paint device with the pixels from the specified file store.
*/
bool read(QIODevice *stream);
public:
/**
* set the parent node of the paint device
*/
void setParentNode(KisNodeWSP parent);
/**
* set the default bounds for the paint device when
* the default pixel is not completely transparent
*/
void setDefaultBounds(KisDefaultBoundsBaseSP bounds);
/**
* the default bounds rect of the paint device
*/
KisDefaultBoundsBaseSP defaultBounds() const;
/**
* Moves the device to these new coordinates (no incremental move)
*/
void moveTo(qint32 x, qint32 y);
/**
* Convenience method for the above.
*/
virtual void moveTo(const QPoint& pt);
/**
* Return an X,Y offset of the device in a convenient form
*/
QPoint offset() const;
/**
* The X offset of the paint device
*/
qint32 x() const;
/**
* The Y offset of the paint device
*/
qint32 y() const;
/**
* set the X offset of the paint device
*/
void setX(qint32 x);
/**
* set the Y offset of the paint device
*/
void setY(qint32 y);
/**
* Retrieve the bounds of the paint device. The size is not exact,
* but may be larger if the underlying datamanager works that way.
* For instance, the tiled datamanager keeps the extent to the nearest
* multiple of 64.
*
* If default pixel is not transparent, then the actual extent
* rect is united with the defaultBounds()->bounds() value
* (the size of the image, usually).
*/
QRect extent() const;
/// Convenience method for the above
void extent(qint32 &x, qint32 &y, qint32 &w, qint32 &h) const;
/**
* Get the exact bounds of this paint device. The real solution is
* very slow because it does a linear scanline search, but it
* uses caching, so calling to this function without changing
* the device is quite cheap.
*
* Exactbounds follows these rules:
*
* <ul>
* <li>if default pixel is transparent, then exact bounds
* of actual pixel data are returned
* <li>if default pixel is not transparent, then the union
* (defaultBounds()->bounds() | nonDefaultPixelArea()) is
* returned
* </ul>
* \see calculateExactBounds()
*/
QRect exactBounds() const;
/**
* Relaxed version of the exactBounds() that can be used in tight
* loops. If the exact bounds value is present in the paint
* device cache, returns this value. If the cache is invalidated,
* returns extent() and tries to recalculate the exact bounds not
* faster than once in 1000 ms.
*/
QRect exactBoundsAmortized() const;
/**
* Returns exact rectangle of the paint device that contains
* non-default pixels. For paint devices with fully transparent
* default pixel is equivalent to exactBounds().
*
* nonDefaultPixelArea() follows these rules:
*
* <ul>
* <li>if default pixel is transparent, then exact bounds
* of actual pixel data are returned. The same as exactBounds()
* <li>if default pixel is not transparent, then calculates the
* rectangle of non-default pixels. May be smaller or greater
* than image bounds
* </ul>
* \see calculateExactBounds()
*/
QRect nonDefaultPixelArea() const;
/**
* Returns a rough approximation of region covered by device.
* For tiled data manager, it region will consist of a number
* of rects each corresponding to a tile.
*/
KisRegion region() const;
/**
* The slow version of region() that searches for exact bounds of
* each rectangle in the region
*/
KisRegion regionExact() const;
/**
* Cut the paint device down to the specified rect. If the crop
* area is bigger than the paint device, nothing will happen.
*/
void crop(qint32 x, qint32 y, qint32 w, qint32 h);
/// Convenience method for the above
void crop(const QRect & r);
/**
* Complete erase the current paint device. Its size will become 0. This
* does not take the selection into account.
*/
virtual void clear();
/**
* Clear the given rectangle to transparent black. The paint device will expand to
* contain the given rect.
*/
void clear(const QRect & rc);
/**
* Frees the memory occupied by the pixels containing default
* values. The extents() and exactBounds() of the paint device will
* probably also shrink
*/
void purgeDefaultPixels();
/**
* Sets the default pixel. New data will be initialised with this pixel. The pixel is copied: the
* caller still owns the pointer and needs to delete it to avoid memory leaks.
* If frame ID is given, set default pixel for that frame. Otherwise use active frame.
*/
void setDefaultPixel(const KoColor &defPixel);
/**
* Get a pointer to the default pixel.
* If the frame parameter is given, get the default pixel of
* specified frame. Otherwise use currently active frame.
*/
KoColor defaultPixel() const;
/**
* Fill the given rectangle with the given pixel. The paint device will expand to
* contain the given rect.
*/
void fill(const QRect & rc, const KoColor &color);
/**
* Overloaded function. For legacy purposes only.
* Please use fill(const QRect & rc, const KoColor &color) instead
*/
void fill(qint32 x, qint32 y, qint32 w, qint32 h, const quint8 *fillPixel);
public:
/**
* Prepares the device for fastBitBlt operation. It clears
* the device, switches x,y shifts and colorspace if needed.
* After this call fastBitBltPossible will return true.
* May be used for initialization of temporary devices.
*/
void prepareClone(KisPaintDeviceSP src);
/**
* Make this device to become a clone of \a src. It will have the same
* x,y shifts, colorspace and will share pixels inside \a rect.
* After calling this function:
* (this->extent() >= this->exactBounds() == rect).
*
* Rule of thumb:
*
* "Use makeCloneFrom() or makeCloneFromRough() if and only if you
* are the only owner of the destination paint device and you are
* 100% sure no other thread has access to it"
*/
void makeCloneFrom(KisPaintDeviceSP src, const QRect &rect);
/**
* Make this device to become a clone of \a src. It will have the same
* x,y shifts, colorspace and will share pixels inside \a rect.
* Be careful, this function will copy *at least* \a rect
* of pixels. Actual copy area will be a bigger - it will
* be aligned by tiles borders. So after calling this function:
* (this->extent() == this->exactBounds() >= rect).
*
* Rule of thumb:
*
* "Use makeCloneFrom() or makeCloneFromRough() if and only if you
* are the only owner of the destination paint device and you are
* 100% sure no other thread has access to it"
*/
void makeCloneFromRough(KisPaintDeviceSP src, const QRect &minimalRect);
protected:
friend class KisPaintDeviceTest;
friend class DataReaderThread;
/**
* Checks whether a src paint device can be used as source
* of fast bitBlt operation. The result of the check may
* depend on whether color spaces coincide, whether there is
* any shift of tiles between the devices and etc.
*
* WARNING: This check must be done <i>before</i> performing any
* fast bitBlt operation!
*
* \see fastBitBlt
* \see fastBitBltRough
*/
bool fastBitBltPossible(KisPaintDeviceSP src);
/**
* Clones rect from another paint device. The cloned area will be
* shared between both paint devices as much as possible using
* copy-on-write. Parts of the rect that cannot be shared
* (cross tiles) are deep-copied,
*
* \see fastBitBltPossible
* \see fastBitBltRough
*/
void fastBitBlt(KisPaintDeviceSP src, const QRect &rect);
/**
* The same as \ref fastBitBlt() but reads old data
*/
void fastBitBltOldData(KisPaintDeviceSP src, const QRect &rect);
/**
* Clones rect from another paint device in a rough and fast way.
* All the tiles touched by rect will be shared, between both
* devices, that means it will copy a bigger area than was
* requested. This method is supposed to be used for bitBlt'ing
* into temporary paint devices.
*
* \see fastBitBltPossible
* \see fastBitBlt
*/
void fastBitBltRough(KisPaintDeviceSP src, const QRect &rect);
/**
* The same as \ref fastBitBltRough() but reads old data
*/
void fastBitBltRoughOldData(KisPaintDeviceSP src, const QRect &rect);
public:
/**
* Read the bytes representing the rectangle described by x, y, w, h into
* data. If data is not big enough, Krita will gladly overwrite the rest
* of your precious memory.
*
* Since this is a copy, you need to make sure you have enough memory.
*
* Reading from areas not previously initialized will read the default
* pixel value into data but not initialize that region.
*/
void readBytes(quint8 * data, qint32 x, qint32 y, qint32 w, qint32 h) const;
/**
* Read the bytes representing the rectangle rect into
* data. If data is not big enough, Krita will gladly overwrite the rest
* of your precious memory.
*
* Since this is a copy, you need to make sure you have enough memory.
*
* Reading from areas not previously initialized will read the default
* pixel value into data but not initialize that region.
* @param data The address of the memory to receive the bytes read
* @param rect The rectangle in the paint device to read from
*/
void readBytes(quint8 * data, const QRect &rect) const;
/**
* Copy the bytes in data into the rect specified by x, y, w, h. If the
* data is too small or uninitialized, Krita will happily read parts of
* memory you never wanted to be read.
*
* If the data is written to areas of the paint device not previously initialized,
* the paint device will grow.
*/
void writeBytes(const quint8 * data, qint32 x, qint32 y, qint32 w, qint32 h);
/**
* Copy the bytes in data into the rectangle rect. If the
* data is too small or uninitialized, Krita will happily read parts of
* memory you never wanted to be read.
*
* If the data is written to areas of the paint device not previously initialized,
* the paint device will grow.
* @param data The address of the memory to write bytes from
* @param rect The rectangle in the paint device to write to
*/
void writeBytes(const quint8 * data, const QRect &rect);
/**
* Copy the bytes in the paint device into a vector of arrays of bytes,
* where the number of arrays is the number of channels in the
* paint device. If the specified area is larger than the paint
* device's extent, the default pixel will be read.
*/
QVector<quint8*> readPlanarBytes(qint32 x, qint32 y, qint32 w, qint32 h) const;
/**
* Write the data in the separate arrays to the channes. If there
* are less vectors than channels, the remaining channels will not
* be copied. If any of the arrays points to 0, the channel in
* that location will not be touched. If the specified area is
* larger than the paint device, the paint device will be
* extended. There are no guards: if the area covers more pixels
* than there are bytes in the arrays, krita will happily fill
* your paint device with areas of memory you never wanted to be
* read. Krita may also crash.
*
* XXX: what about undo?
*/
void writePlanarBytes(QVector<quint8*> planes, qint32 x, qint32 y, qint32 w, qint32 h);
/**
* Converts the paint device to a different colorspace
*/
void convertTo(const KoColorSpace * dstColorSpace,
KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags(),
KUndo2Command *parentCommand = 0);
/**
* Changes the profile of the colorspace of this paint device to the given
* profile. If the given profile is 0, nothing happens.
*/
bool setProfile(const KoColorProfile * profile, KUndo2Command *parentCommand);
/**
* Fill this paint device with the data from image; starting at (offsetX, offsetY)
* @param image the image
* @param profile name of the RGB profile to interpret the image as. 0 is interpreted as sRGB
* @param offsetX x offset
* @param offsetY y offset
*/
void convertFromQImage(const QImage& image, const KoColorProfile *profile, qint32 offsetX = 0, qint32 offsetY = 0);
/**
* Create an RGBA QImage from a rectangle in the paint device.
*
* @param dstProfile RGB profile to use in conversion. May be 0, in which
* case it's up to the color strategy to choose a profile (most
* like sRGB).
* @param x Left coordinate of the rectangle
* @param y Top coordinate of the rectangle
* @param w Width of the rectangle in pixels
* @param h Height of the rectangle in pixels
* @param renderingIntent Rendering intent
* @param conversionFlags Conversion flags
*/
QImage convertToQImage(const KoColorProfile *dstProfile, qint32 x, qint32 y, qint32 w, qint32 h,
KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags()) const;
/**
* Overridden method for convenience
*/
QImage convertToQImage(const KoColorProfile *dstProfile,
const QRect &rc,
KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags()) const;
/**
* Create an RGBA QImage from a rectangle in the paint device. The
* rectangle is defined by the parent image's bounds.
*
* @param dstProfile RGB profile to use in conversion. May be 0, in which
* case it's up to the color strategy to choose a profile (most
* like sRGB).
* @param renderingIntent Rendering intent
* @param conversionFlags Conversion flags
*/
QImage convertToQImage(const KoColorProfile * dstProfile,
KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags()) const;
/**
* Creates a paint device thumbnail of the paint device, retaining
* the aspect ratio. The width and height of the returned device
* won't exceed \p maxw and \p maxw, but they may be smaller.
*
* @param w maximum width
* @param h maximum height
* @param rect only this rect will be used for the thumbnail
* @param outputRect output rectangle
*
*/
KisPaintDeviceSP createThumbnailDevice(qint32 w, qint32 h, QRect rect = QRect(), QRect outputRect = QRect()) const;
KisPaintDeviceSP createThumbnailDeviceOversampled(qint32 w, qint32 h, qreal oversample, QRect rect = QRect(), QRect outputRect = QRect()) const;
/**
* Creates a thumbnail of the paint device, retaining the aspect ratio.
* The width and height of the returned QImage won't exceed \p maxw and \p maxw, but they may be smaller.
* The colors are not corrected for display!
*
* @param maxw: maximum width
* @param maxh: maximum height
* @param rect: only this rect will be used for the thumbnail
* @param oversample: ratio used for antialiasing
* @param renderingIntent Rendering intent
* @param conversionFlags Conversion flags
*/
QImage createThumbnail(qint32 maxw, qint32 maxh, QRect rect, qreal oversample = 1,
KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags());
/**
* Cached version of createThumbnail(qint32 maxw, qint32 maxh, const KisSelection *selection, QRect rect)
*/
QImage createThumbnail(qint32 maxw, qint32 maxh, qreal oversample = 1,
KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags());
+ /**
+ * Cached version of createThumbnail that also adjusts aspect ratio of the
+ * thumbnail to fit the extents of the paint device.
+ */
+ QImage createThumbnail(qint32 maxw, qint32 maxh,
+ Qt::AspectRatioMode aspectRatioMode,
+ qreal oversample = 1,
+ KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent(),
+ KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags());
+
/**
* Fill c and opacity with the values found at x and y.
*
* The color values will be transformed from the profile of
* this paint device to the display profile.
*
* @return true if the operation was successful.
*/
bool pixel(qint32 x, qint32 y, QColor *c) const;
/**
* Fill kc with the values found at x and y. This method differs
* from the above in using KoColor, which can be of any colorspace
*
* The color values will be transformed from the profile of
* this paint device to the display profile.
*
* @return true if the operation was successful.
*/
bool pixel(qint32 x, qint32 y, KoColor * kc) const;
/**
* Return pixel value in a form of KoColor. Please don't use this method
* for iteration, it is highly inefficient. Use iterators instead.
*/
KoColor pixel(const QPoint &pos) const;
/**
* Set the specified pixel to the specified color. Note that this
* bypasses KisPainter. the PaintDevice is here used as an equivalent
* to QImage, not QPixmap. This means that this is not undoable; also,
* there is no compositing with an existing value at this location.
*
* The color values will be transformed from the display profile to
* the paint device profile.
*
* Note that this will use 8-bit values and may cause a significant
* degradation when used on 16-bit or hdr quality images.
*
* @return true if the operation was successful
*/
bool setPixel(qint32 x, qint32 y, const QColor& c);
/// Convenience method for the above
bool setPixel(qint32 x, qint32 y, const KoColor& kc);
/**
* @return the colorspace of the pixels in this paint device
*/
const KoColorSpace* colorSpace() const;
/**
* There is quite a common technique in Krita. It is used in
* cases, when we want to paint something over a paint device
* using the composition, opacity or selection. E.g. painting a
* dab in a paint op, filling the selection in the Fill Tool.
* Such work is usually done in the following way:
*
* 1) Create a paint device
*
* 2) Fill it with the desired color or data
*
* 3) Create a KisPainter and set all the properties of the
* transaction: selection, compositeOp, opacity and etc.
*
* 4) Paint a newly created paint device over the destination
* device.
*
* The following two methods (createCompositionSourceDevice() or
* createCompositionSourceDeviceFixed())should be used for the
* accomplishing the step 1). The point is that the desired color
* space of the temporary device may not coincide with the color
* space of the destination. That is the case, for example, for
* the alpha8() colorspace used in the selections. So for such
* devices the temporary target would have a different (grayscale)
* color space.
*
* So there are two rules of thumb:
*
* 1) If you need a temporary device which you are going to fill
* with some data and then paint over the paint device, create
* it with either createCompositionSourceDevice() or
* createCompositionSourceDeviceFixed().
*
* 2) Do *not* expect that the color spaces of the destination and
* the temporary device would coincide. If you need to copy a
* single pixel from one device to another, you can use
* KisCrossDeviceColorPicker class, that will handle all the
* necessary conversions for you.
*
* \see createCompositionSourceDeviceFixed()
* \see compositionSourceColorSpace()
* \see KisCrossDeviceColorPicker
* \see KisCrossDeviceColorPickerInt
*/
KisPaintDeviceSP createCompositionSourceDevice() const;
/**
* The same as createCompositionSourceDevice(), but initializes the
* newly created device with the content of \p cloneSource
*
* \see createCompositionSourceDevice()
*/
KisPaintDeviceSP createCompositionSourceDevice(KisPaintDeviceSP cloneSource) const;
/**
* The same as createCompositionSourceDevice(), but initializes
* the newly created device with the *rough* \p roughRect of
* \p cloneSource.
*
* "Rough rect" means that it may copy a bit more than
* requested. It is expected that the caller will not use the area
* outside \p roughRect.
*
* \see createCompositionSourceDevice()
*/
KisPaintDeviceSP createCompositionSourceDevice(KisPaintDeviceSP cloneSource, const QRect roughRect) const;
/**
* This is a convenience method for createCompositionSourceDevice()
*
* \see createCompositionSourceDevice()
*/
KisFixedPaintDeviceSP createCompositionSourceDeviceFixed() const;
/**
* This is a lowlevel method for the principle used in
* createCompositionSourceDevice(). In most of the cases the paint
* device creation methods should be used instead of this function.
*
* \see createCompositionSourceDevice()
* \see createCompositionSourceDeviceFixed()
*/
virtual const KoColorSpace* compositionSourceColorSpace() const;
/**
* @return the internal datamanager that keeps the pixels.
*/
KisDataManagerSP dataManager() const;
/**
* Replace the pixel data, color strategy, and profile.
*/
void setDataManager(KisDataManagerSP data, const KoColorSpace * colorSpace = 0);
/**
* Return the number of bytes a pixel takes.
*/
quint32 pixelSize() const;
/**
* Return the number of channels a pixel takes
*/
quint32 channelCount() const;
/**
* Create a keyframe channel for the content on this device.
* @param id identifier for the channel
* @return keyframe channel or 0 if there is not one
*/
KisRasterKeyframeChannel *createKeyframeChannel(const KoID &id);
KisRasterKeyframeChannel* keyframeChannel() const;
/**
* An interface to modify/load/save frames stored inside this device
*/
KisPaintDeviceFramesInterface* framesInterface();
public:
/**
* Add the specified rect to the parent layer's set of dirty rects
* (if there is a parent layer)
*/
void setDirty(const QRect & rc);
void setDirty(const KisRegion &region);
/**
* Set the parent layer completely dirty, if this paint device has
* as parent layer.
*/
void setDirty();
void setDirty(const QVector<QRect> &rects);
/**
* Called by KisTransactionData when it thinks current time should
* be changed. And the requests is forwarded to the image if
* needed.
*/
void requestTimeSwitch(int time);
/**
* \return a sequence number corresponding to the current paint
* device state. Every time the paint device is changed,
* the sequence number is increased
*/
int sequenceNumber() const;
void estimateMemoryStats(qint64 &imageData, qint64 &temporaryData, qint64 &lodData) const;
public:
KisHLineIteratorSP createHLineIteratorNG(qint32 x, qint32 y, qint32 w);
KisHLineConstIteratorSP createHLineConstIteratorNG(qint32 x, qint32 y, qint32 w) const;
KisVLineIteratorSP createVLineIteratorNG(qint32 x, qint32 y, qint32 h);
KisVLineConstIteratorSP createVLineConstIteratorNG(qint32 x, qint32 y, qint32 h) const;
KisRandomAccessorSP createRandomAccessorNG();
KisRandomConstAccessorSP createRandomConstAccessorNG() const;
/**
* Create an iterator that will "artificially" extend the paint device with the
* value of the border when trying to access values outside the range of data.
*
* @param x x of top left corner
* @param y y of top left corner
* @param w width of the border
* @param _dataWidth indicates the rectangle that truly contains data
*/
KisRepeatHLineConstIteratorSP createRepeatHLineConstIterator(qint32 x, qint32 y, qint32 w, const QRect& _dataWidth) const;
/**
* Create an iterator that will "artificially" extend the paint device with the
* value of the border when trying to access values outside the range of data.
*
* @param x x of top left corner
* @param y y of top left corner
* @param h height of the border
* @param _dataWidth indicates the rectangle that truly contains data
*/
KisRepeatVLineConstIteratorSP createRepeatVLineConstIterator(qint32 x, qint32 y, qint32 h, const QRect& _dataWidth) const;
/**
* This function create a random accessor which can easily access to sub pixel values.
*/
KisRandomSubAccessorSP createRandomSubAccessor() const;
/** Clear the selected pixels from the paint device */
void clearSelection(KisSelectionSP selection);
+ /**
+ * Converts a paint device into a "new" paint device, that has
+ * unconnected history. That is, after reincarnation, the device's
+ * life starts a new page. No history. No memories.
+ *
+ * When the device is fed up with the new life, it can reincarnate
+ * back to its previous life by undoing the command returned by
+ * reincarnateWithDetachedHistory(). The old undo will continue
+ * working as if nothing has happened.
+ *
+ * NOTE: reincarnation affects only the current lod plane and/or
+ * current frame. All other frames are kept unaffected.
+ *
+ * @param copyContent decides if the device should take its current
+ * content to the new life
+ * @return undo command for execution and undoing of the reincarnation
+ */
+ KUndo2Command* reincarnateWithDetachedHistory(bool copyContent);
+
Q_SIGNALS:
void profileChanged(const KoColorProfile * profile);
void colorSpaceChanged(const KoColorSpace *colorspace);
public:
friend class PaintDeviceCache;
/**
* Caclculates exact bounds of the device. Used internally
* by a transparent caching system. The solution is very slow
* because it does a linear scanline search. So the complexity
* is n*n at worst.
*
* \see exactBounds(), nonDefaultPixelArea()
*/
QRect calculateExactBounds(bool nonDefaultOnly) const;
public:
struct MemoryReleaseObject : public QObject {
~MemoryReleaseObject() override;
};
static MemoryReleaseObject* createMemoryReleaseObject();
public:
struct LodDataStruct {
virtual ~LodDataStruct();
};
KisRegion regionForLodSyncing() const;
LodDataStruct* createLodDataStruct(int lod);
void updateLodDataStruct(LodDataStruct *dst, const QRect &srcRect);
void uploadLodDataStruct(LodDataStruct *dst);
void generateLodCloneDevice(KisPaintDeviceSP dst, const QRect &originalRect, int lod);
void setProjectionDevice(bool value);
void tesingFetchLodDevice(KisPaintDeviceSP targetDevice);
private:
KisPaintDevice& operator=(const KisPaintDevice&);
void init(const KoColorSpace *colorSpace,
KisDefaultBoundsBaseSP defaultBounds,
KisNodeWSP parent, const QString& name);
// Only KisPainter is allowed to have access to these low-level methods
friend class KisPainter;
/**
* Return a vector with in order the size in bytes of the channels
* in the colorspace of this paint device.
*/
QVector<qint32> channelSizes() const;
void emitColorSpaceChanged();
void emitProfileChanged();
private:
friend class KisPaintDeviceFramesInterface;
protected:
friend class KisSelectionTest;
KisNodeWSP parentNode() const;
private:
struct Private;
Private * const m_d;
};
#endif // KIS_PAINT_DEVICE_IMPL_H_
diff --git a/libs/image/kis_paint_device_data.h b/libs/image/kis_paint_device_data.h
index 836b972d63..aa6624dc31 100644
--- a/libs/image/kis_paint_device_data.h
+++ b/libs/image/kis_paint_device_data.h
@@ -1,317 +1,357 @@
/*
* Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_PAINT_DEVICE_DATA_H
#define __KIS_PAINT_DEVICE_DATA_H
#include "KoAlwaysInline.h"
#include "kundo2command.h"
+#include "kis_command_utils.h"
struct DirectDataAccessPolicy {
DirectDataAccessPolicy(KisDataManager *dataManager, KisIteratorCompleteListener *completionListener)
: m_dataManager(dataManager),
m_completionListener(completionListener){}
KisHLineConstIteratorSP createConstIterator(const QRect &rect) {
const int xOffset = 0;
const int yOffset = 0;
return new KisHLineIterator2(m_dataManager, rect.x(), rect.y(), rect.width(), xOffset, yOffset, false, m_completionListener);
}
KisHLineIteratorSP createIterator(const QRect &rect) {
const int xOffset = 0;
const int yOffset = 0;
return new KisHLineIterator2(m_dataManager, rect.x(), rect.y(), rect.width(), xOffset, yOffset, true, m_completionListener);
}
int pixelSize() const {
return m_dataManager->pixelSize();
}
KisDataManager *m_dataManager;
KisIteratorCompleteListener *m_completionListener;
};
class KisPaintDeviceData
{
public:
KisPaintDeviceData(KisPaintDevice *paintDevice)
: m_cache(paintDevice),
m_x(0), m_y(0),
m_colorSpace(0),
m_levelOfDetail(0),
m_cacheInvalidator(this)
{
}
KisPaintDeviceData(KisPaintDevice *paintDevice, const KisPaintDeviceData *rhs, bool cloneContent)
: m_dataManager(cloneContent ?
new KisDataManager(*rhs->m_dataManager) :
new KisDataManager(rhs->m_dataManager->pixelSize(), rhs->m_dataManager->defaultPixel())),
m_cache(paintDevice),
m_x(rhs->m_x),
m_y(rhs->m_y),
m_colorSpace(rhs->m_colorSpace),
m_levelOfDetail(rhs->m_levelOfDetail),
m_cacheInvalidator(this)
{
m_cache.setupCache();
}
void init(const KoColorSpace *cs, KisDataManagerSP dataManager) {
m_colorSpace = cs;
m_dataManager = dataManager;
m_cache.setupCache();
}
class ChangeProfileCommand : public KUndo2Command {
public:
ChangeProfileCommand(KisPaintDeviceData *data,
const KoColorSpace *oldCs, const KoColorSpace *newCs,
KUndo2Command *parent)
: KUndo2Command(parent),
m_data(data),
m_oldCs(oldCs),
m_newCs(newCs)
{
}
virtual void forcedRedo() {
m_data->m_colorSpace = m_newCs;
m_data->m_cache.setupCache();
}
void redo() override {
if (m_firstRun) {
m_firstRun = false;
return;
}
KUndo2Command::redo();
forcedRedo();
}
void undo() override {
m_data->m_colorSpace = m_oldCs;
m_data->m_cache.setupCache();
KUndo2Command::undo();
}
protected:
KisPaintDeviceData *m_data;
private:
bool m_firstRun {true};
const KoColorSpace *m_oldCs;
const KoColorSpace *m_newCs;
};
class ChangeColorSpaceCommand : public ChangeProfileCommand {
public:
ChangeColorSpaceCommand(KisPaintDeviceData *data,
KisDataManagerSP oldDm, KisDataManagerSP newDm,
const KoColorSpace *oldCs, const KoColorSpace *newCs,
KUndo2Command *parent)
: ChangeProfileCommand(data, oldCs, newCs, parent),
m_oldDm(oldDm),
m_newDm(newDm)
{
}
void forcedRedo() override {
m_data->m_dataManager = m_newDm;
ChangeProfileCommand::forcedRedo();
}
void undo() override {
m_data->m_dataManager = m_oldDm;
ChangeProfileCommand::undo();
}
private:
KisDataManagerSP m_oldDm;
KisDataManagerSP m_newDm;
};
void assignColorSpace(const KoColorSpace *dstColorSpace, KUndo2Command *parentCommand) {
if (*m_colorSpace->profile() == *dstColorSpace->profile()) return;
KIS_ASSERT_RECOVER_RETURN(m_colorSpace->pixelSize() == dstColorSpace->pixelSize());
ChangeProfileCommand *cmd =
new ChangeProfileCommand(this,
m_colorSpace, dstColorSpace,
parentCommand);
cmd->forcedRedo();
if (!parentCommand) {
delete cmd;
}
}
void convertDataColorSpace(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags, KUndo2Command *parentCommand) {
typedef KisSequentialIteratorBase<ReadOnlyIteratorPolicy<DirectDataAccessPolicy>, DirectDataAccessPolicy> InternalSequentialConstIterator;
typedef KisSequentialIteratorBase<WritableIteratorPolicy<DirectDataAccessPolicy>, DirectDataAccessPolicy> InternalSequentialIterator;
if (m_colorSpace == dstColorSpace || *m_colorSpace == *dstColorSpace) {
return;
}
QRect rc = m_dataManager->region().boundingRect();
const int dstPixelSize = dstColorSpace->pixelSize();
QScopedArrayPointer<quint8> dstDefaultPixel(new quint8[dstPixelSize]);
memset(dstDefaultPixel.data(), 0, dstPixelSize);
m_colorSpace->convertPixelsTo(m_dataManager->defaultPixel(), dstDefaultPixel.data(), dstColorSpace, 1, renderingIntent, conversionFlags);
KisDataManagerSP dstDataManager = new KisDataManager(dstPixelSize, dstDefaultPixel.data());
if (!rc.isEmpty()) {
InternalSequentialConstIterator srcIt(DirectDataAccessPolicy(m_dataManager.data(), cacheInvalidator()), rc);
InternalSequentialIterator dstIt(DirectDataAccessPolicy(dstDataManager.data(), cacheInvalidator()), rc);
int nConseqPixels = srcIt.nConseqPixels();
// since we are accessing data managers directly, the columns are always aligned
KIS_SAFE_ASSERT_RECOVER_NOOP(srcIt.nConseqPixels() == dstIt.nConseqPixels());
while(srcIt.nextPixels(nConseqPixels) &&
dstIt.nextPixels(nConseqPixels)) {
nConseqPixels = srcIt.nConseqPixels();
const quint8 *srcData = srcIt.rawDataConst();
quint8 *dstData = dstIt.rawData();
m_colorSpace->convertPixelsTo(srcData, dstData,
dstColorSpace,
nConseqPixels,
renderingIntent, conversionFlags);
}
}
// becomes owned by the parent
ChangeColorSpaceCommand *cmd =
new ChangeColorSpaceCommand(this,
m_dataManager, dstDataManager,
m_colorSpace, dstColorSpace,
parentCommand);
cmd->forcedRedo();
if (!parentCommand) {
delete cmd;
}
}
+ void reincarnateWithDetachedHistory(bool copyContent, KUndo2Command *parentCommand) {
+ struct SwitchDataManager : public KUndo2Command
+ {
+ SwitchDataManager(KisPaintDeviceData *data,
+ KisDataManagerSP oldDm, KisDataManagerSP newDm,
+ KUndo2Command *parent = 0)
+ : KUndo2Command(parent),
+ m_data(data),
+ m_oldDm(oldDm),
+ m_newDm(newDm)
+ {
+ }
+
+ void redo() override {
+ m_data->m_dataManager = m_newDm;
+ m_data->cache()->invalidate();
+ }
+
+ void undo() override {
+ m_data->m_dataManager = m_oldDm;
+ m_data->cache()->invalidate();
+ }
+
+ private:
+ KisPaintDeviceData *m_data;
+ KisDataManagerSP m_oldDm;
+ KisDataManagerSP m_newDm;
+ };
+
+ new KisCommandUtils::LambdaCommand(parentCommand,
+ [this, copyContent] () {
+ KisDataManagerSP newDm =
+ copyContent ?
+ new KisDataManager(*this->dataManager()) :
+ new KisDataManager(this->dataManager()->pixelSize(), this->dataManager()->defaultPixel());
+ return new SwitchDataManager(this, this->dataManager(), newDm);
+ });
+ }
+
void prepareClone(const KisPaintDeviceData *srcData, bool copyContent = false) {
m_x = srcData->x();
m_y = srcData->y();
if (copyContent) {
m_dataManager = new KisDataManager(*srcData->dataManager());
} else if (m_dataManager->pixelSize() !=
srcData->dataManager()->pixelSize()) {
// NOTE: we don't check default pixel value! it is the task of
// the higher level!
m_dataManager = new KisDataManager(srcData->dataManager()->pixelSize(), srcData->dataManager()->defaultPixel());
m_cache.setupCache();
} else {
m_dataManager->clear();
const quint8 *srcDefPixel = srcData->dataManager()->defaultPixel();
const int cmp =
memcmp(srcDefPixel,
m_dataManager->defaultPixel(),
m_dataManager->pixelSize());
if (cmp != 0) {
m_dataManager->setDefaultPixel(srcDefPixel);
}
}
m_levelOfDetail = srcData->levelOfDetail();
m_colorSpace = srcData->colorSpace();
m_cache.invalidate();
}
ALWAYS_INLINE KisDataManagerSP dataManager() const {
return m_dataManager;
}
ALWAYS_INLINE KisPaintDeviceCache* cache() {
return &m_cache;
}
ALWAYS_INLINE qint32 x() const {
return m_x;
}
ALWAYS_INLINE void setX(qint32 value) {
m_x = value;
}
ALWAYS_INLINE qint32 y() const {
return m_y;
}
ALWAYS_INLINE void setY(qint32 value) {
m_y = value;
}
ALWAYS_INLINE const KoColorSpace* colorSpace() const {
return m_colorSpace;
}
ALWAYS_INLINE qint32 levelOfDetail() const {
return m_levelOfDetail;
}
ALWAYS_INLINE void setLevelOfDetail(qint32 value) {
m_levelOfDetail = value;
}
ALWAYS_INLINE KisIteratorCompleteListener* cacheInvalidator() {
return &m_cacheInvalidator;
}
private:
struct CacheInvalidator : public KisIteratorCompleteListener {
CacheInvalidator(KisPaintDeviceData *_q) : q(_q) {}
void notifyWritableIteratorCompleted() override {
q->cache()->invalidate();
}
private:
KisPaintDeviceData *q;
};
private:
KisDataManagerSP m_dataManager;
KisPaintDeviceCache m_cache;
qint32 m_x;
qint32 m_y;
const KoColorSpace* m_colorSpace;
qint32 m_levelOfDetail;
CacheInvalidator m_cacheInvalidator;
};
#endif /* __KIS_PAINT_DEVICE_DATA_H */
diff --git a/libs/image/kis_painter.cc b/libs/image/kis_painter.cc
index 44f44fdc9a..59fb0f3261 100644
--- a/libs/image/kis_painter.cc
+++ b/libs/image/kis_painter.cc
@@ -1,3038 +1,3067 @@
/*
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
* Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
* Copyright (c) 2004 Clarence Dang <dang@kde.org>
* Copyright (c) 2004 Adrian Page <adrian@pagenet.plus.com>
* Copyright (c) 2004 Cyrille Berger <cberger@cberger.net>
* Copyright (c) 2008-2010 Lukáš Tvrdý <lukast.dev@gmail.com>
* Copyright (c) 2010 José Luis Vergara Toloza <pentalis@gmail.com>
* Copyright (c) 2011 Silvio Heinrich <plassy@web.de>
*
* 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_painter.h"
#include <stdlib.h>
#include <string.h>
#include <cfloat>
#include <cmath>
#include <climits>
#ifndef Q_OS_WIN
#include <strings.h>
#endif
#include <QImage>
#include <QRect>
#include <QString>
#include <QStringList>
#include <kundo2command.h>
#include <kis_debug.h>
#include <klocalizedstring.h>
#include "kis_image.h"
#include "filter/kis_filter.h"
#include "kis_layer.h"
#include "kis_paint_device.h"
#include "kis_fixed_paint_device.h"
#include "kis_transaction.h"
#include "kis_vec.h"
#include "kis_iterator_ng.h"
#include "kis_random_accessor_ng.h"
#include "filter/kis_filter_configuration.h"
#include "kis_pixel_selection.h"
#include <brushengine/kis_paint_information.h>
#include "kis_paintop_registry.h"
#include "kis_perspective_math.h"
#include "tiles3/kis_random_accessor.h"
#include <kis_distance_information.h>
#include <KoColorSpaceMaths.h>
#include "kis_lod_transform.h"
#include "kis_algebra_2d.h"
#include "krita_utils.h"
// Maximum distance from a Bezier control point to the line through the start
// and end points for the curve to be considered flat.
#define BEZIER_FLATNESS_THRESHOLD 0.5
#include "kis_painter_p.h"
KisPainter::KisPainter()
: d(new Private(this))
{
init();
}
KisPainter::KisPainter(KisPaintDeviceSP device)
: d(new Private(this, device->colorSpace()))
{
init();
Q_ASSERT(device);
begin(device);
}
KisPainter::KisPainter(KisPaintDeviceSP device, KisSelectionSP selection)
: d(new Private(this, device->colorSpace()))
{
init();
Q_ASSERT(device);
begin(device);
d->selection = selection;
}
void KisPainter::init()
{
d->selection = 0 ;
d->transaction = 0;
d->paintOp = 0;
d->sourceLayer = 0;
d->fillStyle = FillStyleNone;
d->strokeStyle = StrokeStyleBrush;
d->antiAliasPolygonFill = true;
d->progressUpdater = 0;
d->maskPainter = 0;
d->fillPainter = 0;
d->maskImageWidth = 255;
d->maskImageHeight = 255;
d->mirrorHorizontally = false;
d->mirrorVertically = false;
d->isOpacityUnit = true;
d->paramInfo = KoCompositeOp::ParameterInfo();
d->renderingIntent = KoColorConversionTransformation::internalRenderingIntent();
d->conversionFlags = KoColorConversionTransformation::internalConversionFlags();
}
KisPainter::~KisPainter()
{
// TODO: Maybe, don't be that strict?
// deleteTransaction();
end();
delete d->paintOp;
delete d->maskPainter;
delete d->fillPainter;
delete d;
}
template <bool useOldData>
void copyAreaOptimizedImpl(const QPoint &dstPt,
KisPaintDeviceSP src,
KisPaintDeviceSP dst,
const QRect &srcRect)
{
const QRect dstRect(dstPt, srcRect.size());
const QRect srcExtent = src->extent();
const QRect dstExtent = dst->extent();
const QRect srcSampleRect = srcExtent & srcRect;
const QRect dstSampleRect = dstExtent & dstRect;
const bool srcEmpty = srcSampleRect.isEmpty();
const bool dstEmpty = dstSampleRect.isEmpty();
if (!srcEmpty || !dstEmpty) {
if (srcEmpty) {
dst->clear(dstRect);
} else {
QRect srcCopyRect = srcRect;
QRect dstCopyRect = dstRect;
if (!srcExtent.contains(srcRect)) {
if (src->defaultPixel() == dst->defaultPixel()) {
const QRect dstSampleInSrcCoords = dstSampleRect.translated(srcRect.topLeft() - dstPt);
if (dstSampleInSrcCoords.isEmpty() || srcSampleRect.contains(dstSampleInSrcCoords)) {
srcCopyRect = srcSampleRect;
} else {
srcCopyRect = srcSampleRect | dstSampleInSrcCoords;
}
dstCopyRect = QRect(dstPt + srcCopyRect.topLeft() - srcRect.topLeft(), srcCopyRect.size());
}
}
KisPainter gc(dst);
gc.setCompositeOp(dst->colorSpace()->compositeOp(COMPOSITE_COPY));
if (useOldData) {
gc.bitBltOldData(dstCopyRect.topLeft(), src, srcCopyRect);
} else {
gc.bitBlt(dstCopyRect.topLeft(), src, srcCopyRect);
}
}
}
}
void KisPainter::copyAreaOptimized(const QPoint &dstPt,
KisPaintDeviceSP src,
KisPaintDeviceSP dst,
const QRect &srcRect)
{
copyAreaOptimizedImpl<false>(dstPt, src, dst, srcRect);
}
void KisPainter::copyAreaOptimizedOldData(const QPoint &dstPt,
KisPaintDeviceSP src,
KisPaintDeviceSP dst,
const QRect &srcRect)
{
copyAreaOptimizedImpl<true>(dstPt, src, dst, srcRect);
}
void KisPainter::copyAreaOptimized(const QPoint &dstPt,
KisPaintDeviceSP src,
KisPaintDeviceSP dst,
const QRect &originalSrcRect,
KisSelectionSP selection)
{
if (!selection) {
copyAreaOptimized(dstPt, src, dst, originalSrcRect);
return;
}
const QRect selectionRect = selection->selectedRect();
const QRect srcRect = originalSrcRect & selectionRect;
const QPoint dstOffset = srcRect.topLeft() - originalSrcRect.topLeft();
const QRect dstRect = QRect(dstPt + dstOffset, srcRect.size());
const bool srcEmpty = (src->extent() & srcRect).isEmpty();
const bool dstEmpty = (dst->extent() & dstRect).isEmpty();
if (!srcEmpty || !dstEmpty) {
//if (srcEmpty) {
// doesn't support dstRect
// dst->clearSelection(selection);
// } else */
{
KisPainter gc(dst);
gc.setSelection(selection);
gc.setCompositeOp(dst->colorSpace()->compositeOp(COMPOSITE_COPY));
gc.bitBlt(dstRect.topLeft(), src, srcRect);
}
}
}
KisPaintDeviceSP KisPainter::convertToAlphaAsAlpha(KisPaintDeviceSP src)
{
const KoColorSpace *srcCS = src->colorSpace();
const QRect processRect = src->extent();
KisPaintDeviceSP dst(new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8()));
if (processRect.isEmpty()) return dst;
KisSequentialConstIterator srcIt(src, processRect);
KisSequentialIterator dstIt(dst, processRect);
while (srcIt.nextPixel() && dstIt.nextPixel()) {
const quint8 *srcPtr = srcIt.rawDataConst();
quint8 *alpha8Ptr = dstIt.rawData();
const quint8 white = srcCS->intensity8(srcPtr);
const quint8 alpha = srcCS->opacityU8(srcPtr);
*alpha8Ptr = KoColorSpaceMaths<quint8>::multiply(alpha, KoColorSpaceMathsTraits<quint8>::unitValue - white);
}
return dst;
}
KisPaintDeviceSP KisPainter::convertToAlphaAsGray(KisPaintDeviceSP src)
{
const KoColorSpace *srcCS = src->colorSpace();
const QRect processRect = src->extent();
KisPaintDeviceSP dst(new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8()));
if (processRect.isEmpty()) return dst;
KisSequentialConstIterator srcIt(src, processRect);
KisSequentialIterator dstIt(dst, processRect);
while (srcIt.nextPixel() && dstIt.nextPixel()) {
const quint8 *srcPtr = srcIt.rawDataConst();
quint8 *alpha8Ptr = dstIt.rawData();
*alpha8Ptr = srcCS->intensity8(srcPtr);
}
return dst;
}
KisPaintDeviceSP KisPainter::convertToAlphaAsPureAlpha(KisPaintDeviceSP src)
{
const KoColorSpace *srcCS = src->colorSpace();
const QRect processRect = src->extent();
KisPaintDeviceSP dst(new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8()));
if (processRect.isEmpty()) return dst;
KisSequentialConstIterator srcIt(src, processRect);
KisSequentialIterator dstIt(dst, processRect);
while (srcIt.nextPixel() && dstIt.nextPixel()) {
const quint8 *srcPtr = srcIt.rawDataConst();
quint8 *alpha8Ptr = dstIt.rawData();
*alpha8Ptr = srcCS->opacityU8(srcPtr);
}
return dst;
}
bool KisPainter::checkDeviceHasTransparency(KisPaintDeviceSP dev)
{
const QRect deviceBounds = dev->exactBounds();
const QRect imageBounds = dev->defaultBounds()->bounds();
if (deviceBounds.isEmpty() ||
(deviceBounds & imageBounds) != imageBounds) {
return true;
}
const KoColorSpace *cs = dev->colorSpace();
KisSequentialConstIterator it(dev, deviceBounds);
while(it.nextPixel()) {
if (cs->opacityU8(it.rawDataConst()) != OPACITY_OPAQUE_U8) {
return true;
}
}
return false;
}
void KisPainter::begin(KisPaintDeviceSP device)
{
begin(device, d->selection);
}
void KisPainter::begin(KisPaintDeviceSP device, KisSelectionSP selection)
{
if (!device) return;
d->selection = selection;
Q_ASSERT(device->colorSpace());
end();
d->device = device;
d->colorSpace = device->colorSpace();
d->compositeOp = d->colorSpace->compositeOp(COMPOSITE_OVER);
d->pixelSize = device->pixelSize();
}
void KisPainter::end()
{
Q_ASSERT_X(!d->transaction, "KisPainter::end()",
"end() was called for the painter having a transaction. "
"Please use end/deleteTransaction() instead");
}
void KisPainter::beginTransaction(const KUndo2MagicString& transactionName,int timedID)
{
Q_ASSERT_X(!d->transaction, "KisPainter::beginTransaction()",
"You asked for a new transaction while still having "
"another one. Please finish the first one with "
"end/deleteTransaction() first");
d->transaction = new KisTransaction(transactionName, d->device);
Q_CHECK_PTR(d->transaction);
d->transaction->undoCommand()->setTimedID(timedID);
}
void KisPainter::revertTransaction()
{
Q_ASSERT_X(d->transaction, "KisPainter::revertTransaction()",
"No transaction is in progress");
d->transaction->revert();
delete d->transaction;
d->transaction = 0;
}
void KisPainter::endTransaction(KisUndoAdapter *undoAdapter)
{
Q_ASSERT_X(d->transaction, "KisPainter::endTransaction()",
"No transaction is in progress");
d->transaction->commit(undoAdapter);
delete d->transaction;
d->transaction = 0;
}
void KisPainter::endTransaction(KisPostExecutionUndoAdapter *undoAdapter)
{
Q_ASSERT_X(d->transaction, "KisPainter::endTransaction()",
"No transaction is in progress");
d->transaction->commit(undoAdapter);
delete d->transaction;
d->transaction = 0;
}
KUndo2Command* KisPainter::endAndTakeTransaction()
{
Q_ASSERT_X(d->transaction, "KisPainter::endTransaction()",
"No transaction is in progress");
KUndo2Command *transactionData = d->transaction->endAndTake();
delete d->transaction;
d->transaction = 0;
return transactionData;
}
void KisPainter::deleteTransaction()
{
if (!d->transaction) return;
delete d->transaction;
d->transaction = 0;
}
void KisPainter::putTransaction(KisTransaction* transaction)
{
Q_ASSERT_X(!d->transaction, "KisPainter::putTransaction()",
"You asked for a new transaction while still having "
"another one. Please finish the first one with "
"end/deleteTransaction() first");
d->transaction = transaction;
}
KisTransaction* KisPainter::takeTransaction()
{
Q_ASSERT_X(d->transaction, "KisPainter::takeTransaction()",
"No transaction is in progress");
KisTransaction *temp = d->transaction;
d->transaction = 0;
return temp;
}
QVector<QRect> KisPainter::takeDirtyRegion()
{
QVector<QRect> vrect = d->dirtyRects;
d->dirtyRects.clear();
return vrect;
}
void KisPainter::addDirtyRect(const QRect & rc)
{
QRect r = rc.normalized();
if (r.isValid()) {
d->dirtyRects.append(rc);
}
}
void KisPainter::addDirtyRects(const QVector<QRect> &rects)
{
d->dirtyRects.reserve(d->dirtyRects.size() + rects.size());
Q_FOREACH (const QRect &rc, rects) {
const QRect r = rc.normalized();
if (r.isValid()) {
d->dirtyRects.append(rc);
}
}
}
inline bool KisPainter::Private::tryReduceSourceRect(const KisPaintDevice *srcDev,
QRect *srcRect,
qint32 *srcX,
qint32 *srcY,
qint32 *srcWidth,
qint32 *srcHeight,
qint32 *dstX,
qint32 *dstY)
{
+ bool needsReadjustParams = false;
+
/**
* In case of COMPOSITE_COPY and Wrap Around Mode even the pixels
* outside the device extent matter, because they will be either
* directly copied (former case) or cloned from another area of
* the image.
*/
if (compositeOp->id() != COMPOSITE_COPY &&
compositeOp->id() != COMPOSITE_DESTINATION_IN &&
compositeOp->id() != COMPOSITE_DESTINATION_ATOP &&
!srcDev->defaultBounds()->wrapAroundMode()) {
/**
* If srcDev->extent() (the area of the tiles containing
* srcDev) is smaller than srcRect, then shrink srcRect to
* that size. This is done as a speed optimization, useful for
* stack recomposition in KisImage. srcRect won't grow if
* srcDev->extent() is larger.
*/
*srcRect &= srcDev->extent();
if (srcRect->isEmpty()) return true;
+ needsReadjustParams = true;
+ }
+
+ if (selection) {
+ /**
+ * We should also crop the blitted area by the selected region,
+ * because we cannot paint outside the selection.
+ */
+ *srcRect &= selection->selectedRect();
+
+ if (srcRect->isEmpty()) return true;
+ needsReadjustParams = true;
+ }
+
+ if (!paramInfo.channelFlags.isEmpty()) {
+ const QBitArray onlyColor = colorSpace->channelFlags(true, false);
+ KIS_SAFE_ASSERT_RECOVER_NOOP(onlyColor.size() == paramInfo.channelFlags.size());
+
+ // check if we have alpha channel locked
+ if ((paramInfo.channelFlags & onlyColor) == paramInfo.channelFlags) {
+ *srcRect &= device->extent();
+
+ if (srcRect->isEmpty()) return true;
+ needsReadjustParams = true;
+ }
+ }
+ if (needsReadjustParams) {
// Readjust the function paramenters to the new dimensions.
*dstX += srcRect->x() - *srcX; // This will only add, not subtract
*dstY += srcRect->y() - *srcY; // Idem
srcRect->getRect(srcX, srcY, srcWidth, srcHeight);
}
return false;
}
void KisPainter::bitBltWithFixedSelection(qint32 dstX, qint32 dstY,
const KisPaintDeviceSP srcDev,
const KisFixedPaintDeviceSP selection,
qint32 selX, qint32 selY,
qint32 srcX, qint32 srcY,
qint32 srcWidth, qint32 srcHeight)
{
// TODO: get selX and selY working as intended
/* This check for nonsense ought to be a Q_ASSERT. However, when paintops are just
initializing they perform some dummy passes with those parameters, and it must not crash */
if (srcWidth == 0 || srcHeight == 0) return;
if (srcDev.isNull()) return;
if (d->device.isNull()) return;
// Check that selection has an alpha colorspace, crash if false
Q_ASSERT(selection->colorSpace() == KoColorSpaceRegistry::instance()->alpha8());
QRect srcRect = QRect(srcX, srcY, srcWidth, srcHeight);
QRect selRect = QRect(selX, selY, srcWidth, srcHeight);
/* Trying to read outside a KisFixedPaintDevice is inherently wrong and shouldn't be done,
so crash if someone attempts to do this. Don't resize YET as it would obfuscate the mistake. */
Q_ASSERT(selection->bounds().contains(selRect));
Q_UNUSED(selRect); // only used by the above Q_ASSERT
/**
* An optimization, which crops the source rect by the bounds of
* the source device when it is possible
*/
if (d->tryReduceSourceRect(srcDev, &srcRect,
&srcX, &srcY,
&srcWidth, &srcHeight,
&dstX, &dstY)) return;
/* Create an intermediate byte array to hold information before it is written
to the current paint device (d->device) */
quint8* dstBytes = 0;
try {
dstBytes = new quint8[srcWidth * srcHeight * d->device->pixelSize()];
} catch (const std::bad_alloc&) {
warnKrita << "KisPainter::bitBltWithFixedSelection std::bad_alloc for " << srcWidth << " * " << srcHeight << " * " << d->device->pixelSize() << "dst bytes";
return;
}
d->device->readBytes(dstBytes, dstX, dstY, srcWidth, srcHeight);
// Copy the relevant bytes of raw data from srcDev
quint8* srcBytes = 0;
try {
srcBytes = new quint8[srcWidth * srcHeight * srcDev->pixelSize()];
} catch (const std::bad_alloc&) {
warnKrita << "KisPainter::bitBltWithFixedSelection std::bad_alloc for " << srcWidth << " * " << srcHeight << " * " << d->device->pixelSize() << "src bytes";
return;
}
srcDev->readBytes(srcBytes, srcX, srcY, srcWidth, srcHeight);
QRect selBounds = selection->bounds();
const quint8 *selRowStart = selection->data() +
(selBounds.width() * (selY - selBounds.top()) + (selX - selBounds.left())) * selection->pixelSize();
/*
* This checks whether there is nothing selected.
*/
if (!d->selection) {
/* As there's nothing selected, blit to dstBytes (intermediary bit array),
ignoring d->selection (the user selection)*/
d->paramInfo.dstRowStart = dstBytes;
d->paramInfo.dstRowStride = srcWidth * d->device->pixelSize();
d->paramInfo.srcRowStart = srcBytes;
d->paramInfo.srcRowStride = srcWidth * srcDev->pixelSize();
d->paramInfo.maskRowStart = selRowStart;
d->paramInfo.maskRowStride = selBounds.width() * selection->pixelSize();
d->paramInfo.rows = srcHeight;
d->paramInfo.cols = srcWidth;
d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags);
}
else {
/* Read the user selection (d->selection) bytes into an array, ready
to merge in the next block*/
quint32 totalBytes = srcWidth * srcHeight * selection->pixelSize();
quint8* mergedSelectionBytes = 0;
try {
mergedSelectionBytes = new quint8[ totalBytes ];
} catch (const std::bad_alloc&) {
warnKrita << "KisPainter::bitBltWithFixedSelection std::bad_alloc for " << srcWidth << " * " << srcHeight << " * " << d->device->pixelSize() << "total bytes";
return;
}
d->selection->projection()->readBytes(mergedSelectionBytes, dstX, dstY, srcWidth, srcHeight);
// Merge selections here by multiplying them - compositeOP(COMPOSITE_MULT)
d->paramInfo.dstRowStart = mergedSelectionBytes;
d->paramInfo.dstRowStride = srcWidth * selection->pixelSize();
d->paramInfo.srcRowStart = selRowStart;
d->paramInfo.srcRowStride = selBounds.width() * selection->pixelSize();
d->paramInfo.maskRowStart = 0;
d->paramInfo.maskRowStride = 0;
d->paramInfo.rows = srcHeight;
d->paramInfo.cols = srcWidth;
KoColorSpaceRegistry::instance()->alpha8()->compositeOp(COMPOSITE_MULT)->composite(d->paramInfo);
// Blit to dstBytes (intermediary bit array)
d->paramInfo.dstRowStart = dstBytes;
d->paramInfo.dstRowStride = srcWidth * d->device->pixelSize();
d->paramInfo.srcRowStart = srcBytes;
d->paramInfo.srcRowStride = srcWidth * srcDev->pixelSize();
d->paramInfo.maskRowStart = mergedSelectionBytes;
d->paramInfo.maskRowStride = srcWidth * selection->pixelSize();
d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags);
delete[] mergedSelectionBytes;
}
d->device->writeBytes(dstBytes, dstX, dstY, srcWidth, srcHeight);
delete[] dstBytes;
delete[] srcBytes;
addDirtyRect(QRect(dstX, dstY, srcWidth, srcHeight));
}
void KisPainter::bitBltWithFixedSelection(qint32 dstX, qint32 dstY,
const KisPaintDeviceSP srcDev,
const KisFixedPaintDeviceSP selection,
qint32 srcWidth, qint32 srcHeight)
{
bitBltWithFixedSelection(dstX, dstY, srcDev, selection, 0, 0, 0, 0, srcWidth, srcHeight);
}
template <bool useOldSrcData>
void KisPainter::bitBltImpl(qint32 dstX, qint32 dstY,
const KisPaintDeviceSP srcDev,
qint32 srcX, qint32 srcY,
qint32 srcWidth, qint32 srcHeight)
{
/* This check for nonsense ought to be a Q_ASSERT. However, when paintops are just
initializing they perform some dummy passes with those parameters, and it must not crash */
if (srcWidth == 0 || srcHeight == 0) return;
if (srcDev.isNull()) return;
if (d->device.isNull()) return;
QRect srcRect = QRect(srcX, srcY, srcWidth, srcHeight);
if (d->compositeOp->id() == COMPOSITE_COPY) {
if(!d->selection && d->isOpacityUnit &&
srcX == dstX && srcY == dstY &&
d->device->fastBitBltPossible(srcDev)) {
if(useOldSrcData) {
d->device->fastBitBltOldData(srcDev, srcRect);
} else {
d->device->fastBitBlt(srcDev, srcRect);
}
addDirtyRect(srcRect);
return;
}
}
else {
/**
* An optimization, which crops the source rect by the bounds of
* the source device when it is possible
*/
if (d->tryReduceSourceRect(srcDev, &srcRect,
&srcX, &srcY,
&srcWidth, &srcHeight,
&dstX, &dstY)) return;
}
qint32 dstY_ = dstY;
qint32 srcY_ = srcY;
qint32 rowsRemaining = srcHeight;
// Read below
KisRandomConstAccessorSP srcIt = srcDev->createRandomConstAccessorNG();
KisRandomAccessorSP dstIt = d->device->createRandomAccessorNG();
/* Here be a huge block of verbose code that does roughly the same than
the other bit blit operations. This one is longer than the rest in an effort to
optimize speed and memory use */
if (d->selection) {
KisPaintDeviceSP selectionProjection(d->selection->projection());
KisRandomConstAccessorSP maskIt = selectionProjection->createRandomConstAccessorNG();
while (rowsRemaining > 0) {
qint32 dstX_ = dstX;
qint32 srcX_ = srcX;
qint32 columnsRemaining = srcWidth;
qint32 numContiguousDstRows = dstIt->numContiguousRows(dstY_);
qint32 numContiguousSrcRows = srcIt->numContiguousRows(srcY_);
qint32 numContiguousSelRows = maskIt->numContiguousRows(dstY_);
qint32 rows = qMin(numContiguousDstRows, numContiguousSrcRows);
rows = qMin(rows, numContiguousSelRows);
rows = qMin(rows, rowsRemaining);
while (columnsRemaining > 0) {
qint32 numContiguousDstColumns = dstIt->numContiguousColumns(dstX_);
qint32 numContiguousSrcColumns = srcIt->numContiguousColumns(srcX_);
qint32 numContiguousSelColumns = maskIt->numContiguousColumns(dstX_);
qint32 columns = qMin(numContiguousDstColumns, numContiguousSrcColumns);
columns = qMin(columns, numContiguousSelColumns);
columns = qMin(columns, columnsRemaining);
qint32 srcRowStride = srcIt->rowStride(srcX_, srcY_);
srcIt->moveTo(srcX_, srcY_);
qint32 dstRowStride = dstIt->rowStride(dstX_, dstY_);
dstIt->moveTo(dstX_, dstY_);
qint32 maskRowStride = maskIt->rowStride(dstX_, dstY_);
maskIt->moveTo(dstX_, dstY_);
d->paramInfo.dstRowStart = dstIt->rawData();
d->paramInfo.dstRowStride = dstRowStride;
// if we don't use the oldRawData, we need to access the rawData of the source device.
d->paramInfo.srcRowStart = useOldSrcData ? srcIt->oldRawData() : static_cast<KisRandomAccessor2*>(srcIt.data())->rawData();
d->paramInfo.srcRowStride = srcRowStride;
d->paramInfo.maskRowStart = static_cast<KisRandomAccessor2*>(maskIt.data())->rawData();
d->paramInfo.maskRowStride = maskRowStride;
d->paramInfo.rows = rows;
d->paramInfo.cols = columns;
d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags);
srcX_ += columns;
dstX_ += columns;
columnsRemaining -= columns;
}
srcY_ += rows;
dstY_ += rows;
rowsRemaining -= rows;
}
}
else {
while (rowsRemaining > 0) {
qint32 dstX_ = dstX;
qint32 srcX_ = srcX;
qint32 columnsRemaining = srcWidth;
qint32 numContiguousDstRows = dstIt->numContiguousRows(dstY_);
qint32 numContiguousSrcRows = srcIt->numContiguousRows(srcY_);
qint32 rows = qMin(numContiguousDstRows, numContiguousSrcRows);
rows = qMin(rows, rowsRemaining);
while (columnsRemaining > 0) {
qint32 numContiguousDstColumns = dstIt->numContiguousColumns(dstX_);
qint32 numContiguousSrcColumns = srcIt->numContiguousColumns(srcX_);
qint32 columns = qMin(numContiguousDstColumns, numContiguousSrcColumns);
columns = qMin(columns, columnsRemaining);
qint32 srcRowStride = srcIt->rowStride(srcX_, srcY_);
srcIt->moveTo(srcX_, srcY_);
qint32 dstRowStride = dstIt->rowStride(dstX_, dstY_);
dstIt->moveTo(dstX_, dstY_);
d->paramInfo.dstRowStart = dstIt->rawData();
d->paramInfo.dstRowStride = dstRowStride;
// if we don't use the oldRawData, we need to access the rawData of the source device.
d->paramInfo.srcRowStart = useOldSrcData ? srcIt->oldRawData() : static_cast<KisRandomAccessor2*>(srcIt.data())->rawData();
d->paramInfo.srcRowStride = srcRowStride;
d->paramInfo.maskRowStart = 0;
d->paramInfo.maskRowStride = 0;
d->paramInfo.rows = rows;
d->paramInfo.cols = columns;
d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags);
srcX_ += columns;
dstX_ += columns;
columnsRemaining -= columns;
}
srcY_ += rows;
dstY_ += rows;
rowsRemaining -= rows;
}
}
addDirtyRect(QRect(dstX, dstY, srcWidth, srcHeight));
}
void KisPainter::bitBlt(qint32 dstX, qint32 dstY,
const KisPaintDeviceSP srcDev,
qint32 srcX, qint32 srcY,
qint32 srcWidth, qint32 srcHeight)
{
bitBltImpl<false>(dstX, dstY, srcDev, srcX, srcY, srcWidth, srcHeight);
}
void KisPainter::bitBlt(const QPoint & pos, const KisPaintDeviceSP srcDev, const QRect & srcRect)
{
bitBlt(pos.x(), pos.y(), srcDev, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height());
}
void KisPainter::bitBltOldData(qint32 dstX, qint32 dstY,
const KisPaintDeviceSP srcDev,
qint32 srcX, qint32 srcY,
qint32 srcWidth, qint32 srcHeight)
{
bitBltImpl<true>(dstX, dstY, srcDev, srcX, srcY, srcWidth, srcHeight);
}
void KisPainter::bitBltOldData(const QPoint & pos, const KisPaintDeviceSP srcDev, const QRect & srcRect)
{
bitBltOldData(pos.x(), pos.y(), srcDev, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height());
}
void KisPainter::fill(qint32 x, qint32 y, qint32 width, qint32 height, const KoColor& color)
{
/* This check for nonsense ought to be a Q_ASSERT. However, when paintops are just
* initializing they perform some dummy passes with those parameters, and it must not crash */
if(width == 0 || height == 0 || d->device.isNull())
return;
KoColor srcColor(color, d->device->compositionSourceColorSpace());
qint32 dstY = y;
qint32 rowsRemaining = height;
KisRandomAccessorSP dstIt = d->device->createRandomAccessorNG();
if(d->selection) {
KisPaintDeviceSP selectionProjection(d->selection->projection());
KisRandomConstAccessorSP maskIt = selectionProjection->createRandomConstAccessorNG();
while(rowsRemaining > 0) {
qint32 dstX = x;
qint32 columnsRemaining = width;
qint32 numContiguousDstRows = dstIt->numContiguousRows(dstY);
qint32 numContiguousSelRows = maskIt->numContiguousRows(dstY);
qint32 rows = qMin(numContiguousDstRows, numContiguousSelRows);
rows = qMin(rows, rowsRemaining);
while (columnsRemaining > 0) {
qint32 numContiguousDstColumns = dstIt->numContiguousColumns(dstX);
qint32 numContiguousSelColumns = maskIt->numContiguousColumns(dstX);
qint32 columns = qMin(numContiguousDstColumns, numContiguousSelColumns);
columns = qMin(columns, columnsRemaining);
qint32 dstRowStride = dstIt->rowStride(dstX, dstY);
dstIt->moveTo(dstX, dstY);
qint32 maskRowStride = maskIt->rowStride(dstX, dstY);
maskIt->moveTo(dstX, dstY);
d->paramInfo.dstRowStart = dstIt->rawData();
d->paramInfo.dstRowStride = dstRowStride;
d->paramInfo.srcRowStart = srcColor.data();
d->paramInfo.srcRowStride = 0; // srcRowStride is set to zero to use the compositeOp with only a single color pixel
d->paramInfo.maskRowStart = maskIt->oldRawData();
d->paramInfo.maskRowStride = maskRowStride;
d->paramInfo.rows = rows;
d->paramInfo.cols = columns;
d->colorSpace->bitBlt(srcColor.colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags);
dstX += columns;
columnsRemaining -= columns;
}
dstY += rows;
rowsRemaining -= rows;
}
}
else {
while(rowsRemaining > 0) {
qint32 dstX = x;
qint32 columnsRemaining = width;
qint32 numContiguousDstRows = dstIt->numContiguousRows(dstY);
qint32 rows = qMin(numContiguousDstRows, rowsRemaining);
while(columnsRemaining > 0) {
qint32 numContiguousDstColumns = dstIt->numContiguousColumns(dstX);
qint32 columns = qMin(numContiguousDstColumns, columnsRemaining);
qint32 dstRowStride = dstIt->rowStride(dstX, dstY);
dstIt->moveTo(dstX, dstY);
d->paramInfo.dstRowStart = dstIt->rawData();
d->paramInfo.dstRowStride = dstRowStride;
d->paramInfo.srcRowStart = srcColor.data();
d->paramInfo.srcRowStride = 0; // srcRowStride is set to zero to use the compositeOp with only a single color pixel
d->paramInfo.maskRowStart = 0;
d->paramInfo.maskRowStride = 0;
d->paramInfo.rows = rows;
d->paramInfo.cols = columns;
d->colorSpace->bitBlt(srcColor.colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags);
dstX += columns;
columnsRemaining -= columns;
}
dstY += rows;
rowsRemaining -= rows;
}
}
addDirtyRect(QRect(x, y, width, height));
}
void KisPainter::bltFixed(qint32 dstX, qint32 dstY,
const KisFixedPaintDeviceSP srcDev,
qint32 srcX, qint32 srcY,
qint32 srcWidth, qint32 srcHeight)
{
/* This check for nonsense ought to be a Q_ASSERT. However, when paintops are just
initializing they perform some dummy passes with those parameters, and it must not crash */
if (srcWidth == 0 || srcHeight == 0) return;
if (srcDev.isNull()) return;
if (d->device.isNull()) return;
QRect srcRect = QRect(srcX, srcY, srcWidth, srcHeight);
QRect srcBounds = srcDev->bounds();
/* Trying to read outside a KisFixedPaintDevice is inherently wrong and shouldn't be done,
so crash if someone attempts to do this. Don't resize as it would obfuscate the mistake. */
KIS_SAFE_ASSERT_RECOVER_RETURN(srcBounds.contains(srcRect));
Q_UNUSED(srcRect); // only used in above assertion
/* Create an intermediate byte array to hold information before it is written
to the current paint device (aka: d->device) */
quint8* dstBytes = 0;
try {
dstBytes = new quint8[srcWidth * srcHeight * d->device->pixelSize()];
} catch (const std::bad_alloc&) {
warnKrita << "KisPainter::bltFixed std::bad_alloc for " << srcWidth << " * " << srcHeight << " * " << d->device->pixelSize() << "total bytes";
return;
}
d->device->readBytes(dstBytes, dstX, dstY, srcWidth, srcHeight);
const quint8 *srcRowStart = srcDev->data() +
(srcBounds.width() * (srcY - srcBounds.top()) + (srcX - srcBounds.left())) * srcDev->pixelSize();
d->paramInfo.dstRowStart = dstBytes;
d->paramInfo.dstRowStride = srcWidth * d->device->pixelSize();
d->paramInfo.srcRowStart = srcRowStart;
d->paramInfo.srcRowStride = srcBounds.width() * srcDev->pixelSize();
d->paramInfo.maskRowStart = 0;
d->paramInfo.maskRowStride = 0;
d->paramInfo.rows = srcHeight;
d->paramInfo.cols = srcWidth;
if (d->selection) {
/* d->selection is a KisPaintDevice, so first a readBytes is performed to
get the area of interest... */
KisPaintDeviceSP selectionProjection(d->selection->projection());
quint8* selBytes = 0;
try {
selBytes = new quint8[srcWidth * srcHeight * selectionProjection->pixelSize()];
}
catch (const std::bad_alloc&) {
delete[] dstBytes;
return;
}
selectionProjection->readBytes(selBytes, dstX, dstY, srcWidth, srcHeight);
d->paramInfo.maskRowStart = selBytes;
d->paramInfo.maskRowStride = srcWidth * selectionProjection->pixelSize();
}
// ...and then blit.
d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags);
d->device->writeBytes(dstBytes, dstX, dstY, srcWidth, srcHeight);
delete[] d->paramInfo.maskRowStart;
delete[] dstBytes;
addDirtyRect(QRect(dstX, dstY, srcWidth, srcHeight));
}
void KisPainter::bltFixed(const QPoint & pos, const KisFixedPaintDeviceSP srcDev, const QRect & srcRect)
{
bltFixed(pos.x(), pos.y(), srcDev, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height());
}
void KisPainter::bltFixedWithFixedSelection(qint32 dstX, qint32 dstY,
const KisFixedPaintDeviceSP srcDev,
const KisFixedPaintDeviceSP selection,
qint32 selX, qint32 selY,
qint32 srcX, qint32 srcY,
quint32 srcWidth, quint32 srcHeight)
{
// TODO: get selX and selY working as intended
/* This check for nonsense ought to be a Q_ASSERT. However, when paintops are just
initializing they perform some dummy passes with those parameters, and it must not crash */
if (srcWidth == 0 || srcHeight == 0) return;
if (srcDev.isNull()) return;
if (d->device.isNull()) return;
// Check that selection has an alpha colorspace, crash if false
Q_ASSERT(selection->colorSpace() == KoColorSpaceRegistry::instance()->alpha8());
QRect srcRect = QRect(srcX, srcY, srcWidth, srcHeight);
QRect selRect = QRect(selX, selY, srcWidth, srcHeight);
QRect srcBounds = srcDev->bounds();
QRect selBounds = selection->bounds();
/* Trying to read outside a KisFixedPaintDevice is inherently wrong and shouldn't be done,
so crash if someone attempts to do this. Don't resize as it would obfuscate the mistake. */
Q_ASSERT(srcBounds.contains(srcRect));
Q_UNUSED(srcRect); // only used in above assertion
Q_ASSERT(selBounds.contains(selRect));
Q_UNUSED(selRect); // only used in above assertion
/* Create an intermediate byte array to hold information before it is written
to the current paint device (aka: d->device) */
quint8* dstBytes = 0;
try {
dstBytes = new quint8[srcWidth * srcHeight * d->device->pixelSize()];
} catch (const std::bad_alloc&) {
warnKrita << "KisPainter::bltFixedWithFixedSelection std::bad_alloc for " << srcWidth << " * " << srcHeight << " * " << d->device->pixelSize() << "total bytes";
return;
}
d->device->readBytes(dstBytes, dstX, dstY, srcWidth, srcHeight);
const quint8 *srcRowStart = srcDev->data() +
(srcBounds.width() * (srcY - srcBounds.top()) + (srcX - srcBounds.left())) * srcDev->pixelSize();
const quint8 *selRowStart = selection->data() +
(selBounds.width() * (selY - selBounds.top()) + (selX - selBounds.left())) * selection->pixelSize();
if (!d->selection) {
/* As there's nothing selected, blit to dstBytes (intermediary bit array),
ignoring d->selection (the user selection)*/
d->paramInfo.dstRowStart = dstBytes;
d->paramInfo.dstRowStride = srcWidth * d->device->pixelSize();
d->paramInfo.srcRowStart = srcRowStart;
d->paramInfo.srcRowStride = srcBounds.width() * srcDev->pixelSize();
d->paramInfo.maskRowStart = selRowStart;
d->paramInfo.maskRowStride = selBounds.width() * selection->pixelSize();
d->paramInfo.rows = srcHeight;
d->paramInfo.cols = srcWidth;
d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags);
}
else {
/* Read the user selection (d->selection) bytes into an array, ready
to merge in the next block*/
quint32 totalBytes = srcWidth * srcHeight * selection->pixelSize();
quint8 * mergedSelectionBytes = 0;
try {
mergedSelectionBytes = new quint8[ totalBytes ];
} catch (const std::bad_alloc&) {
warnKrita << "KisPainter::bltFixedWithFixedSelection std::bad_alloc for " << totalBytes << "total bytes";
delete[] dstBytes;
return;
}
d->selection->projection()->readBytes(mergedSelectionBytes, dstX, dstY, srcWidth, srcHeight);
// Merge selections here by multiplying them - compositeOp(COMPOSITE_MULT)
d->paramInfo.dstRowStart = mergedSelectionBytes;
d->paramInfo.dstRowStride = srcWidth * selection->pixelSize();
d->paramInfo.srcRowStart = selRowStart;
d->paramInfo.srcRowStride = selBounds.width() * selection->pixelSize();
d->paramInfo.maskRowStart = 0;
d->paramInfo.maskRowStride = 0;
d->paramInfo.rows = srcHeight;
d->paramInfo.cols = srcWidth;
KoColorSpaceRegistry::instance()->alpha8()->compositeOp(COMPOSITE_MULT)->composite(d->paramInfo);
// Blit to dstBytes (intermediary bit array)
d->paramInfo.dstRowStart = dstBytes;
d->paramInfo.dstRowStride = srcWidth * d->device->pixelSize();
d->paramInfo.srcRowStart = srcRowStart;
d->paramInfo.srcRowStride = srcBounds.width() * srcDev->pixelSize();
d->paramInfo.maskRowStart = mergedSelectionBytes;
d->paramInfo.maskRowStride = srcWidth * selection->pixelSize();
d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags);
delete[] mergedSelectionBytes;
}
d->device->writeBytes(dstBytes, dstX, dstY, srcWidth, srcHeight);
delete[] dstBytes;
addDirtyRect(QRect(dstX, dstY, srcWidth, srcHeight));
}
void KisPainter::bltFixedWithFixedSelection(qint32 dstX, qint32 dstY,
const KisFixedPaintDeviceSP srcDev,
const KisFixedPaintDeviceSP selection,
quint32 srcWidth, quint32 srcHeight)
{
bltFixedWithFixedSelection(dstX, dstY, srcDev, selection, 0, 0, 0, 0, srcWidth, srcHeight);
}
void KisPainter::paintLine(const KisPaintInformation &pi1,
const KisPaintInformation &pi2,
KisDistanceInformation *currentDistance)
{
if (d->device && d->paintOp && d->paintOp->canPaint()) {
d->paintOp->paintLine(pi1, pi2, currentDistance);
}
}
void KisPainter::paintPolyline(const vQPointF &points,
int index, int numPoints)
{
if (d->fillStyle != FillStyleNone) {
fillPolygon(points, d->fillStyle);
}
if (d->strokeStyle == StrokeStyleNone) return;
if (index >= points.count())
return;
if (numPoints < 0)
numPoints = points.count();
if (index + numPoints > points.count())
numPoints = points.count() - index;
if (numPoints > 1) {
KisDistanceInformation saveDist(points[0],
KisAlgebra2D::directionBetweenPoints(points[0], points[1], 0.0));
for (int i = index; i < index + numPoints - 1; i++) {
paintLine(points [i], points [i + 1], &saveDist);
}
}
}
static void getBezierCurvePoints(const KisVector2D &pos1,
const KisVector2D &control1,
const KisVector2D &control2,
const KisVector2D &pos2,
vQPointF& points)
{
LineEquation line = LineEquation::Through(pos1, pos2);
qreal d1 = line.absDistance(control1);
qreal d2 = line.absDistance(control2);
if (d1 < BEZIER_FLATNESS_THRESHOLD && d2 < BEZIER_FLATNESS_THRESHOLD) {
points.push_back(toQPointF(pos1));
} else {
// Midpoint subdivision. See Foley & Van Dam Computer Graphics P.508
KisVector2D l2 = (pos1 + control1) / 2;
KisVector2D h = (control1 + control2) / 2;
KisVector2D l3 = (l2 + h) / 2;
KisVector2D r3 = (control2 + pos2) / 2;
KisVector2D r2 = (h + r3) / 2;
KisVector2D l4 = (l3 + r2) / 2;
getBezierCurvePoints(pos1, l2, l3, l4, points);
getBezierCurvePoints(l4, r2, r3, pos2, points);
}
}
void KisPainter::getBezierCurvePoints(const QPointF &pos1,
const QPointF &control1,
const QPointF &control2,
const QPointF &pos2,
vQPointF& points) const
{
::getBezierCurvePoints(toKisVector2D(pos1), toKisVector2D(control1), toKisVector2D(control2), toKisVector2D(pos2), points);
}
void KisPainter::paintBezierCurve(const KisPaintInformation &pi1,
const QPointF &control1,
const QPointF &control2,
const KisPaintInformation &pi2,
KisDistanceInformation *currentDistance)
{
if (d->paintOp && d->paintOp->canPaint()) {
d->paintOp->paintBezierCurve(pi1, control1, control2, pi2, currentDistance);
}
}
void KisPainter::paintRect(const QRectF &rect)
{
QRectF normalizedRect = rect.normalized();
vQPointF points;
points.push_back(normalizedRect.topLeft());
points.push_back(normalizedRect.bottomLeft());
points.push_back(normalizedRect.bottomRight());
points.push_back(normalizedRect.topRight());
paintPolygon(points);
}
void KisPainter::paintRect(const qreal x,
const qreal y,
const qreal w,
const qreal h)
{
paintRect(QRectF(x, y, w, h));
}
void KisPainter::paintEllipse(const QRectF &rect)
{
QRectF r = rect.normalized(); // normalize before checking as negative width and height are empty too
if (r.isEmpty()) return;
// See http://www.whizkidtech.redprince.net/bezier/circle/ for explanation.
// kappa = (4/3*(sqrt(2)-1))
const qreal kappa = 0.5522847498;
const qreal lx = (r.width() / 2) * kappa;
const qreal ly = (r.height() / 2) * kappa;
QPointF center = r.center();
QPointF p0(r.left(), center.y());
QPointF p1(r.left(), center.y() - ly);
QPointF p2(center.x() - lx, r.top());
QPointF p3(center.x(), r.top());
vQPointF points;
getBezierCurvePoints(p0, p1, p2, p3, points);
QPointF p4(center.x() + lx, r.top());
QPointF p5(r.right(), center.y() - ly);
QPointF p6(r.right(), center.y());
getBezierCurvePoints(p3, p4, p5, p6, points);
QPointF p7(r.right(), center.y() + ly);
QPointF p8(center.x() + lx, r.bottom());
QPointF p9(center.x(), r.bottom());
getBezierCurvePoints(p6, p7, p8, p9, points);
QPointF p10(center.x() - lx, r.bottom());
QPointF p11(r.left(), center.y() + ly);
getBezierCurvePoints(p9, p10, p11, p0, points);
paintPolygon(points);
}
void KisPainter::paintEllipse(const qreal x,
const qreal y,
const qreal w,
const qreal h)
{
paintEllipse(QRectF(x, y, w, h));
}
void KisPainter::paintAt(const KisPaintInformation& pi,
KisDistanceInformation *savedDist)
{
if (d->paintOp && d->paintOp->canPaint()) {
d->paintOp->paintAt(pi, savedDist);
}
}
void KisPainter::fillPolygon(const vQPointF& points, FillStyle fillStyle)
{
if (points.count() < 3) {
return;
}
if (fillStyle == FillStyleNone) {
return;
}
QPainterPath polygonPath;
polygonPath.moveTo(points.at(0));
for (int pointIndex = 1; pointIndex < points.count(); pointIndex++) {
polygonPath.lineTo(points.at(pointIndex));
}
polygonPath.closeSubpath();
d->fillStyle = fillStyle;
fillPainterPath(polygonPath);
}
void KisPainter::paintPolygon(const vQPointF& points)
{
if (d->fillStyle != FillStyleNone) {
fillPolygon(points, d->fillStyle);
}
if (d->strokeStyle != StrokeStyleNone) {
if (points.count() > 1) {
KisDistanceInformation distance(points[0],
KisAlgebra2D::directionBetweenPoints(points[0], points[1], 0.0));
for (int i = 0; i < points.count() - 1; i++) {
paintLine(KisPaintInformation(points[i]), KisPaintInformation(points[i + 1]), &distance);
}
paintLine(points[points.count() - 1], points[0], &distance);
}
}
}
void KisPainter::paintPainterPath(const QPainterPath& path)
{
if (d->fillStyle != FillStyleNone) {
fillPainterPath(path);
}
if (d->strokeStyle == StrokeStyleNone) return;
QPointF lastPoint, nextPoint;
int elementCount = path.elementCount();
KisDistanceInformation saveDist;
for (int i = 0; i < elementCount; i++) {
QPainterPath::Element element = path.elementAt(i);
switch (element.type) {
case QPainterPath::MoveToElement:
lastPoint = QPointF(element.x, element.y);
break;
case QPainterPath::LineToElement:
nextPoint = QPointF(element.x, element.y);
paintLine(KisPaintInformation(lastPoint), KisPaintInformation(nextPoint), &saveDist);
lastPoint = nextPoint;
break;
case QPainterPath::CurveToElement:
nextPoint = QPointF(path.elementAt(i + 2).x, path.elementAt(i + 2).y);
paintBezierCurve(KisPaintInformation(lastPoint),
QPointF(path.elementAt(i).x, path.elementAt(i).y),
QPointF(path.elementAt(i + 1).x, path.elementAt(i + 1).y),
KisPaintInformation(nextPoint), &saveDist);
lastPoint = nextPoint;
break;
default:
continue;
}
}
}
void KisPainter::fillPainterPath(const QPainterPath& path)
{
fillPainterPath(path, QRect());
}
void KisPainter::fillPainterPath(const QPainterPath& path, const QRect &requestedRect)
{
if (d->mirrorHorizontally || d->mirrorVertically) {
KisLodTransform lod(d->device);
QPointF effectiveAxesCenter = lod.map(d->axesCenter);
QTransform C1 = QTransform::fromTranslate(-effectiveAxesCenter.x(), -effectiveAxesCenter.y());
QTransform C2 = QTransform::fromTranslate(effectiveAxesCenter.x(), effectiveAxesCenter.y());
QTransform t;
QPainterPath newPath;
QRect newRect;
if (d->mirrorHorizontally) {
t = C1 * QTransform::fromScale(-1,1) * C2;
newPath = t.map(path);
newRect = t.mapRect(requestedRect);
d->fillPainterPathImpl(newPath, newRect);
}
if (d->mirrorVertically) {
t = C1 * QTransform::fromScale(1,-1) * C2;
newPath = t.map(path);
newRect = t.mapRect(requestedRect);
d->fillPainterPathImpl(newPath, newRect);
}
if (d->mirrorHorizontally && d->mirrorVertically) {
t = C1 * QTransform::fromScale(-1,-1) * C2;
newPath = t.map(path);
newRect = t.mapRect(requestedRect);
d->fillPainterPathImpl(newPath, newRect);
}
}
d->fillPainterPathImpl(path, requestedRect);
}
void KisPainter::Private::fillPainterPathImpl(const QPainterPath& path, const QRect &requestedRect)
{
if (fillStyle == FillStyleNone) {
return;
}
// Fill the polygon bounding rectangle with the required contents then we'll
// create a mask for the actual polygon coverage.
if (!fillPainter) {
polygon = device->createCompositionSourceDevice();
fillPainter = new KisFillPainter(polygon);
} else {
polygon->clear();
}
Q_CHECK_PTR(polygon);
QRectF boundingRect = path.boundingRect();
QRect fillRect = boundingRect.toAlignedRect();
// Expand the rectangle to allow for anti-aliasing.
fillRect.adjust(-1, -1, 1, 1);
if (requestedRect.isValid()) {
fillRect &= requestedRect;
}
switch (fillStyle) {
default:
Q_FALLTHROUGH();
case FillStyleForegroundColor:
fillPainter->fillRect(fillRect, q->paintColor(), OPACITY_OPAQUE_U8);
break;
case FillStyleBackgroundColor:
fillPainter->fillRect(fillRect, q->backgroundColor(), OPACITY_OPAQUE_U8);
break;
case FillStylePattern:
if (pattern) { // if the user hasn't got any patterns installed, we shouldn't crash...
fillPainter->fillRect(fillRect, pattern);
}
break;
case FillStyleGenerator:
if (generator) { // if the user hasn't got any generators, we shouldn't crash...
fillPainter->fillRect(fillRect.x(), fillRect.y(), fillRect.width(), fillRect.height(), q->generator());
}
break;
}
if (polygonMaskImage.isNull() || (maskPainter == 0)) {
polygonMaskImage = QImage(maskImageWidth, maskImageHeight, QImage::Format_ARGB32_Premultiplied);
maskPainter = new QPainter(&polygonMaskImage);
maskPainter->setRenderHint(QPainter::Antialiasing, q->antiAliasPolygonFill());
}
// Break the mask up into chunks so we don't have to allocate a potentially very large QImage.
const QColor black(Qt::black);
const QBrush brush(Qt::white);
for (qint32 x = fillRect.x(); x < fillRect.x() + fillRect.width(); x += maskImageWidth) {
for (qint32 y = fillRect.y(); y < fillRect.y() + fillRect.height(); y += maskImageHeight) {
polygonMaskImage.fill(black.rgb());
maskPainter->translate(-x, -y);
maskPainter->fillPath(path, brush);
maskPainter->translate(x, y);
qint32 rectWidth = qMin(fillRect.x() + fillRect.width() - x, maskImageWidth);
qint32 rectHeight = qMin(fillRect.y() + fillRect.height() - y, maskImageHeight);
KisHLineIteratorSP lineIt = polygon->createHLineIteratorNG(x, y, rectWidth);
quint8 tmp;
for (int row = y; row < y + rectHeight; row++) {
QRgb* line = reinterpret_cast<QRgb*>(polygonMaskImage.scanLine(row - y));
do {
tmp = qRed(line[lineIt->x() - x]);
polygon->colorSpace()->applyAlphaU8Mask(lineIt->rawData(), &tmp, 1);
} while (lineIt->nextPixel());
lineIt->nextRow();
}
}
}
QRect bltRect = !requestedRect.isEmpty() ? requestedRect : fillRect;
q->bitBlt(bltRect.x(), bltRect.y(), polygon, bltRect.x(), bltRect.y(), bltRect.width(), bltRect.height());
}
void KisPainter::drawPainterPath(const QPainterPath& path, const QPen& pen)
{
drawPainterPath(path, pen, QRect());
}
void KisPainter::drawPainterPath(const QPainterPath& path, const QPen& _pen, const QRect &requestedRect)
{
QPen pen(_pen);
pen.setColor(Qt::white);
if (!d->fillPainter) {
d->polygon = d->device->createCompositionSourceDevice();
d->fillPainter = new KisFillPainter(d->polygon);
} else {
d->polygon->clear();
}
Q_CHECK_PTR(d->polygon);
QRectF boundingRect = path.boundingRect();
QRect fillRect = boundingRect.toAlignedRect();
// take width of the pen into account
int penWidth = qRound(pen.widthF());
fillRect.adjust(-penWidth, -penWidth, penWidth, penWidth);
// Expand the rectangle to allow for anti-aliasing.
fillRect.adjust(-1, -1, 1, 1);
if (!requestedRect.isNull()) {
fillRect &= requestedRect;
}
d->fillPainter->fillRect(fillRect, paintColor(), OPACITY_OPAQUE_U8);
if (d->polygonMaskImage.isNull() || (d->maskPainter == 0)) {
d->polygonMaskImage = QImage(d->maskImageWidth, d->maskImageHeight, QImage::Format_ARGB32_Premultiplied);
d->maskPainter = new QPainter(&d->polygonMaskImage);
d->maskPainter->setRenderHint(QPainter::Antialiasing, antiAliasPolygonFill());
}
// Break the mask up into chunks so we don't have to allocate a potentially very large QImage.
const QColor black(Qt::black);
QPen oldPen = d->maskPainter->pen();
d->maskPainter->setPen(pen);
for (qint32 x = fillRect.x(); x < fillRect.x() + fillRect.width(); x += d->maskImageWidth) {
for (qint32 y = fillRect.y(); y < fillRect.y() + fillRect.height(); y += d->maskImageHeight) {
d->polygonMaskImage.fill(black.rgb());
d->maskPainter->translate(-x, -y);
d->maskPainter->drawPath(path);
d->maskPainter->translate(x, y);
qint32 rectWidth = qMin(fillRect.x() + fillRect.width() - x, d->maskImageWidth);
qint32 rectHeight = qMin(fillRect.y() + fillRect.height() - y, d->maskImageHeight);
KisHLineIteratorSP lineIt = d->polygon->createHLineIteratorNG(x, y, rectWidth);
quint8 tmp;
for (int row = y; row < y + rectHeight; row++) {
QRgb* line = reinterpret_cast<QRgb*>(d->polygonMaskImage.scanLine(row - y));
do {
tmp = qRed(line[lineIt->x() - x]);
d->polygon->colorSpace()->applyAlphaU8Mask(lineIt->rawData(), &tmp, 1);
} while (lineIt->nextPixel());
lineIt->nextRow();
}
}
}
d->maskPainter->setPen(oldPen);
QRect r = d->polygon->extent();
bitBlt(r.x(), r.y(), d->polygon, r.x(), r.y(), r.width(), r.height());
}
inline void KisPainter::compositeOnePixel(quint8 *dst, const KoColor &color)
{
d->paramInfo.dstRowStart = dst;
d->paramInfo.dstRowStride = 0;
d->paramInfo.srcRowStart = color.data();
d->paramInfo.srcRowStride = 0;
d->paramInfo.maskRowStart = 0;
d->paramInfo.maskRowStride = 0;
d->paramInfo.rows = 1;
d->paramInfo.cols = 1;
d->colorSpace->bitBlt(color.colorSpace(), d->paramInfo, d->compositeOp,
d->renderingIntent,
d->conversionFlags);
}
/**/
void KisPainter::drawLine(const QPointF& start, const QPointF& end, qreal width, bool antialias){
int x1 = qFloor(start.x());
int y1 = qFloor(start.y());
int x2 = qFloor(end.x());
int y2 = qFloor(end.y());
if ((x2 == x1 ) && (y2 == y1)) return;
int dstX = x2-x1;
int dstY = y2-y1;
qreal uniC = dstX*y1 - dstY*x1;
qreal projectionDenominator = 1.0 / (pow((double)dstX, 2) + pow((double)dstY, 2));
qreal subPixel;
if (qAbs(dstX) > qAbs(dstY)){
subPixel = start.x() - x1;
}else{
subPixel = start.y() - y1;
}
qreal halfWidth = width * 0.5 + subPixel;
int W_ = qRound(halfWidth) + 1;
// save the state
int X1_ = x1;
int Y1_ = y1;
int X2_ = x2;
int Y2_ = y2;
if (x2<x1) std::swap(x1,x2);
if (y2<y1) std::swap(y1,y2);
qreal denominator = sqrt(pow((double)dstY,2) + pow((double)dstX,2));
if (denominator == 0.0) {
denominator = 1.0;
}
denominator = 1.0/denominator;
qreal projection,scanX,scanY,AA_;
KisRandomAccessorSP accessor = d->device->createRandomAccessorNG();
KisRandomConstAccessorSP selectionAccessor;
if (d->selection) {
selectionAccessor = d->selection->projection()->createRandomConstAccessorNG();
}
for (int y = y1-W_; y < y2+W_ ; y++){
for (int x = x1-W_; x < x2+W_; x++){
projection = ( (x-X1_)* dstX + (y-Y1_)*dstY ) * projectionDenominator;
scanX = X1_ + projection * dstX;
scanY = Y1_ + projection * dstY;
if (((scanX < x1) || (scanX > x2)) || ((scanY < y1) || (scanY > y2))) {
AA_ = qMin( sqrt( pow((double)x - X1_, 2) + pow((double)y - Y1_, 2) ),
sqrt( pow((double)x - X2_, 2) + pow((double)y - Y2_, 2) ));
}else{
AA_ = qAbs(dstY*x - dstX*y + uniC) * denominator;
}
if (AA_>halfWidth) {
continue;
}
accessor->moveTo(x, y);
if (selectionAccessor) selectionAccessor->moveTo(x,y);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
KoColor mycolor = d->paintColor;
if (antialias && AA_ > halfWidth-1.0) {
mycolor.colorSpace()->multiplyAlpha(mycolor.data(), 1.0 - (AA_-(halfWidth-1.0)), 1);
}
compositeOnePixel(accessor->rawData(), mycolor);
}
}
}
}
/**/
void KisPainter::drawLine(const QPointF & start, const QPointF & end)
{
drawThickLine(start, end, 1, 1);
}
void KisPainter::drawDDALine(const QPointF & start, const QPointF & end)
{
int x = qFloor(start.x());
int y = qFloor(start.y());
int x2 = qFloor(end.x());
int y2 = qFloor(end.y());
// Width and height of the line
int xd = x2 - x;
int yd = y2 - y;
float m = 0;
bool lockAxis = true;
if (xd == 0) {
m = 2.0;
} else if ( yd != 0) {
lockAxis = false;
m = (float)yd / (float)xd;
}
float fx = x;
float fy = y;
int inc;
KisRandomAccessorSP accessor = d->device->createRandomAccessorNG();
KisRandomConstAccessorSP selectionAccessor;
if (d->selection) {
selectionAccessor = d->selection->projection()->createRandomConstAccessorNG();
}
accessor->moveTo(x, y);
if (selectionAccessor) selectionAccessor->moveTo(x,y);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
compositeOnePixel(accessor->rawData(), d->paintColor);
}
if (fabs(m) > 1.0f) {
inc = (yd > 0) ? 1 : -1;
m = (lockAxis)? 0 : 1.0f / m;
m *= inc;
while (y != y2) {
y = y + inc;
fx = fx + m;
x = qRound(fx);
accessor->moveTo(x, y);
if (selectionAccessor) selectionAccessor->moveTo(x, y);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
compositeOnePixel(accessor->rawData(), d->paintColor);
}
}
} else {
inc = (xd > 0) ? 1 : -1;
m *= inc;
while (x != x2) {
x = x + inc;
fy = fy + m;
y = qRound(fy);
accessor->moveTo(x, y);
if (selectionAccessor) selectionAccessor->moveTo(x, y);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
compositeOnePixel(accessor->rawData(), d->paintColor);
}
}
}
}
void KisPainter::drawWobblyLine(const QPointF & start, const QPointF & end)
{
KoColor mycolor(d->paintColor);
int x1 = qFloor(start.x());
int y1 = qFloor(start.y());
int x2 = qFloor(end.x());
int y2 = qFloor(end.y());
KisRandomAccessorSP accessor = d->device->createRandomAccessorNG();
KisRandomConstAccessorSP selectionAccessor;
if (d->selection) {
selectionAccessor = d->selection->projection()->createRandomConstAccessorNG();
}
// Width and height of the line
int xd = (x2 - x1);
int yd = (y2 - y1);
int x;
int y;
float fx = (x = x1);
float fy = (y = y1);
float m = (float)yd / (float)xd;
int inc;
if (fabs(m) > 1) {
inc = (yd > 0) ? 1 : -1;
m = 1.0f / m;
m *= inc;
while (y != y2) {
fx = fx + m;
y = y + inc;
x = qRound(fx);
float br1 = qFloor(fx + 1) - fx;
float br2 = fx - qFloor(fx);
accessor->moveTo(x, y);
if (selectionAccessor) selectionAccessor->moveTo(x, y);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
mycolor.setOpacity((quint8)(255*br1));
compositeOnePixel(accessor->rawData(), mycolor);
}
accessor->moveTo(x + 1, y);
if (selectionAccessor) selectionAccessor->moveTo(x + 1, y);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
mycolor.setOpacity((quint8)(255*br2));
compositeOnePixel(accessor->rawData(), mycolor);
}
}
} else {
inc = (xd > 0) ? 1 : -1;
m *= inc;
while (x != x2) {
fy = fy + m;
x = x + inc;
y = qRound(fy);
float br1 = qFloor(fy + 1) - fy;
float br2 = fy - qFloor(fy);
accessor->moveTo(x, y);
if (selectionAccessor) selectionAccessor->moveTo(x, y);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
mycolor.setOpacity((quint8)(255*br1));
compositeOnePixel(accessor->rawData(), mycolor);
}
accessor->moveTo(x, y + 1);
if (selectionAccessor) selectionAccessor->moveTo(x, y + 1);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
mycolor.setOpacity((quint8)(255*br2));
compositeOnePixel(accessor->rawData(), mycolor);
}
}
}
}
void KisPainter::drawWuLine(const QPointF & start, const QPointF & end)
{
KoColor lineColor(d->paintColor);
int x1 = qFloor(start.x());
int y1 = qFloor(start.y());
int x2 = qFloor(end.x());
int y2 = qFloor(end.y());
KisRandomAccessorSP accessor = d->device->createRandomAccessorNG();
KisRandomConstAccessorSP selectionAccessor;
if (d->selection) {
selectionAccessor = d->selection->projection()->createRandomConstAccessorNG();
}
float grad, xd, yd;
float xgap, ygap, xend, yend, yf, xf;
float brightness1, brightness2;
int ix1, ix2, iy1, iy2;
quint8 c1, c2;
// gradient of line
xd = (x2 - x1);
yd = (y2 - y1);
if (yd == 0) {
/* Horizontal line */
int incr = (x1 < x2) ? 1 : -1;
ix1 = x1;
ix2 = x2;
iy1 = y1;
while (ix1 != ix2) {
ix1 = ix1 + incr;
accessor->moveTo(ix1, iy1);
if (selectionAccessor) selectionAccessor->moveTo(ix1, iy1);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
compositeOnePixel(accessor->rawData(), lineColor);
}
}
return;
}
if (xd == 0) {
/* Vertical line */
int incr = (y1 < y2) ? 1 : -1;
iy1 = y1;
iy2 = y2;
ix1 = x1;
while (iy1 != iy2) {
iy1 = iy1 + incr;
accessor->moveTo(ix1, iy1);
if (selectionAccessor) selectionAccessor->moveTo(ix1, iy1);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
compositeOnePixel(accessor->rawData(), lineColor);
}
}
return;
}
if (fabs(xd) > fabs(yd)) {
// horizontal line
// line have to be paint from left to right
if (x1 > x2) {
std::swap(x1, x2);
std::swap(y1, y2);
xd = (x2 - x1);
yd = (y2 - y1);
}
grad = yd / xd;
// nearest X,Y integer coordinates
xend = x1;
yend = y1 + grad * (xend - x1);
xgap = invertFrac(x1 + 0.5f);
ix1 = x1;
iy1 = qFloor(yend);
// calc the intensity of the other end point pixel pair.
brightness1 = invertFrac(yend) * xgap;
brightness2 = frac(yend) * xgap;
c1 = (int)(brightness1 * OPACITY_OPAQUE_U8);
c2 = (int)(brightness2 * OPACITY_OPAQUE_U8);
accessor->moveTo(ix1, iy1);
if (selectionAccessor) selectionAccessor->moveTo(ix1, iy1);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
lineColor.setOpacity(c1);
compositeOnePixel(accessor->rawData(), lineColor);
}
accessor->moveTo(ix1, iy1 + 1);
if (selectionAccessor) selectionAccessor->moveTo(ix1, iy1 + 1);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
lineColor.setOpacity(c2);
compositeOnePixel(accessor->rawData(), lineColor);
}
// calc first Y-intersection for main loop
yf = yend + grad;
xend = x2;
yend = y2 + grad * (xend - x2);
xgap = invertFrac(x2 - 0.5f);
ix2 = x2;
iy2 = qFloor(yend);
brightness1 = invertFrac(yend) * xgap;
brightness2 = frac(yend) * xgap;
c1 = (int)(brightness1 * OPACITY_OPAQUE_U8);
c2 = (int)(brightness2 * OPACITY_OPAQUE_U8);
accessor->moveTo(ix2, iy2);
if (selectionAccessor) selectionAccessor->moveTo(ix2, iy2);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
lineColor.setOpacity(c1);
compositeOnePixel(accessor->rawData(), lineColor);
}
accessor->moveTo(ix2, iy2 + 1);
if (selectionAccessor) selectionAccessor->moveTo(ix2, iy2 + 1);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
lineColor.setOpacity(c2);
compositeOnePixel(accessor->rawData(), lineColor);
}
// main loop
for (int x = ix1 + 1; x <= ix2 - 1; x++) {
brightness1 = invertFrac(yf);
brightness2 = frac(yf);
c1 = (int)(brightness1 * OPACITY_OPAQUE_U8);
c2 = (int)(brightness2 * OPACITY_OPAQUE_U8);
accessor->moveTo(x, qFloor(yf));
if (selectionAccessor) selectionAccessor->moveTo(x, qFloor(yf));
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
lineColor.setOpacity(c1);
compositeOnePixel(accessor->rawData(), lineColor);
}
accessor->moveTo(x, qFloor(yf) + 1);
if (selectionAccessor) selectionAccessor->moveTo(x, qFloor(yf) + 1);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
lineColor.setOpacity(c2);
compositeOnePixel(accessor->rawData(), lineColor);
}
yf = yf + grad;
}
} else {
//vertical
// line have to be painted from left to right
if (y1 > y2) {
std::swap(x1, x2);
std::swap(y1, y2);
xd = (x2 - x1);
yd = (y2 - y1);
}
grad = xd / yd;
// nearest X,Y integer coordinates
yend = y1;
xend = x1 + grad * (yend - y1);
ygap = y1;
ix1 = qFloor(xend);
iy1 = y1;
// calc the intensity of the other end point pixel pair.
brightness1 = invertFrac(xend) * ygap;
brightness2 = frac(xend) * ygap;
c1 = (int)(brightness1 * OPACITY_OPAQUE_U8);
c2 = (int)(brightness2 * OPACITY_OPAQUE_U8);
accessor->moveTo(ix1, iy1);
if (selectionAccessor) selectionAccessor->moveTo(ix1, iy1);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
lineColor.setOpacity(c1);
compositeOnePixel(accessor->rawData(), lineColor);
}
accessor->moveTo(x1 + 1, y1);
if (selectionAccessor) selectionAccessor->moveTo(x1 + 1, y1);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
lineColor.setOpacity(c2);
compositeOnePixel(accessor->rawData(), lineColor);
}
// calc first Y-intersection for main loop
xf = xend + grad;
yend = y2;
xend = x2 + grad * (yend - y2);
ygap = invertFrac(y2 - 0.5f);
ix2 = qFloor(xend);
iy2 = y2;
brightness1 = invertFrac(xend) * ygap;
brightness2 = frac(xend) * ygap;
c1 = (int)(brightness1 * OPACITY_OPAQUE_U8);
c2 = (int)(brightness2 * OPACITY_OPAQUE_U8);
accessor->moveTo(ix2, iy2);
if (selectionAccessor) selectionAccessor->moveTo(ix2, iy2);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
lineColor.setOpacity(c1);
compositeOnePixel(accessor->rawData(), lineColor);
}
accessor->moveTo(ix2 + 1, iy2);
if (selectionAccessor) selectionAccessor->moveTo(ix2 + 1, iy2);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
lineColor.setOpacity(c2);
compositeOnePixel(accessor->rawData(), lineColor);
}
// main loop
for (int y = iy1 + 1; y <= iy2 - 1; y++) {
brightness1 = invertFrac(xf);
brightness2 = frac(xf);
c1 = (int)(brightness1 * OPACITY_OPAQUE_U8);
c2 = (int)(brightness2 * OPACITY_OPAQUE_U8);
accessor->moveTo(qFloor(xf), y);
if (selectionAccessor) selectionAccessor->moveTo(qFloor(xf), y);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
lineColor.setOpacity(c1);
compositeOnePixel(accessor->rawData(), lineColor);
}
accessor->moveTo(qFloor(xf) + 1, y);
if (selectionAccessor) selectionAccessor->moveTo(qFloor(xf) + 1, y);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
lineColor.setOpacity(c2);
compositeOnePixel(accessor->rawData(), lineColor);
}
xf = xf + grad;
}
}//end-of-else
}
void KisPainter::drawThickLine(const QPointF & start, const QPointF & end, int startWidth, int endWidth)
{
KisRandomAccessorSP accessor = d->device->createRandomAccessorNG();
KisRandomConstAccessorSP selectionAccessor;
if (d->selection) {
selectionAccessor = d->selection->projection()->createRandomConstAccessorNG();
}
const KoColorSpace *cs = d->device->colorSpace();
KoColor c1(d->paintColor);
KoColor c2(d->paintColor);
KoColor c3(d->paintColor);
KoColor col1(c1);
KoColor col2(c1);
float grada, gradb, dxa, dxb, dya, dyb, fraca, fracb,
xfa, yfa, xfb, yfb, b1a, b2a, b1b, b2b, dstX, dstY;
int x, y, ix1, ix2, iy1, iy2;
int x0a, y0a, x1a, y1a, x0b, y0b, x1b, y1b;
int tp0, tn0, tp1, tn1;
int horizontal = 0;
float opacity = 1.0;
tp0 = startWidth / 2;
tn0 = startWidth / 2;
if (startWidth % 2 == 0) // even width startWidth
tn0--;
tp1 = endWidth / 2;
tn1 = endWidth / 2;
if (endWidth % 2 == 0) // even width endWidth
tn1--;
int x0 = qRound(start.x());
int y0 = qRound(start.y());
int x1 = qRound(end.x());
int y1 = qRound(end.y());
dstX = x1 - x0; // run of general line
dstY = y1 - y0; // rise of general line
if (dstY < 0) dstY = -dstY;
if (dstX < 0) dstX = -dstX;
if (dstX > dstY) { // horizontalish
horizontal = 1;
x0a = x0; y0a = y0 - tn0;
x0b = x0; y0b = y0 + tp0;
x1a = x1; y1a = y1 - tn1;
x1b = x1; y1b = y1 + tp1;
} else {
x0a = x0 - tn0; y0a = y0;
x0b = x0 + tp0; y0b = y0;
x1a = x1 - tn1; y1a = y1;
x1b = x1 + tp1; y1b = y1;
}
if (horizontal) { // draw endpoints
for (int i = y0a; i <= y0b; i++) {
accessor->moveTo(x0, i);
if (selectionAccessor) selectionAccessor->moveTo(x0, i);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
compositeOnePixel(accessor->rawData(), c1);
}
}
for (int i = y1a; i <= y1b; i++) {
accessor->moveTo(x1, i);
if (selectionAccessor) selectionAccessor->moveTo(x1, i);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
compositeOnePixel(accessor->rawData(), c1);
}
}
} else {
for (int i = x0a; i <= x0b; i++) {
accessor->moveTo(i, y0);
if (selectionAccessor) selectionAccessor->moveTo(i, y0);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
compositeOnePixel(accessor->rawData(), c1);
}
}
for (int i = x1a; i <= x1b; i++) {
accessor->moveTo(i, y1);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
compositeOnePixel(accessor->rawData(), c1);
}
}
}
//antialias endpoints
if (x1 != x0 && y1 != y0) {
if (horizontal) {
accessor->moveTo(x0a, y0a - 1);
if (selectionAccessor) selectionAccessor->moveTo(x0a, y0a - 1);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
qreal alpha = cs->opacityF(accessor->rawData());
opacity = .25 * c1.opacityF() + (1 - .25) * alpha;
col1.setOpacity(opacity);
compositeOnePixel(accessor->rawData(), col1);
}
accessor->moveTo(x1b, y1b + 1);
if (selectionAccessor) selectionAccessor->moveTo(x1b, y1b + 1);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
qreal alpha = cs->opacityF(accessor->rawData());
opacity = .25 * c2.opacityF() + (1 - .25) * alpha;
col1.setOpacity(opacity);
compositeOnePixel(accessor->rawData(), col1);
}
} else {
accessor->moveTo(x0a - 1, y0a);
if (selectionAccessor) selectionAccessor->moveTo(x0a - 1, y0a);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
qreal alpha = cs->opacityF(accessor->rawData());
opacity = .25 * c1.opacityF() + (1 - .25) * alpha;
col1.setOpacity(opacity);
compositeOnePixel(accessor->rawData(), col1);
}
accessor->moveTo(x1b + 1, y1b);
if (selectionAccessor) selectionAccessor->moveTo(x1b + 1, y1b);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
qreal alpha = cs->opacityF(accessor->rawData());
opacity = .25 * c2.opacityF() + (1 - .25) * alpha;
col1.setOpacity(opacity);
compositeOnePixel(accessor->rawData(), col1);
}
}
}
dxa = x1a - x0a; // run of a
dya = y1a - y0a; // rise of a
dxb = x1b - x0b; // run of b
dyb = y1b - y0b; // rise of b
if (horizontal) { // horizontal-ish lines
if (x1 < x0) {
int xt, yt, wt;
KoColor tmp;
xt = x1a; x1a = x0a; x0a = xt;
yt = y1a; y1a = y0a; y0a = yt;
xt = x1b; x1b = x0b; x0b = xt;
yt = y1b; y1b = y0b; y0b = yt;
xt = x1; x1 = x0; x0 = xt;
yt = y1; y1 = y0; y0 = yt;
tmp = c1; c1 = c2; c2 = tmp;
wt = startWidth; startWidth = endWidth; endWidth = wt;
}
grada = dya / dxa;
gradb = dyb / dxb;
ix1 = x0; iy1 = y0;
ix2 = x1; iy2 = y1;
yfa = y0a + grada;
yfb = y0b + gradb;
for (x = ix1 + 1; x <= ix2 - 1; x++) {
fraca = yfa - qFloor(yfa);
b1a = 1 - fraca;
b2a = fraca;
fracb = yfb - qFloor(yfb);
b1b = 1 - fracb;
b2b = fracb;
// color first pixel of bottom line
opacity = ((x - ix1) / dstX) * c2.opacityF() + (1 - (x - ix1) / dstX) * c1.opacityF();
c3.setOpacity(opacity);
accessor->moveTo(x, qFloor(yfa));
if (selectionAccessor) selectionAccessor->moveTo(x, qFloor(yfa));
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
qreal alpha = cs->opacityF(accessor->rawData());
opacity = b1a * c3.opacityF() + (1 - b1a) * alpha;
col1.setOpacity(opacity);
compositeOnePixel(accessor->rawData(), col1);
}
// color first pixel of top line
if (!(startWidth == 1 && endWidth == 1)) {
accessor->moveTo(x, qFloor(yfb));
if (selectionAccessor) selectionAccessor->moveTo(x, qFloor(yfb));
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
qreal alpha = cs->opacityF(accessor->rawData());
opacity = b1b * c3.opacityF() + (1 - b1b) * alpha;
col1.setOpacity(opacity);
compositeOnePixel(accessor->rawData(), col1);
}
}
// color second pixel of bottom line
if (grada != 0 && grada != 1) { // if not flat or exact diagonal
accessor->moveTo(x, qFloor(yfa) + 1);
if (selectionAccessor) selectionAccessor->moveTo(x, qFloor(yfa) + 1);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
qreal alpha = cs->opacityF(accessor->rawData());
opacity = b2a * c3.opacityF() + (1 - b2a) * alpha;
col2.setOpacity(opacity);
compositeOnePixel(accessor->rawData(), col2);
}
}
// color second pixel of top line
if (gradb != 0 && gradb != 1 && !(startWidth == 1 && endWidth == 1)) {
accessor->moveTo(x, qFloor(yfb) + 1);
if (selectionAccessor) selectionAccessor->moveTo(x, qFloor(yfb) + 1);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
qreal alpha = cs->opacityF(accessor->rawData());
opacity = b2b * c3.opacityF() + (1 - b2b) * alpha;
col2.setOpacity(opacity);
compositeOnePixel(accessor->rawData(), col2);
}
}
// fill remaining pixels
if (!(startWidth == 1 && endWidth == 1)) {
if (yfa < yfb)
for (int i = qFloor(yfa) + 1; i <= qFloor(yfb); i++) {
accessor->moveTo(x, i);
if (selectionAccessor) selectionAccessor->moveTo(x, i);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
compositeOnePixel(accessor->rawData(), c3);
}
}
else
for (int i = qFloor(yfa) + 1; i >= qFloor(yfb); i--) {
accessor->moveTo(x, i);
if (selectionAccessor) selectionAccessor->moveTo(x, i);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
compositeOnePixel(accessor->rawData(), c3);
}
}
}
yfa += grada;
yfb += gradb;
}
} else { // vertical-ish lines
if (y1 < y0) {
int xt, yt, wt;
xt = x1a; x1a = x0a; x0a = xt;
yt = y1a; y1a = y0a; y0a = yt;
xt = x1b; x1b = x0b; x0b = xt;
yt = y1b; y1b = y0b; y0b = yt;
xt = x1; x1 = x0; x0 = xt;
yt = y1; y1 = y0; y0 = yt;
KoColor tmp;
tmp = c1; c1 = c2; c2 = tmp;
wt = startWidth; startWidth = endWidth; endWidth = wt;
}
grada = dxa / dya;
gradb = dxb / dyb;
ix1 = x0; iy1 = y0;
ix2 = x1; iy2 = y1;
xfa = x0a + grada;
xfb = x0b + gradb;
for (y = iy1 + 1; y <= iy2 - 1; y++) {
fraca = xfa - qFloor(xfa);
b1a = 1 - fraca;
b2a = fraca;
fracb = xfb - qFloor(xfb);
b1b = 1 - fracb;
b2b = fracb;
// color first pixel of left line
opacity = ((y - iy1) / dstY) * c2.opacityF() + (1 - (y - iy1) / dstY) * c1.opacityF();
c3.setOpacity(opacity);
accessor->moveTo(qFloor(xfa), y);
if (selectionAccessor) selectionAccessor->moveTo(qFloor(xfa), y);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
qreal alpha = cs->opacityF(accessor->rawData());
opacity = b1a * c3.opacityF() + (1 - b1a) * alpha;
col1.setOpacity(opacity);
compositeOnePixel(accessor->rawData(), col1);
}
// color first pixel of right line
if (!(startWidth == 1 && endWidth == 1)) {
accessor->moveTo(qFloor(xfb), y);
if (selectionAccessor) selectionAccessor->moveTo(qFloor(xfb), y);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
qreal alpha = cs->opacityF(accessor->rawData());
opacity = b1b * c3.opacityF() + (1 - b1b) * alpha;
col1.setOpacity(opacity);
compositeOnePixel(accessor->rawData(), col1);
}
}
// color second pixel of left line
if (grada != 0 && grada != 1) { // if not flat or exact diagonal
accessor->moveTo(qFloor(xfa) + 1, y);
if (selectionAccessor) selectionAccessor->moveTo(qFloor(xfa) + 1, y);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
qreal alpha = cs->opacityF(accessor->rawData());
opacity = b2a * c3.opacityF() + (1 - b2a) * alpha;
col2.setOpacity(opacity);
compositeOnePixel(accessor->rawData(), col2);
}
}
// color second pixel of right line
if (gradb != 0 && gradb != 1 && !(startWidth == 1 && endWidth == 1)) {
accessor->moveTo(qFloor(xfb) + 1, y);
if (selectionAccessor) selectionAccessor->moveTo(qFloor(xfb) + 1, y);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
qreal alpha = cs->opacityF(accessor->rawData());
opacity = b2b * c3.opacityF() + (1 - b2b) * alpha;
col2.setOpacity(opacity);
compositeOnePixel(accessor->rawData(), col2);
}
}
// fill remaining pixels between current xfa,xfb
if (!(startWidth == 1 && endWidth == 1)) {
if (xfa < xfb)
for (int i = qFloor(xfa) + 1; i <= qFloor(xfb); i++) {
accessor->moveTo(i, y);
if (selectionAccessor) selectionAccessor->moveTo(i, y);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
compositeOnePixel(accessor->rawData(), c3);
}
}
else
for (int i = qFloor(xfb); i <= qFloor(xfa) + 1; i++) {
accessor->moveTo(i, y);
if (selectionAccessor) selectionAccessor->moveTo(i, y);
if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) {
compositeOnePixel(accessor->rawData(), c3);
}
}
}
xfa += grada;
xfb += gradb;
}
}
}
void KisPainter::setProgress(KoUpdater * progressUpdater)
{
d->progressUpdater = progressUpdater;
}
const KisPaintDeviceSP KisPainter::device() const
{
return d->device;
}
KisPaintDeviceSP KisPainter::device()
{
return d->device;
}
void KisPainter::setChannelFlags(QBitArray channelFlags)
{
// Q_ASSERT(channelFlags.isEmpty() || quint32(channelFlags.size()) == d->colorSpace->channelCount());
// Now, if all bits in the channelflags are true, pass an empty channel flags bitarray
// because otherwise the compositeops cannot optimize.
d->paramInfo.channelFlags = channelFlags;
if (!channelFlags.isEmpty() && channelFlags == QBitArray(channelFlags.size(), true)) {
d->paramInfo.channelFlags = QBitArray();
}
}
QBitArray KisPainter::channelFlags()
{
return d->paramInfo.channelFlags;
}
void KisPainter::setPattern(const KoPatternSP pattern)
{
d->pattern = pattern;
}
const KoPatternSP KisPainter::pattern() const
{
return d->pattern;
}
void KisPainter::setPaintColor(const KoColor& color)
{
d->paintColor = color;
if (d->device) {
d->paintColor.convertTo(d->device->compositionSourceColorSpace());
}
}
const KoColor &KisPainter::paintColor() const
{
return d->paintColor;
}
void KisPainter::setBackgroundColor(const KoColor& color)
{
d->backgroundColor = color;
if (d->device) {
d->backgroundColor.convertTo(d->device->compositionSourceColorSpace());
}
}
const KoColor &KisPainter::backgroundColor() const
{
return d->backgroundColor;
}
void KisPainter::setGenerator(KisFilterConfigurationSP generator)
{
d->generator = generator;
}
const KisFilterConfigurationSP KisPainter::generator() const
{
return d->generator;
}
void KisPainter::setFillStyle(FillStyle fillStyle)
{
d->fillStyle = fillStyle;
}
KisPainter::FillStyle KisPainter::fillStyle() const
{
return d->fillStyle;
}
void KisPainter::setAntiAliasPolygonFill(bool antiAliasPolygonFill)
{
d->antiAliasPolygonFill = antiAliasPolygonFill;
}
bool KisPainter::antiAliasPolygonFill()
{
return d->antiAliasPolygonFill;
}
void KisPainter::setStrokeStyle(KisPainter::StrokeStyle strokeStyle)
{
d->strokeStyle = strokeStyle;
}
KisPainter::StrokeStyle KisPainter::strokeStyle() const
{
return d->strokeStyle;
}
void KisPainter::setFlow(quint8 flow)
{
d->paramInfo.flow = float(flow) / 255.0f;
}
quint8 KisPainter::flow() const
{
return quint8(d->paramInfo.flow * 255.0f);
}
void KisPainter::setOpacityUpdateAverage(quint8 opacity)
{
d->isOpacityUnit = opacity == OPACITY_OPAQUE_U8;
d->paramInfo.updateOpacityAndAverage(float(opacity) / 255.0f);
}
void KisPainter::setAverageOpacity(qreal averageOpacity)
{
d->paramInfo.setOpacityAndAverage(d->paramInfo.opacity, averageOpacity);
}
qreal KisPainter::blendAverageOpacity(qreal opacity, qreal averageOpacity)
{
const float exponent = 0.1;
return averageOpacity < opacity ?
opacity :
exponent * opacity + (1.0 - exponent) * (averageOpacity);
}
void KisPainter::setOpacity(quint8 opacity)
{
d->isOpacityUnit = opacity == OPACITY_OPAQUE_U8;
d->paramInfo.opacity = float(opacity) / 255.0f;
}
quint8 KisPainter::opacity() const
{
return quint8(d->paramInfo.opacity * 255.0f);
}
void KisPainter::setCompositeOp(const KoCompositeOp * op)
{
d->compositeOp = op;
}
const KoCompositeOp * KisPainter::compositeOp()
{
return d->compositeOp;
}
/**
* TODO: Rename this setCompositeOpId(). See KoCompositeOpRegistry.h
*/
void KisPainter::setCompositeOp(const QString& op)
{
d->compositeOp = d->colorSpace->compositeOp(op);
}
void KisPainter::setSelection(KisSelectionSP selection)
{
d->selection = selection;
}
KisSelectionSP KisPainter::selection()
{
return d->selection;
}
KoUpdater * KisPainter::progressUpdater()
{
return d->progressUpdater;
}
void KisPainter::setGradient(const KoAbstractGradientSP gradient)
{
d->gradient = gradient;
}
const KoAbstractGradientSP KisPainter::gradient() const
{
return d->gradient;
}
void KisPainter::setPaintOpPreset(KisPaintOpPresetSP preset, KisNodeSP node, KisImageSP image)
{
d->paintOpPreset = preset;
KisPaintOp *paintop = KisPaintOpRegistry::instance()->paintOp(preset, this, node, image);
Q_ASSERT(paintop);
if (paintop) {
delete d->paintOp;
d->paintOp = paintop;
}
else {
warnKrita << "Could not create paintop for preset " << preset->name();
}
}
KisPaintOpPresetSP KisPainter::preset() const
{
return d->paintOpPreset;
}
KisPaintOp* KisPainter::paintOp() const
{
return d->paintOp;
}
void KisPainter::setMirrorInformation(const QPointF& axesCenter, bool mirrorHorizontally, bool mirrorVertically)
{
d->axesCenter = axesCenter;
d->mirrorHorizontally = mirrorHorizontally;
d->mirrorVertically = mirrorVertically;
}
void KisPainter::copyMirrorInformationFrom(const KisPainter *other)
{
d->axesCenter = other->d->axesCenter;
d->mirrorHorizontally = other->d->mirrorHorizontally;
d->mirrorVertically = other->d->mirrorVertically;
}
bool KisPainter::hasMirroring() const
{
return d->mirrorHorizontally || d->mirrorVertically;
}
bool KisPainter::hasHorizontalMirroring() const
{
return d->mirrorHorizontally;
}
bool KisPainter::hasVerticalMirroring() const
{
return d->mirrorVertically;
}
void KisPainter::setMaskImageSize(qint32 width, qint32 height)
{
d->maskImageWidth = qBound(1, width, 256);
d->maskImageHeight = qBound(1, height, 256);
d->fillPainter = 0;
d->polygonMaskImage = QImage();
}
//void KisPainter::setLockAlpha(bool protect)
//{
// if(d->paramInfo.channelFlags.isEmpty()) {
// d->paramInfo.channelFlags = d->colorSpace->channelFlags(true, true);
// }
// QBitArray switcher =
// d->colorSpace->channelFlags(protect, !protect);
// if(protect) {
// d->paramInfo.channelFlags &= switcher;
// }
// else {
// d->paramInfo.channelFlags |= switcher;
// }
// Q_ASSERT(quint32(d->paramInfo.channelFlags.size()) == d->colorSpace->channelCount());
//}
//bool KisPainter::alphaLocked() const
//{
// QBitArray switcher = d->colorSpace->channelFlags(false, true);
// return !(d->paramInfo.channelFlags & switcher).count(true);
//}
void KisPainter::setRenderingIntent(KoColorConversionTransformation::Intent intent)
{
d->renderingIntent = intent;
}
void KisPainter::setColorConversionFlags(KoColorConversionTransformation::ConversionFlags conversionFlags)
{
d->conversionFlags = conversionFlags;
}
void KisPainter::setRunnableStrokeJobsInterface(KisRunnableStrokeJobsInterface *interface)
{
d->runnableStrokeJobsInterface = interface;
}
KisRunnableStrokeJobsInterface *KisPainter::runnableStrokeJobsInterface() const
{
if (!d->runnableStrokeJobsInterface) {
if (!d->fakeRunnableStrokeJobsInterface) {
d->fakeRunnableStrokeJobsInterface.reset(new KisFakeRunnableStrokeJobsExecutor());
}
return d->fakeRunnableStrokeJobsInterface.data();
}
return d->runnableStrokeJobsInterface;
}
void KisPainter::renderMirrorMaskSafe(QRect rc, KisFixedPaintDeviceSP dab, bool preserveDab)
{
if (!d->mirrorHorizontally && !d->mirrorVertically) return;
KisFixedPaintDeviceSP dabToProcess = dab;
if (preserveDab) {
dabToProcess = new KisFixedPaintDevice(*dab);
}
renderMirrorMask(rc, dabToProcess);
}
void KisPainter::renderMirrorMaskSafe(QRect rc, KisPaintDeviceSP dab, int sx, int sy, KisFixedPaintDeviceSP mask, bool preserveMask)
{
if (!d->mirrorHorizontally && !d->mirrorVertically) return;
KisFixedPaintDeviceSP maskToProcess = mask;
if (preserveMask) {
maskToProcess = new KisFixedPaintDevice(*mask);
}
renderMirrorMask(rc, dab, sx, sy, maskToProcess);
}
void KisPainter::renderMirrorMask(QRect rc, KisFixedPaintDeviceSP dab)
{
int x = rc.topLeft().x();
int y = rc.topLeft().y();
KisLodTransform t(d->device);
QPoint effectiveAxesCenter = t.map(d->axesCenter).toPoint();
int mirrorX = -((x+rc.width()) - effectiveAxesCenter.x()) + effectiveAxesCenter.x();
int mirrorY = -((y+rc.height()) - effectiveAxesCenter.y()) + effectiveAxesCenter.y();
if (d->mirrorHorizontally && d->mirrorVertically){
dab->mirror(true, false);
bltFixed(mirrorX, y, dab, 0,0,rc.width(),rc.height());
dab->mirror(false,true);
bltFixed(mirrorX, mirrorY, dab, 0,0,rc.width(),rc.height());
dab->mirror(true, false);
bltFixed(x, mirrorY, dab, 0,0,rc.width(),rc.height());
}
else if (d->mirrorHorizontally){
dab->mirror(true, false);
bltFixed(mirrorX, y, dab, 0,0,rc.width(),rc.height());
}
else if (d->mirrorVertically){
dab->mirror(false, true);
bltFixed(x, mirrorY, dab, 0,0,rc.width(),rc.height());
}
}
void KisPainter::renderMirrorMask(QRect rc, KisFixedPaintDeviceSP dab, KisFixedPaintDeviceSP mask)
{
int x = rc.topLeft().x();
int y = rc.topLeft().y();
KisLodTransform t(d->device);
QPoint effectiveAxesCenter = t.map(d->axesCenter).toPoint();
int mirrorX = -((x+rc.width()) - effectiveAxesCenter.x()) + effectiveAxesCenter.x();
int mirrorY = -((y+rc.height()) - effectiveAxesCenter.y()) + effectiveAxesCenter.y();
if (d->mirrorHorizontally && d->mirrorVertically){
dab->mirror(true, false);
mask->mirror(true, false);
bltFixedWithFixedSelection(mirrorX,y, dab, mask, rc.width() ,rc.height() );
dab->mirror(false,true);
mask->mirror(false, true);
bltFixedWithFixedSelection(mirrorX,mirrorY, dab, mask, rc.width() ,rc.height() );
dab->mirror(true, false);
mask->mirror(true, false);
bltFixedWithFixedSelection(x,mirrorY, dab, mask, rc.width() ,rc.height() );
}else if (d->mirrorHorizontally){
dab->mirror(true, false);
mask->mirror(true, false);
bltFixedWithFixedSelection(mirrorX,y, dab, mask, rc.width() ,rc.height() );
}else if (d->mirrorVertically){
dab->mirror(false, true);
mask->mirror(false, true);
bltFixedWithFixedSelection(x,mirrorY, dab, mask, rc.width() ,rc.height() );
}
}
void KisPainter::renderMirrorMask(QRect rc, KisPaintDeviceSP dab){
if (d->mirrorHorizontally || d->mirrorVertically){
KisFixedPaintDeviceSP mirrorDab(new KisFixedPaintDevice(dab->colorSpace()));
QRect dabRc( QPoint(0,0), QSize(rc.width(),rc.height()) );
mirrorDab->setRect(dabRc);
mirrorDab->lazyGrowBufferWithoutInitialization();
dab->readBytes(mirrorDab->data(),rc);
renderMirrorMask( QRect(rc.topLeft(),dabRc.size()), mirrorDab);
}
}
void KisPainter::renderMirrorMask(QRect rc, KisPaintDeviceSP dab, int sx, int sy, KisFixedPaintDeviceSP mask)
{
if (d->mirrorHorizontally || d->mirrorVertically){
KisFixedPaintDeviceSP mirrorDab(new KisFixedPaintDevice(dab->colorSpace()));
QRect dabRc( QPoint(0,0), QSize(rc.width(),rc.height()) );
mirrorDab->setRect(dabRc);
mirrorDab->lazyGrowBufferWithoutInitialization();
dab->readBytes(mirrorDab->data(),QRect(QPoint(sx,sy),rc.size()));
renderMirrorMask(rc, mirrorDab, mask);
}
}
void KisPainter::renderDabWithMirroringNonIncremental(QRect rc, KisPaintDeviceSP dab)
{
QVector<QRect> rects;
int x = rc.topLeft().x();
int y = rc.topLeft().y();
KisLodTransform t(d->device);
QPoint effectiveAxesCenter = t.map(d->axesCenter).toPoint();
int mirrorX = -((x+rc.width()) - effectiveAxesCenter.x()) + effectiveAxesCenter.x();
int mirrorY = -((y+rc.height()) - effectiveAxesCenter.y()) + effectiveAxesCenter.y();
rects << rc;
if (d->mirrorHorizontally && d->mirrorVertically){
rects << QRect(mirrorX, y, rc.width(), rc.height());
rects << QRect(mirrorX, mirrorY, rc.width(), rc.height());
rects << QRect(x, mirrorY, rc.width(), rc.height());
} else if (d->mirrorHorizontally) {
rects << QRect(mirrorX, y, rc.width(), rc.height());
} else if (d->mirrorVertically) {
rects << QRect(x, mirrorY, rc.width(), rc.height());
}
Q_FOREACH (const QRect &rc, rects) {
d->device->clear(rc);
}
QRect resultRect = dab->extent() | rc;
bool intersects = false;
for (int i = 1; i < rects.size(); i++) {
if (rects[i].intersects(resultRect)) {
intersects = true;
break;
}
}
/**
* If there are no cross-intersections, we can use a fast path
* and do no cycling recompositioning
*/
if (!intersects) {
rects.resize(1);
}
Q_FOREACH (const QRect &rc, rects) {
bitBlt(rc.topLeft(), dab, rc);
}
Q_FOREACH (const QRect &rc, rects) {
renderMirrorMask(rc, dab);
}
}
bool KisPainter::hasDirtyRegion() const
{
return !d->dirtyRects.isEmpty();
}
void KisPainter::mirrorRect(Qt::Orientation direction, QRect *rc) const
{
KisLodTransform t(d->device);
QPoint effectiveAxesCenter = t.map(d->axesCenter).toPoint();
KritaUtils::mirrorRect(direction, effectiveAxesCenter, rc);
}
void KisPainter::mirrorDab(Qt::Orientation direction, KisRenderedDab *dab, bool skipMirrorPixels) const
{
KisLodTransform t(d->device);
QPoint effectiveAxesCenter = t.map(d->axesCenter).toPoint();
KritaUtils::mirrorDab(direction, effectiveAxesCenter, dab, skipMirrorPixels);
}
namespace {
inline void mirrorOneObject(Qt::Orientation dir, const QPoint &center, QRect *rc) {
KritaUtils::mirrorRect(dir, center, rc);
}
inline void mirrorOneObject(Qt::Orientation dir, const QPoint &center, QPointF *pt) {
KritaUtils::mirrorPoint(dir, center, pt);
}
inline void mirrorOneObject(Qt::Orientation dir, const QPoint &center, QPair<QPointF, QPointF> *pair) {
KritaUtils::mirrorPoint(dir, center, &pair->first);
KritaUtils::mirrorPoint(dir, center, &pair->second);
}
}
template<class T> QVector<T> KisPainter::Private::calculateMirroredObjects(const T &object)
{
QVector<T> result;
KisLodTransform t(this->device);
const QPoint effectiveAxesCenter = t.map(this->axesCenter).toPoint();
T baseObject = object;
result << baseObject;
if (this->mirrorHorizontally && this->mirrorVertically){
mirrorOneObject(Qt::Horizontal, effectiveAxesCenter, &baseObject);
result << baseObject;
mirrorOneObject(Qt::Vertical, effectiveAxesCenter, &baseObject);
result << baseObject;
mirrorOneObject(Qt::Horizontal, effectiveAxesCenter, &baseObject);
result << baseObject;
} else if (this->mirrorHorizontally) {
mirrorOneObject(Qt::Horizontal, effectiveAxesCenter, &baseObject);
result << baseObject;
} else if (this->mirrorVertically) {
mirrorOneObject(Qt::Vertical, effectiveAxesCenter, &baseObject);
result << baseObject;
}
return result;
}
const QVector<QRect> KisPainter::calculateAllMirroredRects(const QRect &rc)
{
return d->calculateMirroredObjects(rc);
}
const QVector<QPointF> KisPainter::calculateAllMirroredPoints(const QPointF &pos)
{
return d->calculateMirroredObjects(pos);
}
const QVector<QPair<QPointF, QPointF>> KisPainter::calculateAllMirroredPoints(const QPair<QPointF, QPointF> &pair)
{
return d->calculateMirroredObjects(pair);
}
diff --git a/libs/image/kis_processing_applicator.cpp b/libs/image/kis_processing_applicator.cpp
index 01e94b1161..0f41217b76 100644
--- a/libs/image/kis_processing_applicator.cpp
+++ b/libs/image/kis_processing_applicator.cpp
@@ -1,362 +1,366 @@
/*
* Copyright (c) 2011 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_processing_applicator.h"
#include "kis_image.h"
#include "kis_paint_layer.h"
#include "kis_node.h"
#include "kis_clone_layer.h"
#include "kis_processing_visitor.h"
#include "commands_new/kis_processing_command.h"
#include "kis_stroke_strategy_undo_command_based.h"
#include "kis_layer_utils.h"
#include "kis_command_utils.h"
#include "kis_image_signal_router.h"
class DisableUIUpdatesCommand : public KisCommandUtils::FlipFlopCommand
{
public:
DisableUIUpdatesCommand(KisImageWSP image,
bool finalUpdate)
: FlipFlopCommand(finalUpdate),
m_image(image)
{
}
void partA() override {
m_image->disableUIUpdates();
}
void partB() override {
m_image->enableUIUpdates();
}
private:
KisImageWSP m_image;
};
class UpdateCommand : public KisCommandUtils::FlipFlopCommand
{
public:
UpdateCommand(KisImageWSP image, KisNodeSP node,
KisProcessingApplicator::ProcessingFlags flags,
- bool finalUpdate, bool multiframeApplication)
- : FlipFlopCommand(finalUpdate),
+ State initialState, QSharedPointer<bool> sharedAllFramesToken)
+ : FlipFlopCommand(initialState),
m_image(image),
m_node(node),
m_flags(flags),
- m_multiframeApplication(multiframeApplication)
+ m_sharedAllFramesToken(sharedAllFramesToken)
{
}
private:
void partA() override {
/**
* We disable all non-centralized updates here. Everything
* should be done by this command's explicit updates.
*
* If you still need third-party updates work, please add a
* flag to the applicator.
*/
m_image->disableDirtyRequests();
}
void partB() override {
m_image->enableDirtyRequests();
- if (m_multiframeApplication) {
+ if (*m_sharedAllFramesToken) {
KisLayerUtils::recursiveApplyNodes(m_image->root(), [](KisNodeSP node){
KisPaintLayer* paintLayer = qobject_cast<KisPaintLayer*>(node.data());
if (paintLayer && paintLayer->onionSkinEnabled()) {
paintLayer->flushOnionSkinCache();
}
});
}
if (!m_flags.testFlag(KisProcessingApplicator::NO_IMAGE_UPDATES)) {
if(m_flags.testFlag(KisProcessingApplicator::RECURSIVE)) {
m_image->refreshGraphAsync(m_node);
}
m_node->setDirty(m_image->bounds());
updateClones(m_node);
}
}
void updateClones(KisNodeSP node) {
// simple tail-recursive iteration
KisNodeSP prevNode = node->lastChild();
while(prevNode) {
updateClones(prevNode);
prevNode = prevNode->prevSibling();
}
KisLayer *layer = qobject_cast<KisLayer*>(m_node.data());
if(layer && layer->hasClones()) {
Q_FOREACH (KisCloneLayerSP clone, layer->registeredClones()) {
if(!clone) continue;
QPoint offset(clone->x(), clone->y());
QRegion dirtyRegion(m_image->bounds());
dirtyRegion -= m_image->bounds().translated(offset);
clone->setDirty(KisRegion::fromQRegion(dirtyRegion));
}
}
}
private:
KisImageWSP m_image;
KisNodeSP m_node;
KisProcessingApplicator::ProcessingFlags m_flags;
- bool m_multiframeApplication;
+ QSharedPointer<bool> m_sharedAllFramesToken;
};
class EmitImageSignalsCommand : public KisCommandUtils::FlipFlopCommand
{
public:
EmitImageSignalsCommand(KisImageWSP image,
KisImageSignalVector emitSignals,
bool finalUpdate)
: FlipFlopCommand(finalUpdate),
m_image(image),
m_emitSignals(emitSignals)
{
}
void partB() override {
if (getState() == State::FINALIZING) {
doUpdate(m_emitSignals);
} else {
KisImageSignalVector reverseSignals;
KisImageSignalVector::iterator i = m_emitSignals.end();
while (i != m_emitSignals.begin()) {
--i;
reverseSignals.append(i->inverted());
}
doUpdate(reverseSignals);
}
}
private:
void doUpdate(KisImageSignalVector emitSignals) {
Q_FOREACH (KisImageSignalType type, emitSignals) {
m_image->signalRouter()->emitNotification(type);
}
}
private:
KisImageWSP m_image;
KisImageSignalVector m_emitSignals;
};
KisProcessingApplicator::KisProcessingApplicator(KisImageWSP image,
KisNodeSP node,
ProcessingFlags flags,
KisImageSignalVector emitSignals,
const KUndo2MagicString &name,
KUndo2CommandExtraData *extraData,
int macroId)
: m_image(image),
m_node(node),
m_flags(flags),
m_emitSignals(emitSignals),
m_finalSignalsEmitted(false),
- m_appliedVisitorToAllFrames(false)
+ m_sharedAllFramesToken(new bool(false))
{
KisStrokeStrategyUndoCommandBased *strategy =
new KisStrokeStrategyUndoCommandBased(name, false, m_image.data());
if (m_flags.testFlag(SUPPORTS_WRAPAROUND_MODE)) {
strategy->setSupportsWrapAroundMode(true);
}
if (extraData) {
strategy->setCommandExtraData(extraData);
}
strategy->setMacroId(macroId);
m_strokeId = m_image->startStroke(strategy);
if(!m_emitSignals.isEmpty()) {
applyCommand(new EmitImageSignalsCommand(m_image, m_emitSignals, false), KisStrokeJobData::BARRIER);
}
if(m_flags.testFlag(NO_UI_UPDATES)) {
applyCommand(new DisableUIUpdatesCommand(m_image, false), KisStrokeJobData::BARRIER);
}
if (m_node) {
- applyCommand(new UpdateCommand(m_image, m_node, m_flags, false, true));
+ applyCommand(new UpdateCommand(m_image, m_node, m_flags,
+ UpdateCommand::INITIALIZING,
+ m_sharedAllFramesToken));
}
}
KisProcessingApplicator::~KisProcessingApplicator()
{
}
void KisProcessingApplicator::applyVisitor(KisProcessingVisitorSP visitor,
KisStrokeJobData::Sequentiality sequentiality,
KisStrokeJobData::Exclusivity exclusivity)
{
KUndo2Command *initCommand = visitor->createInitCommand();
if (initCommand) {
applyCommand(initCommand,
KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::NORMAL);
}
if(!m_flags.testFlag(RECURSIVE)) {
applyCommand(new KisProcessingCommand(visitor, m_node),
sequentiality, exclusivity);
}
else {
visitRecursively(m_node, visitor, sequentiality, exclusivity);
}
}
void KisProcessingApplicator::applyVisitorAllFrames(KisProcessingVisitorSP visitor,
KisStrokeJobData::Sequentiality sequentiality,
KisStrokeJobData::Exclusivity exclusivity)
{
- m_appliedVisitorToAllFrames = true;
+ *m_sharedAllFramesToken = true;
KUndo2Command *initCommand = visitor->createInitCommand();
if (initCommand) {
applyCommand(initCommand,
KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::NORMAL);
}
KisLayerUtils::FrameJobs jobs;
// TODO: implement a nonrecursive case when !m_flags.testFlag(RECURSIVE)
// (such case is not yet used anywhere)
KIS_SAFE_ASSERT_RECOVER_NOOP(m_flags.testFlag(RECURSIVE));
KisLayerUtils::updateFrameJobsRecursive(&jobs, m_node);
if (jobs.isEmpty()) {
applyVisitor(visitor, sequentiality, exclusivity);
return;
}
KisLayerUtils::FrameJobs::const_iterator it = jobs.constBegin();
KisLayerUtils::FrameJobs::const_iterator end = jobs.constEnd();
KisLayerUtils::SwitchFrameCommand::SharedStorageSP switchFrameStorage(
new KisLayerUtils::SwitchFrameCommand::SharedStorage());
for (; it != end; ++it) {
const int frame = it.key();
const QSet<KisNodeSP> &nodes = it.value();
applyCommand(new KisLayerUtils::SwitchFrameCommand(m_image, frame, false, switchFrameStorage), KisStrokeJobData::BARRIER, KisStrokeJobData::EXCLUSIVE);
foreach (KisNodeSP node, nodes) {
applyCommand(new KisProcessingCommand(visitor, node),
sequentiality, exclusivity);
}
applyCommand(new KisLayerUtils::SwitchFrameCommand(m_image, frame, true, switchFrameStorage), KisStrokeJobData::BARRIER, KisStrokeJobData::EXCLUSIVE);
}
}
void KisProcessingApplicator::visitRecursively(KisNodeSP node,
KisProcessingVisitorSP visitor,
KisStrokeJobData::Sequentiality sequentiality,
KisStrokeJobData::Exclusivity exclusivity)
{
// simple tail-recursive iteration
KisNodeSP prevNode = node->lastChild();
while(prevNode) {
visitRecursively(prevNode, visitor, sequentiality, exclusivity);
prevNode = prevNode->prevSibling();
}
applyCommand(new KisProcessingCommand(visitor, node),
sequentiality, exclusivity);
}
void KisProcessingApplicator::applyCommand(KUndo2Command *command,
KisStrokeJobData::Sequentiality sequentiality,
KisStrokeJobData::Exclusivity exclusivity)
{
/*
* One should not add commands after the final signals have been
* emitted, only end or cancel the stroke
*/
KIS_ASSERT_RECOVER_RETURN(!m_finalSignalsEmitted);
m_image->addJob(m_strokeId,
new KisStrokeStrategyUndoCommandBased::Data(KUndo2CommandSP(command),
false,
sequentiality,
exclusivity));
}
void KisProcessingApplicator::explicitlyEmitFinalSignals()
{
KIS_ASSERT_RECOVER_RETURN(!m_finalSignalsEmitted);
if (m_node) {
- applyCommand(new UpdateCommand(m_image, m_node, m_flags, true, m_appliedVisitorToAllFrames));
+ applyCommand(new UpdateCommand(m_image, m_node, m_flags,
+ UpdateCommand::FINALIZING,
+ m_sharedAllFramesToken));
}
if(m_flags.testFlag(NO_UI_UPDATES)) {
applyCommand(new DisableUIUpdatesCommand(m_image, true), KisStrokeJobData::BARRIER);
}
if(!m_emitSignals.isEmpty()) {
applyCommand(new EmitImageSignalsCommand(m_image, m_emitSignals, true), KisStrokeJobData::BARRIER);
}
// simple consistency check
m_finalSignalsEmitted = true;
}
void KisProcessingApplicator::end()
{
if (!m_finalSignalsEmitted) {
explicitlyEmitFinalSignals();
}
m_image->endStroke(m_strokeId);
}
void KisProcessingApplicator::cancel()
{
m_image->cancelStroke(m_strokeId);
}
void KisProcessingApplicator::runSingleCommandStroke(KisImageSP image, KUndo2Command *cmd, KisStrokeJobData::Sequentiality sequentiality, KisStrokeJobData::Exclusivity exclusivity)
{
KisProcessingApplicator applicator(image, 0,
KisProcessingApplicator::NONE,
KisImageSignalVector() << ModifiedSignal,
cmd->text());
applicator.applyCommand(cmd, sequentiality, exclusivity);
applicator.end();
}
diff --git a/libs/image/kis_processing_applicator.h b/libs/image/kis_processing_applicator.h
index 0695d6ac07..8f6b2f12f5 100644
--- a/libs/image/kis_processing_applicator.h
+++ b/libs/image/kis_processing_applicator.h
@@ -1,114 +1,114 @@
/*
* Copyright (c) 2011 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_PROCESSING_APPLICATOR_H
#define __KIS_PROCESSING_APPLICATOR_H
#include "kritaimage_export.h"
#include "kis_types.h"
#include "kis_stroke_job_strategy.h"
#include "KisImageSignals.h"
#include "kundo2magicstring.h"
#include "kundo2commandextradata.h"
class KRITAIMAGE_EXPORT KisProcessingApplicator
{
public:
enum ProcessingFlag {
NONE = 0x0,
RECURSIVE = 0x1,
NO_UI_UPDATES = 0x2,
SUPPORTS_WRAPAROUND_MODE = 0x4,
NO_IMAGE_UPDATES = 0x8
};
Q_DECLARE_FLAGS(ProcessingFlags, ProcessingFlag)
public:
KisProcessingApplicator(KisImageWSP image,
KisNodeSP node,
ProcessingFlags flags = NONE,
KisImageSignalVector emitSignals = KisImageSignalVector(),
const KUndo2MagicString &name = KUndo2MagicString(),
KUndo2CommandExtraData *extraData = 0,
int macroId = -1);
~KisProcessingApplicator();
void applyVisitor(KisProcessingVisitorSP visitor,
KisStrokeJobData::Sequentiality sequentiality = KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::Exclusivity exclusivity = KisStrokeJobData::NORMAL);
void applyCommand(KUndo2Command *command,
KisStrokeJobData::Sequentiality sequentiality = KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::Exclusivity exclusivity = KisStrokeJobData::NORMAL);
void applyVisitorAllFrames(KisProcessingVisitorSP visitor,
KisStrokeJobData::Sequentiality sequentiality = KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::Exclusivity exclusivity = KisStrokeJobData::NORMAL);
/**
* This method emits all the final update signals of the stroke
* without actually ending the stroke. This can be used for
* long-running strokes which are kept open to implement preview
* of the actions.
*
* WARNING: you cannot add new commands/processings after the
* final signals has been emitted. You should either call end() or
* cancel().
*/
void explicitlyEmitFinalSignals();
void end();
void cancel();
/**
* @brief runSingleCommandStroke creates a stroke and runs \p cmd in it.
* The text() field fo \p cmd is used as a title of the stroke.
* @param image the image to run the stroke on
* @param cmd the command to be executed
* @param sequentiality sequentiality property of the command being executed (see strokes documentation)
* @param exclusivity sequentiality property of the command being executed (see strokes documentation)
*/
static void runSingleCommandStroke(KisImageSP image,
KUndo2Command *cmd,
KisStrokeJobData::Sequentiality sequentiality = KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::Exclusivity exclusivity = KisStrokeJobData::NORMAL);
private:
void visitRecursively(KisNodeSP node,
KisProcessingVisitorSP visitor,
KisStrokeJobData::Sequentiality sequentiality,
KisStrokeJobData::Exclusivity exclusivity);
private:
KisImageWSP m_image;
KisNodeSP m_node;
ProcessingFlags m_flags;
KisImageSignalVector m_emitSignals;
KisStrokeId m_strokeId;
bool m_finalSignalsEmitted;
- bool m_appliedVisitorToAllFrames;
+ QSharedPointer<bool> m_sharedAllFramesToken;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(KisProcessingApplicator::ProcessingFlags)
#endif /* __KIS_PROCESSING_APPLICATOR_H */
diff --git a/libs/image/kis_projection_updates_filter.cpp b/libs/image/kis_projection_updates_filter.cpp
index 3e3fc6be59..1449eb91ec 100644
--- a/libs/image/kis_projection_updates_filter.cpp
+++ b/libs/image/kis_projection_updates_filter.cpp
@@ -1,36 +1,45 @@
/*
* Copyright (c) 2014 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_projection_updates_filter.h"
#include <QtGlobal>
#include <QRect>
KisProjectionUpdatesFilter::~KisProjectionUpdatesFilter()
{
}
bool KisDropAllProjectionUpdatesFilter::filter(KisImage *image, KisNode *node, const QVector<QRect> &rects, bool resetAnimationCache)
{
Q_UNUSED(image);
Q_UNUSED(node);
Q_UNUSED(rects);
Q_UNUSED(resetAnimationCache);
return true;
}
+
+bool KisDropAllProjectionUpdatesFilter::filterRefreshGraph(KisImage *image, KisNode *node, const QVector<QRect> &rects, const QRect &cropRect)
+{
+ Q_UNUSED(image);
+ Q_UNUSED(node);
+ Q_UNUSED(rects);
+ Q_UNUSED(cropRect);
+ return true;
+}
diff --git a/libs/image/kis_projection_updates_filter.h b/libs/image/kis_projection_updates_filter.h
index 23c9f78a4f..5ba5130f41 100644
--- a/libs/image/kis_projection_updates_filter.h
+++ b/libs/image/kis_projection_updates_filter.h
@@ -1,51 +1,53 @@
/*
* Copyright (c) 2014 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_PROJECTION_UPDATES_FILTER_H
#define __KIS_PROJECTION_UPDATES_FILTER_H
#include <QSharedPointer>
#include "kritaimage_export.h"
class KisImage;
class KisNode;
class QRect;
class KRITAIMAGE_EXPORT KisProjectionUpdatesFilter
{
public:
virtual ~KisProjectionUpdatesFilter();
/**
* \return true if an update should be dropped by the image
*/
virtual bool filter(KisImage *image, KisNode *node, const QVector<QRect> &rects, bool resetAnimationCache) = 0;
+ virtual bool filterRefreshGraph(KisImage *image, KisNode *node, const QVector<QRect> &rect, const QRect &cropRect) = 0;
};
/**
* A dummy filter implementation that eats all the updates
*/
class KRITAIMAGE_EXPORT KisDropAllProjectionUpdatesFilter : public KisProjectionUpdatesFilter
{
public:
bool filter(KisImage *image, KisNode *node, const QVector<QRect> &rects, bool resetAnimationCache) override;
+ bool filterRefreshGraph(KisImage *image, KisNode *node, const QVector<QRect> &rects, const QRect &cropRect) override;
};
#endif /* __KIS_PROJECTION_UPDATES_FILTER_H */
diff --git a/libs/image/kis_selection.cc b/libs/image/kis_selection.cc
index 59dc9c3bd8..5594822c3b 100644
--- a/libs/image/kis_selection.cc
+++ b/libs/image/kis_selection.cc
@@ -1,361 +1,485 @@
/*
* Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
* Copyright (c) 2007 Sven Langkamp <sven.langkamp@gmail.com>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_selection.h"
#include "kundo2command.h"
#include "kis_selection_component.h"
#include "kis_pixel_selection.h"
#include "kis_node_graph_listener.h"
#include "kis_node.h"
#include "kis_image.h"
#include "kis_default_bounds.h"
#include "kis_iterator_ng.h"
#include "KisLazyStorage.h"
#include "KisSelectionUpdateCompressor.h"
+#include "kis_simple_stroke_strategy.h"
+#include "KisDeleteLaterWrapper.h"
+#include "kis_command_utils.h"
struct Q_DECL_HIDDEN KisSelection::Private {
Private(KisSelection *q)
: isVisible(true),
shapeSelection(0),
updateCompressor(q)
{
}
+ static void safeDeleteShapeSelection(KisSelectionComponent *shapeSelection, KisSelection *selection);
+
// used for forwarding setDirty signals only
KisNodeWSP parentNode;
bool isVisible; //false is the selection decoration should not be displayed
KisDefaultBoundsBaseSP defaultBounds;
KisPixelSelectionSP pixelSelection;
KisSelectionComponent *shapeSelection;
KisLazyStorage<KisSelectionUpdateCompressor> updateCompressor;
};
+void KisSelection::Private::safeDeleteShapeSelection(KisSelectionComponent *shapeSelection, KisSelection *selection)
+{
+ struct ShapeSelectionReleaseStroke : public KisSimpleStrokeStrategy {
+ ShapeSelectionReleaseStroke(KisSelectionComponent *shapeSelection)
+ : KisSimpleStrokeStrategy(QLatin1String("ShapeSelectionReleaseStroke")),
+ m_shapeSelection(shapeSelection)
+ {
+ setRequestsOtherStrokesToEnd(false);
+ setClearsRedoOnStart(false);
+ setNeedsExplicitCancel(true);
+
+ this->enableJob(JOB_FINISH, true, KisStrokeJobData::BARRIER);
+ this->enableJob(JOB_CANCEL, true, KisStrokeJobData::BARRIER);
+ }
+
+ void finishStrokeCallback() {
+ makeKisDeleteLaterWrapper(m_shapeSelection)->deleteLater();
+ }
+
+ void cancelStrokeCallback() {
+ finishStrokeCallback();
+ }
+
+ private:
+ KisSelectionComponent *m_shapeSelection = 0;
+ };
+
+
+
+ KisImageSP image = 0;
+
+ KisNodeSP parentNode = selection->parentNode();
+ if (parentNode) {
+ image = parentNode->image();
+ }
+
+ if (image) {
+ KisStrokeId strokeId = image->startStroke(new ShapeSelectionReleaseStroke(shapeSelection));
+ image->endStroke(strokeId);
+ } else {
+ makeKisDeleteLaterWrapper(shapeSelection)->deleteLater();
+ }
+}
+
+struct KisSelection::ChangeShapeSelectionCommand : public KUndo2Command
+{
+ ChangeShapeSelectionCommand(KisSelection *selection, KisSelectionComponent *shapeSelection)
+ : m_selection(selection),
+ m_shapeSelection(shapeSelection)
+ {
+ m_isFlatten = !shapeSelection;
+ }
+
+ ~ChangeShapeSelectionCommand() {
+ if (m_shapeSelection) {
+ Private::safeDeleteShapeSelection(m_shapeSelection, m_selection);
+ }
+ }
+
+ void undo() override
+ {
+ if (m_reincarnationCommand) {
+ m_reincarnationCommand->undo();
+ }
+
+ std::swap(m_selection->m_d->shapeSelection, m_shapeSelection);
+
+ if (!m_isFlatten) {
+ m_selection->requestCompressedProjectionUpdate(QRect());
+ }
+ }
+
+ void redo() override
+ {
+ if (m_firstRedo) {
+ if (bool(m_selection->m_d->shapeSelection) != bool(m_shapeSelection)) {
+ m_reincarnationCommand.reset(
+ m_selection->m_d->pixelSelection->reincarnateWithDetachedHistory(m_isFlatten));
+ }
+ m_firstRedo = false;
+
+ }
+
+ if (m_reincarnationCommand) {
+ m_reincarnationCommand->redo();
+ }
+
+ std::swap(m_selection->m_d->shapeSelection, m_shapeSelection);
+
+ if (!m_isFlatten) {
+ m_selection->requestCompressedProjectionUpdate(QRect());
+ }
+ }
+
+private:
+ KisSelection *m_selection = 0;
+ KisSelectionComponent *m_shapeSelection = 0;
+ QScopedPointer<KUndo2Command> m_reincarnationCommand;
+ bool m_firstRedo = true;
+ bool m_isFlatten = false;
+};
+
KisSelection::KisSelection(KisDefaultBoundsBaseSP defaultBounds)
: m_d(new Private(this))
{
if (!defaultBounds) {
defaultBounds = new KisSelectionEmptyBounds(0);
}
m_d->defaultBounds = defaultBounds;
m_d->pixelSelection = new KisPixelSelection(m_d->defaultBounds, this);
m_d->pixelSelection->setParentNode(m_d->parentNode);
}
KisSelection::KisSelection(const KisSelection& rhs)
: KisShared(),
m_d(new Private(this))
{
copyFrom(rhs);
}
KisSelection::KisSelection(const KisPaintDeviceSP source, KritaUtils::DeviceCopyMode copyMode, KisDefaultBoundsBaseSP defaultBounds)
: m_d(new Private(this))
{
if (!defaultBounds) {
defaultBounds = new KisSelectionEmptyBounds(0);
}
m_d->defaultBounds = defaultBounds;
m_d->pixelSelection = new KisPixelSelection(source, copyMode);
m_d->pixelSelection->setParentSelection(this);
m_d->pixelSelection->setParentNode(m_d->parentNode);
m_d->pixelSelection->setDefaultBounds(m_d->defaultBounds);
}
KisSelection &KisSelection::operator=(const KisSelection &rhs)
{
if (&rhs != this) {
copyFrom(rhs);
}
return *this;
}
void KisSelection::copyFrom(const KisSelection &rhs)
{
m_d->isVisible = rhs.m_d->isVisible;
m_d->defaultBounds = rhs.m_d->defaultBounds;
m_d->parentNode = 0; // not supposed to be shared
Q_ASSERT(rhs.m_d->pixelSelection);
m_d->pixelSelection = new KisPixelSelection(*rhs.m_d->pixelSelection, KritaUtils::CopyAllFrames);
m_d->pixelSelection->setParentSelection(this);
-
- if (rhs.m_d->shapeSelection) {
+ if (rhs.m_d->shapeSelection && !rhs.m_d->shapeSelection->isEmpty()) {
m_d->shapeSelection = rhs.m_d->shapeSelection->clone(this);
- Q_ASSERT(m_d->shapeSelection);
- Q_ASSERT(m_d->shapeSelection != rhs.m_d->shapeSelection);
+ KIS_SAFE_ASSERT_RECOVER_NOOP(m_d->shapeSelection);
+ KIS_SAFE_ASSERT_RECOVER(m_d->shapeSelection &&
+ m_d->shapeSelection != rhs.m_d->shapeSelection) {
+ m_d->shapeSelection = 0;
+ }
}
else {
- m_d->shapeSelection = 0;
+ if (m_d->shapeSelection) {
+ Private::safeDeleteShapeSelection(m_d->shapeSelection, this);
+ m_d->shapeSelection = 0;
+ }
}
}
KisSelection::~KisSelection()
{
delete m_d->shapeSelection;
delete m_d;
}
void KisSelection::setParentNode(KisNodeWSP node)
{
m_d->parentNode = node;
m_d->pixelSelection->setParentNode(node);
// the updates come through the parent image, so all the updates
// that happened in the meantime are considered "stalled"
if (node) {
m_d->updateCompressor->tryProcessStalledUpdate();
}
}
// for testing purposes only
KisNodeWSP KisSelection::parentNode() const
{
return m_d->parentNode;
}
bool KisSelection::outlineCacheValid() const
{
- return hasShapeSelection() ||
+ return m_d->shapeSelection ||
m_d->pixelSelection->outlineCacheValid();
}
QPainterPath KisSelection::outlineCache() const
{
QPainterPath outline;
- if (hasShapeSelection()) {
+ if (m_d->shapeSelection) {
outline += m_d->shapeSelection->outlineCache();
} else if (m_d->pixelSelection->outlineCacheValid()) {
outline += m_d->pixelSelection->outlineCache();
}
return outline;
}
void KisSelection::recalculateOutlineCache()
{
Q_ASSERT(m_d->pixelSelection);
- if (hasShapeSelection()) {
+ if (m_d->shapeSelection) {
m_d->shapeSelection->recalculateOutlineCache();
} else if (!m_d->pixelSelection->outlineCacheValid()) {
m_d->pixelSelection->recalculateOutlineCache();
}
}
bool KisSelection::thumbnailImageValid() const
{
return m_d->pixelSelection->thumbnailImageValid();
}
void KisSelection::recalculateThumbnailImage(const QColor &maskColor)
{
m_d->pixelSelection->recalculateThumbnailImage(maskColor);
}
QImage KisSelection::thumbnailImage() const
{
return m_d->pixelSelection->thumbnailImage();
}
QTransform KisSelection::thumbnailImageTransform() const
{
return m_d->pixelSelection->thumbnailImageTransform();
}
-bool KisSelection::hasPixelSelection() const
+bool KisSelection::hasNonEmptyPixelSelection() const
{
return m_d->pixelSelection && !m_d->pixelSelection->isEmpty();
}
-bool KisSelection::hasShapeSelection() const
+bool KisSelection::hasNonEmptyShapeSelection() const
{
return m_d->shapeSelection && !m_d->shapeSelection->isEmpty();
}
+bool KisSelection::hasShapeSelection() const
+{
+ return m_d->shapeSelection;
+}
+
KisPixelSelectionSP KisSelection::pixelSelection() const
{
return m_d->pixelSelection;
}
KisSelectionComponent* KisSelection::shapeSelection() const
{
return m_d->shapeSelection;
}
-void KisSelection::setShapeSelection(KisSelectionComponent* shapeSelection)
+void KisSelection::convertToVectorSelectionNoUndo(KisSelectionComponent* shapeSelection)
{
- const bool needsNotification = shapeSelection != m_d->shapeSelection;
-
- m_d->shapeSelection = shapeSelection;
+ QScopedPointer<KUndo2Command> cmd(new ChangeShapeSelectionCommand(this, shapeSelection));
+ cmd->redo();
+}
- if (needsNotification) {
- requestCompressedProjectionUpdate(QRect());
- }
+KUndo2Command *KisSelection::convertToVectorSelection(KisSelectionComponent *shapeSelection)
+{
+ KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!m_d->shapeSelection, nullptr);
+ return new ChangeShapeSelectionCommand(this, shapeSelection);
}
KisPixelSelectionSP KisSelection::projection() const
{
return m_d->pixelSelection;
}
void KisSelection::updateProjection(const QRect &rc)
{
- if(hasShapeSelection()) {
+ if(m_d->shapeSelection) {
m_d->shapeSelection->renderToProjection(m_d->pixelSelection, rc);
m_d->pixelSelection->setOutlineCache(m_d->shapeSelection->outlineCache());
}
}
void KisSelection::updateProjection()
{
- if(hasShapeSelection()) {
+ if(m_d->shapeSelection) {
m_d->pixelSelection->clear();
m_d->shapeSelection->renderToProjection(m_d->pixelSelection);
m_d->pixelSelection->setOutlineCache(m_d->shapeSelection->outlineCache());
}
}
void KisSelection::setVisible(bool visible)
{
bool needsNotification = visible != m_d->isVisible;
m_d->isVisible = visible;
if (needsNotification) {
notifySelectionChanged();
}
}
bool KisSelection::isVisible()
{
return m_d->isVisible;
}
bool KisSelection::isTotallyUnselected(const QRect & r) const
{
return m_d->pixelSelection->isTotallyUnselected(r);
}
QRect KisSelection::selectedRect() const
{
return m_d->pixelSelection->selectedRect();
}
QRect KisSelection::selectedExactRect() const
{
return m_d->pixelSelection->selectedExactRect();
}
qint32 KisSelection::x() const
{
return m_d->pixelSelection->x();
}
qint32 KisSelection::y() const
{
return m_d->pixelSelection->y();
}
void KisSelection::setX(qint32 x)
{
Q_ASSERT(m_d->pixelSelection);
qint32 delta = x - m_d->pixelSelection->x();
m_d->pixelSelection->setX(x);
if (m_d->shapeSelection) {
m_d->shapeSelection->moveX(delta);
}
}
void KisSelection::setY(qint32 y)
{
Q_ASSERT(m_d->pixelSelection);
qint32 delta = y - m_d->pixelSelection->y();
m_d->pixelSelection->setY(y);
if (m_d->shapeSelection) {
m_d->shapeSelection->moveY(delta);
}
}
void KisSelection::setDefaultBounds(KisDefaultBoundsBaseSP bounds)
{
m_d->defaultBounds = bounds;
m_d->pixelSelection->setDefaultBounds(bounds);
}
void KisSelection::clear()
{
- // FIXME: check whether this is safe
- delete m_d->shapeSelection;
- m_d->shapeSelection = 0;
+ if (m_d->shapeSelection) {
+ Private::safeDeleteShapeSelection(m_d->shapeSelection, this);
+ m_d->shapeSelection = 0;
+ }
m_d->pixelSelection->clear();
}
KUndo2Command* KisSelection::flatten()
{
KUndo2Command *command = 0;
- if (hasShapeSelection()) {
+ if (m_d->shapeSelection) {
command = m_d->shapeSelection->resetToEmpty();
+
+ if (command) {
+ KisCommandUtils::CompositeCommand *cmd = new KisCommandUtils::CompositeCommand();
+ cmd->addCommand(command);
+ cmd->addCommand(new ChangeShapeSelectionCommand(this, nullptr));
+ command = cmd;
+ } else {
+ command = new ChangeShapeSelectionCommand(this, nullptr);
+ }
}
return command;
}
void KisSelection::notifySelectionChanged()
{
KisNodeWSP parentNode;
if (!(parentNode = this->parentNode())) return;
KisNodeGraphListener *listener;
if (!(listener = parentNode->graphListener())) return;
listener->notifySelectionChanged();
}
void KisSelection::requestCompressedProjectionUpdate(const QRect &rc)
{
m_d->updateCompressor->requestUpdate(rc);
}
-void KisSelection::notifyShapeSelectionBecameEmpty()
-{
- m_d->pixelSelection->clear();
-}
-
quint8 KisSelection::selected(qint32 x, qint32 y) const
{
KisHLineConstIteratorSP iter = m_d->pixelSelection->createHLineConstIteratorNG(x, y, 1);
const quint8 *pix = iter->oldRawData();
return *pix;
}
+
diff --git a/libs/image/kis_selection.h b/libs/image/kis_selection.h
index d8908185a1..8d455d3856 100644
--- a/libs/image/kis_selection.h
+++ b/libs/image/kis_selection.h
@@ -1,227 +1,242 @@
/*
* Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
*
* 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_H_
#define KIS_SELECTION_H_
#include <QRect>
#include "kis_types.h"
#include "kritaimage_export.h"
#include "kis_default_bounds.h"
#include "kis_image.h"
#include "KisSelectionTags.h"
#include "kis_pixel_selection.h"
class KisSelectionComponent;
class QPainterPath;
/**
* KisSelection is a composite object. It may contain an instance
* of KisPixelSelection and a KisShapeSelection object. Both these
* selections are merged into a projection of the KisSelection.
*
* Every pixel in the paint device can indicate a degree of selectedness, varying
* between MIN_SELECTED and MAX_SELECTED.
*
* The projection() paint device itself is only a projection: you can
* read from it, but not write to it. You need to keep track of
* the need for updating the projection yourself: there is no
* automatic updating after changing the contents of one or more
* of the selection components.
*/
class KRITAIMAGE_EXPORT KisSelection : public KisShared
{
+private:
+ struct ChangeShapeSelectionCommand;
public:
/**
* Create a new KisSelection.
*
* @param defaultBounds defines the bounds of the selection when
* Select All is initiated.
*/
KisSelection(KisDefaultBoundsBaseSP defaultBounds = KisDefaultBoundsBaseSP());
/**
* Copy the selection. The selection components are copied, too.
*/
KisSelection(const KisSelection& rhs);
KisSelection& operator=(const KisSelection &rhs);
/**
* Delete the selection. The shape selection component is deleted, the
* pixel selection component is contained in a shared pointer, so that
* may still be valid.
*/
virtual ~KisSelection();
/**
* Create a new selection using the content of copySource as the mask.
*/
KisSelection(const KisPaintDeviceSP copySource, KritaUtils::DeviceCopyMode copyMode, KisDefaultBoundsBaseSP defaultBounds);
/**
* The paint device of the pixel selection should report
* about it's setDirty events to its parent. The creator
* should set the parent manually if it wants to get the
* signals
*/
void setParentNode(KisNodeWSP node);
- bool hasPixelSelection() const;
+ bool hasNonEmptyPixelSelection() const;
+ bool hasNonEmptyShapeSelection() const;
bool hasShapeSelection() const;
bool outlineCacheValid() const;
QPainterPath outlineCache() const;
void recalculateOutlineCache();
/**
* Tells whether the cached thumbnail of the selection is still valid
*/
bool thumbnailImageValid() const;
/**
* Recalculates the thumbnail of the selection
*/
void recalculateThumbnailImage(const QColor &maskColor);
/**
* Returns the thumbnail of the selection.
*/
QImage thumbnailImage() const;
/**
* Returns the transformation which should be applied to the thumbnail before
* being painted over the image
*/
QTransform thumbnailImageTransform() const;
/**
* return the pixel selection component of this selection. Pixel
* selection component is always present in the selection. In case
* the user wants a vector selection, pixel selection will store
* the pixelated version of it.
*
* NOTE: use pixelSelection() for changing the selection only. For
* reading the selection and passing the data to bitBlt function use
* projection(). Although projection() and pixelSelection() currently
* point ot the same paint device, this behavior may change in the
* future.
*/
KisPixelSelectionSP pixelSelection() const;
/**
* return the vector selection component of this selection or zero
* if hasShapeSelection() returns false.
*/
KisSelectionComponent* shapeSelection() const;
- void setShapeSelection(KisSelectionComponent* shapeSelection);
+ /**
+ * @brief converts shape selection into the vector state
+ *
+ * The selection must not have any shape selection active. It should
+ * be checked by calling hasShapeSelection() in advance.
+ *
+ * @param shapeSelection new shape selection object that should be
+ * attached to the selection
+ * @return undo command that exectes and undos the conversion
+ */
+ KUndo2Command* convertToVectorSelection(KisSelectionComponent* shapeSelection);
+
+ /**
+ * @see convertToVectorSelection()
+ */
+ void convertToVectorSelectionNoUndo(KisSelectionComponent* shapeSelection);
/**
* Returns the projection of the selection. It may be the same
* as pixel selection. You must read selection data from this
* paint device only
*/
KisPixelSelectionSP projection() const;
/**
* Updates the projection of the selection. You should call this
* method after the every change of the selection components.
* There is no automatic updates framework present
*/
void updateProjection(const QRect& rect);
void updateProjection();
void setVisible(bool visible);
bool isVisible();
/**
* Convenience functions. Just call the corresponding methods
* of the underlying projection
*/
bool isTotallyUnselected(const QRect & r) const;
QRect selectedRect() const;
/**
* @brief Slow, but exact way of determining the rectangle
* that encloses the selection.
*
* Default pixel of the selection device may vary and you would get wrong bounds.
* selectedExactRect() handles all these cases.
*
*/
QRect selectedExactRect() const;
void setX(qint32 x);
void setY(qint32 y);
qint32 x() const;
qint32 y() const;
void setDefaultBounds(KisDefaultBoundsBaseSP bounds);
void clear();
/**
* @brief flatten creates a new pixel selection component from the shape selection
* and throws away the shape selection. This has no effect if there is no
* shape selection.
*/
KUndo2Command* flatten();
void notifySelectionChanged();
/**
* Request rerendering of the shape selection component in a
* compressed way. Usually, you don't need to call it manually,
* because all the work is done by KisShapeSelectionModel.
*/
void requestCompressedProjectionUpdate(const QRect &rc);
- void notifyShapeSelectionBecameEmpty();
-
/// XXX: This method was marked KDE_DEPRECATED but without information on what to
/// replace it with. Undeprecate, therefore.
quint8 selected(qint32 x, qint32 y) const;
KisNodeWSP parentNode() const;
private:
friend class KisSelectionTest;
friend class KisMaskTest;
friend class KisAdjustmentLayerTest;
friend class KisUpdateSelectionJob;
friend class KisSelectionUpdateCompressor;
friend class KisDeselectActiveSelectionCommand;
-
void copyFrom(const KisSelection &rhs);
private:
struct Private;
Private * const m_d;
};
#endif // KIS_SELECTION_H_
diff --git a/libs/image/kis_selection_based_layer.cpp b/libs/image/kis_selection_based_layer.cpp
index 3bad0c4d41..bcd3bdfa87 100644
--- a/libs/image/kis_selection_based_layer.cpp
+++ b/libs/image/kis_selection_based_layer.cpp
@@ -1,358 +1,358 @@
/*
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
* Copyright (c) 2005 C. Boemann <cbo@boemann.dk>
* Copyright (c) 2009 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_selection_based_layer.h"
#include <klocalizedstring.h>
#include "kis_debug.h"
#include <KoCompositeOpRegistry.h>
#include "kis_image.h"
#include "kis_painter.h"
#include "kis_default_bounds.h"
#include "kis_selection.h"
#include "kis_pixel_selection.h"
#include "filter/kis_filter_configuration.h"
#include "filter/kis_filter_registry.h"
#include "filter/kis_filter.h"
#include "kis_raster_keyframe_channel.h"
struct Q_DECL_HIDDEN KisSelectionBasedLayer::Private
{
public:
Private() : useSelectionInProjection(true) {}
Private(const Private &rhs) : useSelectionInProjection(rhs.useSelectionInProjection) {}
KisSelectionSP selection;
KisPaintDeviceSP paintDevice;
bool useSelectionInProjection;
};
KisSelectionBasedLayer::KisSelectionBasedLayer(KisImageWSP image,
const QString &name,
KisSelectionSP selection,
KisFilterConfigurationSP filterConfig)
: KisLayer(image.data(), name, OPACITY_OPAQUE_U8),
KisNodeFilterInterface(filterConfig),
m_d(new Private())
{
if (!selection) {
initSelection();
} else {
setInternalSelection(selection);
}
KisImageSP imageSP = image.toStrongRef();
if (!imageSP) {
return;
}
m_d->paintDevice = KisPaintDeviceSP(new KisPaintDevice(this, imageSP->colorSpace(), KisDefaultBoundsSP(new KisDefaultBounds(image))));
connect(imageSP.data(), SIGNAL(sigSizeChanged(QPointF,QPointF)), SLOT(slotImageSizeChanged()));
}
KisSelectionBasedLayer::KisSelectionBasedLayer(const KisSelectionBasedLayer& rhs)
: KisLayer(rhs)
, KisIndirectPaintingSupport()
, KisNodeFilterInterface(rhs)
, m_d(new Private(*rhs.m_d))
{
setInternalSelection(rhs.m_d->selection);
m_d->paintDevice = new KisPaintDevice(*rhs.m_d->paintDevice.data());
}
KisSelectionBasedLayer::~KisSelectionBasedLayer()
{
delete m_d;
}
void KisSelectionBasedLayer::initSelection()
{
m_d->selection = KisSelectionSP(new KisSelection(KisDefaultBoundsSP(new KisDefaultBounds(image()))));
m_d->selection->pixelSelection()->setDefaultPixel(KoColor(Qt::white, m_d->selection->pixelSelection()->colorSpace()));
m_d->selection->setParentNode(this);
m_d->selection->updateProjection();
}
void KisSelectionBasedLayer::slotImageSizeChanged()
{
if (m_d->selection) {
/**
* Make sure exactBounds() of the selection got recalculated after
* the image changed
*/
m_d->selection->pixelSelection()->setDirty();
setDirty();
}
}
void KisSelectionBasedLayer::setImage(KisImageWSP image)
{
m_d->paintDevice->setDefaultBounds(KisDefaultBoundsSP(new KisDefaultBounds(image)));
m_d->selection->pixelSelection()->setDefaultBounds(KisDefaultBoundsSP(new KisDefaultBounds(image)));
KisLayer::setImage(image);
connect(image.data(), SIGNAL(sigSizeChanged(QPointF,QPointF)), SLOT(slotImageSizeChanged()));
}
bool KisSelectionBasedLayer::allowAsChild(KisNodeSP node) const
{
return node->inherits("KisMask");
}
KisPaintDeviceSP KisSelectionBasedLayer::original() const
{
return m_d->paintDevice;
}
KisPaintDeviceSP KisSelectionBasedLayer::paintDevice() const
{
return m_d->selection->pixelSelection();
}
bool KisSelectionBasedLayer::needProjection() const
{
return m_d->selection;
}
void KisSelectionBasedLayer::setUseSelectionInProjection(bool value) const
{
m_d->useSelectionInProjection = value;
}
KisSelectionSP KisSelectionBasedLayer::fetchComposedInternalSelection(const QRect &rect) const
{
if (!m_d->selection) return KisSelectionSP();
m_d->selection->updateProjection(rect);
KisSelectionSP tempSelection = m_d->selection;
KisIndirectPaintingSupport::ReadLocker l(this);
if (hasTemporaryTarget()) {
/**
* WARNING: we don't try to clone the selection entirely, because
* it might be unsafe for shape selections.
*
* TODO: make cloning of vector selections safe! See a comment in
* KisShapeSelection::clone().
*/
tempSelection = new KisSelection();
KisPainter::copyAreaOptimized(rect.topLeft(), m_d->selection->pixelSelection(), tempSelection->pixelSelection(), rect);
KisPainter gc2(tempSelection->pixelSelection());
setupTemporaryPainter(&gc2);
gc2.bitBlt(rect.topLeft(), temporaryTarget(), rect);
}
return tempSelection;
}
void KisSelectionBasedLayer::copyOriginalToProjection(const KisPaintDeviceSP original,
KisPaintDeviceSP projection,
const QRect& rect) const
{
KisSelectionSP tempSelection;
if (m_d->useSelectionInProjection) {
tempSelection = fetchComposedInternalSelection(rect);
/**
* When we paint with a selection, the deselected areas will *not* be
* overwritten by copyAreaOptimized(), so we need to clear them beforehand
*/
projection->clear(rect);
}
KisPainter::copyAreaOptimized(rect.topLeft(), original, projection, rect, tempSelection);
}
QRect KisSelectionBasedLayer::cropChangeRectBySelection(const QRect &rect) const
{
return m_d->selection ?
rect & m_d->selection->selectedRect() :
rect;
}
QRect KisSelectionBasedLayer::needRect(const QRect &rect, PositionToFilthy pos) const
{
Q_UNUSED(pos);
return rect;
}
void KisSelectionBasedLayer::resetCache()
{
KisImageSP imageSP = image().toStrongRef();
if (!imageSP) {
return;
}
if (!m_d->paintDevice || *m_d->paintDevice->colorSpace() != *imageSP->colorSpace()) {
m_d->paintDevice = KisPaintDeviceSP(new KisPaintDevice(KisNodeWSP(this), imageSP->colorSpace(), new KisDefaultBounds(image())));
} else {
m_d->paintDevice->clear();
}
}
KisSelectionSP KisSelectionBasedLayer::internalSelection() const
{
return m_d->selection;
}
void KisSelectionBasedLayer::setInternalSelection(KisSelectionSP selection)
{
if (selection) {
m_d->selection = new KisSelection(*selection.data());
m_d->selection->setParentNode(this);
m_d->selection->setDefaultBounds(new KisDefaultBounds(image()));
m_d->selection->updateProjection();
KisPixelSelectionSP pixelSelection = m_d->selection->pixelSelection();
if (pixelSelection->framesInterface()) {
addKeyframeChannel(pixelSelection->keyframeChannel());
enableAnimation();
}
KisImageSP imageSP = image().toStrongRef();
KIS_SAFE_ASSERT_RECOVER_RETURN(imageSP);
if (m_d->selection->pixelSelection()->defaultBounds()->bounds() != imageSP->bounds()) {
qWarning() << "WARNING: KisSelectionBasedLayer::setInternalSelection"
<< "New selection has suspicious default bounds";
qWarning() << "WARNING:" << ppVar(m_d->selection->pixelSelection()->defaultBounds()->bounds());
qWarning() << "WARNING:" << ppVar(imageSP->bounds());
}
} else {
m_d->selection = 0;
}
}
qint32 KisSelectionBasedLayer::x() const
{
return m_d->selection ? m_d->selection->x() : 0;
}
qint32 KisSelectionBasedLayer::y() const
{
return m_d->selection ? m_d->selection->y() : 0;
}
void KisSelectionBasedLayer::setX(qint32 x)
{
if (m_d->selection) {
m_d->selection->setX(x);
}
}
void KisSelectionBasedLayer::setY(qint32 y)
{
if (m_d->selection) {
m_d->selection->setY(y);
}
}
KisKeyframeChannel *KisSelectionBasedLayer::requestKeyframeChannel(const QString &id)
{
if (id == KisKeyframeChannel::Content.id()) {
KisRasterKeyframeChannel *contentChannel = m_d->selection->pixelSelection()->createKeyframeChannel(KisKeyframeChannel::Content);
contentChannel->setFilenameSuffix(".pixelselection");
return contentChannel;
}
return KisLayer::requestKeyframeChannel(id);
}
void KisSelectionBasedLayer::setDirty()
{
Q_ASSERT(image());
KisImageSP imageSP = image().toStrongRef();
if (!imageSP) {
return;
}
setDirty(imageSP->bounds());
}
QRect KisSelectionBasedLayer::extent() const
{
QRect resultRect;
if (m_d->selection) {
resultRect = m_d->selection->selectedRect();
// copy for thread safety!
KisPaintDeviceSP temporaryTarget = this->temporaryTarget();
if (temporaryTarget) {
resultRect |= temporaryTarget->extent();
}
} else {
KisImageSP image = this->image().toStrongRef();
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(image, QRect());
resultRect = image->bounds();
}
return resultRect;
}
QRect KisSelectionBasedLayer::exactBounds() const
{
QRect resultRect;
if (m_d->selection) {
resultRect = m_d->selection->selectedExactRect();
// copy for thread safety!
KisPaintDeviceSP temporaryTarget = this->temporaryTarget();
if (temporaryTarget) {
resultRect |= temporaryTarget->exactBounds();
}
} else {
KisImageSP image = this->image().toStrongRef();
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(image, QRect());
resultRect = image->bounds();
}
return resultRect;
}
-QImage KisSelectionBasedLayer::createThumbnail(qint32 w, qint32 h)
+QImage KisSelectionBasedLayer::createThumbnail(qint32 w, qint32 h, Qt::AspectRatioMode aspectRatioMode)
{
KisSelectionSP originalSelection = internalSelection();
KisPaintDeviceSP originalDevice = original();
return originalDevice && originalSelection ?
- originalDevice->createThumbnail(w, h, 1,
+ originalDevice->createThumbnail(w, h, aspectRatioMode, 1,
KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags()) :
QImage();
}
diff --git a/libs/image/kis_selection_based_layer.h b/libs/image/kis_selection_based_layer.h
index 80a8eefdef..57604c0e44 100644
--- a/libs/image/kis_selection_based_layer.h
+++ b/libs/image/kis_selection_based_layer.h
@@ -1,211 +1,211 @@
/*
* Copyright (c) 2006 Boudewijn Rempt <boud@valdyas.org>
* (c) 2009 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#ifndef KIS_SELECTION_BASED_LAYER_H_
#define KIS_SELECTION_BASED_LAYER_H_
#include <QObject>
#include "kis_types.h"
#include "kis_layer.h"
#include "kis_indirect_painting_support.h"
#include <kritaimage_export.h>
#include "kis_node_filter_interface.h"
class KisFilterConfiguration;
/**
* @class KisSelectionBasedLayer
* @brief Describes base behaviour for
* selection base classes like KisAdjustmentLayer and KisGeneratorLayer.
* These classes should have a persistent selection that controls
* the area where filter/generators are applied. The area outside
* this selection is not affected by the layer
*/
class KRITAIMAGE_EXPORT KisSelectionBasedLayer : public KisLayer, public KisIndirectPaintingSupport, public KisNodeFilterInterface
{
Q_OBJECT
public:
/**
* creates a new layer with the given selection.
* Note that the selection will be _copied_ (with COW, though).
* @param image the image to set this layer to
* @param name name of the layer
* @param selection is a mask used by the layer to know
* where to apply the filter/generator.
*/
KisSelectionBasedLayer(KisImageWSP image, const QString &name, KisSelectionSP selection, KisFilterConfigurationSP filterConfig);
KisSelectionBasedLayer(const KisSelectionBasedLayer& rhs);
~KisSelectionBasedLayer() override;
/**
* tells whether the @node can be a child of this layer
* @param node to be connected node
* @return tells if to be connected is a child of KisMask
*/
bool allowAsChild(KisNodeSP node) const override;
void setImage(KisImageWSP image) override;
KisPaintDeviceSP original() const override;
KisPaintDeviceSP paintDevice() const override;
bool needProjection() const override;
/**
* resets cached projection of lower layer to a new device
* @return void
*/
virtual void resetCache();
/**
* for KisLayer::setDirty(const KisRegion&)
*/
using KisLayer::setDirty;
/**
* Mark a layer as dirty. We can't use KisLayer's one
* as our extent() function doesn't fit for this
*/
void setDirty() override;
public:
/**
* Returns the selection of the layer
*
* Do not mix it with selection() which returns
* the currently active selection of the image
*/
KisSelectionSP internalSelection() const;
/**
* sets the selection of this layer to a copy of
* selection
* @param selection the selection to set
* @return void
*/
void setInternalSelection(KisSelectionSP selection);
/**
* When painted in indirect painting mode, the internal selection
* might not contain actual selection, because a part of it is
* stored on an indirect painting device. This method returns the
* merged copy of the real selection. The area in \p rect only is
* guaranteed to be prepared. The content of the rest of the
* selection is undefined.
*/
KisSelectionSP fetchComposedInternalSelection(const QRect &rect) const;
/**
* gets this layer's x coordinate, taking selection into account
* @return x-coordinate value
*/
qint32 x() const override;
/**
* gets this layer's y coordinate, taking selection into account
* @return y-coordinate value
*/
qint32 y() const override;
/**
* sets this layer's y coordinate, taking selection into account
* @param x x coordinate
*/
void setX(qint32 x) override;
/**
* sets this layer's y coordinate, taking selection into account
* @param y y coordinate
*/
void setY(qint32 y) override;
public:
/**
* gets an approximation of where the bounds on actual data
* are in this layer, taking selection into account
*/
QRect extent() const override;
/**
* returns the exact bounds of where the actual data resides
* in this layer, taking selection into account
*/
QRect exactBounds() const override;
/**
* copies the image and reformats it to thumbnail size
* and returns the new thumbnail image.
* @param w width of the thumbnail to create
* @param h height of the thumbnail to create
* @return the thumbnail image created.
*/
- QImage createThumbnail(qint32 w, qint32 h) override;
+ QImage createThumbnail(qint32 w, qint32 h, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio) override;
protected:
// override from KisLayer
void copyOriginalToProjection(const KisPaintDeviceSP original,
KisPaintDeviceSP projection,
const QRect& rect) const override;
// override from KisNode
QRect needRect(const QRect &rect, PositionToFilthy pos = N_FILTHY) const override;
protected:
void initSelection();
QRect cropChangeRectBySelection(const QRect &rect) const;
/**
* Sets if the selection should be used in
* copyOriginalToProjection() method.
*
* Default value is 'true'. The descendants should override it to
* get desired behaviour.
*
* Must be called only once in the child's constructor
*/
void setUseSelectionInProjection(bool value) const;
KisKeyframeChannel *requestKeyframeChannel(const QString &id) override;
public Q_SLOTS:
void slotImageSizeChanged();
/**
* gets this layer. Overriddes function in
* KisIndirectPaintingSupport
* @return this AdjustmentLayer
*/
KisLayer* layer() {
return this;
}
private:
struct Private;
Private * const m_d;
};
#endif /* KIS_SELECTION_BASED_LAYER_H_ */
diff --git a/libs/image/kis_simple_update_queue.cpp b/libs/image/kis_simple_update_queue.cpp
index 1e367714a7..7b0c5791c8 100644
--- a/libs/image/kis_simple_update_queue.cpp
+++ b/libs/image/kis_simple_update_queue.cpp
@@ -1,397 +1,402 @@
/*
* Copyright (c) 2010 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_simple_update_queue.h"
#include <QMutexLocker>
#include <QVector>
#include "kis_image_config.h"
#include "kis_full_refresh_walker.h"
#include "kis_spontaneous_job.h"
//#define ENABLE_DEBUG_JOIN
//#define ENABLE_ACCUMULATOR
#ifdef ENABLE_DEBUG_JOIN
#define DEBUG_JOIN(baseRect, newRect, alpha) \
dbgKrita << "Two rects were joined:\t" \
<< (baseRect) << "+" << (newRect) << "->" \
<< ((baseRect) | (newRect)) << "(" << alpha << ")"
#else
#define DEBUG_JOIN(baseRect, newRect, alpha)
#endif /* ENABLE_DEBUG_JOIN */
#ifdef ENABLE_ACCUMULATOR
#define DECLARE_ACCUMULATOR() static qreal _baseAmount=0, _newAmount=0
#define ACCUMULATOR_ADD(baseAmount, newAmount) \
do {_baseAmount += baseAmount; _newAmount += newAmount;} while (0)
#define ACCUMULATOR_DEBUG() \
dbgKrita << "Accumulated alpha:" << _newAmount / _baseAmount
#else
#define DECLARE_ACCUMULATOR()
#define ACCUMULATOR_ADD(baseAmount, newAmount)
#define ACCUMULATOR_DEBUG()
#endif /* ENABLE_ACCUMULATOR */
KisSimpleUpdateQueue::KisSimpleUpdateQueue()
: m_overrideLevelOfDetail(-1)
{
updateSettings();
}
KisSimpleUpdateQueue::~KisSimpleUpdateQueue()
{
QMutexLocker locker(&m_lock);
while (!m_spontaneousJobsList.isEmpty()) {
delete m_spontaneousJobsList.takeLast();
}
}
void KisSimpleUpdateQueue::updateSettings()
{
QMutexLocker locker(&m_lock);
KisImageConfig config(true);
m_patchWidth = config.updatePatchWidth();
m_patchHeight = config.updatePatchHeight();
m_maxCollectAlpha = config.maxCollectAlpha();
m_maxMergeAlpha = config.maxMergeAlpha();
m_maxMergeCollectAlpha = config.maxMergeCollectAlpha();
}
int KisSimpleUpdateQueue::overrideLevelOfDetail() const
{
return m_overrideLevelOfDetail;
}
void KisSimpleUpdateQueue::processQueue(KisUpdaterContext &updaterContext)
{
updaterContext.lock();
while(updaterContext.hasSpareThread() &&
processOneJob(updaterContext));
updaterContext.unlock();
}
bool KisSimpleUpdateQueue::processOneJob(KisUpdaterContext &updaterContext)
{
QMutexLocker locker(&m_lock);
KisBaseRectsWalkerSP item;
KisMutableWalkersListIterator iter(m_updatesList);
bool jobAdded = false;
int currentLevelOfDetail = updaterContext.currentLevelOfDetail();
while(iter.hasNext()) {
item = iter.next();
if ((currentLevelOfDetail < 0 || currentLevelOfDetail == item->levelOfDetail()) &&
!item->checksumValid()) {
m_overrideLevelOfDetail = item->levelOfDetail();
item->recalculate(item->requestedRect());
m_overrideLevelOfDetail = -1;
}
if ((currentLevelOfDetail < 0 || currentLevelOfDetail == item->levelOfDetail()) &&
updaterContext.isJobAllowed(item)) {
updaterContext.addMergeJob(item);
iter.remove();
jobAdded = true;
break;
}
}
if (jobAdded) return true;
if (!m_spontaneousJobsList.isEmpty()) {
/**
* WARNING: Please note that this still doesn't guarantee that
* the spontaneous jobs are exclusive, since updates and/or
* strokes can be added after them. The only thing it
* guarantees that two spontaneous jobs will not be executed
* in parallel.
*
* Right now it works as it is. Probably will need to be fixed
* in the future.
*/
qint32 numMergeJobs;
qint32 numStrokeJobs;
updaterContext.getJobsSnapshot(numMergeJobs, numStrokeJobs);
if (!numMergeJobs && !numStrokeJobs) {
KisSpontaneousJob *job = m_spontaneousJobsList.takeFirst();
updaterContext.addSpontaneousJob(job);
jobAdded = true;
}
}
return jobAdded;
}
void KisSimpleUpdateQueue::addUpdateJob(KisNodeSP node, const QVector<QRect> &rects, const QRect& cropRect, int levelOfDetail)
{
addJob(node, rects, cropRect, levelOfDetail, KisBaseRectsWalker::UPDATE);
}
void KisSimpleUpdateQueue::addUpdateJob(KisNodeSP node, const QRect &rc, const QRect& cropRect, int levelOfDetail)
{
addJob(node, {rc}, cropRect, levelOfDetail, KisBaseRectsWalker::UPDATE);
}
void KisSimpleUpdateQueue::addUpdateNoFilthyJob(KisNodeSP node, const QRect& rc, const QRect& cropRect, int levelOfDetail)
{
addJob(node, {rc}, cropRect, levelOfDetail, KisBaseRectsWalker::UPDATE_NO_FILTHY);
}
-void KisSimpleUpdateQueue::addFullRefreshJob(KisNodeSP node, const QRect& rc, const QRect& cropRect, int levelOfDetail)
+void KisSimpleUpdateQueue::addFullRefreshJob(KisNodeSP node, const QRect &rc, const QRect& cropRect, int levelOfDetail)
{
addJob(node, {rc}, cropRect, levelOfDetail, KisBaseRectsWalker::FULL_REFRESH);
}
+void KisSimpleUpdateQueue::addFullRefreshJob(KisNodeSP node, const QVector<QRect>& rects, const QRect& cropRect, int levelOfDetail)
+{
+ addJob(node, rects, cropRect, levelOfDetail, KisBaseRectsWalker::FULL_REFRESH);
+}
+
void KisSimpleUpdateQueue::addJob(KisNodeSP node, const QVector<QRect> &rects,
const QRect& cropRect,
int levelOfDetail,
KisBaseRectsWalker::UpdateType type)
{
QList<KisBaseRectsWalkerSP> walkers;
Q_FOREACH (const QRect &rc, rects) {
if (rc.isEmpty()) continue;
KisBaseRectsWalkerSP walker;
if(trySplitJob(node, rc, cropRect, levelOfDetail, type)) continue;
if(tryMergeJob(node, rc, cropRect, levelOfDetail, type)) continue;
if (type == KisBaseRectsWalker::UPDATE) {
walker = new KisMergeWalker(cropRect, KisMergeWalker::DEFAULT);
}
else if (type == KisBaseRectsWalker::FULL_REFRESH) {
walker = new KisFullRefreshWalker(cropRect);
}
else if (type == KisBaseRectsWalker::UPDATE_NO_FILTHY) {
walker = new KisMergeWalker(cropRect, KisMergeWalker::NO_FILTHY);
}
/* else if(type == KisBaseRectsWalker::UNSUPPORTED) fatalKrita; */
walker->collectRects(node, rc);
walkers.append(walker);
}
if (!walkers.isEmpty()) {
m_lock.lock();
m_updatesList.append(walkers);
m_lock.unlock();
}
}
void KisSimpleUpdateQueue::addSpontaneousJob(KisSpontaneousJob *spontaneousJob)
{
QMutexLocker locker(&m_lock);
KisSpontaneousJob *item;
KisMutableSpontaneousJobsListIterator iter(m_spontaneousJobsList);
iter.toBack();
while(iter.hasPrevious()) {
item = iter.previous();
if (spontaneousJob->overrides(item)) {
iter.remove();
delete item;
}
}
m_spontaneousJobsList.append(spontaneousJob);
}
bool KisSimpleUpdateQueue::isEmpty() const
{
QMutexLocker locker(&m_lock);
return m_updatesList.isEmpty() && m_spontaneousJobsList.isEmpty();
}
qint32 KisSimpleUpdateQueue::sizeMetric() const
{
QMutexLocker locker(&m_lock);
return m_updatesList.size() + m_spontaneousJobsList.size();
}
bool KisSimpleUpdateQueue::trySplitJob(KisNodeSP node, const QRect& rc,
const QRect& cropRect,
int levelOfDetail,
KisBaseRectsWalker::UpdateType type)
{
if(rc.width() <= m_patchWidth || rc.height() <= m_patchHeight)
return false;
// a bit of recursive splitting...
qint32 firstCol = rc.x() / m_patchWidth;
qint32 firstRow = rc.y() / m_patchHeight;
qint32 lastCol = (rc.x() + rc.width()) / m_patchWidth;
qint32 lastRow = (rc.y() + rc.height()) / m_patchHeight;
QVector<QRect> splitRects;
for(qint32 i = firstRow; i <= lastRow; i++) {
for(qint32 j = firstCol; j <= lastCol; j++) {
QRect maxPatchRect(j * m_patchWidth, i * m_patchHeight,
m_patchWidth, m_patchHeight);
QRect patchRect = rc & maxPatchRect;
splitRects.append(patchRect);
}
}
KIS_SAFE_ASSERT_RECOVER_NOOP(!splitRects.isEmpty());
addJob(node, splitRects, cropRect, levelOfDetail, type);
return true;
}
bool KisSimpleUpdateQueue::tryMergeJob(KisNodeSP node, const QRect& rc,
const QRect& cropRect,
int levelOfDetail,
KisBaseRectsWalker::UpdateType type)
{
QMutexLocker locker(&m_lock);
QRect baseRect = rc;
KisBaseRectsWalkerSP goodCandidate;
KisBaseRectsWalkerSP item;
KisWalkersListIterator iter(m_updatesList);
/**
* We add new jobs to the tail of the list,
* so it's more probable to find a good candidate here.
*/
iter.toBack();
while(iter.hasPrevious()) {
item = iter.previous();
if(item->startNode() != node) continue;
if(item->type() != type) continue;
if(item->cropRect() != cropRect) continue;
if(item->levelOfDetail() != levelOfDetail) continue;
if(joinRects(baseRect, item->requestedRect(), m_maxMergeAlpha)) {
goodCandidate = item;
break;
}
}
if(goodCandidate)
collectJobs(goodCandidate, baseRect, m_maxMergeCollectAlpha);
return (bool)goodCandidate;
}
void KisSimpleUpdateQueue::optimize()
{
QMutexLocker locker(&m_lock);
if(m_updatesList.size() <= 1) return;
KisBaseRectsWalkerSP baseWalker = m_updatesList.first();
QRect baseRect = baseWalker->requestedRect();
collectJobs(baseWalker, baseRect, m_maxCollectAlpha);
}
void KisSimpleUpdateQueue::collectJobs(KisBaseRectsWalkerSP &baseWalker,
QRect baseRect,
const qreal maxAlpha)
{
KisBaseRectsWalkerSP item;
KisMutableWalkersListIterator iter(m_updatesList);
while(iter.hasNext()) {
item = iter.next();
if(item == baseWalker) continue;
if(item->type() != baseWalker->type()) continue;
if(item->startNode() != baseWalker->startNode()) continue;
if(item->cropRect() != baseWalker->cropRect()) continue;
if(item->levelOfDetail() != baseWalker->levelOfDetail()) continue;
if(joinRects(baseRect, item->requestedRect(), maxAlpha)) {
iter.remove();
}
}
if(baseWalker->requestedRect() != baseRect) {
baseWalker->collectRects(baseWalker->startNode(), baseRect);
}
}
bool KisSimpleUpdateQueue::joinRects(QRect& baseRect,
const QRect& newRect, qreal maxAlpha)
{
QRect unitedRect = baseRect | newRect;
if(unitedRect.width() > m_patchWidth || unitedRect.height() > m_patchHeight)
return false;
bool result = false;
qint64 baseWork = baseRect.width() * baseRect.height() +
newRect.width() * newRect.height();
qint64 newWork = unitedRect.width() * unitedRect.height();
qreal alpha = qreal(newWork) / baseWork;
if(alpha < maxAlpha) {
DEBUG_JOIN(baseRect, newRect, alpha);
DECLARE_ACCUMULATOR();
ACCUMULATOR_ADD(baseWork, newWork);
ACCUMULATOR_DEBUG();
baseRect = unitedRect;
result = true;
}
return result;
}
KisWalkersList& KisTestableSimpleUpdateQueue::getWalkersList()
{
return m_updatesList;
}
KisSpontaneousJobsList& KisTestableSimpleUpdateQueue::getSpontaneousJobsList()
{
return m_spontaneousJobsList;
}
diff --git a/libs/image/kis_simple_update_queue.h b/libs/image/kis_simple_update_queue.h
index e51065c53d..10db708f64 100644
--- a/libs/image/kis_simple_update_queue.h
+++ b/libs/image/kis_simple_update_queue.h
@@ -1,116 +1,117 @@
/*
* Copyright (c) 2010 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_SIMPLE_UPDATE_QUEUE_H
#define __KIS_SIMPLE_UPDATE_QUEUE_H
#include <QMutex>
#include "kis_updater_context.h"
typedef QList<KisBaseRectsWalkerSP> KisWalkersList;
typedef QListIterator<KisBaseRectsWalkerSP> KisWalkersListIterator;
typedef QMutableListIterator<KisBaseRectsWalkerSP> KisMutableWalkersListIterator;
typedef QList<KisSpontaneousJob*> KisSpontaneousJobsList;
typedef QListIterator<KisSpontaneousJob*> KisSpontaneousJobsListIterator;
typedef QMutableListIterator<KisSpontaneousJob*> KisMutableSpontaneousJobsListIterator;
class KRITAIMAGE_EXPORT KisSimpleUpdateQueue
{
public:
KisSimpleUpdateQueue();
virtual ~KisSimpleUpdateQueue();
void processQueue(KisUpdaterContext &updaterContext);
void addUpdateJob(KisNodeSP node, const QVector<QRect> &rects, const QRect& cropRect, int levelOfDetail);
void addUpdateJob(KisNodeSP node, const QRect &rc, const QRect& cropRect, int levelOfDetail);
void addUpdateNoFilthyJob(KisNodeSP node, const QRect& rc, const QRect& cropRect, int levelOfDetail);
- void addFullRefreshJob(KisNodeSP node, const QRect& rc, const QRect& cropRect, int levelOfDetail);
+ void addFullRefreshJob(KisNodeSP node, const QRect &rc, const QRect& cropRect, int levelOfDetail);
+ void addFullRefreshJob(KisNodeSP node, const QVector<QRect> &rects, const QRect& cropRect, int levelOfDetail);
void addSpontaneousJob(KisSpontaneousJob *spontaneousJob);
void optimize();
bool isEmpty() const;
qint32 sizeMetric() const;
void updateSettings();
int overrideLevelOfDetail() const;
protected:
void addJob(KisNodeSP node, const QVector<QRect> &rects, const QRect& cropRect, int levelOfDetail, KisBaseRectsWalker::UpdateType type);
bool processOneJob(KisUpdaterContext &updaterContext);
bool trySplitJob(KisNodeSP node, const QRect& rc, const QRect& cropRect, int levelOfDetail, KisBaseRectsWalker::UpdateType type);
bool tryMergeJob(KisNodeSP node, const QRect& rc, const QRect& cropRect, int levelOfDetail, KisBaseRectsWalker::UpdateType type);
void collectJobs(KisBaseRectsWalkerSP &baseWalker, QRect baseRect,
const qreal maxAlpha);
bool joinRects(QRect& baseRect, const QRect& newRect, qreal maxAlpha);
protected:
mutable QMutex m_lock;
KisWalkersList m_updatesList;
KisSpontaneousJobsList m_spontaneousJobsList;
/**
* Parameters of optimization
* (loaded from a configuration file)
*/
/**
* Big update areas are split into a set of smaller
* ones, m_patchWidth and m_patchHeight represent the
* size of these areas.
*/
qint32 m_patchWidth;
qint32 m_patchHeight;
/**
* Maximum coefficient of work while regular optimization()
*/
qreal m_maxCollectAlpha;
/**
* Maximum coefficient of work when to rects are considered
* similar and are merged in tryMergeJob()
*/
qreal m_maxMergeAlpha;
/**
* The coefficient of work used while collecting phase of tryToMerge()
*/
qreal m_maxMergeCollectAlpha;
int m_overrideLevelOfDetail;
};
class KRITAIMAGE_EXPORT KisTestableSimpleUpdateQueue : public KisSimpleUpdateQueue
{
public:
KisWalkersList& getWalkersList();
KisSpontaneousJobsList& getSpontaneousJobsList();
};
#endif /* __KIS_SIMPLE_UPDATE_QUEUE_H */
diff --git a/libs/image/kis_suspend_projection_updates_stroke_strategy.cpp b/libs/image/kis_suspend_projection_updates_stroke_strategy.cpp
index 9013ee4ca1..2af45b0576 100644
--- a/libs/image/kis_suspend_projection_updates_stroke_strategy.cpp
+++ b/libs/image/kis_suspend_projection_updates_stroke_strategy.cpp
@@ -1,569 +1,622 @@
/*
* Copyright (c) 2014 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_suspend_projection_updates_stroke_strategy.h"
#include <kis_image.h>
#include <krita_utils.h>
#include <kis_projection_updates_filter.h>
#include "kis_image_signal_router.h"
#include "kundo2command.h"
#include "KisRunnableStrokeJobDataBase.h"
#include "KisRunnableStrokeJobsInterface.h"
#include "kis_paintop_utils.h"
inline uint qHash(const QRect &rc) {
return rc.x() +
(rc.y() << 16) +
(rc.width() << 8) +
(rc.height() << 24);
}
struct KisSuspendProjectionUpdatesStrokeStrategy::Private
{
KisImageWSP image;
bool suspend;
QVector<QRect> accumulatedDirtyRects;
bool sanityResumingFinished = false;
int updatesEpoch = 0;
bool haveDisabledGUILodSync = false;
SharedDataSP sharedData;
void tryFetchUsedUpdatesFilter(KisImageSP image);
void tryIssueRecordedDirtyRequests(KisImageSP image);
class SuspendLod0Updates : public KisProjectionUpdatesFilter
{
struct Request {
Request() : resetAnimationCache(false) {}
Request(const QRect &_rect, bool _resetAnimationCache)
: rect(_rect), resetAnimationCache(_resetAnimationCache)
{
}
QRect rect;
bool resetAnimationCache;
};
- typedef QHash<KisNodeSP, QVector<Request> > RectsHash;
+ struct FullRefreshRequest {
+ FullRefreshRequest() {}
+ FullRefreshRequest(const QRect &_rect, const QRect &_cropRect)
+ : rect(_rect), cropRect(_cropRect)
+ {
+ }
+
+ QRect rect;
+ QRect cropRect;
+ };
+
+ typedef QHash<KisNodeSP, QVector<Request> > UpdatesHash;
+ typedef QHash<KisNodeSP, QVector<FullRefreshRequest> > RefreshesHash;
public:
SuspendLod0Updates()
{
}
bool filter(KisImage *image, KisNode *node, const QVector<QRect> &rects, bool resetAnimationCache) override {
if (image->currentLevelOfDetail() > 0) return false;
QMutexLocker l(&m_mutex);
Q_FOREACH(const QRect &rc, rects) {
m_requestsHash[KisNodeSP(node)].append(Request(rc, resetAnimationCache));
}
return true;
}
+ bool filterRefreshGraph(KisImage *image, KisNode *node, const QVector<QRect> &rects, const QRect &cropRect) override {
+ if (image->currentLevelOfDetail() > 0) return false;
+
+ QMutexLocker l(&m_mutex);
+
+ Q_FOREACH(const QRect &rc, rects) {
+ m_refreshesHash[KisNodeSP(node)].append(FullRefreshRequest(rc, cropRect));
+ }
+
+ return true;
+ }
+
static inline QRect alignRect(const QRect &rc, const int step) {
static const int decstep = step - 1;
static const int invstep = ~decstep;
int x0, y0, x1, y1;
rc.getCoords(&x0, &y0, &x1, &y1);
x0 &= invstep;
y0 &= invstep;
x1 |= decstep;
y1 |= decstep;
QRect result;
result.setCoords(x0, y0, x1, y1);
return result;
}
- void notifyUpdates(KisNodeGraphListener *listener) {
- RectsHash::const_iterator it = m_requestsHash.constBegin();
- RectsHash::const_iterator end = m_requestsHash.constEnd();
-
+ void notifyUpdates(KisImageSP image) {
const int step = 64;
- for (; it != end; ++it) {
- KisNodeSP node = it.key();
+ {
+ RefreshesHash::const_iterator it = m_refreshesHash.constBegin();
+ RefreshesHash::const_iterator end = m_refreshesHash.constEnd();
+
- QVector<QRect> dirtyRects;
+ for (; it != end; ++it) {
+ KisNodeSP node = it.key();
- bool resetAnimationCache = false;
- Q_FOREACH (const Request &req, it.value()) {
- dirtyRects += alignRect(req.rect, step);
- resetAnimationCache |= req.resetAnimationCache;
+ QHash<QRect, QVector<QRect>> fullRefreshRequests;
+
+ Q_FOREACH (const FullRefreshRequest &req, it.value()) {
+ fullRefreshRequests[req.cropRect] += req.rect;
+ }
+
+ auto reqIt = fullRefreshRequests.begin();
+ for (; reqIt != fullRefreshRequests.end(); ++reqIt) {
+ const QVector<QRect> simplifiedRects = KisRegion::fromOverlappingRects(reqIt.value(), step).rects();
+
+ // FIXME: constness: port rPU to SP
+ image->refreshGraphAsync(const_cast<KisNode*>(node.data()), simplifiedRects, reqIt.key());
+ }
}
+ }
- // FIXME: constness: port rPU to SP
- listener->requestProjectionUpdate(const_cast<KisNode*>(node.data()), KisRegion(dirtyRects).rects(), resetAnimationCache);
+ {
+ UpdatesHash::const_iterator it = m_requestsHash.constBegin();
+ UpdatesHash::const_iterator end = m_requestsHash.constEnd();
+
+ for (; it != end; ++it) {
+ KisNodeSP node = it.key();
+
+ QVector<QRect> dirtyRects;
+
+ bool resetAnimationCache = false;
+ Q_FOREACH (const Request &req, it.value()) {
+ dirtyRects += req.rect;
+ resetAnimationCache |= req.resetAnimationCache;
+ }
+
+ const QVector<QRect> simplifiedRects = KisRegion::fromOverlappingRects(dirtyRects, step).rects();
+
+ // FIXME: constness: port rPU to SP
+ image->requestProjectionUpdate(const_cast<KisNode*>(node.data()), simplifiedRects, resetAnimationCache);
+ }
}
}
private:
- RectsHash m_requestsHash;
+ UpdatesHash m_requestsHash;
+ RefreshesHash m_refreshesHash;
QMutex m_mutex;
};
QVector<QSharedPointer<SuspendLod0Updates>> usedFilters;
struct StrokeJobCommand : public KUndo2Command
{
StrokeJobCommand(KisStrokeJobData::Sequentiality sequentiality = KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::Exclusivity exclusivity = KisStrokeJobData::NORMAL)
: m_sequentiality(sequentiality),
m_exclusivity(exclusivity)
{}
KisStrokeJobData::Sequentiality m_sequentiality;
KisStrokeJobData::Exclusivity m_exclusivity;
};
struct UndoableData : public KisRunnableStrokeJobDataBase
{
UndoableData(StrokeJobCommand *command)
: KisRunnableStrokeJobDataBase(command->m_sequentiality, command->m_exclusivity),
m_command(command)
{
}
void run() override {
KIS_SAFE_ASSERT_RECOVER_RETURN(m_command);
m_command->redo();
}
QScopedPointer<StrokeJobCommand> m_command;
};
// Suspend job should be a barrier to ensure all
// previous lodN strokes reach the GUI. Otherwise,
// they will be blocked in
// KisImage::notifyProjectionUpdated()
struct SuspendUpdatesCommand : public StrokeJobCommand
{
SuspendUpdatesCommand(Private *d)
: StrokeJobCommand(KisStrokeJobData::BARRIER),
m_d(d) {}
void redo() override {
KisImageSP image = m_d->image.toStrongRef();
KIS_SAFE_ASSERT_RECOVER_RETURN(image);
KIS_SAFE_ASSERT_RECOVER_RETURN(!image->currentProjectionUpdatesFilter());
KIS_SAFE_ASSERT_RECOVER_RETURN(!m_d->sharedData->installedFilterCookie);
m_d->sharedData->installedFilterCookie = image->addProjectionUpdatesFilter(
toQShared(new Private::SuspendLod0Updates()));
}
void undo() override {
KisImageSP image = m_d->image.toStrongRef();
KIS_SAFE_ASSERT_RECOVER_RETURN(image);
KIS_SAFE_ASSERT_RECOVER_RETURN(image->currentProjectionUpdatesFilter());
KIS_SAFE_ASSERT_RECOVER_RETURN(image->currentProjectionUpdatesFilter() == m_d->sharedData->installedFilterCookie);
m_d->tryFetchUsedUpdatesFilter(image);
}
Private *m_d;
};
struct ResumeAndIssueGraphUpdatesCommand : public StrokeJobCommand
{
ResumeAndIssueGraphUpdatesCommand(Private *d)
: StrokeJobCommand(KisStrokeJobData::BARRIER),
m_d(d) {}
void redo() override {
KisImageSP image = m_d->image.toStrongRef();
KIS_SAFE_ASSERT_RECOVER_RETURN(image);
KIS_SAFE_ASSERT_RECOVER_RETURN(image->currentProjectionUpdatesFilter());
KIS_SAFE_ASSERT_RECOVER_RETURN(image->currentProjectionUpdatesFilter() == m_d->sharedData->installedFilterCookie);
image->disableUIUpdates();
m_d->tryFetchUsedUpdatesFilter(image);
m_d->tryIssueRecordedDirtyRequests(image);
}
void undo() override {
KisImageSP image = m_d->image.toStrongRef();
KIS_SAFE_ASSERT_RECOVER_RETURN(image);
KIS_SAFE_ASSERT_RECOVER_RETURN(!image->currentProjectionUpdatesFilter());
KIS_SAFE_ASSERT_RECOVER_RETURN(!m_d->sharedData->installedFilterCookie);
m_d->sharedData->installedFilterCookie = image->addProjectionUpdatesFilter(
toQShared(new Private::SuspendLod0Updates()));
image->enableUIUpdates();
}
Private *m_d;
};
struct UploadDataToUIData : public KisRunnableStrokeJobDataBase
{
UploadDataToUIData(const QRect &rc, int updateEpoch, KisSuspendProjectionUpdatesStrokeStrategy *strategy)
: KisRunnableStrokeJobDataBase(KisStrokeJobData::CONCURRENT),
m_strategy(strategy),
m_rc(rc),
m_updateEpoch(updateEpoch)
{
}
void run() override {
// check if we've already started stinking...
if (m_strategy->m_d->updatesEpoch > m_updateEpoch) {
return;
}
KisImageSP image = m_strategy->m_d->image.toStrongRef();
KIS_SAFE_ASSERT_RECOVER_RETURN(image);
image->notifyProjectionUpdated(m_rc);
}
KisSuspendProjectionUpdatesStrokeStrategy *m_strategy;
QRect m_rc;
int m_updateEpoch;
};
struct BlockUILodSync : public KisRunnableStrokeJobDataBase
{
BlockUILodSync(bool block, KisSuspendProjectionUpdatesStrokeStrategy *strategy)
: KisRunnableStrokeJobDataBase(KisStrokeJobData::BARRIER),
m_strategy(strategy),
m_block(block)
{}
void run() override {
KisImageSP image = m_strategy->m_d->image.toStrongRef();
KIS_SAFE_ASSERT_RECOVER_RETURN(image);
image->signalRouter()->emitRequestLodPlanesSyncBlocked(m_block);
m_strategy->m_d->haveDisabledGUILodSync = m_block;
}
KisSuspendProjectionUpdatesStrokeStrategy *m_strategy;
bool m_block;
};
struct StartBatchUIUpdatesCommand : public StrokeJobCommand
{
StartBatchUIUpdatesCommand(KisSuspendProjectionUpdatesStrokeStrategy *strategy)
: StrokeJobCommand(KisStrokeJobData::BARRIER),
m_strategy(strategy) {}
void redo() override {
KisImageSP image = m_strategy->m_d->image.toStrongRef();
KIS_SAFE_ASSERT_RECOVER_RETURN(image);
/**
* We accumulate dirty rects from all(!) epochs, because some updates of the
* previous epochs might have been cancelled without doing any real work.
*/
const QVector<QRect> totalDirtyRects =
image->enableUIUpdates() + m_strategy->m_d->accumulatedDirtyRects;
const QRect totalRect =
image->bounds() &
std::accumulate(totalDirtyRects.begin(), totalDirtyRects.end(), QRect(), std::bit_or<QRect>());
m_strategy->m_d->accumulatedDirtyRects =
KisPaintOpUtils::splitAndFilterDabRect(totalRect,
totalDirtyRects,
KritaUtils::optimalPatchSize().width());
image->signalRouter()->emitNotifyBatchUpdateStarted();
QVector<KisRunnableStrokeJobDataBase*> jobsData;
Q_FOREACH (const QRect &rc, m_strategy->m_d->accumulatedDirtyRects) {
jobsData << new Private::UploadDataToUIData(rc, m_strategy->m_d->updatesEpoch, m_strategy);
}
m_strategy->runnableJobsInterface()->addRunnableJobs(jobsData);
}
void undo() override {
KisImageSP image = m_strategy->m_d->image.toStrongRef();
KIS_SAFE_ASSERT_RECOVER_RETURN(image);
image->signalRouter()->emitNotifyBatchUpdateEnded();
image->disableUIUpdates();
}
KisSuspendProjectionUpdatesStrokeStrategy *m_strategy;
};
struct EndBatchUIUpdatesCommand : public StrokeJobCommand
{
EndBatchUIUpdatesCommand(KisSuspendProjectionUpdatesStrokeStrategy *strategy)
: StrokeJobCommand(KisStrokeJobData::BARRIER),
m_strategy(strategy) {}
void redo() override {
KisImageSP image = m_strategy->m_d->image.toStrongRef();
KIS_SAFE_ASSERT_RECOVER_RETURN(image);
image->signalRouter()->emitNotifyBatchUpdateEnded();
m_strategy->m_d->sanityResumingFinished = true;
m_strategy->m_d->accumulatedDirtyRects.clear();
KIS_SAFE_ASSERT_RECOVER_NOOP(m_strategy->m_d->usedFilters.isEmpty());
}
void undo() override {
/**
* Even though this comand is the last command of the stroke is can
* still be undone by suspendStrokeCallback(). It happens when a LodN
* stroke is started right after the last job of resume strategy was
* being executed. In such a case new stroke is placed right in front
* of our resume strategy and all the resuming work is undone (mimicing
* a normal suspend strategy).
*
* The only thing we should control here is whether the state of the
* stroke is reset to default. Otherwise we'll do all the updates twice.
*/
KIS_SAFE_ASSERT_RECOVER_NOOP(m_strategy->m_d->usedFilters.isEmpty());
KIS_SAFE_ASSERT_RECOVER_NOOP(m_strategy->m_d->accumulatedDirtyRects.isEmpty());
m_strategy->m_d->sanityResumingFinished = false;
KisImageSP image = m_strategy->m_d->image.toStrongRef();
KIS_SAFE_ASSERT_RECOVER_RETURN(image);
image->signalRouter()->emitNotifyBatchUpdateStarted();
}
KisSuspendProjectionUpdatesStrokeStrategy *m_strategy;
};
QVector<StrokeJobCommand*> executedCommands;
};
KisSuspendProjectionUpdatesStrokeStrategy::KisSuspendProjectionUpdatesStrokeStrategy(KisImageWSP image, bool suspend, SharedDataSP sharedData)
: KisRunnableBasedStrokeStrategy(suspend ?
QLatin1String("suspend_stroke_strategy") :
QLatin1String("resume_stroke_strategy")),
m_d(new Private)
{
m_d->image = image;
m_d->suspend = suspend;
m_d->sharedData = sharedData;
/**
* Here we add a dumb INIT job so that KisStrokesQueue would know that the
* stroke has already started or not. When the queue reaches the resume
* stroke and starts its execution, no Lod0 can execute anymore. So all the
* new Lod0 strokes should go to the end of the queue and wrapped into
* their own Suspend/Resume pair.
*/
enableJob(JOB_INIT, true);
enableJob(JOB_DOSTROKE, true);
enableJob(JOB_CANCEL, true);
enableJob(JOB_SUSPEND, true, KisStrokeJobData::BARRIER);
enableJob(JOB_RESUME, true, KisStrokeJobData::BARRIER);
setNeedsExplicitCancel(true);
}
KisSuspendProjectionUpdatesStrokeStrategy::~KisSuspendProjectionUpdatesStrokeStrategy()
{
qDeleteAll(m_d->executedCommands);
}
void KisSuspendProjectionUpdatesStrokeStrategy::initStrokeCallback()
{
QVector<KisRunnableStrokeJobDataBase*> jobs;
if (m_d->suspend) {
jobs << new Private::UndoableData(new Private::SuspendUpdatesCommand(m_d.data()));
} else {
jobs << new Private::UndoableData(new Private::ResumeAndIssueGraphUpdatesCommand(m_d.data()));
jobs << new Private::BlockUILodSync(true, this);
jobs << new Private::UndoableData(new Private::StartBatchUIUpdatesCommand(this));
jobs << new Private::UndoableData(new Private::EndBatchUIUpdatesCommand(this));
jobs << new Private::BlockUILodSync(false, this);
}
runnableJobsInterface()->addRunnableJobs(jobs);
}
/**
* When the Lod0 stroke is being recalculated in the background we
* should block all the updates it issues to avoid user distraction.
* The result of the final stroke should be shown to the user in the
* very end when everything is fully ready. Ideally the use should not
* notice that the image has changed :)
*
* (Don't mix this process with suspend/resume capabilities of a
* single stroke. That is a different system!)
*
* The process of the Lod0 regeneration consists of the following:
*
* 1) Suspend stroke executes. It sets a special updates filter on the
* image. The filter blocks all the updates and saves them in an
* internal structure to be emitted in the future.
*
* 2) Lod0 strokes are being recalculated. All their updates are
* blocked and saved in the filter.
*
* 3) Resume stroke starts:
*
* 3.1) First it disables emitting of sigImageUpdated() so the gui
* will not get any update notifications.
*
* 3.2) Then it enables updates themselves.
*
* 3.3) Initiates all the updates that were requested by the Lod0
* stroke. The node graph is regenerated, but the GUI does
* not get this change.
*
* 3.4) Special barrier job waits for all the updates to finish
* and, when they are done, enables GUI notifications again.
*
* 3.5) In a multithreaded way emits the GUI notifications for the
* entire image. Multithreaded way is used to conform the
* double-stage update principle of KisCanvas2.
*/
void KisSuspendProjectionUpdatesStrokeStrategy::doStrokeCallback(KisStrokeJobData *data)
{
KisRunnableStrokeJobDataBase *runnable = dynamic_cast<KisRunnableStrokeJobDataBase*>(data);
if (runnable) {
runnable->run();
if (Private::UndoableData *undoable = dynamic_cast<Private::UndoableData*>(data)) {
Private::StrokeJobCommand *command = undoable->m_command.take();
m_d->executedCommands.append(command);
}
}
}
QList<KisStrokeJobData*> KisSuspendProjectionUpdatesStrokeStrategy::createSuspendJobsData(KisImageWSP /*image*/)
{
return QList<KisStrokeJobData*>();
}
QList<KisStrokeJobData*> KisSuspendProjectionUpdatesStrokeStrategy::createResumeJobsData(KisImageWSP /*_image*/)
{
return QList<KisStrokeJobData*>();
}
KisSuspendProjectionUpdatesStrokeStrategy::SharedDataSP KisSuspendProjectionUpdatesStrokeStrategy::createSharedData()
{
return toQShared(new SharedData());
}
void KisSuspendProjectionUpdatesStrokeStrategy::Private::tryFetchUsedUpdatesFilter(KisImageSP image)
{
if (!this->sharedData->installedFilterCookie) return;
KisProjectionUpdatesFilterSP filter = image->removeProjectionUpdatesFilter(image->currentProjectionUpdatesFilter());
this->sharedData->installedFilterCookie = KisProjectionUpdatesFilterCookie();
KIS_SAFE_ASSERT_RECOVER_RETURN(filter);
QSharedPointer<Private::SuspendLod0Updates> localFilter =
filter.dynamicCast<Private::SuspendLod0Updates>();
KIS_SAFE_ASSERT_RECOVER_RETURN(localFilter);
this->usedFilters.append(localFilter);
}
void KisSuspendProjectionUpdatesStrokeStrategy::Private::tryIssueRecordedDirtyRequests(KisImageSP image)
{
Q_FOREACH (QSharedPointer<Private::SuspendLod0Updates> filter, usedFilters) {
filter->notifyUpdates(image.data());
}
usedFilters.clear();
}
void KisSuspendProjectionUpdatesStrokeStrategy::cancelStrokeCallback()
{
KisImageSP image = m_d->image.toStrongRef();
if (!image) {
return;
}
for (auto it = m_d->executedCommands.rbegin(); it != m_d->executedCommands.rend(); ++it) {
(*it)->undo();
}
m_d->tryFetchUsedUpdatesFilter(image);
if (m_d->haveDisabledGUILodSync) {
image->signalRouter()->emitRequestLodPlanesSyncBlocked(false);
}
/**
* We shouldn't emit any ad-hoc updates when cancelling the
* stroke. It generates weird temporary holes on the canvas,
* making the user feel awful, thinking his image got
* corrupted. We will just emit a common refreshGraphAsync() that
* will do all the work in a beautiful way
*/
if (!m_d->suspend) {
// FIXME: optimize
image->refreshGraphAsync();
}
}
void KisSuspendProjectionUpdatesStrokeStrategy::suspendStrokeCallback()
{
/**
* The resume stroke can be suspended even when all its jobs are completed.
* In such a case, we should just ensure that all the internal state is reset
* to default.
*/
KIS_SAFE_ASSERT_RECOVER_NOOP(m_d->suspend ||
!m_d->sanityResumingFinished ||
(m_d->sanityResumingFinished &&
m_d->usedFilters.isEmpty() &&
m_d->accumulatedDirtyRects.isEmpty()));
for (auto it = m_d->executedCommands.rbegin(); it != m_d->executedCommands.rend(); ++it) {
(*it)->undo();
}
// reset all the issued updates
m_d->updatesEpoch++;
}
void KisSuspendProjectionUpdatesStrokeStrategy::resumeStrokeCallback()
{
QVector<KisRunnableStrokeJobDataBase*> jobs;
Q_FOREACH (Private::StrokeJobCommand *command, m_d->executedCommands) {
jobs << new Private::UndoableData(command);
}
m_d->executedCommands.clear();
runnableJobsInterface()->addRunnableJobs(jobs);
}
diff --git a/libs/image/kis_transaction_data.cpp b/libs/image/kis_transaction_data.cpp
index d40648f44e..0e0db683df 100644
--- a/libs/image/kis_transaction_data.cpp
+++ b/libs/image/kis_transaction_data.cpp
@@ -1,324 +1,343 @@
/*
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
*
* 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_transaction_data.h"
#include "kis_pixel_selection.h"
#include "kis_paint_device.h"
#include "kis_paint_device_frames_interface.h"
#include "kis_datamanager.h"
#include "kis_image.h"
#include "KoColor.h"
//#define DEBUG_TRANSACTIONS
#ifdef DEBUG_TRANSACTIONS
# define DEBUG_ACTION(action) dbgKrita << action << "for" << m_d->device->dataManager()
#else
# define DEBUG_ACTION(action)
#endif
class Q_DECL_HIDDEN KisTransactionData::Private
{
public:
KisPaintDeviceSP device;
KisMementoSP memento;
bool firstRedo;
bool transactionFinished;
QPoint oldOffset;
QPoint newOffset;
KoColor oldDefaultPixel;
bool defaultPixelChanged = false;
bool savedOutlineCacheValid;
QPainterPath savedOutlineCache;
- KUndo2Command *flattenUndoCommand;
+ QScopedPointer<KUndo2Command> flattenUndoCommand;
bool resetSelectionOutlineCache;
int transactionTime;
int transactionFrameId;
KisDataManagerSP savedDataManager;
KUndo2Command newFrameCommand;
void possiblySwitchCurrentTime();
KisDataManagerSP dataManager();
void moveDevice(const QPoint newOffset);
void tryCreateNewFrame(KisPaintDeviceSP device, int time);
};
KisTransactionData::KisTransactionData(const KUndo2MagicString& name, KisPaintDeviceSP device, bool resetSelectionOutlineCache, KUndo2Command* parent)
: KUndo2Command(name, parent)
, m_d(new Private())
{
m_d->resetSelectionOutlineCache = resetSelectionOutlineCache;
setTimedID(-1);
+
+ possiblyFlattenSelection(device);
init(device);
saveSelectionOutlineCache();
}
#include "kis_raster_keyframe_channel.h"
#include "kis_image_config.h"
void KisTransactionData::Private::tryCreateNewFrame(KisPaintDeviceSP device, int time)
{
if (!device->framesInterface()) return;
KisImageConfig cfg(true);
if (!cfg.lazyFrameCreationEnabled()) return;
KisRasterKeyframeChannel *channel = device->keyframeChannel();
KIS_ASSERT_RECOVER(channel) { return; }
KisKeyframeSP keyframe = channel->keyframeAt(time);
if (!keyframe) {
keyframe = channel->activeKeyframeAt(time);
KisKeyframeSP newKeyframe = channel->copyKeyframe(keyframe, time, &newFrameCommand);
newKeyframe->setColorLabel(KisImageConfig(true).defaultFrameColorLabel());
}
}
void KisTransactionData::init(KisPaintDeviceSP device)
{
m_d->device = device;
DEBUG_ACTION("Transaction started");
m_d->oldOffset = QPoint(device->x(), device->y());
m_d->oldDefaultPixel = device->defaultPixel();
m_d->firstRedo = true;
m_d->transactionFinished = false;
- m_d->flattenUndoCommand = 0;
m_d->transactionTime = device->defaultBounds()->currentTime();
m_d->tryCreateNewFrame(m_d->device, m_d->transactionTime);
m_d->transactionFrameId = device->framesInterface() ? device->framesInterface()->currentFrameId() : -1;
m_d->savedDataManager = m_d->transactionFrameId >= 0 ?
m_d->device->framesInterface()->frameDataManager(m_d->transactionFrameId) :
m_d->device->dataManager();
m_d->memento = m_d->savedDataManager->getMemento();
}
KisTransactionData::~KisTransactionData()
{
Q_ASSERT(m_d->memento);
m_d->savedDataManager->purgeHistory(m_d->memento);
delete m_d;
}
void KisTransactionData::Private::moveDevice(const QPoint newOffset)
{
if (transactionFrameId >= 0) {
device->framesInterface()->setFrameOffset(transactionFrameId, newOffset);
} else {
device->moveTo(newOffset);
}
}
void KisTransactionData::endTransaction()
{
if(!m_d->transactionFinished) {
// make sure the time didn't change during the transaction
KIS_ASSERT_RECOVER_RETURN(
m_d->transactionTime == m_d->device->defaultBounds()->currentTime());
DEBUG_ACTION("Transaction ended");
m_d->transactionFinished = true;
m_d->savedDataManager->commit();
m_d->newOffset = QPoint(m_d->device->x(), m_d->device->y());
m_d->defaultPixelChanged = m_d->oldDefaultPixel != m_d->device->defaultPixel();
}
}
void KisTransactionData::startUpdates()
{
if (m_d->transactionFrameId == -1 ||
m_d->transactionFrameId ==
m_d->device->framesInterface()->currentFrameId()) {
QRect rc;
QRect mementoExtent = m_d->memento->extent();
if (m_d->newOffset == m_d->oldOffset) {
rc = mementoExtent.translated(m_d->device->x(), m_d->device->y());
} else {
QRect totalExtent =
m_d->savedDataManager->extent() | mementoExtent;
rc = totalExtent.translated(m_d->oldOffset) |
totalExtent.translated(m_d->newOffset);
}
if (m_d->defaultPixelChanged) {
rc |= m_d->device->defaultBounds()->bounds();
}
m_d->device->setDirty(rc);
} else {
m_d->device->framesInterface()->invalidateFrameCache(m_d->transactionFrameId);
}
}
void KisTransactionData::possiblyNotifySelectionChanged()
{
KisPixelSelectionSP pixelSelection =
dynamic_cast<KisPixelSelection*>(m_d->device.data());
KisSelectionSP selection;
if (pixelSelection && (selection = pixelSelection->parentSelection())) {
selection->notifySelectionChanged();
}
}
void KisTransactionData::possiblyResetOutlineCache()
{
KisPixelSelectionSP pixelSelection;
if (m_d->resetSelectionOutlineCache &&
(pixelSelection =
dynamic_cast<KisPixelSelection*>(m_d->device.data()))) {
pixelSelection->invalidateOutlineCache();
}
}
+void KisTransactionData::possiblyFlattenSelection(KisPaintDeviceSP device)
+{
+ KisPixelSelectionSP pixelSelection =
+ dynamic_cast<KisPixelSelection*>(device.data());
+
+ if (pixelSelection) {
+ KisSelection *selection = pixelSelection->parentSelection().data();
+ if (selection) {
+ m_d->flattenUndoCommand.reset(selection->flatten());
+
+ if (m_d->flattenUndoCommand) {
+ m_d->flattenUndoCommand->redo();
+ }
+ }
+ }
+}
+
+void KisTransactionData::doFlattenUndoRedo(bool undo)
+{
+ KisPixelSelectionSP pixelSelection =
+ dynamic_cast<KisPixelSelection*>(m_d->device.data());
+
+ if (pixelSelection) {
+ if (m_d->flattenUndoCommand) {
+ if (undo) {
+ m_d->flattenUndoCommand->undo();
+ } else {
+ m_d->flattenUndoCommand->redo();
+ }
+ }
+ }
+}
+
void KisTransactionData::Private::possiblySwitchCurrentTime()
{
if (device->defaultBounds()->currentTime() == transactionTime) return;
qWarning() << "WARNING: undo command has been executed, when another frame has been active. That shouldn't have happened.";
device->requestTimeSwitch(transactionTime);
}
void KisTransactionData::redo()
{
//KUndo2QStack calls redo(), so the first call needs to be blocked
if (m_d->firstRedo) {
m_d->firstRedo = false;
possiblyResetOutlineCache();
possiblyNotifySelectionChanged();
return;
}
-
+ doFlattenUndoRedo(false);
restoreSelectionOutlineCache(false);
m_d->newFrameCommand.redo();
DEBUG_ACTION("Redo()");
Q_ASSERT(m_d->memento);
m_d->savedDataManager->rollforward(m_d->memento);
if (m_d->newOffset != m_d->oldOffset) {
m_d->moveDevice(m_d->newOffset);
}
m_d->possiblySwitchCurrentTime();
startUpdates();
possiblyNotifySelectionChanged();
}
void KisTransactionData::undo()
{
DEBUG_ACTION("Undo()");
Q_ASSERT(m_d->memento);
m_d->savedDataManager->rollback(m_d->memento);
if (m_d->newOffset != m_d->oldOffset) {
m_d->moveDevice(m_d->oldOffset);
}
restoreSelectionOutlineCache(true);
+ doFlattenUndoRedo(true);
m_d->possiblySwitchCurrentTime();
startUpdates();
possiblyNotifySelectionChanged();
m_d->newFrameCommand.undo();
}
void KisTransactionData::saveSelectionOutlineCache()
{
m_d->savedOutlineCacheValid = false;
KisPixelSelectionSP pixelSelection =
dynamic_cast<KisPixelSelection*>(m_d->device.data());
if (pixelSelection) {
m_d->savedOutlineCacheValid = pixelSelection->outlineCacheValid();
if (m_d->savedOutlineCacheValid) {
m_d->savedOutlineCache = pixelSelection->outlineCache();
possiblyResetOutlineCache();
}
-
- KisSelectionSP selection = pixelSelection->parentSelection();
- if (selection) {
- m_d->flattenUndoCommand = selection->flatten();
- if (m_d->flattenUndoCommand) {
- m_d->flattenUndoCommand->redo();
- }
- }
}
}
void KisTransactionData::restoreSelectionOutlineCache(bool undo)
{
KisPixelSelectionSP pixelSelection =
dynamic_cast<KisPixelSelection*>(m_d->device.data());
if (pixelSelection) {
bool savedOutlineCacheValid;
QPainterPath savedOutlineCache;
savedOutlineCacheValid = pixelSelection->outlineCacheValid();
if (savedOutlineCacheValid) {
savedOutlineCache = pixelSelection->outlineCache();
}
if (m_d->savedOutlineCacheValid) {
pixelSelection->setOutlineCache(m_d->savedOutlineCache);
} else {
pixelSelection->invalidateOutlineCache();
}
m_d->savedOutlineCacheValid = savedOutlineCacheValid;
if (m_d->savedOutlineCacheValid) {
m_d->savedOutlineCache = savedOutlineCache;
}
-
- if (m_d->flattenUndoCommand) {
- if (undo) {
- m_d->flattenUndoCommand->undo();
- } else {
- m_d->flattenUndoCommand->redo();
- }
- }
}
}
diff --git a/libs/image/kis_transaction_data.h b/libs/image/kis_transaction_data.h
index 74a82b6861..9af33ec17b 100644
--- a/libs/image/kis_transaction_data.h
+++ b/libs/image/kis_transaction_data.h
@@ -1,64 +1,66 @@
/*
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
*
* 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_TRANSACTION_DATA_H_
#define KIS_TRANSACTION_DATA_H_
#include <kundo2command.h>
#include "kis_types.h"
#include <kritaimage_export.h>
/**
* A tile based undo command.
*
* Ordinary KUndo2Command subclasses store parameters and apply the action in
* the redo() command, however, Krita doesn't work like this. Undo replaces
* the current tiles in a paint device with the old tiles, redo replaces them
* again with the new tiles without actually executing the command that changed
* the image data again.
*/
class KRITAIMAGE_EXPORT KisTransactionData : public KUndo2Command
{
public:
KisTransactionData(const KUndo2MagicString& name, KisPaintDeviceSP device, bool resetSelectionOutlineCache, KUndo2Command* parent);
~KisTransactionData() override;
public:
void redo() override;
void undo() override;
virtual void endTransaction();
protected:
virtual void saveSelectionOutlineCache();
virtual void restoreSelectionOutlineCache(bool undo);
private:
void init(KisPaintDeviceSP device);
void startUpdates();
void possiblyNotifySelectionChanged();
void possiblyResetOutlineCache();
+ void possiblyFlattenSelection(KisPaintDeviceSP device);
+ void doFlattenUndoRedo(bool undo);
private:
class Private;
Private * const m_d;
};
#endif /* KIS_TRANSACTION_DATA_H_ */
diff --git a/libs/image/kis_update_scheduler.cpp b/libs/image/kis_update_scheduler.cpp
index 4f90fc0010..a592a20f49 100644
--- a/libs/image/kis_update_scheduler.cpp
+++ b/libs/image/kis_update_scheduler.cpp
@@ -1,492 +1,492 @@
/*
* Copyright (c) 2010 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_update_scheduler.h"
#include "klocalizedstring.h"
#include "kis_image_config.h"
#include "kis_merge_walker.h"
#include "kis_full_refresh_walker.h"
#include "kis_updater_context.h"
#include "kis_simple_update_queue.h"
#include "kis_strokes_queue.h"
#include "kis_queues_progress_updater.h"
#include "KisImageConfigNotifier.h"
#include <QReadWriteLock>
#include "kis_lazy_wait_condition.h"
#include <mutex>
//#define DEBUG_BALANCING
#ifdef DEBUG_BALANCING
#define DEBUG_BALANCING_METRICS(decidedFirst, excl) \
dbgKrita << "Balance decision:" << decidedFirst \
<< "(" << excl << ")" \
<< "updates:" << m_d->updatesQueue.sizeMetric() \
<< "strokes:" << m_d->strokesQueue.sizeMetric()
#else
#define DEBUG_BALANCING_METRICS(decidedFirst, excl)
#endif
struct Q_DECL_HIDDEN KisUpdateScheduler::Private {
Private(KisUpdateScheduler *_q, KisProjectionUpdateListener *p)
: q(_q)
, updaterContext(KisImageConfig(true).maxNumberOfThreads(), q)
, projectionUpdateListener(p)
{}
KisUpdateScheduler *q;
KisSimpleUpdateQueue updatesQueue;
KisStrokesQueue strokesQueue;
KisUpdaterContext updaterContext;
bool processingBlocked = false;
qreal defaultBalancingRatio = 1.0; // desired strokes-queue-size / updates-queue-size
KisProjectionUpdateListener *projectionUpdateListener;
KisQueuesProgressUpdater *progressUpdater = 0;
QAtomicInt updatesLockCounter;
QReadWriteLock updatesStartLock;
KisLazyWaitCondition updatesFinishedCondition;
qreal balancingRatio() const {
const qreal strokeRatioOverride = strokesQueue.balancingRatioOverride();
return strokeRatioOverride > 0 ? strokeRatioOverride : defaultBalancingRatio;
}
};
KisUpdateScheduler::KisUpdateScheduler(KisProjectionUpdateListener *projectionUpdateListener, QObject *parent)
: QObject(parent),
m_d(new Private(this, projectionUpdateListener))
{
updateSettings();
connectSignals();
}
KisUpdateScheduler::KisUpdateScheduler()
: m_d(new Private(this, 0))
{
}
KisUpdateScheduler::~KisUpdateScheduler()
{
delete m_d->progressUpdater;
delete m_d;
}
void KisUpdateScheduler::setThreadsLimit(int value)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(!m_d->processingBlocked);
/**
* Thread limit can be changed without the full-featured barrier
* lock, we can avoid waiting for all the jobs to complete. We
* should just ensure there is no more jobs in the updater context.
*/
lock();
m_d->updaterContext.lock();
m_d->updaterContext.setThreadsLimit(value);
m_d->updaterContext.unlock();
unlock(false);
}
int KisUpdateScheduler::threadsLimit() const
{
std::lock_guard<KisUpdaterContext> l(m_d->updaterContext);
return m_d->updaterContext.threadsLimit();
}
void KisUpdateScheduler::connectSignals()
{
connect(KisImageConfigNotifier::instance(), SIGNAL(configChanged()),
SLOT(updateSettings()));
}
void KisUpdateScheduler::setProgressProxy(KoProgressProxy *progressProxy)
{
delete m_d->progressUpdater;
m_d->progressUpdater = progressProxy ?
new KisQueuesProgressUpdater(progressProxy, this) : 0;
}
void KisUpdateScheduler::progressUpdate()
{
if (!m_d->progressUpdater) return;
if(!m_d->strokesQueue.hasOpenedStrokes()) {
QString jobName = m_d->strokesQueue.currentStrokeName().toString();
if(jobName.isEmpty()) {
jobName = i18n("Updating...");
}
int sizeMetric = m_d->strokesQueue.sizeMetric();
if (!sizeMetric) {
sizeMetric = m_d->updatesQueue.sizeMetric();
}
m_d->progressUpdater->updateProgress(sizeMetric, jobName);
}
else {
m_d->progressUpdater->hide();
}
}
void KisUpdateScheduler::updateProjection(KisNodeSP node, const QVector<QRect> &rects, const QRect &cropRect)
{
m_d->updatesQueue.addUpdateJob(node, rects, cropRect, currentLevelOfDetail());
processQueues();
}
void KisUpdateScheduler::updateProjection(KisNodeSP node, const QRect &rc, const QRect &cropRect)
{
m_d->updatesQueue.addUpdateJob(node, rc, cropRect, currentLevelOfDetail());
processQueues();
}
void KisUpdateScheduler::updateProjectionNoFilthy(KisNodeSP node, const QRect& rc, const QRect &cropRect)
{
m_d->updatesQueue.addUpdateNoFilthyJob(node, rc, cropRect, currentLevelOfDetail());
processQueues();
}
-void KisUpdateScheduler::fullRefreshAsync(KisNodeSP root, const QRect& rc, const QRect &cropRect)
+void KisUpdateScheduler::fullRefreshAsync(KisNodeSP root, const QVector<QRect>& rects, const QRect &cropRect)
{
- m_d->updatesQueue.addFullRefreshJob(root, rc, cropRect, currentLevelOfDetail());
+ m_d->updatesQueue.addFullRefreshJob(root, rects, cropRect, currentLevelOfDetail());
processQueues();
}
void KisUpdateScheduler::fullRefresh(KisNodeSP root, const QRect& rc, const QRect &cropRect)
{
KisBaseRectsWalkerSP walker = new KisFullRefreshWalker(cropRect);
walker->collectRects(root, rc);
bool needLock = true;
if(m_d->processingBlocked) {
warnImage << "WARNING: Calling synchronous fullRefresh under a scheduler lock held";
warnImage << "We will not assert for now, but please port caller's to strokes";
warnImage << "to avoid this warning";
needLock = false;
}
if(needLock) lock();
m_d->updaterContext.lock();
Q_ASSERT(m_d->updaterContext.isJobAllowed(walker));
m_d->updaterContext.addMergeJob(walker);
m_d->updaterContext.waitForDone();
m_d->updaterContext.unlock();
if(needLock) unlock(true);
}
void KisUpdateScheduler::addSpontaneousJob(KisSpontaneousJob *spontaneousJob)
{
m_d->updatesQueue.addSpontaneousJob(spontaneousJob);
processQueues();
}
bool KisUpdateScheduler::hasUpdatesRunning() const
{
return !m_d->updatesQueue.isEmpty();
}
KisStrokeId KisUpdateScheduler::startStroke(KisStrokeStrategy *strokeStrategy)
{
KisStrokeId id = m_d->strokesQueue.startStroke(strokeStrategy);
processQueues();
return id;
}
void KisUpdateScheduler::addJob(KisStrokeId id, KisStrokeJobData *data)
{
m_d->strokesQueue.addJob(id, data);
processQueues();
}
void KisUpdateScheduler::endStroke(KisStrokeId id)
{
m_d->strokesQueue.endStroke(id);
processQueues();
}
bool KisUpdateScheduler::cancelStroke(KisStrokeId id)
{
bool result = m_d->strokesQueue.cancelStroke(id);
processQueues();
return result;
}
bool KisUpdateScheduler::tryCancelCurrentStrokeAsync()
{
return m_d->strokesQueue.tryCancelCurrentStrokeAsync();
}
UndoResult KisUpdateScheduler::tryUndoLastStrokeAsync()
{
return m_d->strokesQueue.tryUndoLastStrokeAsync();
}
bool KisUpdateScheduler::wrapAroundModeSupported() const
{
return m_d->strokesQueue.wrapAroundModeSupported();
}
void KisUpdateScheduler::setDesiredLevelOfDetail(int lod)
{
m_d->strokesQueue.setDesiredLevelOfDetail(lod);
/**
* The queue might have started an internal stroke for
* cache synchronization. Process the queues to execute
* it if needed.
*/
processQueues();
}
void KisUpdateScheduler::explicitRegenerateLevelOfDetail()
{
m_d->strokesQueue.explicitRegenerateLevelOfDetail();
// \see a comment in setDesiredLevelOfDetail()
processQueues();
}
int KisUpdateScheduler::currentLevelOfDetail() const
{
int levelOfDetail = m_d->updaterContext.currentLevelOfDetail();
if (levelOfDetail < 0) {
levelOfDetail = m_d->updatesQueue.overrideLevelOfDetail();
}
if (levelOfDetail < 0) {
levelOfDetail = 0;
}
return levelOfDetail;
}
void KisUpdateScheduler::setLod0ToNStrokeStrategyFactory(const KisLodSyncStrokeStrategyFactory &factory)
{
m_d->strokesQueue.setLod0ToNStrokeStrategyFactory(factory);
}
void KisUpdateScheduler::setSuspendResumeUpdatesStrokeStrategyFactory(const KisSuspendResumeStrategyPairFactory &factory)
{
m_d->strokesQueue.setSuspendResumeUpdatesStrokeStrategyFactory(factory);
}
KisPostExecutionUndoAdapter *KisUpdateScheduler::lodNPostExecutionUndoAdapter() const
{
return m_d->strokesQueue.lodNPostExecutionUndoAdapter();
}
void KisUpdateScheduler::updateSettings()
{
m_d->updatesQueue.updateSettings();
KisImageConfig config(true);
m_d->defaultBalancingRatio = config.schedulerBalancingRatio();
setThreadsLimit(config.maxNumberOfThreads());
}
void KisUpdateScheduler::lock()
{
m_d->processingBlocked = true;
m_d->updaterContext.waitForDone();
}
void KisUpdateScheduler::unlock(bool resetLodLevels)
{
if (resetLodLevels) {
/**
* Legacy strokes may have changed the image while we didn't
* control it. Notify the queue to take it into account.
*/
m_d->strokesQueue.notifyUFOChangedImage();
}
m_d->processingBlocked = false;
processQueues();
}
bool KisUpdateScheduler::isIdle()
{
bool result = false;
if (tryBarrierLock()) {
result = true;
unlock(false);
}
return result;
}
void KisUpdateScheduler::waitForDone()
{
do {
processQueues();
m_d->updaterContext.waitForDone();
} while(!m_d->updatesQueue.isEmpty() || !m_d->strokesQueue.isEmpty());
}
bool KisUpdateScheduler::tryBarrierLock()
{
if(!m_d->updatesQueue.isEmpty() || !m_d->strokesQueue.isEmpty()) {
return false;
}
m_d->processingBlocked = true;
m_d->updaterContext.waitForDone();
if(!m_d->updatesQueue.isEmpty() || !m_d->strokesQueue.isEmpty()) {
m_d->processingBlocked = false;
processQueues();
return false;
}
return true;
}
void KisUpdateScheduler::barrierLock()
{
do {
m_d->processingBlocked = false;
processQueues();
m_d->processingBlocked = true;
m_d->updaterContext.waitForDone();
} while(!m_d->updatesQueue.isEmpty() || !m_d->strokesQueue.isEmpty());
}
void KisUpdateScheduler::processQueues()
{
wakeUpWaitingThreads();
if(m_d->processingBlocked) return;
if(m_d->strokesQueue.needsExclusiveAccess()) {
DEBUG_BALANCING_METRICS("STROKES", "X");
m_d->strokesQueue.processQueue(m_d->updaterContext,
!m_d->updatesQueue.isEmpty());
if(!m_d->strokesQueue.needsExclusiveAccess()) {
tryProcessUpdatesQueue();
}
}
else if(m_d->balancingRatio() * m_d->strokesQueue.sizeMetric() > m_d->updatesQueue.sizeMetric()) {
DEBUG_BALANCING_METRICS("STROKES", "N");
m_d->strokesQueue.processQueue(m_d->updaterContext,
!m_d->updatesQueue.isEmpty());
tryProcessUpdatesQueue();
}
else {
DEBUG_BALANCING_METRICS("UPDATES", "N");
tryProcessUpdatesQueue();
m_d->strokesQueue.processQueue(m_d->updaterContext,
!m_d->updatesQueue.isEmpty());
}
progressUpdate();
}
void KisUpdateScheduler::blockUpdates()
{
m_d->updatesFinishedCondition.initWaiting();
m_d->updatesLockCounter.ref();
while(haveUpdatesRunning()) {
m_d->updatesFinishedCondition.wait();
}
m_d->updatesFinishedCondition.endWaiting();
}
void KisUpdateScheduler::unblockUpdates()
{
m_d->updatesLockCounter.deref();
processQueues();
}
void KisUpdateScheduler::wakeUpWaitingThreads()
{
if(m_d->updatesLockCounter && !haveUpdatesRunning()) {
m_d->updatesFinishedCondition.wakeAll();
}
}
void KisUpdateScheduler::tryProcessUpdatesQueue()
{
QReadLocker locker(&m_d->updatesStartLock);
if(m_d->updatesLockCounter) return;
m_d->updatesQueue.processQueue(m_d->updaterContext);
}
bool KisUpdateScheduler::haveUpdatesRunning()
{
QWriteLocker locker(&m_d->updatesStartLock);
qint32 numMergeJobs, numStrokeJobs;
m_d->updaterContext.getJobsSnapshot(numMergeJobs, numStrokeJobs);
return numMergeJobs;
}
void KisUpdateScheduler::continueUpdate(const QRect &rect)
{
Q_ASSERT(m_d->projectionUpdateListener);
m_d->projectionUpdateListener->notifyProjectionUpdated(rect);
}
void KisUpdateScheduler::doSomeUsefulWork()
{
m_d->updatesQueue.optimize();
}
void KisUpdateScheduler::spareThreadAppeared()
{
processQueues();
}
KisTestableUpdateScheduler::KisTestableUpdateScheduler(KisProjectionUpdateListener *projectionUpdateListener,
qint32 threadCount)
{
Q_UNUSED(threadCount);
updateSettings();
m_d->projectionUpdateListener = projectionUpdateListener;
// The queue will update settings in a constructor itself
// m_d->updatesQueue = new KisTestableSimpleUpdateQueue();
// m_d->strokesQueue = new KisStrokesQueue();
connectSignals();
}
KisUpdaterContext *KisTestableUpdateScheduler::updaterContext()
{
return &m_d->updaterContext;
}
KisTestableSimpleUpdateQueue* KisTestableUpdateScheduler::updateQueue()
{
return dynamic_cast<KisTestableSimpleUpdateQueue*>(&m_d->updatesQueue);
}
diff --git a/libs/image/kis_update_scheduler.h b/libs/image/kis_update_scheduler.h
index 36a1e416e4..820401a1b8 100644
--- a/libs/image/kis_update_scheduler.h
+++ b/libs/image/kis_update_scheduler.h
@@ -1,249 +1,249 @@
/*
* Copyright (c) 2010 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_UPDATE_SCHEDULER_H
#define __KIS_UPDATE_SCHEDULER_H
#include <QObject>
#include "kritaimage_export.h"
#include "kis_types.h"
#include "kis_image_interfaces.h"
#include "kis_stroke_strategy_factory.h"
#include "kis_strokes_queue_undo_result.h"
class QRect;
class KoProgressProxy;
class KisProjectionUpdateListener;
class KisSpontaneousJob;
class KisPostExecutionUndoAdapter;
class KRITAIMAGE_EXPORT KisUpdateScheduler : public QObject, public KisStrokesFacade
{
Q_OBJECT
public:
KisUpdateScheduler(KisProjectionUpdateListener *projectionUpdateListener, QObject *parent = 0);
~KisUpdateScheduler() override;
/**
* Set the number of threads used by the scheduler
*/
void setThreadsLimit(int value);
/**
* Return the number of threads available to the scheduler
*/
int threadsLimit() const;
/**
* Sets the proxy that is going to be notified about the progress
* of processing of the queues. If you want to switch the proxy
* on runtime, you should do it under the lock held.
*
* \see lock(), unlock()
*/
void setProgressProxy(KoProgressProxy *progressProxy);
/**
* Blocks processing of the queues.
* The function will wait until all the executing jobs
* are finished.
* NOTE: you may add new jobs while the block held, but they
* will be delayed until unlock() is called.
*
* \see unlock()
*/
void lock();
/**
* Unblocks the process and calls processQueues()
*
* \see processQueues()
*/
void unlock(bool resetLodLevels = true);
/**
* Waits until all the running jobs are finished.
*
* If some other thread adds jobs in parallel, then you may
* wait forever. If you you don't want it, consider lock() instead.
*
* \see lock()
*/
void waitForDone();
/**
* Waits until the queues become empty, then blocks the processing.
* To unblock processing you should use unlock().
*
* If some other thread adds jobs in parallel, then you may
* wait forever. If you you don't want it, consider lock() instead.
*
* \see unlock(), lock()
*/
void barrierLock();
/**
* Works like barrier lock, but returns false immediately if barrierLock
* can't be acquired.
*
* \see barrierLock()
*/
bool tryBarrierLock();
/**
* Tells if there are no strokes or updates are running at the
* moment. Internally calls to tryBarrierLock(), so it is not O(1).
*/
bool isIdle();
/**
* Blocks all the updates from execution. It doesn't affect
* strokes execution in any way. This type of lock is supposed
* to be held by the strokes themselves when they need a short
* access to some parts of the projection of the image.
*
* From all the other places you should use usual lock()/unlock()
* methods
*
* \see lock(), unlock()
*/
void blockUpdates();
/**
* Unblocks updates from execution previously locked by blockUpdates()
*
* \see blockUpdates()
*/
void unblockUpdates();
void updateProjection(KisNodeSP node, const QVector<QRect> &rects, const QRect &cropRect);
void updateProjection(KisNodeSP node, const QRect &rc, const QRect &cropRect);
void updateProjectionNoFilthy(KisNodeSP node, const QRect& rc, const QRect &cropRect);
- void fullRefreshAsync(KisNodeSP root, const QRect& rc, const QRect &cropRect);
+ void fullRefreshAsync(KisNodeSP root, const QVector<QRect>& rc, const QRect &cropRect);
void fullRefresh(KisNodeSP root, const QRect& rc, const QRect &cropRect);
void addSpontaneousJob(KisSpontaneousJob *spontaneousJob);
bool hasUpdatesRunning() const;
KisStrokeId startStroke(KisStrokeStrategy *strokeStrategy) override;
void addJob(KisStrokeId id, KisStrokeJobData *data) override;
void endStroke(KisStrokeId id) override;
bool cancelStroke(KisStrokeId id) override;
/**
* Sets the desired level of detail on which the strokes should
* work. Please note that this configuration will be applied
* starting from the next stroke. Please also note that this value
* is not guaranteed to coincide with the one returned by
* currentLevelOfDetail()
*/
void setDesiredLevelOfDetail(int lod);
/**
* Explicitly start regeneration of LoD planes of all the devices
* in the image. This call should be performed when the user is idle,
* just to make the quality of image updates better.
*/
void explicitRegenerateLevelOfDetail();
/**
* Install a factory of a stroke strategy, that will be started
* every time when the scheduler needs to synchronize LOD caches
* of all the paint devices of the image.
*/
void setLod0ToNStrokeStrategyFactory(const KisLodSyncStrokeStrategyFactory &factory);
/**
* Install a factory of a stroke strategies, that will be started
* every time when the scheduler needs to postpone/resume all the updates
* of the *LOD0* strokes.
*/
void setSuspendResumeUpdatesStrokeStrategyFactory(const KisSuspendResumeStrategyPairFactory &factory);
KisPostExecutionUndoAdapter* lodNPostExecutionUndoAdapter() const;
/**
* tryCancelCurrentStrokeAsync() checks whether there is a
* *running* stroke (which is being executed at this very moment)
* which is not still open by the owner (endStroke() or
* cancelStroke() have already been called) and cancels it.
*
* \return true if some stroke has been found and cancelled
*
* \note This method is *not* part of KisStrokesFacade! It is too
* low level for KisImage. In KisImage it is combined with
* more high level requestStrokeCancellation().
*/
bool tryCancelCurrentStrokeAsync();
UndoResult tryUndoLastStrokeAsync();
bool wrapAroundModeSupported() const;
int currentLevelOfDetail() const;
void continueUpdate(const QRect &rect);
void doSomeUsefulWork();
void spareThreadAppeared();
protected:
// Trivial constructor for testing support
KisUpdateScheduler();
void connectSignals();
void processQueues();
protected Q_SLOTS:
/**
* Called when it is necessary to reread configuration
*/
void updateSettings();
private:
friend class UpdatesBlockTester;
bool haveUpdatesRunning();
void tryProcessUpdatesQueue();
void wakeUpWaitingThreads();
void progressUpdate();
protected:
struct Private;
Private * const m_d;
};
class KisTestableSimpleUpdateQueue;
class KisUpdaterContext;
class KRITAIMAGE_EXPORT KisTestableUpdateScheduler : public KisUpdateScheduler
{
public:
KisTestableUpdateScheduler(KisProjectionUpdateListener *projectionUpdateListener,
qint32 threadCount);
KisUpdaterContext* updaterContext();
KisTestableSimpleUpdateQueue* updateQueue();
using KisUpdateScheduler::processQueues;
};
#endif /* __KIS_UPDATE_SCHEDULER_H */
diff --git a/libs/image/lazybrush/kis_colorize_mask.cpp b/libs/image/lazybrush/kis_colorize_mask.cpp
index 698a26479c..16731c941e 100644
--- a/libs/image/lazybrush/kis_colorize_mask.cpp
+++ b/libs/image/lazybrush/kis_colorize_mask.cpp
@@ -1,1173 +1,1173 @@
/*
* Copyright (c) 2016 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_colorize_mask.h"
#include <QCoreApplication>
#include <QStack>
#include <KoColorSpaceRegistry.h>
#include "kis_pixel_selection.h"
#include "kis_icon_utils.h"
#include "kis_node_visitor.h"
#include "kis_processing_visitor.h"
#include "kis_painter.h"
#include "kis_fill_painter.h"
#include "kis_lazy_fill_tools.h"
#include "kis_cached_paint_device.h"
#include "kis_paint_device_debug_utils.h"
#include "kis_layer_properties_icons.h"
#include "kis_thread_safe_signal_compressor.h"
#include "kis_colorize_stroke_strategy.h"
#include "kis_multiway_cut.h"
#include "kis_image.h"
#include "kis_layer.h"
#include "kis_macro_based_undo_store.h"
#include "kis_post_execution_undo_adapter.h"
#include "kis_command_utils.h"
#include "kis_processing_applicator.h"
#include "krita_utils.h"
using namespace KisLazyFillTools;
struct KisColorizeMask::Private
{
Private(KisColorizeMask *_q)
: q(_q),
coloringProjection(new KisPaintDevice(KoColorSpaceRegistry::instance()->rgb8())),
fakePaintDevice(new KisPaintDevice(KoColorSpaceRegistry::instance()->rgb8())),
filteredSource(new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8())),
needAddCurrentKeyStroke(false),
showKeyStrokes(true),
showColoring(true),
needsUpdate(true),
originalSequenceNumber(-1),
updateCompressor(1000, KisSignalCompressor::FIRST_ACTIVE_POSTPONE_NEXT),
dirtyParentUpdateCompressor(200, KisSignalCompressor::FIRST_ACTIVE_POSTPONE_NEXT),
prefilterRecalculationCompressor(1000, KisSignalCompressor::POSTPONE),
updateIsRunning(false),
filteringOptions(false, 4.0, 15, 0.7),
limitToDeviceBounds(false)
{
}
Private(const Private &rhs, KisColorizeMask *_q)
: q(_q),
coloringProjection(new KisPaintDevice(*rhs.coloringProjection)),
fakePaintDevice(new KisPaintDevice(*rhs.fakePaintDevice)),
filteredSource(new KisPaintDevice(*rhs.filteredSource)),
filteredDeviceBounds(rhs.filteredDeviceBounds),
needAddCurrentKeyStroke(rhs.needAddCurrentKeyStroke),
showKeyStrokes(rhs.showKeyStrokes),
showColoring(rhs.showColoring),
needsUpdate(false),
originalSequenceNumber(-1),
updateCompressor(1000, KisSignalCompressor::FIRST_ACTIVE_POSTPONE_NEXT),
dirtyParentUpdateCompressor(200, KisSignalCompressor::FIRST_ACTIVE_POSTPONE_NEXT),
prefilterRecalculationCompressor(1000, KisSignalCompressor::POSTPONE),
offset(rhs.offset),
updateIsRunning(false),
filteringOptions(rhs.filteringOptions),
limitToDeviceBounds(rhs.limitToDeviceBounds)
{
Q_FOREACH (const KeyStroke &stroke, rhs.keyStrokes) {
keyStrokes << KeyStroke(KisPaintDeviceSP(new KisPaintDevice(*stroke.dev)), stroke.color, stroke.isTransparent);
}
}
KisColorizeMask *q = 0;
QList<KeyStroke> keyStrokes;
KisPaintDeviceSP coloringProjection;
KisPaintDeviceSP fakePaintDevice;
KisPaintDeviceSP filteredSource;
QRect filteredDeviceBounds;
KoColor currentColor;
KisPaintDeviceSP currentKeyStrokeDevice;
bool needAddCurrentKeyStroke;
bool showKeyStrokes;
bool showColoring;
KisCachedSelection cachedSelection;
bool needsUpdate;
int originalSequenceNumber;
KisThreadSafeSignalCompressor updateCompressor;
KisThreadSafeSignalCompressor dirtyParentUpdateCompressor;
KisThreadSafeSignalCompressor prefilterRecalculationCompressor;
QPoint offset;
bool updateIsRunning;
QStack<QRect> extentBeforeUpdateStart;
FilteringOptions filteringOptions;
bool filteringDirty = true;
bool limitToDeviceBounds = false;
bool filteredSourceValid(KisPaintDeviceSP parentDevice) {
return !filteringDirty && originalSequenceNumber == parentDevice->sequenceNumber();
}
void setNeedsUpdateImpl(bool value, bool requestedByUser);
bool shouldShowFilteredSource() const;
bool shouldShowColoring() const;
};
KisColorizeMask::KisColorizeMask(const QString name)
: KisEffectMask(name)
, m_d(new Private(this))
{
connect(&m_d->updateCompressor,
SIGNAL(timeout()),
SLOT(slotUpdateRegenerateFilling()));
connect(this, SIGNAL(sigUpdateOnDirtyParent()),
&m_d->dirtyParentUpdateCompressor, SLOT(start()));
connect(&m_d->dirtyParentUpdateCompressor,
SIGNAL(timeout()),
SLOT(slotUpdateOnDirtyParent()));
connect(&m_d->prefilterRecalculationCompressor,
SIGNAL(timeout()),
SLOT(slotRecalculatePrefilteredImage()));
m_d->updateCompressor.moveToThread(qApp->thread());
}
KisColorizeMask::~KisColorizeMask()
{
}
KisColorizeMask::KisColorizeMask(const KisColorizeMask& rhs)
: KisEffectMask(rhs),
m_d(new Private(*rhs.m_d, this))
{
connect(&m_d->updateCompressor,
SIGNAL(timeout()),
SLOT(slotUpdateRegenerateFilling()));
connect(this, SIGNAL(sigUpdateOnDirtyParent()),
&m_d->dirtyParentUpdateCompressor, SLOT(start()));
connect(&m_d->dirtyParentUpdateCompressor,
SIGNAL(timeout()),
SLOT(slotUpdateOnDirtyParent()));
m_d->updateCompressor.moveToThread(qApp->thread());
}
void KisColorizeMask::initializeCompositeOp()
{
KisLayerSP parentLayer(qobject_cast<KisLayer*>(parent().data()));
if (!parentLayer || !parentLayer->original()) return;
KisImageSP image = parentLayer->image();
if (!image) return;
const qreal samplePortion = 0.1;
const qreal alphaPortion =
KritaUtils::estimatePortionOfTransparentPixels(parentLayer->original(),
image->bounds(),
samplePortion);
setCompositeOpId(alphaPortion > 0.3 ? COMPOSITE_BEHIND : COMPOSITE_MULT);
}
const KoColorSpace* KisColorizeMask::colorSpace() const
{
return m_d->fakePaintDevice->colorSpace();
}
struct SetKeyStrokesColorSpaceCommand : public KUndo2Command {
SetKeyStrokesColorSpaceCommand(const KoColorSpace *dstCS,
KoColorConversionTransformation::Intent renderingIntent,
KoColorConversionTransformation::ConversionFlags conversionFlags,
QList<KeyStroke> *list,
KisColorizeMaskSP node)
: m_dstCS(dstCS),
m_renderingIntent(renderingIntent),
m_conversionFlags(conversionFlags),
m_list(list),
m_node(node) {}
void undo() override {
KIS_ASSERT_RECOVER_RETURN(m_list->size() == m_oldColors.size());
for (int i = 0; i < m_list->size(); i++) {
(*m_list)[i].color = m_oldColors[i];
}
m_node->setNeedsUpdate(true);
emit m_node->sigKeyStrokesListChanged();
}
void redo() override {
if (m_oldColors.isEmpty()) {
Q_FOREACH(const KeyStroke &stroke, *m_list) {
m_oldColors << stroke.color;
m_newColors << stroke.color;
m_newColors.last().convertTo(m_dstCS, m_renderingIntent, m_conversionFlags);
}
}
KIS_ASSERT_RECOVER_RETURN(m_list->size() == m_newColors.size());
for (int i = 0; i < m_list->size(); i++) {
(*m_list)[i].color = m_newColors[i];
}
m_node->setNeedsUpdate(true);
emit m_node->sigKeyStrokesListChanged();
}
private:
QVector<KoColor> m_oldColors;
QVector<KoColor> m_newColors;
const KoColorSpace *m_dstCS;
KoColorConversionTransformation::Intent m_renderingIntent;
KoColorConversionTransformation::ConversionFlags m_conversionFlags;
QList<KeyStroke> *m_list;
KisColorizeMaskSP m_node;
};
void KisColorizeMask::setProfile(const KoColorProfile *profile, KUndo2Command *parentCommand)
{
m_d->fakePaintDevice->setProfile(profile, parentCommand);
m_d->coloringProjection->setProfile(profile, parentCommand);
for (auto stroke : m_d->keyStrokes) {
stroke.color.setProfile(profile);
}
}
KUndo2Command* KisColorizeMask::setColorSpace(const KoColorSpace * dstColorSpace,
KoColorConversionTransformation::Intent renderingIntent,
KoColorConversionTransformation::ConversionFlags conversionFlags)
{
using namespace KisCommandUtils;
CompositeCommand *composite = new CompositeCommand();
m_d->fakePaintDevice->convertTo(dstColorSpace, renderingIntent, conversionFlags, composite);
m_d->coloringProjection->convertTo(dstColorSpace, renderingIntent, conversionFlags, composite);
KUndo2Command *strokesConversionCommand =
new SetKeyStrokesColorSpaceCommand(
dstColorSpace, renderingIntent, conversionFlags,
&m_d->keyStrokes, KisColorizeMaskSP(this));
strokesConversionCommand->redo();
composite->addCommand(new SkipFirstRedoWrapper(strokesConversionCommand));
return composite;
}
bool KisColorizeMask::needsUpdate() const
{
return m_d->needsUpdate;
}
void KisColorizeMask::setNeedsUpdate(bool value)
{
m_d->setNeedsUpdateImpl(value, true);
}
void KisColorizeMask::Private::setNeedsUpdateImpl(bool value, bool requestedByUser)
{
if (value != needsUpdate) {
needsUpdate = value;
q->baseNodeChangedCallback();
if (!value && requestedByUser) {
updateCompressor.start();
}
}
}
void KisColorizeMask::slotUpdateRegenerateFilling(bool prefilterOnly)
{
KisPaintDeviceSP src = parent()->original();
KIS_ASSERT_RECOVER_RETURN(src);
const bool filteredSourceValid = m_d->filteredSourceValid(src);
m_d->originalSequenceNumber = src->sequenceNumber();
m_d->filteringDirty = false;
if (!prefilterOnly) {
m_d->coloringProjection->clear();
}
KisLayerSP parentLayer(qobject_cast<KisLayer*>(parent().data()));
if (!parentLayer) return;
KisImageSP image = parentLayer->image();
if (image) {
m_d->updateIsRunning = true;
QRect fillBounds;
if (m_d->limitToDeviceBounds) {
fillBounds |= src->exactBounds();
Q_FOREACH (const KeyStroke &stroke, m_d->keyStrokes) {
fillBounds |= stroke.dev->exactBounds();
}
fillBounds &= image->bounds();
} else {
fillBounds = image->bounds();
}
m_d->filteredDeviceBounds = fillBounds;
KisColorizeStrokeStrategy *strategy =
new KisColorizeStrokeStrategy(src,
m_d->coloringProjection,
m_d->filteredSource,
filteredSourceValid,
fillBounds,
this,
prefilterOnly);
strategy->setFilteringOptions(m_d->filteringOptions);
Q_FOREACH (const KeyStroke &stroke, m_d->keyStrokes) {
const KoColor color =
!stroke.isTransparent ?
stroke.color :
KoColor(Qt::transparent, stroke.color.colorSpace());
strategy->addKeyStroke(stroke.dev, color);
}
m_d->extentBeforeUpdateStart.push(extent());
connect(strategy, SIGNAL(sigFinished(bool)), SLOT(slotRegenerationFinished(bool)));
connect(strategy, SIGNAL(sigCancelled()), SLOT(slotRegenerationCancelled()));
KisStrokeId id = image->startStroke(strategy);
image->endStroke(id);
}
}
void KisColorizeMask::slotUpdateOnDirtyParent()
{
if (!parent()) {
// When the colorize mask is being merged,
// the update is performed for all the layers,
// so the invisible areas around the canvas are included in the merged layer.
// Colorize Mask gets the info that its parent is "dirty" (needs updating),
- // but when it arrives, the parent doesn't exists anymore and is set to null.
+ // but when it arrives, the parent doesn't exist anymore and is set to null.
// Colorize Mask doesn't work outside of the canvas anyway (at least in time of writing).
return;
}
KisPaintDeviceSP src = parent()->original();
KIS_ASSERT_RECOVER_RETURN(src);
if (!m_d->filteredSourceValid(src)) {
const QRect &oldExtent = extent();
m_d->setNeedsUpdateImpl(true, false);
m_d->filteringDirty = true;
setDirty(oldExtent | extent());
}
}
void KisColorizeMask::slotRecalculatePrefilteredImage()
{
slotUpdateRegenerateFilling(true);
}
void KisColorizeMask::slotRegenerationFinished(bool prefilterOnly)
{
m_d->updateIsRunning = false;
if (!prefilterOnly) {
m_d->setNeedsUpdateImpl(false, false);
}
QRect oldExtent;
if (!m_d->extentBeforeUpdateStart.isEmpty()) {
oldExtent = m_d->extentBeforeUpdateStart.pop();
} else {
KIS_SAFE_ASSERT_RECOVER_NOOP(!m_d->extentBeforeUpdateStart.isEmpty()); // always fail!
}
setDirty(oldExtent | extent());
}
void KisColorizeMask::slotRegenerationCancelled()
{
slotRegenerationFinished(true);
}
KisBaseNode::PropertyList KisColorizeMask::sectionModelProperties() const
{
KisBaseNode::PropertyList l = KisMask::sectionModelProperties();
l << KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::colorizeNeedsUpdate, needsUpdate());
l << KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::colorizeEditKeyStrokes, showKeyStrokes());
l << KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::colorizeShowColoring, showColoring());
return l;
}
void KisColorizeMask::setSectionModelProperties(const KisBaseNode::PropertyList &properties)
{
KisMask::setSectionModelProperties(properties);
Q_FOREACH (const KisBaseNode::Property &property, properties) {
if (property.id == KisLayerPropertiesIcons::colorizeNeedsUpdate.id()) {
if (m_d->needsUpdate && m_d->needsUpdate != property.state.toBool()) {
setNeedsUpdate(property.state.toBool());
}
}
if (property.id == KisLayerPropertiesIcons::colorizeEditKeyStrokes.id()) {
if (m_d->showKeyStrokes != property.state.toBool()) {
setShowKeyStrokes(property.state.toBool());
}
}
if (property.id == KisLayerPropertiesIcons::colorizeShowColoring.id()) {
if (m_d->showColoring != property.state.toBool()) {
setShowColoring(property.state.toBool());
}
}
}
}
KisPaintDeviceSP KisColorizeMask::paintDevice() const
{
return m_d->showKeyStrokes && !m_d->updateIsRunning ? m_d->fakePaintDevice : KisPaintDeviceSP();
}
KisPaintDeviceSP KisColorizeMask::coloringProjection() const
{
return m_d->coloringProjection;
}
KisPaintDeviceSP KisColorizeMask::colorPickSourceDevice() const
{
return
m_d->shouldShowColoring() && !m_d->coloringProjection->extent().isEmpty() ?
m_d->coloringProjection : projection();
}
QIcon KisColorizeMask::icon() const
{
return KisIconUtils::loadIcon("colorizeMask");
}
bool KisColorizeMask::accept(KisNodeVisitor &v)
{
return v.visit(this);
}
void KisColorizeMask::accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter)
{
return visitor.visit(this, undoAdapter);
}
bool KisColorizeMask::Private::shouldShowFilteredSource() const
{
return !updateIsRunning &&
showKeyStrokes &&
!filteringDirty &&
filteredSource &&
!filteredSource->extent().isEmpty();
}
bool KisColorizeMask::Private::shouldShowColoring() const
{
return !updateIsRunning &&
showColoring &&
coloringProjection;
}
QRect KisColorizeMask::decorateRect(KisPaintDeviceSP &src,
KisPaintDeviceSP &dst,
const QRect &rect,
PositionToFilthy maskPos) const
{
Q_UNUSED(maskPos);
if (maskPos == N_ABOVE_FILTHY) {
// the source layer has changed, we should update the filtered cache!
if (!m_d->filteringDirty) {
emit sigUpdateOnDirtyParent();
}
}
KIS_ASSERT(dst != src);
// Draw the filling and the original layer
{
KisPainter gc(dst);
if (m_d->shouldShowFilteredSource()) {
const QRect drawRect = m_d->limitToDeviceBounds ? rect & m_d->filteredDeviceBounds : rect;
gc.setOpacity(128);
gc.bitBlt(drawRect.topLeft(), m_d->filteredSource, drawRect);
} else {
gc.setOpacity(255);
gc.bitBlt(rect.topLeft(), src, rect);
}
if (m_d->shouldShowColoring()) {
gc.setOpacity(opacity());
gc.setCompositeOp(compositeOpId());
gc.bitBlt(rect.topLeft(), m_d->coloringProjection, rect);
}
}
// Draw the key strokes
if (m_d->showKeyStrokes) {
KisIndirectPaintingSupport::ReadLocker locker(this);
KisCachedSelection::Guard s1(m_d->cachedSelection);
KisCachedSelection::Guard s2(m_d->cachedSelection);
KisSelectionSP selection = s1.selection();
KisPixelSelectionSP tempSelection = s2.selection()->pixelSelection();
KisPaintDeviceSP temporaryTarget = this->temporaryTarget();
const bool isTemporaryTargetErasing = temporaryCompositeOp() == COMPOSITE_ERASE;
const QRect temporaryExtent = temporaryTarget ? temporaryTarget->extent() : QRect();
KisFillPainter gc(dst);
QList<KeyStroke> extendedStrokes = m_d->keyStrokes;
if (m_d->currentKeyStrokeDevice &&
m_d->needAddCurrentKeyStroke &&
!isTemporaryTargetErasing) {
extendedStrokes << KeyStroke(m_d->currentKeyStrokeDevice, m_d->currentColor);
}
Q_FOREACH (const KeyStroke &stroke, extendedStrokes) {
selection->pixelSelection()->makeCloneFromRough(stroke.dev, rect);
gc.setSelection(selection);
if (stroke.color == m_d->currentColor ||
(isTemporaryTargetErasing &&
temporaryExtent.intersects(selection->pixelSelection()->selectedRect()))) {
if (temporaryTarget) {
tempSelection->copyAlphaFrom(temporaryTarget, rect);
KisPainter selectionPainter(selection->pixelSelection());
setupTemporaryPainter(&selectionPainter);
selectionPainter.bitBlt(rect.topLeft(), tempSelection, rect);
}
}
gc.fillSelection(rect, stroke.color);
}
}
return rect;
}
struct DeviceExtentPolicy
{
inline QRect operator() (const KisPaintDevice *dev) {
return dev->extent();
}
};
struct DeviceExactBoundsPolicy
{
inline QRect operator() (const KisPaintDevice *dev) {
return dev->exactBounds();
}
};
template <class DeviceMetricPolicy>
QRect KisColorizeMask::calculateMaskBounds(DeviceMetricPolicy boundsPolicy) const
{
QRect rc;
if (m_d->shouldShowFilteredSource()) {
rc |= boundsPolicy(m_d->filteredSource);
}
if (m_d->shouldShowColoring()) {
rc |= boundsPolicy(m_d->coloringProjection);
}
if (m_d->showKeyStrokes) {
Q_FOREACH (const KeyStroke &stroke, m_d->keyStrokes) {
rc |= boundsPolicy(stroke.dev);
}
KisIndirectPaintingSupport::ReadLocker locker(this);
KisPaintDeviceSP temporaryTarget = this->temporaryTarget();
if (temporaryTarget) {
rc |= boundsPolicy(temporaryTarget);
}
}
return rc;
}
QRect KisColorizeMask::extent() const
{
return calculateMaskBounds(DeviceExtentPolicy());
}
QRect KisColorizeMask::exactBounds() const
{
return calculateMaskBounds(DeviceExactBoundsPolicy());
}
QRect KisColorizeMask::nonDependentExtent() const
{
return extent();
}
KisImageSP KisColorizeMask::fetchImage() const
{
KisLayerSP parentLayer(qobject_cast<KisLayer*>(parent().data()));
if (!parentLayer) return KisImageSP();
return parentLayer->image();
}
void KisColorizeMask::setImage(KisImageWSP image)
{
KisDefaultBoundsSP bounds(new KisDefaultBounds(image));
auto it = m_d->keyStrokes.begin();
for(; it != m_d->keyStrokes.end(); ++it) {
it->dev->setDefaultBounds(bounds);
}
m_d->coloringProjection->setDefaultBounds(bounds);
m_d->fakePaintDevice->setDefaultBounds(bounds);
m_d->filteredSource->setDefaultBounds(bounds);
}
void KisColorizeMask::setCurrentColor(const KoColor &_color)
{
KoColor color = _color;
color.convertTo(colorSpace());
WriteLocker locker(this);
m_d->setNeedsUpdateImpl(true, false);
QList<KeyStroke>::const_iterator it =
std::find_if(m_d->keyStrokes.constBegin(),
m_d->keyStrokes.constEnd(),
[color] (const KeyStroke &s) {
return s.color == color;
});
KisPaintDeviceSP activeDevice;
bool newKeyStroke = false;
if (it == m_d->keyStrokes.constEnd()) {
activeDevice = new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8());
activeDevice->setParentNode(this);
activeDevice->setDefaultBounds(KisDefaultBoundsBaseSP(new KisDefaultBounds(fetchImage())));
newKeyStroke = true;
} else {
activeDevice = it->dev;
}
m_d->currentColor = color;
m_d->currentKeyStrokeDevice = activeDevice;
m_d->needAddCurrentKeyStroke = newKeyStroke;
}
struct KeyStrokeAddRemoveCommand : public KisCommandUtils::FlipFlopCommand {
KeyStrokeAddRemoveCommand(bool add, int index, KeyStroke stroke, QList<KeyStroke> *list, KisColorizeMaskSP node)
: FlipFlopCommand(!add),
m_index(index), m_stroke(stroke),
m_list(list), m_node(node) {}
void partA() override {
m_list->insert(m_index, m_stroke);
m_node->setNeedsUpdate(true);
emit m_node->sigKeyStrokesListChanged();
}
void partB() override {
KIS_ASSERT_RECOVER_RETURN((*m_list)[m_index] == m_stroke);
m_list->removeAt(m_index);
m_node->setNeedsUpdate(true);
emit m_node->sigKeyStrokesListChanged();
}
private:
int m_index;
KeyStroke m_stroke;
QList<KeyStroke> *m_list;
KisColorizeMaskSP m_node;
};
void KisColorizeMask::mergeToLayer(KisNodeSP layer, KisPostExecutionUndoAdapter *undoAdapter, const KUndo2MagicString &transactionText,int timedID)
{
Q_UNUSED(layer);
WriteLocker locker(this);
KisPaintDeviceSP temporaryTarget = this->temporaryTarget();
const bool isTemporaryTargetErasing = temporaryCompositeOp() == COMPOSITE_ERASE;
const QRect temporaryExtent = temporaryTarget ? temporaryTarget->extent() : QRect();
KisSavedMacroCommand *macro = undoAdapter->createMacro(transactionText);
KisMacroBasedUndoStore store(macro);
KisPostExecutionUndoAdapter fakeUndoAdapter(&store, undoAdapter->strokesFacade());
/**
* Add a new key stroke plane
*/
if (m_d->needAddCurrentKeyStroke && !isTemporaryTargetErasing) {
KeyStroke key(m_d->currentKeyStrokeDevice, m_d->currentColor);
KUndo2Command *cmd =
new KeyStrokeAddRemoveCommand(
true, m_d->keyStrokes.size(), key, &m_d->keyStrokes, KisColorizeMaskSP(this));
cmd->redo();
fakeUndoAdapter.addCommand(toQShared(cmd));
}
/**
* When erasing, the brush affects all the key strokes, not only
* the current one.
*/
if (!isTemporaryTargetErasing) {
mergeToLayerImpl(m_d->currentKeyStrokeDevice, &fakeUndoAdapter, transactionText, timedID, false);
} else {
Q_FOREACH (const KeyStroke &stroke, m_d->keyStrokes) {
if (temporaryExtent.intersects(stroke.dev->extent())) {
mergeToLayerImpl(stroke.dev, &fakeUndoAdapter, transactionText, timedID, false);
}
}
}
mergeToLayerImpl(m_d->fakePaintDevice, &fakeUndoAdapter, transactionText, timedID, false);
m_d->currentKeyStrokeDevice = 0;
m_d->currentColor = KoColor();
releaseResources();
/**
* Try removing the key strokes that has been completely erased
*/
if (isTemporaryTargetErasing) {
for (int index = 0; index < m_d->keyStrokes.size(); /*noop*/) {
const KeyStroke &stroke = m_d->keyStrokes[index];
if (stroke.dev->exactBounds().isEmpty()) {
KUndo2Command *cmd =
new KeyStrokeAddRemoveCommand(
false, index, stroke, &m_d->keyStrokes, KisColorizeMaskSP(this));
cmd->redo();
fakeUndoAdapter.addCommand(toQShared(cmd));
} else {
index++;
}
}
}
undoAdapter->addMacro(macro);
}
void KisColorizeMask::writeMergeData(KisPainter *painter, KisPaintDeviceSP src)
{
const KoColorSpace *alpha8 = KoColorSpaceRegistry::instance()->alpha8();
const bool nonAlphaDst = !(*painter->device()->colorSpace() == *alpha8);
if (nonAlphaDst) {
Q_FOREACH (const QRect &rc, src->region().rects()) {
painter->bitBlt(rc.topLeft(), src, rc);
}
} else {
KisCachedSelection::Guard s1(m_d->cachedSelection);
KisPixelSelectionSP tempSelection = s1.selection()->pixelSelection();
Q_FOREACH (const QRect &rc, src->region().rects()) {
tempSelection->copyAlphaFrom(src, rc);
painter->bitBlt(rc.topLeft(), tempSelection, rc);
}
}
}
bool KisColorizeMask::supportsNonIndirectPainting() const
{
return false;
}
bool KisColorizeMask::showColoring() const
{
return m_d->showColoring;
}
void KisColorizeMask::setShowColoring(bool value)
{
QRect savedExtent;
if (m_d->showColoring && !value) {
savedExtent = extent();
}
m_d->showColoring = value;
baseNodeChangedCallback();
if (!savedExtent.isEmpty()) {
setDirty(savedExtent);
}
}
bool KisColorizeMask::showKeyStrokes() const
{
return m_d->showKeyStrokes;
}
void KisColorizeMask::setShowKeyStrokes(bool value)
{
QRect savedExtent;
if (m_d->showKeyStrokes && !value) {
savedExtent = extent();
}
m_d->showKeyStrokes = value;
baseNodeChangedCallback();
if (!savedExtent.isEmpty()) {
setDirty(savedExtent);
}
regeneratePrefilteredDeviceIfNeeded();
}
KisColorizeMask::KeyStrokeColors KisColorizeMask::keyStrokesColors() const
{
KeyStrokeColors colors;
// TODO: thread safety!
for (int i = 0; i < m_d->keyStrokes.size(); i++) {
colors.colors << m_d->keyStrokes[i].color;
if (m_d->keyStrokes[i].isTransparent) {
colors.transparentIndex = i;
}
}
return colors;
}
struct SetKeyStrokeColorsCommand : public KUndo2Command {
SetKeyStrokeColorsCommand(const QList<KeyStroke> newList, QList<KeyStroke> *list, KisColorizeMaskSP node)
: m_newList(newList),
m_oldList(*list),
m_list(list),
m_node(node) {}
void redo() override {
*m_list = m_newList;
m_node->setNeedsUpdate(true);
emit m_node->sigKeyStrokesListChanged();
m_node->setDirty();
}
void undo() override {
*m_list = m_oldList;
m_node->setNeedsUpdate(true);
emit m_node->sigKeyStrokesListChanged();
m_node->setDirty();
}
private:
QList<KeyStroke> m_newList;
QList<KeyStroke> m_oldList;
QList<KeyStroke> *m_list;
KisColorizeMaskSP m_node;
};
void KisColorizeMask::setKeyStrokesColors(KeyStrokeColors colors)
{
KIS_ASSERT_RECOVER_RETURN(colors.colors.size() == m_d->keyStrokes.size());
QList<KeyStroke> newList = m_d->keyStrokes;
for (int i = 0; i < newList.size(); i++) {
newList[i].color = colors.colors[i];
newList[i].color.convertTo(colorSpace());
newList[i].isTransparent = colors.transparentIndex == i;
}
KisProcessingApplicator applicator(fetchImage(), KisNodeSP(this),
KisProcessingApplicator::NONE,
KisImageSignalVector(),
kundo2_i18n("Change Key Stroke Color"));
applicator.applyCommand(
new SetKeyStrokeColorsCommand(
newList, &m_d->keyStrokes, KisColorizeMaskSP(this)));
applicator.end();
}
void KisColorizeMask::removeKeyStroke(const KoColor &_color)
{
KoColor color = _color;
color.convertTo(colorSpace());
QList<KeyStroke>::iterator it =
std::find_if(m_d->keyStrokes.begin(),
m_d->keyStrokes.end(),
[color] (const KeyStroke &s) {
return s.color == color;
});
KIS_SAFE_ASSERT_RECOVER_RETURN(it != m_d->keyStrokes.end());
const int index = it - m_d->keyStrokes.begin();
KisProcessingApplicator applicator(KisImageWSP(fetchImage()), KisNodeSP(this),
KisProcessingApplicator::NONE,
KisImageSignalVector(),
kundo2_i18n("Remove Key Stroke"));
applicator.applyCommand(
new KeyStrokeAddRemoveCommand(
false, index, *it, &m_d->keyStrokes, KisColorizeMaskSP(this)));
applicator.end();
}
QVector<KisPaintDeviceSP> KisColorizeMask::allPaintDevices() const
{
QVector<KisPaintDeviceSP> devices;
Q_FOREACH (const KeyStroke &stroke, m_d->keyStrokes) {
devices << stroke.dev;
}
devices << m_d->coloringProjection;
devices << m_d->fakePaintDevice;
return devices;
}
void KisColorizeMask::resetCache()
{
m_d->filteredSource->clear();
m_d->originalSequenceNumber = -1;
m_d->filteringDirty = true;
rerenderFakePaintDevice();
slotUpdateRegenerateFilling(true);
}
void KisColorizeMask::setUseEdgeDetection(bool value)
{
m_d->filteringOptions.useEdgeDetection = value;
m_d->filteringDirty = true;
setNeedsUpdate(true);
}
bool KisColorizeMask::useEdgeDetection() const
{
return m_d->filteringOptions.useEdgeDetection;
}
void KisColorizeMask::setEdgeDetectionSize(qreal value)
{
m_d->filteringOptions.edgeDetectionSize = value;
m_d->filteringDirty = true;
setNeedsUpdate(true);
}
qreal KisColorizeMask::edgeDetectionSize() const
{
return m_d->filteringOptions.edgeDetectionSize;
}
void KisColorizeMask::setFuzzyRadius(qreal value)
{
m_d->filteringOptions.fuzzyRadius = value;
m_d->filteringDirty = true;
setNeedsUpdate(true);
}
qreal KisColorizeMask::fuzzyRadius() const
{
return m_d->filteringOptions.fuzzyRadius;
}
void KisColorizeMask::setCleanUpAmount(qreal value)
{
m_d->filteringOptions.cleanUpAmount = value;
setNeedsUpdate(true);
}
qreal KisColorizeMask::cleanUpAmount() const
{
return m_d->filteringOptions.cleanUpAmount;
}
void KisColorizeMask::setLimitToDeviceBounds(bool value)
{
m_d->limitToDeviceBounds = value;
m_d->filteringDirty = true;
setNeedsUpdate(true);
}
bool KisColorizeMask::limitToDeviceBounds() const
{
return m_d->limitToDeviceBounds;
}
void KisColorizeMask::rerenderFakePaintDevice()
{
m_d->fakePaintDevice->clear();
KisFillPainter gc(m_d->fakePaintDevice);
KisCachedSelection::Guard s1(m_d->cachedSelection);
KisSelectionSP selection = s1.selection();
Q_FOREACH (const KeyStroke &stroke, m_d->keyStrokes) {
const QRect rect = stroke.dev->extent();
selection->pixelSelection()->makeCloneFromRough(stroke.dev, rect);
gc.setSelection(selection);
gc.fillSelection(rect, stroke.color);
}
}
void KisColorizeMask::testingAddKeyStroke(KisPaintDeviceSP dev, const KoColor &color, bool isTransparent)
{
m_d->keyStrokes << KeyStroke(dev, color, isTransparent);
}
void KisColorizeMask::testingRegenerateMask()
{
slotUpdateRegenerateFilling();
m_d->updateIsRunning = false;
}
KisPaintDeviceSP KisColorizeMask::testingFilteredSource() const
{
return m_d->filteredSource;
}
QList<KeyStroke> KisColorizeMask::fetchKeyStrokesDirect() const
{
return m_d->keyStrokes;
}
void KisColorizeMask::setKeyStrokesDirect(const QList<KisLazyFillTools::KeyStroke> &strokes)
{
m_d->keyStrokes = strokes;
for (auto it = m_d->keyStrokes.begin(); it != m_d->keyStrokes.end(); ++it) {
it->dev->setParentNode(this);
}
KisImageSP image = fetchImage();
KIS_SAFE_ASSERT_RECOVER_RETURN(image);
setImage(image);
}
qint32 KisColorizeMask::x() const
{
return m_d->offset.x();
}
qint32 KisColorizeMask::y() const
{
return m_d->offset.y();
}
void KisColorizeMask::setX(qint32 x)
{
const QPoint oldOffset = m_d->offset;
m_d->offset.rx() = x;
moveAllInternalDevices(m_d->offset - oldOffset);
}
void KisColorizeMask::setY(qint32 y)
{
const QPoint oldOffset = m_d->offset;
m_d->offset.ry() = y;
moveAllInternalDevices(m_d->offset - oldOffset);
}
KisPaintDeviceList KisColorizeMask::getLodCapableDevices() const
{
KisPaintDeviceList list;
auto it = m_d->keyStrokes.begin();
for(; it != m_d->keyStrokes.end(); ++it) {
list << it->dev;
}
list << m_d->coloringProjection;
list << m_d->fakePaintDevice;
list << m_d->filteredSource;
return list;
}
void KisColorizeMask::regeneratePrefilteredDeviceIfNeeded()
{
if (!parent()) return;
KisPaintDeviceSP src = parent()->original();
KIS_ASSERT_RECOVER_RETURN(src);
if (!m_d->filteredSourceValid(src)) {
// update the prefiltered source if needed
slotUpdateRegenerateFilling(true);
}
}
void KisColorizeMask::moveAllInternalDevices(const QPoint &diff)
{
QVector<KisPaintDeviceSP> devices = allPaintDevices();
Q_FOREACH (KisPaintDeviceSP dev, devices) {
dev->moveTo(dev->offset() + diff);
}
}
diff --git a/libs/image/tests/CMakeLists.txt b/libs/image/tests/CMakeLists.txt
index fddafbc361..351b7b374c 100644
--- a/libs/image/tests/CMakeLists.txt
+++ b/libs/image/tests/CMakeLists.txt
@@ -1,192 +1,187 @@
# cmake in some versions for some not yet known reasons fails to run automoc
# on random targets (changing target names already has an effect)
# As temporary workaround skipping build of tests on these versions for now
# See https://mail.kde.org/pipermail/kde-buildsystem/2015-June/010819.html
# extend range of affected cmake versions as needed
if(NOT ${CMAKE_VERSION} VERSION_LESS 3.1.3 AND
NOT ${CMAKE_VERSION} VERSION_GREATER 3.2.3)
message(WARNING "Skipping krita/image/tests, CMake in at least versions 3.1.3 - 3.2.3 seems to have a problem with automoc. \n(FRIENDLY REMINDER: PLEASE DON'T BREAK THE TESTS!)")
set (HAVE_FAILING_CMAKE TRUE)
else()
set (HAVE_FAILING_CMAKE FALSE)
endif()
include_directories(
${CMAKE_BINARY_DIR}/libs/image/
${CMAKE_SOURCE_DIR}/libs/image/
${CMAKE_SOURCE_DIR}/libs/image/brushengine
${CMAKE_SOURCE_DIR}/libs/image/tiles3
${CMAKE_SOURCE_DIR}/libs/image/tiles3/swap
${CMAKE_SOURCE_DIR}/sdk/tests
)
include_Directories(SYSTEM
${EIGEN3_INCLUDE_DIR}
)
if(HAVE_VC)
include_directories(${Vc_INCLUDE_DIR})
endif()
include(ECMAddTests)
macro_add_unittest_definitions()
set(KisRandomGeneratorDemoSources kis_random_generator_demo.cpp kimageframe.cpp)
ki18n_wrap_ui(KisRandomGeneratorDemoSources kis_random_generator_demo.ui)
add_executable(KisRandomGeneratorDemo ${KisRandomGeneratorDemoSources})
target_link_libraries(KisRandomGeneratorDemo kritaimage)
ecm_mark_as_test(KisRandomGeneratorDemo)
ecm_add_tests(
kis_base_node_test.cpp
kis_fast_math_test.cpp
kis_node_test.cpp
kis_node_facade_test.cpp
kis_fixed_paint_device_test.cpp
kis_layer_test.cpp
kis_effect_mask_test.cpp
kis_iterator_test.cpp
kis_painter_test.cpp
kis_count_visitor_test.cpp
kis_projection_test.cpp
kis_properties_configuration_test.cpp
kis_transaction_test.cpp
kis_pixel_selection_test.cpp
kis_group_layer_test.cpp
kis_paint_layer_test.cpp
kis_adjustment_layer_test.cpp
kis_annotation_test.cpp
kis_clone_layer_test.cpp
kis_convolution_painter_test.cpp
kis_crop_processing_visitor_test.cpp
kis_processing_applicator_test.cpp
kis_datamanager_test.cpp
kis_fill_painter_test.cpp
kis_filter_configuration_test.cpp
kis_filter_test.cpp
kis_filter_processing_information_test.cpp
kis_filter_registry_test.cpp
kis_filter_strategy_test.cpp
kis_gradient_painter_test.cpp
kis_image_commands_test.cpp
kis_image_test.cpp
kis_image_signal_router_test.cpp
kis_iterators_ng_test.cpp
kis_iterator_benchmark.cpp
kis_updater_context_test.cpp
kis_simple_update_queue_test.cpp
kis_stroke_test.cpp
kis_simple_stroke_strategy_test.cpp
kis_stroke_strategy_undo_command_based_test.cpp
kis_strokes_queue_test.cpp
kis_mask_test.cpp
kis_math_toolbox_test.cpp
kis_name_server_test.cpp
kis_node_commands_test.cpp
kis_node_graph_listener_test.cpp
kis_node_visitor_test.cpp
kis_paint_information_test.cpp
kis_distance_information_test.cpp
kis_paintop_test.cpp
kis_pattern_test.cpp
kis_selection_mask_test.cpp
kis_shared_ptr_test.cpp
kis_bsplines_test.cpp
kis_warp_transform_worker_test.cpp
kis_liquify_transform_worker_test.cpp
kis_transparency_mask_test.cpp
kis_types_test.cpp
kis_vec_test.cpp
kis_filter_config_widget_test.cpp
kis_mask_generator_test.cpp
kis_cubic_curve_test.cpp
kis_fixed_point_maths_test.cpp
kis_node_query_path_test.cpp
kis_filter_weights_buffer_test.cpp
kis_filter_weights_applicator_test.cpp
kis_fill_interval_test.cpp
kis_fill_interval_map_test.cpp
kis_scanline_fill_test.cpp
kis_psd_layer_style_test.cpp
kis_layer_style_projection_plane_test.cpp
kis_lod_capable_layer_offset_test.cpp
kis_algebra_2d_test.cpp
kis_marker_painter_test.cpp
kis_lazy_brush_test.cpp
kis_mask_similarity_test.cpp
KisMaskGeneratorTest.cpp
kis_layer_style_filter_environment_test.cpp
kis_asl_parser_test.cpp
KisPerStrokeRandomSourceTest.cpp
KisWatershedWorkerTest.cpp
kis_dom_utils_test.cpp
kis_transform_worker_test.cpp
kis_cs_conversion_test.cpp
kis_projection_leaf_test.cpp
kis_histogram_test.cpp
kis_onion_skin_compositor_test.cpp
kis_queues_progress_updater_test.cpp
kis_image_animation_interface_test.cpp
kis_walkers_test.cpp
kis_cage_transform_worker_test.cpp
kis_random_generator_test.cpp
kis_keyframing_test.cpp
kis_filter_mask_test.cpp
kis_asl_layer_style_serializer_test.cpp
TestAslStorage.cpp
kis_async_merger_test.cpp
+ kis_selection_test.cpp
LINK_LIBRARIES kritaimage Qt5::Test
NAME_PREFIX "libs-image-"
)
include(KritaAddBrokenUnitTest)
krita_add_broken_unit_test( kis_transform_mask_test.cpp
TEST_NAME kis_transform_mask_test
LINK_LIBRARIES kritaimage Qt5::Test
NAME_PREFIX "libs-image-"
)
krita_add_broken_unit_test( kis_layer_styles_test.cpp
TEST_NAME kis_layer_styles_test
LINK_LIBRARIES kritaimage Qt5::Test
NAME_PREFIX "libs-image-"
)
krita_add_broken_unit_test( kis_update_scheduler_test.cpp
TEST_NAME kis_update_scheduler_test
LINK_LIBRARIES kritaimage Qt5::Test
NAME_PREFIX "libs-image-"
)
krita_add_broken_unit_test( kis_paint_device_test.cpp
TEST_NAME kis_paint_device_test
LINK_LIBRARIES kritaimage Qt5::Test
NAME_PREFIX "libs-image-"
)
krita_add_broken_unit_test( kis_colorize_mask_test.cpp
TEST_NAME kis_colorize_mask_test
LINK_LIBRARIES kritaimage Qt5::Test
NAME_PREFIX "libs-image-"
)
-krita_add_broken_unit_test( kis_selection_test.cpp
- TEST_NAME kis_selection_test
- LINK_LIBRARIES kritaimage Qt5::Test
- NAME_PREFIX "libs-image-"
-)
-
krita_add_broken_unit_test( kis_processings_test.cpp
TEST_NAME kis_processings_test
LINK_LIBRARIES kritaimage Qt5::Test
NAME_PREFIX "libs-image-"
)
krita_add_broken_unit_test( kis_perspective_transform_worker_test.cpp
TEST_NAME kis_perspective_transform_worker_test
LINK_LIBRARIES kritaimage Qt5::Test
NAME_PREFIX "libs-image-"
)
diff --git a/libs/image/tests/kis_selection_test.cpp b/libs/image/tests/kis_selection_test.cpp
index 1fc12397a7..83f43e7214 100644
--- a/libs/image/tests/kis_selection_test.cpp
+++ b/libs/image/tests/kis_selection_test.cpp
@@ -1,340 +1,341 @@
/*
* Copyright (c) 2007 Sven Langkamp <sven.langkamp@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_selection_test.h"
#include <QTest>
#include <kis_debug.h>
#include <QRect>
#include <KoColorSpace.h>
#include <KoColorSpaceRegistry.h>
#include <KoCompositeOpRegistry.h>
#include "kis_datamanager.h"
#include "kis_pixel_selection.h"
#include "kis_selection.h"
#include "kis_fill_painter.h"
#include "kis_mask.h"
#include "kis_image.h"
#include "kis_transparency_mask.h"
#include "testutil.h"
#include <KoColorModelStandardIds.h>
void KisSelectionTest::testGrayColorspaceConversion()
{
const KoColorSpace *csA =
KoColorSpaceRegistry::instance()->
colorSpace(GrayAColorModelID.id(),
Integer8BitsColorDepthID.id(),
QString());
const KoColorSpace *csNoA =
KoColorSpaceRegistry::instance()->alpha8();
QVERIFY(csA);
QVERIFY(csNoA);
QCOMPARE(csA->pixelSize(), 2U);
QCOMPARE(csNoA->pixelSize(), 1U);
quint8 color1[1] = {128};
quint8 color2[2] = {64,32};
csA->convertPixelsTo(color2, color1, csNoA, 1,
KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags());
QCOMPARE((int)color1[0], 8);
csNoA->convertPixelsTo(color1, color2, csA, 1,
KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags());
QCOMPARE((int)color2[0], 8);
QCOMPARE((int)color2[1], 255);
}
void KisSelectionTest::testGrayColorspaceOverComposition()
{
const KoColorSpace *csA =
KoColorSpaceRegistry::instance()->
colorSpace(GrayAColorModelID.id(),
Integer8BitsColorDepthID.id(),
QString());
const KoColorSpace *csNoA =
KoColorSpaceRegistry::instance()->alpha8();
QVERIFY(csA);
QVERIFY(csNoA);
QCOMPARE(csA->pixelSize(), 2U);
QCOMPARE(csNoA->pixelSize(), 1U);
quint8 color0[2] = {32,255};
quint8 color1[2] = {128,64};
quint8 color3[1] = {32};
KoCompositeOp::ParameterInfo params;
params.dstRowStart = color0;
params.dstRowStride = 0;
params.srcRowStart = color1;
params.srcRowStride = 0;
params.maskRowStart = 0;
params.maskRowStride = 0;
params.rows = 1;
params.cols = 1;
params.opacity = 1.0;
params.flow = 1.0;
csA->bitBlt(csA, params, csA->compositeOp(COMPOSITE_OVER),
KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags());
QCOMPARE((int)color0[0], 56);
QCOMPARE((int)color0[1], 255);
params.dstRowStart = color3;
csNoA->bitBlt(csA, params, csNoA->compositeOp(COMPOSITE_OVER),
KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags());
QCOMPARE((int)color3[0], 56);
}
void KisSelectionTest::testSelectionComponents()
{
KisSelectionSP selection = new KisSelection();
- QCOMPARE(selection->hasPixelSelection(), false);
- QCOMPARE(selection->hasShapeSelection(), false);
+ QCOMPARE(selection->hasNonEmptyPixelSelection(), false);
+ QCOMPARE(selection->hasNonEmptyShapeSelection(), false);
QCOMPARE(selection->shapeSelection(), (void*)0);
selection->pixelSelection()->select(QRect(10,10,10,10));
- QCOMPARE(selection->hasPixelSelection(), true);
+ QCOMPARE(selection->hasNonEmptyPixelSelection(), true);
QCOMPARE(selection->selectedExactRect(), QRect(10,10,10,10));
}
void KisSelectionTest::testSelectionActions()
{
KisSelectionSP selection = new KisSelection();
- QVERIFY(selection->hasPixelSelection() == false);
- QVERIFY(selection->hasShapeSelection() == false);
+ QVERIFY(selection->hasNonEmptyPixelSelection() == false);
+ QVERIFY(selection->hasNonEmptyShapeSelection() == false);
KisPixelSelectionSP pixelSelection = selection->pixelSelection();
pixelSelection->select(QRect(0, 0, 20, 20));
KisPixelSelectionSP tmpSel = new KisPixelSelection();
tmpSel->select(QRect(10, 0, 20, 20));
pixelSelection->applySelection(tmpSel, SELECTION_ADD);
QCOMPARE(pixelSelection->selectedExactRect(), QRect(0, 0, 30, 20));
QCOMPARE(selection->selectedExactRect(), QRect(0, 0, 30, 20));
pixelSelection->clear();
pixelSelection->select(QRect(0, 0, 20, 20));
pixelSelection->applySelection(tmpSel, SELECTION_SUBTRACT);
QCOMPARE(pixelSelection->selectedExactRect(), QRect(0, 0, 10, 20));
QCOMPARE(selection->selectedExactRect(), QRect(0, 0, 10, 20));
pixelSelection->clear();
pixelSelection->select(QRect(0, 0, 20, 20));
pixelSelection->applySelection(tmpSel, SELECTION_INTERSECT);
QCOMPARE(pixelSelection->selectedExactRect(), QRect(10, 0, 10, 20));
QCOMPARE(selection->selectedExactRect(), QRect(10, 0, 10, 20));
}
void KisSelectionTest::testInvertSelection()
{
const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
KisImageSP image = new KisImage(0, 1024, 1024, cs, "stest");
KisSelectionSP selection = new KisSelection(new KisDefaultBounds(image));
KisPixelSelectionSP pixelSelection = selection->pixelSelection();
pixelSelection->select(QRect(20, 20, 20, 20));
QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 30, 30), MAX_SELECTED);
QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 0, 0), MIN_SELECTED);
QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 512, 512), MIN_SELECTED);
QCOMPARE(pixelSelection->selectedExactRect(), QRect(20, 20, 20, 20));
pixelSelection->invert();
QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 100, 100), MAX_SELECTED);
QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 22, 22), MIN_SELECTED);
QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 0, 0), MAX_SELECTED);
QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 512, 512), MAX_SELECTED);
QCOMPARE(pixelSelection->selectedExactRect(), QRect(0,0,1024,1024));
QCOMPARE(pixelSelection->selectedRect(), QRect(0,0,1024,1024));
selection->updateProjection();
QCOMPARE(selection->selectedExactRect(), QRect(0,0,1024,1024));
QCOMPARE(selection->selectedRect(), QRect(0,0,1024,1024));
QCOMPARE(TestUtil::alphaDevicePixel(selection->projection(), 100, 100), MAX_SELECTED);
QCOMPARE(TestUtil::alphaDevicePixel(selection->projection(), 22, 22), MIN_SELECTED);
QCOMPARE(TestUtil::alphaDevicePixel(selection->projection(), 10, 10), MAX_SELECTED);
QCOMPARE(TestUtil::alphaDevicePixel(selection->projection(), 0, 0), MAX_SELECTED);
QCOMPARE(TestUtil::alphaDevicePixel(selection->projection(), 512, 512), MAX_SELECTED);
}
void KisSelectionTest::testInvertSelectionSemi()
{
const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
KisImageSP image = new KisImage(0, 1024, 1024, cs, "stest");
KisSelectionSP selection = new KisSelection(new KisDefaultBounds(image));
KisPixelSelectionSP pixelSelection = selection->pixelSelection();
quint8 selectedness = 42;
pixelSelection->select(QRect(20, 20, 20, 20), selectedness);
QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 30, 30), selectedness);
QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 0, 0), MIN_SELECTED);
QCOMPARE(pixelSelection->selectedExactRect(), QRect(20, 20, 20, 20));
pixelSelection->invert();
quint8 invertedSelectedness = MAX_SELECTED - selectedness;
QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 30, 30), invertedSelectedness);
QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 0, 0), MAX_SELECTED);
QCOMPARE(pixelSelection->selectedExactRect(), QRect(0,0,1024,1024));
QCOMPARE(pixelSelection->selectedRect(), QRect(0,0,1024,1024));
selection->updateProjection();
QCOMPARE(selection->selectedExactRect(), QRect(0,0,1024,1024));
QCOMPARE(selection->selectedRect(), QRect(0,0,1024,1024));
QCOMPARE(TestUtil::alphaDevicePixel(selection->projection(), 30, 30), invertedSelectedness);
QCOMPARE(TestUtil::alphaDevicePixel(selection->projection(), 0, 0), MAX_SELECTED);
}
void KisSelectionTest::testCopy()
{
KisSelectionSP sel = new KisSelection();
sel->pixelSelection()->select(QRect(10, 10, 200, 200), 128);
sel->updateProjection();
KisSelectionSP sel2 = new KisSelection(*sel.data());
QCOMPARE(sel2->selectedExactRect(), sel->selectedExactRect());
QPoint errpoint;
if (!TestUtil::comparePaintDevices(errpoint, sel->projection(), sel2->projection())) {
sel2->projection()->convertToQImage(0, 0, 0, 200, 200).save("merge_visitor6.png");
QFAIL(QString("Failed to copy selection, first different pixel: %1,%2 ")
.arg(errpoint.x())
.arg(errpoint.y())
.toLatin1());
}
}
void KisSelectionTest::testSelectionExactBounds()
{
QRect referenceImageRect(0,0,1000,1000);
QRect referenceDeviceRect(100,100,1040,1040);
const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
KisImageSP image = new KisImage(0, referenceImageRect.width(),
referenceImageRect.height(),
cs, "stest");
KisPaintDeviceSP device = new KisPaintDevice(cs);
+ device->setDefaultBounds(new KisDefaultBounds(image));
device->fill(referenceDeviceRect, KoColor(Qt::white, cs));
QCOMPARE(device->exactBounds(), referenceDeviceRect);
KisSelectionSP selection = new KisSelection(new KisSelectionDefaultBounds(device));
quint8 defaultPixel = MAX_SELECTED;
selection->pixelSelection()->setDefaultPixel(KoColor(&defaultPixel, selection->pixelSelection()->colorSpace()));
// the selection uses device's extent only for performance reasons
// \see bug 320213
QCOMPARE(selection->selectedExactRect(), device->extent() | referenceImageRect);
}
void KisSelectionTest::testSetParentNodeAfterCreation()
{
const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
KisImageSP image = new KisImage(0, 100, 100, cs, "stest");
KisSelectionSP selection = new KisSelection();
KisPixelSelectionSP pixelSelection = selection->pixelSelection();
QCOMPARE(selection->parentNode(), KisNodeWSP(0));
QCOMPARE(selection->pixelSelection()->parentNode(), KisNodeWSP(0));
selection->setParentNode(image->root());
QCOMPARE(selection->parentNode(), KisNodeWSP(image->root()));
QCOMPARE(selection->pixelSelection()->parentNode(), KisNodeWSP(image->root()));
}
void KisSelectionTest::testSetParentNodeBeforeCreation()
{
const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
KisImageSP image = new KisImage(0, 100, 100, cs, "stest");
KisSelectionSP selection = new KisSelection();
selection->setParentNode(image->root());
KisPixelSelectionSP pixelSelection = selection->pixelSelection();
QCOMPARE(selection->parentNode(), KisNodeWSP(image->root()));
QCOMPARE(selection->pixelSelection()->parentNode(), KisNodeWSP(image->root()));
}
void KisSelectionTest::testOutlineGeneration()
{
KisSelectionSP sel = new KisSelection();
sel->pixelSelection()->select(QRect(428,436, 430,211), 128);
QVERIFY(sel->outlineCacheValid());
QPainterPath originalOutline = sel->outlineCache();
sel->pixelSelection()->invalidateOutlineCache();
sel->recalculateOutlineCache();
QPainterPath calculatedOutline = sel->outlineCache();
QPainterPath closedSubPath = calculatedOutline;
closedSubPath.closeSubpath();
/**
* Our outline generation code has a small problem: it can
* generate a polygon, which isn't closed (it'll repeat the first
* point instead). There is a special workaround for it in
* KisPixelSelection::recalculateOutlineCache(), which explicitly
* closes the path, so here we just check it.
*/
bool isClosed = closedSubPath == calculatedOutline;
QVERIFY(isClosed);
}
KISTEST_MAIN(KisSelectionTest)
diff --git a/libs/image/tiles3/tests/kis_tiled_data_manager_test.cpp b/libs/image/tiles3/tests/kis_tiled_data_manager_test.cpp
index fce68797ae..5578513554 100644
--- a/libs/image/tiles3/tests/kis_tiled_data_manager_test.cpp
+++ b/libs/image/tiles3/tests/kis_tiled_data_manager_test.cpp
@@ -1,1051 +1,1126 @@
/*
* Copyright (c) 2010 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_tiled_data_manager_test.h"
#include <QTest>
#include "tiles3/kis_tiled_data_manager.h"
#include "tiles_test_utils.h"
#include "config-limit-long-tests.h"
bool KisTiledDataManagerTest::checkHole(quint8* buffer,
quint8 holeColor, QRect holeRect,
quint8 backgroundColor, QRect backgroundRect)
{
for(qint32 y = backgroundRect.y(); y <= backgroundRect.bottom(); y++) {
for(qint32 x = backgroundRect.x(); x <= backgroundRect.right(); x++) {
quint8 expectedColor = holeRect.contains(x,y) ? holeColor : backgroundColor;
if(*buffer != expectedColor) {
qDebug() << "Expected" << expectedColor << "but found" << *buffer;
return false;
}
buffer++;
}
}
return true;
}
bool KisTiledDataManagerTest::checkTilesShared(KisTiledDataManager *srcDM,
KisTiledDataManager *dstDM,
bool takeOldSrc,
bool takeOldDst,
QRect tilesRect)
{
for(qint32 row = tilesRect.y(); row <= tilesRect.bottom(); row++) {
for(qint32 col = tilesRect.x(); col <= tilesRect.right(); col++) {
KisTileSP srcTile = takeOldSrc ? srcDM->getOldTile(col, row)
: srcDM->getTile(col, row, false);
KisTileSP dstTile = takeOldDst ? dstDM->getOldTile(col, row)
: dstDM->getTile(col, row, false);
if(srcTile->tileData() != dstTile->tileData()) {
qDebug() << "Expected tile data (" << col << row << ")"
<< srcTile->extent()
<< srcTile->tileData()
<< "but found" << dstTile->tileData();
qDebug() << "Expected" << srcTile->data()[0] << "but found" << dstTile->data()[0];
return false;
}
}
}
return true;
}
bool KisTiledDataManagerTest::checkTilesNotShared(KisTiledDataManager *srcDM,
KisTiledDataManager *dstDM,
bool takeOldSrc,
bool takeOldDst,
QRect tilesRect)
{
for(qint32 row = tilesRect.y(); row <= tilesRect.bottom(); row++) {
for(qint32 col = tilesRect.x(); col <= tilesRect.right(); col++) {
KisTileSP srcTile = takeOldSrc ? srcDM->getOldTile(col, row)
: srcDM->getTile(col, row, false);
KisTileSP dstTile = takeOldDst ? dstDM->getOldTile(col, row)
: dstDM->getTile(col, row, false);
if(srcTile->tileData() == dstTile->tileData()) {
qDebug() << "Expected tiles not be shared:"<< srcTile->extent();
return false;
}
}
}
return true;
}
void KisTiledDataManagerTest::testUndoingNewTiles()
{
// "growing extent bug"
const QRect nullRect;
quint8 defaultPixel = 0;
KisTiledDataManager srcDM(1, &defaultPixel);
KisTileSP emptyTile = srcDM.getTile(0, 0, false);
QCOMPARE(srcDM.extent(), nullRect);
KisMementoSP memento0 = srcDM.getMemento();
KisTileSP createdTile = srcDM.getTile(0, 0, true);
srcDM.commit();
QCOMPARE(srcDM.extent(), QRect(0,0,64,64));
srcDM.rollback(memento0);
QCOMPARE(srcDM.extent(), nullRect);
}
void KisTiledDataManagerTest::testPurgedAndEmptyTransactions()
{
quint8 defaultPixel = 0;
KisTiledDataManager srcDM(1, &defaultPixel);
quint8 oddPixel1 = 128;
QRect rect(0,0,512,512);
QRect clearRect1(50,50,100,100);
QRect clearRect2(150,50,100,100);
quint8 *buffer = new quint8[rect.width()*rect.height()];
// purged transaction
KisMementoSP memento0 = srcDM.getMemento();
srcDM.clear(clearRect1, &oddPixel1);
srcDM.purgeHistory(memento0);
memento0 = 0;
srcDM.readBytes(buffer, rect.x(), rect.y(), rect.width(), rect.height());
QVERIFY(checkHole(buffer, oddPixel1, clearRect1,
defaultPixel, rect));
// one more purged transaction
KisMementoSP memento1 = srcDM.getMemento();
srcDM.clear(clearRect2, &oddPixel1);
srcDM.readBytes(buffer, rect.x(), rect.y(), rect.width(), rect.height());
QVERIFY(checkHole(buffer, oddPixel1, clearRect1 | clearRect2,
defaultPixel, rect));
srcDM.purgeHistory(memento1);
memento1 = 0;
srcDM.readBytes(buffer, rect.x(), rect.y(), rect.width(), rect.height());
QVERIFY(checkHole(buffer, oddPixel1, clearRect1 | clearRect2,
defaultPixel, rect));
// empty one
KisMementoSP memento2 = srcDM.getMemento();
srcDM.commit();
srcDM.rollback(memento2);
srcDM.readBytes(buffer, rect.x(), rect.y(), rect.width(), rect.height());
QVERIFY(checkHole(buffer, oddPixel1, clearRect1 | clearRect2,
defaultPixel, rect));
// now check that everything works still
KisMementoSP memento3 = srcDM.getMemento();
srcDM.setExtent(clearRect2);
srcDM.commit();
srcDM.readBytes(buffer, rect.x(), rect.y(), rect.width(), rect.height());
QVERIFY(checkHole(buffer, oddPixel1, clearRect2,
defaultPixel, rect));
srcDM.rollback(memento3);
srcDM.readBytes(buffer, rect.x(), rect.y(), rect.width(), rect.height());
QVERIFY(checkHole(buffer, oddPixel1, clearRect1 | clearRect2,
defaultPixel, rect));
}
void KisTiledDataManagerTest::testUnversionedBitBlt()
{
quint8 defaultPixel = 0;
KisTiledDataManager srcDM(1, &defaultPixel);
KisTiledDataManager dstDM(1, &defaultPixel);
quint8 oddPixel1 = 128;
quint8 oddPixel2 = 129;
QRect rect(0,0,512,512);
QRect cloneRect(81,80,250,250);
QRect tilesRect(2,2,3,3);
srcDM.clear(rect, &oddPixel1);
dstDM.clear(rect, &oddPixel2);
dstDM.bitBlt(&srcDM, cloneRect);
quint8 *buffer = new quint8[rect.width()*rect.height()];
dstDM.readBytes(buffer, rect.x(), rect.y(), rect.width(), rect.height());
QVERIFY(checkHole(buffer, oddPixel1, cloneRect,
oddPixel2, rect));
delete[] buffer;
// Test whether tiles became shared
QVERIFY(checkTilesShared(&srcDM, &dstDM, false, false, tilesRect));
}
void KisTiledDataManagerTest::testVersionedBitBlt()
{
quint8 defaultPixel = 0;
KisTiledDataManager srcDM1(1, &defaultPixel);
KisTiledDataManager srcDM2(1, &defaultPixel);
KisTiledDataManager dstDM(1, &defaultPixel);
quint8 oddPixel1 = 128;
quint8 oddPixel2 = 129;
quint8 oddPixel3 = 130;
quint8 oddPixel4 = 131;
QRect rect(0,0,512,512);
QRect cloneRect(81,80,250,250);
QRect tilesRect(2,2,3,3);
KisMementoSP memento1 = srcDM1.getMemento();
srcDM1.clear(rect, &oddPixel1);
srcDM2.clear(rect, &oddPixel2);
dstDM.clear(rect, &oddPixel3);
KisMementoSP memento2 = dstDM.getMemento();
dstDM.bitBlt(&srcDM1, cloneRect);
QVERIFY(checkTilesShared(&srcDM1, &dstDM, false, false, tilesRect));
QVERIFY(checkTilesNotShared(&srcDM1, &srcDM1, true, false, tilesRect));
QVERIFY(checkTilesNotShared(&dstDM, &dstDM, true, false, tilesRect));
dstDM.commit();
QVERIFY(checkTilesShared(&dstDM, &dstDM, true, false, tilesRect));
KisMementoSP memento3 = srcDM2.getMemento();
srcDM2.clear(rect, &oddPixel4);
KisMementoSP memento4 = dstDM.getMemento();
dstDM.bitBlt(&srcDM2, cloneRect);
QVERIFY(checkTilesShared(&srcDM2, &dstDM, false, false, tilesRect));
QVERIFY(checkTilesNotShared(&srcDM2, &srcDM2, true, false, tilesRect));
QVERIFY(checkTilesNotShared(&dstDM, &dstDM, true, false, tilesRect));
dstDM.commit();
QVERIFY(checkTilesShared(&dstDM, &dstDM, true, false, tilesRect));
dstDM.rollback(memento4);
QVERIFY(checkTilesShared(&srcDM1, &dstDM, false, false, tilesRect));
QVERIFY(checkTilesShared(&dstDM, &dstDM, true, false, tilesRect));
QVERIFY(checkTilesNotShared(&srcDM1, &srcDM1, true, false, tilesRect));
dstDM.rollforward(memento4);
QVERIFY(checkTilesShared(&srcDM2, &dstDM, false, false, tilesRect));
QVERIFY(checkTilesShared(&dstDM, &dstDM, true, false, tilesRect));
QVERIFY(checkTilesNotShared(&srcDM1, &srcDM1, true, false, tilesRect));
}
void KisTiledDataManagerTest::testBitBltOldData()
{
quint8 defaultPixel = 0;
KisTiledDataManager srcDM(1, &defaultPixel);
KisTiledDataManager dstDM(1, &defaultPixel);
quint8 oddPixel1 = 128;
quint8 oddPixel2 = 129;
QRect rect(0,0,512,512);
QRect cloneRect(81,80,250,250);
quint8 *buffer = new quint8[rect.width()*rect.height()];
KisMementoSP memento1 = srcDM.getMemento();
srcDM.clear(rect, &oddPixel1);
srcDM.commit();
dstDM.bitBltOldData(&srcDM, cloneRect);
dstDM.readBytes(buffer, rect.x(), rect.y(), rect.width(), rect.height());
QVERIFY(checkHole(buffer, oddPixel1, cloneRect,
defaultPixel, rect));
KisMementoSP memento2 = srcDM.getMemento();
srcDM.clear(rect, &oddPixel2);
dstDM.bitBltOldData(&srcDM, cloneRect);
srcDM.commit();
dstDM.readBytes(buffer, rect.x(), rect.y(), rect.width(), rect.height());
QVERIFY(checkHole(buffer, oddPixel1, cloneRect,
defaultPixel, rect));
delete[] buffer;
}
void KisTiledDataManagerTest::testBitBltRough()
{
quint8 defaultPixel = 0;
KisTiledDataManager srcDM(1, &defaultPixel);
KisTiledDataManager dstDM(1, &defaultPixel);
quint8 oddPixel1 = 128;
quint8 oddPixel2 = 129;
quint8 oddPixel3 = 130;
QRect rect(0,0,512,512);
QRect cloneRect(81,80,250,250);
QRect actualCloneRect(64,64,320,320);
QRect tilesRect(1,1,4,4);
srcDM.clear(rect, &oddPixel1);
dstDM.clear(rect, &oddPixel2);
dstDM.bitBltRough(&srcDM, cloneRect);
quint8 *buffer = new quint8[rect.width()*rect.height()];
dstDM.readBytes(buffer, rect.x(), rect.y(), rect.width(), rect.height());
QVERIFY(checkHole(buffer, oddPixel1, actualCloneRect,
oddPixel2, rect));
// Test whether tiles became shared
QVERIFY(checkTilesShared(&srcDM, &dstDM, false, false, tilesRect));
// check bitBltRoughOldData
KisMementoSP memento1 = srcDM.getMemento();
srcDM.clear(rect, &oddPixel3);
dstDM.bitBltRoughOldData(&srcDM, cloneRect);
srcDM.commit();
dstDM.readBytes(buffer, rect.x(), rect.y(), rect.width(), rect.height());
QVERIFY(checkHole(buffer, oddPixel1, actualCloneRect,
oddPixel2, rect));
delete[] buffer;
}
void KisTiledDataManagerTest::testTransactions()
{
quint8 defaultPixel = 0;
KisTiledDataManager dm(1, &defaultPixel);
quint8 oddPixel1 = 128;
quint8 oddPixel2 = 129;
quint8 oddPixel3 = 130;
KisTileSP tile00;
KisTileSP oldTile00;
// Create a named transaction: versioning is enabled
KisMementoSP memento1 = dm.getMemento();
dm.clear(0, 0, 64, 64, &oddPixel1);
tile00 = dm.getTile(0, 0, false);
oldTile00 = dm.getOldTile(0, 0);
QVERIFY(memoryIsFilled(oddPixel1, tile00->data(), TILESIZE));
QVERIFY(memoryIsFilled(defaultPixel, oldTile00->data(), TILESIZE));
tile00 = oldTile00 = 0;
// Create an anonymous transaction: versioning is disabled
dm.commit();
tile00 = dm.getTile(0, 0, false);
oldTile00 = dm.getOldTile(0, 0);
QVERIFY(memoryIsFilled(oddPixel1, tile00->data(), TILESIZE));
QVERIFY(memoryIsFilled(oddPixel1, oldTile00->data(), TILESIZE));
tile00 = oldTile00 = 0;
dm.clear(0, 0, 64, 64, &oddPixel2);
// Versioning is disabled, i said! >:)
tile00 = dm.getTile(0, 0, false);
oldTile00 = dm.getOldTile(0, 0);
QVERIFY(memoryIsFilled(oddPixel2, tile00->data(), TILESIZE));
QVERIFY(memoryIsFilled(oddPixel2, oldTile00->data(), TILESIZE));
tile00 = oldTile00 = 0;
// And the last round: named transaction:
KisMementoSP memento2 = dm.getMemento();
dm.clear(0, 0, 64, 64, &oddPixel3);
tile00 = dm.getTile(0, 0, false);
oldTile00 = dm.getOldTile(0, 0);
QVERIFY(memoryIsFilled(oddPixel3, tile00->data(), TILESIZE));
QVERIFY(memoryIsFilled(oddPixel2, oldTile00->data(), TILESIZE));
tile00 = oldTile00 = 0;
}
void KisTiledDataManagerTest::testPurgeHistory()
{
quint8 defaultPixel = 0;
KisTiledDataManager dm(1, &defaultPixel);
quint8 oddPixel1 = 128;
quint8 oddPixel2 = 129;
quint8 oddPixel3 = 130;
quint8 oddPixel4 = 131;
KisMementoSP memento1 = dm.getMemento();
dm.clear(0, 0, 64, 64, &oddPixel1);
dm.commit();
KisMementoSP memento2 = dm.getMemento();
dm.clear(0, 0, 64, 64, &oddPixel2);
KisTileSP tile00;
KisTileSP oldTile00;
tile00 = dm.getTile(0, 0, false);
oldTile00 = dm.getOldTile(0, 0);
QVERIFY(memoryIsFilled(oddPixel2, tile00->data(), TILESIZE));
QVERIFY(memoryIsFilled(oddPixel1, oldTile00->data(), TILESIZE));
tile00 = oldTile00 = 0;
dm.purgeHistory(memento1);
/**
* Nothing nas changed in the visible state of the data manager
*/
tile00 = dm.getTile(0, 0, false);
oldTile00 = dm.getOldTile(0, 0);
QVERIFY(memoryIsFilled(oddPixel2, tile00->data(), TILESIZE));
QVERIFY(memoryIsFilled(oddPixel1, oldTile00->data(), TILESIZE));
tile00 = oldTile00 = 0;
dm.commit();
dm.purgeHistory(memento2);
/**
* We've removed all the history of the device, so it
* became "unversioned".
* NOTE: the return value for getOldTile() when there is no
* history present is a subject for change
*/
tile00 = dm.getTile(0, 0, false);
oldTile00 = dm.getOldTile(0, 0);
QVERIFY(memoryIsFilled(oddPixel2, tile00->data(), TILESIZE));
QVERIFY(memoryIsFilled(oddPixel2, oldTile00->data(), TILESIZE));
tile00 = oldTile00 = 0;
/**
* Just test we won't crash when the memento is not
* present in history anymore
*/
KisMementoSP memento3 = dm.getMemento();
dm.clear(0, 0, 64, 64, &oddPixel3);
dm.commit();
KisMementoSP memento4 = dm.getMemento();
dm.clear(0, 0, 64, 64, &oddPixel4);
dm.commit();
dm.rollback(memento4);
dm.purgeHistory(memento3);
dm.purgeHistory(memento4);
}
void KisTiledDataManagerTest::testUndoSetDefaultPixel()
{
quint8 defaultPixel = 0;
KisTiledDataManager dm(1, &defaultPixel);
quint8 oddPixel1 = 128;
quint8 oddPixel2 = 129;
QRect fillRect(0,0,64,64);
KisTileSP tile00;
KisTileSP tile10;
tile00 = dm.getTile(0, 0, false);
tile10 = dm.getTile(1, 0, false);
QVERIFY(memoryIsFilled(defaultPixel, tile00->data(), TILESIZE));
QVERIFY(memoryIsFilled(defaultPixel, tile10->data(), TILESIZE));
KisMementoSP memento1 = dm.getMemento();
dm.clear(fillRect, &oddPixel1);
dm.commit();
tile00 = dm.getTile(0, 0, false);
tile10 = dm.getTile(1, 0, false);
QVERIFY(memoryIsFilled(oddPixel1, tile00->data(), TILESIZE));
QVERIFY(memoryIsFilled(defaultPixel, tile10->data(), TILESIZE));
KisMementoSP memento2 = dm.getMemento();
dm.setDefaultPixel(&oddPixel2);
dm.commit();
tile00 = dm.getTile(0, 0, false);
tile10 = dm.getTile(1, 0, false);
QVERIFY(memoryIsFilled(oddPixel1, tile00->data(), TILESIZE));
QVERIFY(memoryIsFilled(oddPixel2, tile10->data(), TILESIZE));
dm.rollback(memento2);
tile00 = dm.getTile(0, 0, false);
tile10 = dm.getTile(1, 0, false);
QVERIFY(memoryIsFilled(oddPixel1, tile00->data(), TILESIZE));
QVERIFY(memoryIsFilled(defaultPixel, tile10->data(), TILESIZE));
dm.rollback(memento1);
tile00 = dm.getTile(0, 0, false);
tile10 = dm.getTile(1, 0, false);
QVERIFY(memoryIsFilled(defaultPixel, tile00->data(), TILESIZE));
QVERIFY(memoryIsFilled(defaultPixel, tile10->data(), TILESIZE));
dm.rollforward(memento1);
tile00 = dm.getTile(0, 0, false);
tile10 = dm.getTile(1, 0, false);
QVERIFY(memoryIsFilled(oddPixel1, tile00->data(), TILESIZE));
QVERIFY(memoryIsFilled(defaultPixel, tile10->data(), TILESIZE));
dm.rollforward(memento2);
tile00 = dm.getTile(0, 0, false);
tile10 = dm.getTile(1, 0, false);
QVERIFY(memoryIsFilled(oddPixel1, tile00->data(), TILESIZE));
QVERIFY(memoryIsFilled(oddPixel2, tile10->data(), TILESIZE));
}
//#include <valgrind/callgrind.h>
void KisTiledDataManagerTest::benchmarkReadOnlyTileLazy()
{
quint8 defaultPixel = 0;
KisTiledDataManager dm(1, &defaultPixel);
/*
* See KisTileHashTableTraits2 for more details
*/
const qint32 numTilesToTest = 0x7fff;
//CALLGRIND_START_INSTRUMENTATION;
QBENCHMARK_ONCE {
for(qint32 i = 0; i < numTilesToTest; i++) {
KisTileSP tile = dm.getTile(i, i, false);
}
}
//CALLGRIND_STOP_INSTRUMENTATION;
}
class KisSimpleClass : public KisShared
{
qint64 m_int;
public:
KisSimpleClass() {
Q_UNUSED(m_int);
}
};
typedef KisSharedPtr<KisSimpleClass> KisSimpleClassSP;
void KisTiledDataManagerTest::benchmarkSharedPointers()
{
const qint32 numIterations = 2 * 1000000;
//CALLGRIND_START_INSTRUMENTATION;
QBENCHMARK_ONCE {
for(qint32 i = 0; i < numIterations; i++) {
KisSimpleClassSP pointer = new KisSimpleClass;
pointer = 0;
}
}
//CALLGRIND_STOP_INSTRUMENTATION;
}
void KisTiledDataManagerTest::benchmarkCOWImpl()
{
const int pixelSize = 8;
quint8 defaultPixel[pixelSize];
memset(defaultPixel, 1, pixelSize);
KisTiledDataManager dm(pixelSize, defaultPixel);
KisMementoSP memento1 = dm.getMemento();
/**
* Imagine a regular image of 4096x2048 pixels
* (64x32 tiles)
*/
for (int i = 0; i < 32; i++) {
for (int j = 0; j < 64; j++) {
KisTileSP tile = dm.getTile(j, i, true);
tile->lockForWrite();
tile->unlockForWrite();
}
}
dm.commit();
QTest::qSleep(200);
KisMementoSP memento2 = dm.getMemento();
QTest::qSleep(200);
QBENCHMARK_ONCE {
for (int i = 0; i < 32; i++) {
for (int j = 0; j < 64; j++) {
KisTileSP tile = dm.getTile(j, i, true);
tile->lockForWrite();
tile->unlockForWrite();
}
}
}
dm.commit();
}
void KisTiledDataManagerTest::benchmarkCOWNoPooler()
{
KisTileDataStore::instance()->testingSuspendPooler();
QTest::qSleep(200);
benchmarkCOWImpl();
KisTileDataStore::instance()->testingResumePooler();
QTest::qSleep(200);
}
void KisTiledDataManagerTest::benchmarkCOWWithPooler()
{
benchmarkCOWImpl();
}
/******************* Stress job ***********************/
#ifdef LIMIT_LONG_TESTS
#define NUM_CYCLES 10000
#else
#define NUM_CYCLES 100000
#endif
#define NUM_TYPES 12
#define TILE_DIMENSION 64
/**
* The data manager has partial guarantees of reentrancy. That is
* you can call any arbitrary number of methods concurrently as long
* as their access areas do not intersect.
*
* Though the rule can be quite tricky -- some of the methods always
* use entire image as their access area, so they cannot be called
* concurrently in any circumstances.
* The examples are: clear(), commit(), rollback() and etc...
*/
#define run_exclusive(lock, _i) for(_i = 0, (lock).lockForWrite(); _i < 1; _i++, (lock).unlock())
#define run_concurrent(lock, _i) for(_i = 0, (lock).lockForRead(); _i < 1; _i++, (lock).unlock())
//#define run_exclusive(lock, _i) while(0)
//#define run_concurrent(lock, _i) while(0)
class KisStressJob : public QRunnable
{
public:
KisStressJob(KisTiledDataManager &dataManager, QRect rect, QReadWriteLock &_lock)
: m_accessRect(rect), dm(dataManager), lock(_lock)
{
}
void run() override {
qsrand(QTime::currentTime().msec());
for(qint32 i = 0; i < NUM_CYCLES; i++) {
qint32 type = qrand() % NUM_TYPES;
qint32 t;
switch(type) {
case 0:
run_concurrent(lock,t) {
quint8 *buf;
buf = new quint8[dm.pixelSize()];
memcpy(buf, dm.defaultPixel(), dm.pixelSize());
dm.setDefaultPixel(buf);
delete[] buf;
}
break;
case 1:
case 2:
run_concurrent(lock,t) {
KisTileSP tile;
tile = dm.getTile(m_accessRect.x() / TILE_DIMENSION,
m_accessRect.y() / TILE_DIMENSION, false);
tile->lockForRead();
tile->unlockForRead();
tile = dm.getTile(m_accessRect.x() / TILE_DIMENSION,
m_accessRect.y() / TILE_DIMENSION, true);
tile->lockForWrite();
tile->unlockForWrite();
tile = dm.getOldTile(m_accessRect.x() / TILE_DIMENSION,
m_accessRect.y() / TILE_DIMENSION);
tile->lockForRead();
tile->unlockForRead();
}
break;
case 3:
run_concurrent(lock,t) {
QRect newRect = dm.extent();
Q_UNUSED(newRect);
}
break;
case 4:
run_concurrent(lock,t) {
dm.clear(m_accessRect.x(), m_accessRect.y(),
m_accessRect.width(), m_accessRect.height(), 4);
}
break;
case 5:
run_concurrent(lock,t) {
quint8 *buf;
buf = new quint8[m_accessRect.width() * m_accessRect.height() *
dm.pixelSize()];
dm.readBytes(buf, m_accessRect.x(), m_accessRect.y(),
m_accessRect.width(), m_accessRect.height());
dm.writeBytes(buf, m_accessRect.x(), m_accessRect.y(),
m_accessRect.width(), m_accessRect.height());
delete[] buf;
}
break;
case 6:
run_concurrent(lock,t) {
quint8 oddPixel = 13;
KisTiledDataManager srcDM(1, &oddPixel);
dm.bitBlt(&srcDM, m_accessRect);
}
break;
case 7:
case 8:
run_exclusive(lock,t) {
m_memento = dm.getMemento();
dm.clear(m_accessRect.x(), m_accessRect.y(),
m_accessRect.width(), m_accessRect.height(), 2);
dm.commit();
dm.rollback(m_memento);
dm.rollforward(m_memento);
dm.purgeHistory(m_memento);
m_memento = 0;
}
break;
case 9:
run_exclusive(lock,t) {
bool b = dm.hasCurrentMemento();
Q_UNUSED(b);
}
break;
case 10:
run_exclusive(lock,t) {
dm.clear();
}
break;
case 11:
run_exclusive(lock,t) {
dm.setExtent(m_accessRect);
}
break;
}
}
}
private:
KisMementoSP m_memento;
QRect m_accessRect;
KisTiledDataManager &dm;
QReadWriteLock &lock;
};
void KisTiledDataManagerTest::stressTest()
{
quint8 defaultPixel = 0;
KisTiledDataManager dm(1, &defaultPixel);
QReadWriteLock lock;
#ifdef LIMIT_LONG_TESTS
const int numThreads = 8;
const int numWorkers = 8;
#else
const int numThreads = 16;
const int numWorkers = 48;
#endif
QThreadPool pool;
pool.setMaxThreadCount(numThreads);
QRect accessRect(0,0,512,512);
for(qint32 i = 0; i < numWorkers; i++) {
KisStressJob *job = new KisStressJob(dm, accessRect, lock);
pool.start(job);
accessRect.translate(512, 0);
}
pool.waitForDone();
}
template <typename Func>
void applyToRect(const QRect &rc, Func func) {
for (int y = rc.y(); y < rc.y() + rc.height(); y += KisTileData::HEIGHT) {
for (int x = rc.x(); x < rc.x() + rc.width(); x += KisTileData::WIDTH) {
const int col = x / KisTileData::WIDTH;
const int row = y / KisTileData::HEIGHT;
func(col, row);
}
}
}
class LazyCopyingStressJob : public QRunnable
{
public:
LazyCopyingStressJob(KisTiledDataManager &dataManager,
const QRect &rect,
QReadWriteLock &dmExclusiveLock,
QReadWriteLock &tileExclusiveLock,
int numCycles,
bool isWriter)
: m_accessRect(rect),
dm(dataManager),
m_dmExclusiveLock(dmExclusiveLock),
m_tileExclusiveLock(tileExclusiveLock),
m_numCycles(numCycles),
m_isWriter(isWriter)
{
}
void run() override {
for(qint32 i = 0; i < m_numCycles; i++) {
//const int epoch = i % 100;
int t;
if (m_isWriter && 0) {
} else {
const bool shouldClear = i % 5 <= 1; // 40% of requests are clears
const bool shouldWrite = i % 5 <= 3; // other 40% of requests are writes
run_concurrent(m_dmExclusiveLock, t) {
if (shouldClear) {
QWriteLocker locker(&m_tileExclusiveLock);
dm.clear(m_accessRect, 4);
} else {
auto readFunc = [this] (int col, int row) {
KisTileSP tile = dm.getTile(col, row, false);
tile->lockForRead();
tile->unlockForRead();
};
auto writeFunc = [this] (int col, int row) {
KisTileSP tile = dm.getTile(col, row, true);
tile->lockForWrite();
tile->unlockForWrite();
};
auto readOldFunc = [this] (int col, int row) {
KisTileSP tile = dm.getOldTile(col, row);
tile->lockForRead();
tile->unlockForRead();
};
applyToRect(m_accessRect, readFunc);
if (shouldWrite) {
QReadLocker locker(&m_tileExclusiveLock);
applyToRect(m_accessRect, writeFunc);
}
applyToRect(m_accessRect, readOldFunc);
}
}
}
}
}
private:
KisMementoSP m_memento;
QRect m_accessRect;
KisTiledDataManager &dm;
QReadWriteLock &m_dmExclusiveLock;
QReadWriteLock &m_tileExclusiveLock;
const int m_numCycles;
const bool m_isWriter;
};
void KisTiledDataManagerTest::stressTestLazyCopying()
{
quint8 defaultPixel = 0;
KisTiledDataManager dm(1, &defaultPixel);
QReadWriteLock dmLock;
QReadWriteLock tileLock;
#ifdef LIMIT_LONG_TESTS
const int numCycles = 10000;
const int numThreads = 8;
const int numWorkers = 8;
#else
const int numThreads = 16;
const int numWorkers = 32;
const int numCycles = 100000;
#endif
QThreadPool pool;
pool.setMaxThreadCount(numThreads);
const QRect accessRect(0,0,512,256);
for(qint32 i = 0; i < numWorkers; i++) {
const bool isWriter = i == 0;
LazyCopyingStressJob *job = new LazyCopyingStressJob(dm, accessRect,
dmLock, tileLock,
numCycles, isWriter);
pool.start(job);
}
pool.waitForDone();
}
void KisTiledDataManagerTest::stressTestExtentsColumn()
{
KisTiledExtentManager::Data column;
struct Job : public QRunnable
{
Job(KisTiledExtentManager::Data &column, int index, int numCycles)
: m_column(column), m_index(index), m_numCycles(numCycles) {}
void run() override {
for(qint32 i = 0; i < m_numCycles; i++) {
if (!m_isCreated) {
m_column.add(m_index);
KIS_SAFE_ASSERT_RECOVER_NOOP(m_column.max() >= m_index);
KIS_SAFE_ASSERT_RECOVER_NOOP(m_column.min() <= m_index);
} else {
m_column.remove(m_index);
}
m_isCreated = !m_isCreated;
}
}
KisTiledExtentManager::Data &m_column;
const int m_index;
const int m_numCycles;
bool m_isCreated = false;
};
#ifdef LIMIT_LONG_TESTS
const int numThreads = 8;
const int numWorkers = 32;
const int numCycles = 10000;
#else
const int numThreads = 16;
const int numWorkers = 32;
const int numCycles = 100000;
#endif
QThreadPool pool;
pool.setMaxThreadCount(numThreads);
for(qint32 i = 0; i < numWorkers; i++) {
const int index = 18 + i / 13;
pool.start(new Job(column, index, numCycles));
}
pool.waitForDone();
QVERIFY(column.isEmpty());
QVERIFY(column.max() < column.min()); // really empty :)
}
void KisTiledDataManagerTest::benchmaskQRegion()
{
QVector<QRect> rects;
int poison = 0;
for (int y = 0; y < 8000; y += 64) {
for (int x = 0; x < 8000; x += 64) {
if (poison++ % 7 == 0) continue;
rects << QRect(x, y, 64, 64);
}
}
std::random_shuffle(rects.begin(), rects.end());
QElapsedTimer timer;
timer.start();
QRegion region;
Q_FOREACH (const QRect &rc, rects) {
region += rc;
}
qDebug() << "compressed rects:" << ppVar(rects.size()) << "-->" << ppVar(region.rectCount());
qDebug() << "compression time:" << timer.elapsed() << "ms";
}
#include "KisRegion.h"
void KisTiledDataManagerTest::benchmaskKisRegion()
{
QVector<QRect> rects;
int poison = 0;
for (int y = 0; y < 8000; y += 64) {
for (int x = 0; x < 8000; x += 64) {
if (poison++ % 7 == 0) continue;
rects << QRect(x, y, 64, 64);
}
}
std::random_shuffle(rects.begin(), rects.end());
QElapsedTimer timer;
timer.start();
auto endIt = KisRegion::mergeSparseRects(rects.begin(), rects.end());
qDebug() << "compressed rects:" << ppVar(rects.size()) << "-->" << ppVar(std::distance(rects.begin(), endIt));
qDebug() << "compression time:" << timer.elapsed() << "ms";
}
+inline bool findPoint (const QPoint &pt, const QVector<QRect> &rects)
+{
+ for (auto it = rects.begin(); it != rects.end(); ++it) {
+ if (it->contains(pt)) return true;
+ }
+
+ return false;
+}
+
+void KisTiledDataManagerTest::benchmaskOverlappedKisRegion()
+{
+ QVector<QRect> rects;
+
+ int poison = 0;
+ for (int y = 0; y < 8000; y += 13) {
+ for (int x = 0; x < 8000; x += 17) {
+ if (poison++ % 7 == 0) continue;
+ rects << QRect(x, y, 13 + (poison % 17) * 7, 17 + (poison % 13) * 7);
+ }
+ }
+
+ const int originalSize = rects.size();
+ QVector<QRect> originalRects = rects;
+
+ std::random_shuffle(rects.begin(), rects.end());
+
+ QElapsedTimer timer;
+ timer.start();
+
+#if 0
+ // speed reference: executes for about 150 seconds! (150000ms)
+ QRegion region;
+ Q_FOREACH (const QRect &rc, rects) {
+ region += rc;
+ }
+#endif
+
+ KisRegion::approximateOverlappingRects(rects, 64);
+
+ qDebug() << "deoverlapped rects:" << ppVar(originalSize) << "-->" << ppVar(rects.size());
+ qDebug() << "deoverlaping time:" << timer.restart() << "ms";
+
+ KisRegion region(rects);
+
+ qDebug() << "compressed rects:" << ppVar(region.rects().size());
+ qDebug() << "compression time:" << timer.restart() << "ms";
+
+ for (auto it1 = rects.begin(); it1 != rects.end(); ++it1) {
+ for (auto it2 = std::next(it1); it2 != rects.end(); ++it2) {
+ QVERIFY(!it1->intersects(*it2));
+ }
+ }
+
+
+#if 0
+ /// very slow sanity check for invariant: "all source rects are
+ /// represented in the deoverlapped set of rects"
+
+ QVector<QRect> comressedRects = region.rects();
+ int i = 0;
+ Q_FOREACH(const QRect &rc, originalRects) {
+ if (i % 1000 == 0) {
+ qDebug() << ppVar(i);
+ }
+
+ for (int y = rc.y(); y <= rc.bottom(); ++y) {
+ for (int x = rc.x(); x <= rc.right(); ++x) {
+ QVERIFY(findPoint(QPoint(x, y), comressedRects));
+ }
+ }
+ i++;
+ }
+#endif
+}
+
QTEST_MAIN(KisTiledDataManagerTest)
diff --git a/libs/image/tiles3/tests/kis_tiled_data_manager_test.h b/libs/image/tiles3/tests/kis_tiled_data_manager_test.h
index 5f03b47cc5..289e330028 100644
--- a/libs/image/tiles3/tests/kis_tiled_data_manager_test.h
+++ b/libs/image/tiles3/tests/kis_tiled_data_manager_test.h
@@ -1,73 +1,74 @@
/*
* Copyright (c) 2010 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KIS_TILED_DATA_MANAGER_TEST_H
#define KIS_TILED_DATA_MANAGER_TEST_H
#include <QtTest>
class KisTiledDataManager;
class KisTiledDataManagerTest : public QObject
{
Q_OBJECT
private:
bool checkHole(quint8* buffer, quint8 holeColor, QRect holeRect,
quint8 backgroundColor, QRect backgroundRect);
bool checkTilesShared(KisTiledDataManager *srcDM,
KisTiledDataManager *dstDM,
bool takeOldSrc, bool takeOldDst,
QRect tilesRect);
bool checkTilesNotShared(KisTiledDataManager *srcDM,
KisTiledDataManager *dstDM,
bool takeOldSrc, bool takeOldDst,
QRect tilesRect);
void benchmarkCOWImpl();
private Q_SLOTS:
void testUndoingNewTiles();
void testPurgedAndEmptyTransactions();
void testUnversionedBitBlt();
void testVersionedBitBlt();
void testBitBltOldData();
void testBitBltRough();
void testTransactions();
void testPurgeHistory();
void testUndoSetDefaultPixel();
void benchmarkReadOnlyTileLazy();
void benchmarkSharedPointers();
void benchmarkCOWNoPooler();
void benchmarkCOWWithPooler();
void stressTest();
void stressTestLazyCopying();
void stressTestExtentsColumn();
void benchmaskQRegion();
void benchmaskKisRegion();
+ void benchmaskOverlappedKisRegion();
};
#endif /* KIS_TILED_DATA_MANAGER_TEST_H */
diff --git a/libs/libkis/CMakeLists.txt b/libs/libkis/CMakeLists.txt
index d69ff46038..958104aaaf 100644
--- a/libs/libkis/CMakeLists.txt
+++ b/libs/libkis/CMakeLists.txt
@@ -1,50 +1,51 @@
set(kritalibkis_LIB_SRCS
Canvas.cpp
Channel.cpp
DockWidget.cpp
DockWidgetFactoryBase.cpp
Document.cpp
Filter.cpp
InfoObject.cpp
Krita.cpp
ManagedColor.cpp
Node.cpp
Notifier.cpp
PresetChooser
Palette.cpp
PaletteView.cpp
+ Scratchpad.cpp
Swatch.cpp
Resource.cpp
Selection.cpp
View.cpp
Extension.cpp
Window.cpp
GroupLayer.cpp
CloneLayer.cpp
FileLayer.cpp
FilterLayer.cpp
FillLayer.cpp
VectorLayer.cpp
FilterMask.cpp
SelectionMask.cpp
Shape.cpp
GroupShape.cpp
LibKisUtils.cpp
)
add_library(kritalibkis SHARED ${kritalibkis_LIB_SRCS} )
generate_export_header(kritalibkis)
target_link_libraries(kritalibkis kritaui kritaimage kritaversion)
target_link_libraries(kritalibkis LINK_INTERFACE_LIBRARIES kritaimage kritaui)
set_target_properties(kritalibkis PROPERTIES
VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION}
)
install(TARGETS kritalibkis ${INSTALL_TARGETS_DEFAULT_ARGS})
add_subdirectory(tests)
diff --git a/libs/libkis/Document.cpp b/libs/libkis/Document.cpp
index c95b38e34e..3257d9cc78 100644
--- a/libs/libkis/Document.cpp
+++ b/libs/libkis/Document.cpp
@@ -1,1010 +1,1026 @@
/*
* Copyright (c) 2016 Boudewijn Rempt <boud@valdyas.org>
*
* This program 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 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 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 "Document.h"
#include <QPointer>
#include <QUrl>
#include <QDomDocument>
#include <KoColorSpaceConstants.h>
#include <KoXmlReader.h>
#include <KisDocument.h>
#include <kis_image.h>
#include <KisPart.h>
#include <kis_paint_device.h>
#include <KisMainWindow.h>
#include <kis_node_manager.h>
#include <kis_node_selection_adapter.h>
#include <KisViewManager.h>
#include <kis_file_layer.h>
#include <kis_adjustment_layer.h>
#include <kis_mask.h>
#include <kis_clone_layer.h>
#include <kis_group_layer.h>
#include <kis_filter_mask.h>
#include <kis_transform_mask.h>
#include <kis_transparency_mask.h>
#include <kis_selection_mask.h>
#include <kis_effect_mask.h>
#include <kis_paint_layer.h>
#include <kis_generator_layer.h>
#include <kis_generator_registry.h>
#include <kis_shape_layer.h>
#include <kis_filter_configuration.h>
#include <kis_filter_registry.h>
#include <kis_selection.h>
#include <KisMimeDatabase.h>
#include <kis_filter_strategy.h>
#include <kis_guides_config.h>
#include <kis_coordinates_converter.h>
#include <kis_time_range.h>
#include <KisImportExportErrorCode.h>
#include <KoColor.h>
#include <KoColorSpace.h>
#include <KoColorProfile.h>
#include <KoColorSpaceRegistry.h>
#include <KoColorConversionTransformation.h>
#include <KoDocumentInfo.h>
#include <KisGlobalResourcesInterface.h>
#include <InfoObject.h>
#include <Node.h>
#include <Selection.h>
#include <LibKisUtils.h>
#include "kis_animation_importer.h"
#include <kis_canvas2.h>
#include <KoUpdater.h>
#include <QMessageBox>
#include <kis_image_animation_interface.h>
struct Document::Private {
Private() {}
QPointer<KisDocument> document;
bool ownsDocument {false};
};
Document::Document(KisDocument *document, bool ownsDocument, QObject *parent)
: QObject(parent)
, d(new Private)
{
d->document = document;
d->ownsDocument = ownsDocument;
}
Document::~Document()
{
if (d->ownsDocument && d->document) {
KisPart::instance()->removeDocument(d->document);
delete d->document;
}
delete d;
}
bool Document::operator==(const Document &other) const
{
return (d->document == other.d->document);
}
bool Document::operator!=(const Document &other) const
{
return !(operator==(other));
}
bool Document::batchmode() const
{
if (!d->document) return false;
return d->document->fileBatchMode();
}
void Document::setBatchmode(bool value)
{
if (!d->document) return;
d->document->setFileBatchMode(value);
}
Node *Document::activeNode() const
{
QList<KisNodeSP> activeNodes;
Q_FOREACH(QPointer<KisView> view, KisPart::instance()->views()) {
if (view && view->document() == d->document) {
activeNodes << view->currentNode();
}
}
if (activeNodes.size() > 0) {
QList<Node*> nodes = LibKisUtils::createNodeList(activeNodes, d->document->image());
return nodes.first();
}
return 0;
}
void Document::setActiveNode(Node* value)
{
if (!value->node()) return;
KisMainWindow *mainWin = KisPart::instance()->currentMainwindow();
if (!mainWin) return;
KisViewManager *viewManager = mainWin->viewManager();
if (!viewManager) return;
if (viewManager->document() != d->document) return;
KisNodeManager *nodeManager = viewManager->nodeManager();
if (!nodeManager) return;
KisNodeSelectionAdapter *selectionAdapter = nodeManager->nodeSelectionAdapter();
if (!selectionAdapter) return;
selectionAdapter->setActiveNode(value->node());
}
QList<Node *> Document::topLevelNodes() const
{
if (!d->document) return QList<Node *>();
Node n(d->document->image(), d->document->image()->rootLayer());
return n.childNodes();
}
Node *Document::nodeByName(const QString &name) const
{
if (!d->document) return 0;
KisNodeSP node = d->document->image()->rootLayer()->findChildByName(name);
if (node.isNull()) return 0;
return Node::createNode(d->document->image(), node);
}
QString Document::colorDepth() const
{
if (!d->document) return "";
return d->document->image()->colorSpace()->colorDepthId().id();
}
QString Document::colorModel() const
{
if (!d->document) return "";
return d->document->image()->colorSpace()->colorModelId().id();
}
QString Document::colorProfile() const
{
if (!d->document) return "";
return d->document->image()->colorSpace()->profile()->name();
}
bool Document::setColorProfile(const QString &value)
{
if (!d->document) return false;
if (!d->document->image()) return false;
const KoColorProfile *profile = KoColorSpaceRegistry::instance()->profileByName(value);
if (!profile) return false;
bool retval = d->document->image()->assignImageProfile(profile);
d->document->image()->waitForDone();
return retval;
}
bool Document::setColorSpace(const QString &colorModel, const QString &colorDepth, const QString &colorProfile)
{
if (!d->document) return false;
if (!d->document->image()) return false;
const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorModel, colorDepth, colorProfile);
if (!colorSpace) return false;
d->document->image()->convertImageColorSpace(colorSpace,
KoColorConversionTransformation::IntentPerceptual,
KoColorConversionTransformation::HighQuality | KoColorConversionTransformation::NoOptimization);
d->document->image()->waitForDone();
return true;
}
QColor Document::backgroundColor()
{
if (!d->document) return QColor();
if (!d->document->image()) return QColor();
const KoColor color = d->document->image()->defaultProjectionColor();
return color.toQColor();
}
bool Document::setBackgroundColor(const QColor &color)
{
if (!d->document) return false;
if (!d->document->image()) return false;
KoColor background = KoColor(color, d->document->image()->colorSpace());
d->document->image()->setDefaultProjectionColor(background);
d->document->image()->setModified();
d->document->image()->initialRefreshGraph();
return true;
}
QString Document::documentInfo() const
{
QDomDocument doc = KisDocument::createDomDocument("document-info"
/*DTD name*/, "document-info" /*tag name*/, "1.1");
doc = d->document->documentInfo()->save(doc);
return doc.toString();
}
void Document::setDocumentInfo(const QString &document)
{
KoXmlDocument doc;
QString errorMsg;
int errorLine, errorColumn;
doc.setContent(document, &errorMsg, &errorLine, &errorColumn);
d->document->documentInfo()->load(doc);
}
QString Document::fileName() const
{
if (!d->document) return QString();
return d->document->url().toLocalFile();
}
void Document::setFileName(QString value)
{
if (!d->document) return;
QString mimeType = KisMimeDatabase::mimeTypeForFile(value, false);
d->document->setMimeType(mimeType.toLatin1());
d->document->setUrl(QUrl::fromLocalFile(value));
}
int Document::height() const
{
if (!d->document) return 0;
KisImageSP image = d->document->image();
if (!image) return 0;
return image->height();
}
void Document::setHeight(int value)
{
if (!d->document) return;
if (!d->document->image()) return;
resizeImage(d->document->image()->bounds().x(),
d->document->image()->bounds().y(),
d->document->image()->width(),
value);
}
QString Document::name() const
{
if (!d->document) return "";
return d->document->documentInfo()->aboutInfo("title");
}
void Document::setName(QString value)
{
if (!d->document) return;
d->document->documentInfo()->setAboutInfo("title", value);
}
int Document::resolution() const
{
if (!d->document) return 0;
KisImageSP image = d->document->image();
if (!image) return 0;
return qRound(d->document->image()->xRes() * 72);
}
void Document::setResolution(int value)
{
if (!d->document) return;
KisImageSP image = d->document->image();
if (!image) return;
- d->document->image()->setResolution(value / 72.0, value / 72.0);
+ KisFilterStrategy *strategy = KisFilterStrategyRegistry::instance()->get("Bicubic");
+ KIS_SAFE_ASSERT_RECOVER_RETURN(strategy);
+
+ image->scaleImage(image->size(), value / 72.0, value / 72.0, strategy);
+ image->waitForDone();
}
Node *Document::rootNode() const
{
if (!d->document) return 0;
KisImageSP image = d->document->image();
if (!image) return 0;
return Node::createNode(image, image->root());
}
Selection *Document::selection() const
{
if (!d->document) return 0;
if (!d->document->image()) return 0;
if (!d->document->image()->globalSelection()) return 0;
return new Selection(d->document->image()->globalSelection());
}
void Document::setSelection(Selection* value)
{
if (!d->document) return;
if (!d->document->image()) return;
if (value) {
d->document->image()->setGlobalSelection(value->selection());
}
else {
d->document->image()->setGlobalSelection(0);
}
}
int Document::width() const
{
if (!d->document) return 0;
KisImageSP image = d->document->image();
if (!image) return 0;
return image->width();
}
void Document::setWidth(int value)
{
if (!d->document) return;
if (!d->document->image()) return;
resizeImage(d->document->image()->bounds().x(),
d->document->image()->bounds().y(),
value,
d->document->image()->height());
}
int Document::xOffset() const
{
if (!d->document) return 0;
KisImageSP image = d->document->image();
if (!image) return 0;
return image->bounds().x();
}
void Document::setXOffset(int x)
{
if (!d->document) return;
if (!d->document->image()) return;
resizeImage(x,
d->document->image()->bounds().y(),
d->document->image()->width(),
d->document->image()->height());
}
int Document::yOffset() const
{
if (!d->document) return 0;
KisImageSP image = d->document->image();
if (!image) return 0;
return image->bounds().y();
}
void Document::setYOffset(int y)
{
if (!d->document) return;
if (!d->document->image()) return;
resizeImage(d->document->image()->bounds().x(),
y,
d->document->image()->width(),
d->document->image()->height());
}
double Document::xRes() const
{
if (!d->document) return 0.0;
if (!d->document->image()) return 0.0;
return d->document->image()->xRes()*72.0;
}
void Document::setXRes(double xRes) const
{
if (!d->document) return;
- if (!d->document->image()) return;
- d->document->image()->setResolution(xRes/72.0, d->document->image()->yRes());
+ KisImageSP image = d->document->image();
+ if (!image) return;
+
+ KisFilterStrategy *strategy = KisFilterStrategyRegistry::instance()->get("Bicubic");
+ KIS_SAFE_ASSERT_RECOVER_RETURN(strategy);
+
+ image->scaleImage(image->size(), xRes / 72.0, image->yRes(), strategy);
+ image->waitForDone();
}
double Document::yRes() const
{
if (!d->document) return 0.0;
if (!d->document->image()) return 0.0;
return d->document->image()->yRes()*72.0;
}
void Document::setYRes(double yRes) const
{
if (!d->document) return;
- if (!d->document->image()) return;
- d->document->image()->setResolution(d->document->image()->xRes(), yRes/72.0);
+ KisImageSP image = d->document->image();
+ if (!image) return;
+
+ KisFilterStrategy *strategy = KisFilterStrategyRegistry::instance()->get("Bicubic");
+ KIS_SAFE_ASSERT_RECOVER_RETURN(strategy);
+
+ image->scaleImage(image->size(), image->xRes(), yRes / 72.0, strategy);
+ image->waitForDone();
}
QByteArray Document::pixelData(int x, int y, int w, int h) const
{
QByteArray ba;
if (!d->document) return ba;
KisImageSP image = d->document->image();
if (!image) return ba;
KisPaintDeviceSP dev = image->projection();
ba.resize(w * h * dev->pixelSize());
dev->readBytes(reinterpret_cast<quint8*>(ba.data()), x, y, w, h);
return ba;
}
bool Document::close()
{
bool retval = d->document->closeUrl(false);
Q_FOREACH(KisView *view, KisPart::instance()->views()) {
if (view->document() == d->document) {
view->close();
view->closeView();
view->deleteLater();
}
}
KisPart::instance()->removeDocument(d->document, !d->ownsDocument);
if (d->ownsDocument) {
delete d->document;
}
d->document = 0;
return retval;
}
void Document::crop(int x, int y, int w, int h)
{
if (!d->document) return;
KisImageSP image = d->document->image();
if (!image) return;
QRect rc(x, y, w, h);
image->cropImage(rc);
image->waitForDone();
}
bool Document::exportImage(const QString &filename, const InfoObject &exportConfiguration)
{
if (!d->document) return false;
const QString outputFormatString = KisMimeDatabase::mimeTypeForFile(filename, false);
const QByteArray outputFormat = outputFormatString.toLatin1();
return d->document->exportDocumentSync(QUrl::fromLocalFile(filename), outputFormat, exportConfiguration.configuration());
}
void Document::flatten()
{
if (!d->document) return;
if (!d->document->image()) return;
d->document->image()->flatten(0);
d->document->image()->waitForDone();
}
void Document::resizeImage(int x, int y, int w, int h)
{
if (!d->document) return;
KisImageSP image = d->document->image();
if (!image) return;
QRect rc;
rc.setX(x);
rc.setY(y);
rc.setWidth(w);
rc.setHeight(h);
image->resizeImage(rc);
image->waitForDone();
}
void Document::scaleImage(int w, int h, int xres, int yres, QString strategy)
{
if (!d->document) return;
KisImageSP image = d->document->image();
if (!image) return;
QRect rc = image->bounds();
rc.setWidth(w);
rc.setHeight(h);
KisFilterStrategy *actualStrategy = KisFilterStrategyRegistry::instance()->get(strategy);
if (!actualStrategy) actualStrategy = KisFilterStrategyRegistry::instance()->get("Bicubic");
image->scaleImage(rc.size(), xres/72, yres/72, actualStrategy);
image->waitForDone();
}
void Document::rotateImage(double radians)
{
if (!d->document) return;
KisImageSP image = d->document->image();
if (!image) return;
image->rotateImage(radians);
image->waitForDone();
}
void Document::shearImage(double angleX, double angleY)
{
if (!d->document) return;
KisImageSP image = d->document->image();
if (!image) return;
image->shear(angleX, angleY);
image->waitForDone();
}
bool Document::save()
{
if (!d->document) return false;
if (d->document->url().isEmpty()) return false;
bool retval = d->document->save(true, 0);
d->document->waitForSavingToComplete();
return retval;
}
bool Document::saveAs(const QString &filename)
{
if (!d->document) return false;
const QString outputFormatString = KisMimeDatabase::mimeTypeForFile(filename, false);
const QByteArray outputFormat = outputFormatString.toLatin1();
QUrl oldUrl = d->document->url();
d->document->setUrl(QUrl::fromLocalFile(filename));
bool retval = d->document->saveAs(QUrl::fromLocalFile(filename), outputFormat, true);
d->document->waitForSavingToComplete();
d->document->setUrl(oldUrl);
return retval;
}
Node* Document::createNode(const QString &name, const QString &nodeType)
{
if (!d->document) return 0;
if (!d->document->image()) return 0;
KisImageSP image = d->document->image();
Node *node = 0;
if (nodeType.toLower()== "paintlayer") {
node = new Node(image, new KisPaintLayer(image, name, OPACITY_OPAQUE_U8));
}
else if (nodeType.toLower() == "grouplayer") {
node = new Node(image, new KisGroupLayer(image, name, OPACITY_OPAQUE_U8));
}
else if (nodeType.toLower() == "filelayer") {
node = new Node(image, new KisFileLayer(image, name, OPACITY_OPAQUE_U8));
}
else if (nodeType.toLower() == "filterlayer") {
node = new Node(image, new KisAdjustmentLayer(image, name, 0, 0));
}
else if (nodeType.toLower() == "filllayer") {
node = new Node(image, new KisGeneratorLayer(image, name, 0, 0));
}
else if (nodeType.toLower() == "clonelayer") {
node = new Node(image, new KisCloneLayer(0, image, name, OPACITY_OPAQUE_U8));
}
else if (nodeType.toLower() == "vectorlayer") {
node = new Node(image, new KisShapeLayer(d->document->shapeController(), image, name, OPACITY_OPAQUE_U8));
}
else if (nodeType.toLower() == "transparencymask") {
node = new Node(image, new KisTransparencyMask(name));
}
else if (nodeType.toLower() == "filtermask") {
node = new Node(image, new KisFilterMask(name));
}
else if (nodeType.toLower() == "transformmask") {
node = new Node(image, new KisTransformMask(name));
}
else if (nodeType.toLower() == "selectionmask") {
node = new Node(image, new KisSelectionMask(image, name));
}
return node;
}
GroupLayer *Document::createGroupLayer(const QString &name)
{
if (!d->document) return 0;
if (!d->document->image()) return 0;
KisImageSP image = d->document->image();
return new GroupLayer(image, name);
}
FileLayer *Document::createFileLayer(const QString &name, const QString fileName, const QString scalingMethod)
{
if (!d->document) return 0;
if (!d->document->image()) return 0;
KisImageSP image = d->document->image();
return new FileLayer(image, name, this->fileName(), fileName, scalingMethod);
}
FilterLayer *Document::createFilterLayer(const QString &name, Filter &filter, Selection &selection)
{
if (!d->document) return 0;
if (!d->document->image()) return 0;
KisImageSP image = d->document->image();
return new FilterLayer(image, name, filter, selection);
}
FillLayer *Document::createFillLayer(const QString &name, const QString generatorName, InfoObject &configuration, Selection &selection)
{
if (!d->document) return 0;
if (!d->document->image()) return 0;
KisImageSP image = d->document->image();
KisGeneratorSP generator = KisGeneratorRegistry::instance()->value(generatorName);
if (generator) {
KisFilterConfigurationSP config = generator->factoryConfiguration(KisGlobalResourcesInterface::instance());
Q_FOREACH(const QString property, configuration.properties().keys()) {
config->setProperty(property, configuration.property(property));
}
return new FillLayer(image, name, config, selection);
}
return 0;
}
CloneLayer *Document::createCloneLayer(const QString &name, const Node *source)
{
if (!d->document) return 0;
if (!d->document->image()) return 0;
KisImageSP image = d->document->image();
KisLayerSP layer = qobject_cast<KisLayer*>(source->node().data());
return new CloneLayer(image, name, layer);
}
VectorLayer *Document::createVectorLayer(const QString &name)
{
if (!d->document) return 0;
if (!d->document->image()) return 0;
KisImageSP image = d->document->image();
return new VectorLayer(d->document->shapeController(), image, name);
}
FilterMask *Document::createFilterMask(const QString &name, Filter &filter, const Node *selection_source)
{
if (!d->document)
return 0;
if (!d->document->image())
return 0;
if(!selection_source)
return 0;
KisLayerSP layer = qobject_cast<KisLayer*>(selection_source->node().data());
if(layer.isNull())
return 0;
KisImageSP image = d->document->image();
FilterMask* mask = new FilterMask(image, name, filter);
qobject_cast<KisMask*>(mask->node().data())->initSelection(layer);
return mask;
}
FilterMask *Document::createFilterMask(const QString &name, Filter &filter, Selection &selection)
{
if (!d->document)
return 0;
if (!d->document->image())
return 0;
KisImageSP image = d->document->image();
FilterMask* mask = new FilterMask(image, name, filter);
qobject_cast<KisMask*>(mask->node().data())->setSelection(selection.selection());
return mask;
}
SelectionMask *Document::createSelectionMask(const QString &name)
{
if (!d->document) return 0;
if (!d->document->image()) return 0;
KisImageSP image = d->document->image();
return new SelectionMask(image, name);
}
QImage Document::projection(int x, int y, int w, int h) const
{
if (!d->document || !d->document->image()) return QImage();
return d->document->image()->convertToQImage(x, y, w, h, 0);
}
QImage Document::thumbnail(int w, int h) const
{
if (!d->document || !d->document->image()) return QImage();
return d->document->generatePreview(QSize(w, h)).toImage();
}
void Document::lock()
{
if (!d->document || !d->document->image()) return;
d->document->image()->barrierLock();
}
void Document::unlock()
{
if (!d->document || !d->document->image()) return;
d->document->image()->unlock();
}
void Document::waitForDone()
{
if (!d->document || !d->document->image()) return;
d->document->image()->waitForDone();
}
bool Document::tryBarrierLock()
{
if (!d->document || !d->document->image()) return false;
return d->document->image()->tryBarrierLock();
}
void Document::refreshProjection()
{
if (!d->document || !d->document->image()) return;
d->document->image()->refreshGraph();
}
QList<qreal> Document::horizontalGuides() const
{
QList<qreal> lines;
if (!d->document || !d->document->image()) return lines;
KisCoordinatesConverter converter;
converter.setImage(d->document->image());
QTransform transform = converter.imageToDocumentTransform().inverted();
QList<qreal> untransformedLines = d->document->guidesConfig().horizontalGuideLines();
for (int i = 0; i< untransformedLines.size(); i++) {
qreal line = untransformedLines[i];
lines.append(transform.map(QPointF(line, line)).x());
}
return lines;
}
QList<qreal> Document::verticalGuides() const
{
QList<qreal> lines;
if (!d->document || !d->document->image()) return lines;
KisCoordinatesConverter converter;
converter.setImage(d->document->image());
QTransform transform = converter.imageToDocumentTransform().inverted();
QList<qreal> untransformedLines = d->document->guidesConfig().verticalGuideLines();
for (int i = 0; i< untransformedLines.size(); i++) {
qreal line = untransformedLines[i];
lines.append(transform.map(QPointF(line, line)).y());
}
return lines;
}
bool Document::guidesVisible() const
{
return d->document->guidesConfig().showGuides();
}
bool Document::guidesLocked() const
{
return d->document->guidesConfig().lockGuides();
}
Document *Document::clone() const
{
if (!d->document) return 0;
QPointer<KisDocument> clone = d->document->clone();
Document * newDocument = new Document(clone, d->ownsDocument);
clone->setParent(newDocument); // It's owned by the document, not KisPart
return newDocument;
}
void Document::setHorizontalGuides(const QList<qreal> &lines)
{
if (!d->document) return;
KisGuidesConfig config = d->document->guidesConfig();
KisCoordinatesConverter converter;
converter.setImage(d->document->image());
QTransform transform = converter.imageToDocumentTransform();
QList<qreal> transformedLines;
for (int i = 0; i< lines.size(); i++) {
qreal line = lines[i];
transformedLines.append(transform.map(QPointF(line, line)).x());
}
config.setHorizontalGuideLines(transformedLines);
d->document->setGuidesConfig(config);
}
void Document::setVerticalGuides(const QList<qreal> &lines)
{
if (!d->document) return;
KisGuidesConfig config = d->document->guidesConfig();
KisCoordinatesConverter converter;
converter.setImage(d->document->image());
QTransform transform = converter.imageToDocumentTransform();
QList<qreal> transformedLines;
for (int i = 0; i< lines.size(); i++) {
qreal line = lines[i];
transformedLines.append(transform.map(QPointF(line, line)).y());
}
config.setVerticalGuideLines(transformedLines);
d->document->setGuidesConfig(config);
}
void Document::setGuidesVisible(bool visible)
{
if (!d->document) return;
KisGuidesConfig config = d->document->guidesConfig();
config.setShowGuides(visible);
d->document->setGuidesConfig(config);
}
void Document::setGuidesLocked(bool locked)
{
if (!d->document) return;
KisGuidesConfig config = d->document->guidesConfig();
config.setLockGuides(locked);
d->document->setGuidesConfig(config);
}
bool Document::modified() const
{
if (!d->document) return false;
return d->document->isModified();
}
QRect Document::bounds() const
{
if (!d->document) return QRect();
return d->document->image()->bounds();
}
QPointer<KisDocument> Document::document() const
{
return d->document;
}
void Document::setOwnsDocument(bool ownsDocument)
{
d->ownsDocument = ownsDocument;
}
/* Animation related function */
bool Document::importAnimation(const QList<QString> &files, int firstFrame, int step)
{
KisView *activeView = KisPart::instance()->currentMainwindow()->activeView();
KoUpdaterPtr updater = 0;
if (activeView && d->document->fileBatchMode()) {
updater = activeView->viewManager()->createUnthreadedUpdater(i18n("Import frames"));
}
KisAnimationImporter importer(d->document->image(), updater);
KisImportExportErrorCode status = importer.import(files, firstFrame, step);
return status.isOk();
}
int Document::framesPerSecond()
{
if (!d->document) return false;
if (!d->document->image()) return false;
return d->document->image()->animationInterface()->framerate();
}
void Document::setFramesPerSecond(int fps)
{
if (!d->document) return;
if (!d->document->image()) return;
d->document->image()->animationInterface()->setFramerate(fps);
}
void Document::setFullClipRangeStartTime(int startTime)
{
if (!d->document) return;
if (!d->document->image()) return;
d->document->image()->animationInterface()->setFullClipRangeStartTime(startTime);
}
int Document::fullClipRangeStartTime()
{
if (!d->document) return false;
if (!d->document->image()) return false;
return d->document->image()->animationInterface()->fullClipRange().start();
}
void Document::setFullClipRangeEndTime(int endTime)
{
if (!d->document) return;
if (!d->document->image()) return;
d->document->image()->animationInterface()->setFullClipRangeEndTime(endTime);
}
int Document::fullClipRangeEndTime()
{
if (!d->document) return false;
if (!d->document->image()) return false;
return d->document->image()->animationInterface()->fullClipRange().end();
}
int Document::animationLength()
{
if (!d->document) return false;
if (!d->document->image()) return false;
return d->document->image()->animationInterface()->totalLength();
}
void Document::setPlayBackRange(int start, int stop)
{
if (!d->document) return;
if (!d->document->image()) return;
const KisTimeRange newTimeRange = KisTimeRange(start, (stop-start));
d->document->image()->animationInterface()->setPlaybackRange(newTimeRange);
}
int Document::playBackStartTime()
{
if (!d->document) return false;
if (!d->document->image()) return false;
return d->document->image()->animationInterface()->playbackRange().start();
}
int Document::playBackEndTime()
{
if (!d->document) return false;
if (!d->document->image()) return false;
return d->document->image()->animationInterface()->playbackRange().end();
}
int Document::currentTime()
{
if (!d->document) return false;
if (!d->document->image()) return false;
return d->document->image()->animationInterface()->currentTime();
}
void Document::setCurrentTime(int time)
{
if (!d->document) return;
if (!d->document->image()) return;
return d->document->image()->animationInterface()->requestTimeSwitchWithUndo(time);
}
diff --git a/libs/libkis/Scratchpad.cpp b/libs/libkis/Scratchpad.cpp
new file mode 100644
index 0000000000..a900d2b718
--- /dev/null
+++ b/libs/libkis/Scratchpad.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2020 Scott Petrovic <scottpetrovic@gmail.com>
+ *
+ * This program 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 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 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 "Scratchpad.h"
+#include <KoResource.h>
+#include <kis_config.h>
+#include "kis_scratch_pad.h"
+#include "Resource.h"
+#include "View.h"
+#include "Canvas.h"
+#include <KoCanvasBase.h>
+#include <kis_canvas2.h>
+
+#include <QColor>
+
+Scratchpad::Scratchpad(View *view, const QColor & defaultColor, QWidget *parent)
+ : KisScratchPad(parent)
+{
+ KisScratchPad::setupScratchPad(view->view()->resourceProvider(), defaultColor);
+ KisScratchPad::setMinimumSize(50, 50);
+}
+
+Scratchpad::~Scratchpad()
+{
+}
+
+void Scratchpad::setModeManually(bool value)
+{
+ KisScratchPad::setModeManually(value);
+}
+
+void Scratchpad::setMode(QString modeType)
+{
+ KisScratchPad::setModeType(modeType);
+}
+
+void Scratchpad::loadScratchpad(QImage image)
+{
+ KisScratchPad::loadScratchpadImage(image);
+}
+
+QImage Scratchpad::copyScratchPadImage()
+{
+ return KisScratchPad::copyScratchpadImageData();
+}
+
+void Scratchpad::clear()
+{
+ // need ability to set color
+ KisScratchPad::fillDefault();
+}
+
+void Scratchpad::setFillColor(QColor color)
+{
+ KisScratchPad::setFillColor(color);
+}
diff --git a/libs/libkis/Scratchpad.h b/libs/libkis/Scratchpad.h
new file mode 100644
index 0000000000..96c79e3fb2
--- /dev/null
+++ b/libs/libkis/Scratchpad.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2020 Scott Petrovic <scottpetrovic@gmail.com>
+ *
+ * This program 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 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 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 LIBKIS_SCRATCHPAD_H
+#define LIBKIS_SCRATCHPAD_H
+
+#include <QObject>
+#include <QColor>
+#include <kis_types.h>
+#include "kritalibkis_export.h"
+#include "libkis.h"
+#include "kis_scratch_pad.h"
+#include "View.h"
+
+class KoCanvasBase;
+class Canvas; // This comes from Python. This would be maybe better
+class KisView;
+
+/**
+ * @brief The Scratchpad class
+ * A scratchpad is a type of blank canvas area that can be painted on
+ * with the normal painting devices
+ *
+ */
+class KRITALIBKIS_EXPORT Scratchpad: public KisScratchPad
+{
+ Q_OBJECT
+public:
+ Scratchpad(View *view, const QColor & defaultColor, QWidget *parent = 0);
+ ~Scratchpad();
+
+
+public Q_SLOTS:
+
+ /**
+ * clears out scratchpad with color specfified set during setup
+ */
+ void clear();
+
+ void setFillColor(QColor color);
+
+ /** Switches between a GUI controlling the current mode and when mouse clicks control mode
+ * Setting to true allows GUI to control the mode with explicity setting mode
+ */
+ void setModeManually(bool value);
+
+
+ /// Manually set what mode scratchpad is in. Ignored if "setModeManually is set to false
+ void setMode(QString modeName);
+
+ /// load scratchpad
+ void loadScratchpad(QImage image);
+
+ /// take what is on scratchpad area and grab image
+ QImage copyScratchPadImage();
+
+};
+
+#endif // LIBKIS_SCRATCHPAD_H
+
diff --git a/libs/libkis/Selection.cpp b/libs/libkis/Selection.cpp
index 7c17819288..3c4989c758 100644
--- a/libs/libkis/Selection.cpp
+++ b/libs/libkis/Selection.cpp
@@ -1,334 +1,334 @@
/*
* Copyright (c) 2016 Boudewijn Rempt <boud@valdyas.org>
*
* This program 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 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 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 "Selection.h"
#include <KoColorSpace.h>
#include "kis_iterator_ng.h"
#include <kis_selection.h>
#include <kis_pixel_selection.h>
#include <kis_paint_device.h>
#include <kis_selection_filters.h>
#include <kis_painter.h>
#include <kis_clipboard.h>
#include <QByteArray>
#include <Node.h>
struct Selection::Private {
Private() {}
KisSelectionSP selection;
};
Selection::Selection(KisSelectionSP selection, QObject *parent)
: QObject(parent)
, d(new Private)
{
d->selection = selection;
}
Selection::Selection(QObject *parent)
: QObject(parent)
, d(new Private)
{
d->selection = new KisSelection();
}
Selection::~Selection()
{
delete d;
}
bool Selection::operator==(const Selection &other) const
{
return (d->selection == other.d->selection);
}
bool Selection::operator!=(const Selection &other) const
{
return !(operator==(other));
}
Selection *Selection::duplicate() const
{
return new Selection(d->selection ? new KisSelection(*d->selection)
: new KisSelection());
}
int Selection::width() const
{
if (!d->selection) return 0;
return d->selection->selectedExactRect().width();
}
int Selection::height() const
{
if (!d->selection) return 0;
return d->selection->selectedExactRect().height();
}
int Selection::x() const
{
if (!d->selection) return 0;
int xPos = d->selection->x();
- if (d->selection->hasPixelSelection()) {
+ if (d->selection->hasNonEmptyPixelSelection()) {
xPos = d->selection->selectedExactRect().x();
}
return xPos;
}
int Selection::y() const
{
if (!d->selection) return 0;
int yPos = d->selection->y();
- if (d->selection->hasPixelSelection()) {
+ if (d->selection->hasNonEmptyPixelSelection()) {
yPos = d->selection->selectedExactRect().y();
}
return yPos;
}
void Selection::move(int x, int y)
{
if (!d->selection) return;
d->selection->pixelSelection()->moveTo(QPoint(x, y));
}
void Selection::clear()
{
if (!d->selection) return;
d->selection->clear();
}
void Selection::contract(int value)
{
if (!d->selection) return;
d->selection->pixelSelection()->select(QRect(x(), y(), width() - value, height() - value));
}
void Selection::copy(Node *node)
{
if (!node) return;
if (!d->selection) return;
if (node->node()->exactBounds().isEmpty()) return;
if (!node->node()->hasEditablePaintDevice()) return;
KisPaintDeviceSP dev = node->node()->paintDevice();
KisPaintDeviceSP clip = new KisPaintDevice(dev->colorSpace());
KisPaintDeviceSP selectionProjection = d->selection->projection();
const KoColorSpace *cs = clip->colorSpace();
const KoColorSpace *selCs = d->selection->projection()->colorSpace();
QRect rc = d->selection->selectedExactRect();
KisPainter::copyAreaOptimized(QPoint(), dev, clip, rc);
KisHLineIteratorSP layerIt = clip->createHLineIteratorNG(0, 0, rc.width());
KisHLineConstIteratorSP selectionIt = selectionProjection->createHLineIteratorNG(rc.x(), rc.y(), rc.width());
for (qint32 y = 0; y < rc.height(); y++) {
for (qint32 x = 0; x < rc.width(); x++) {
qreal dstAlpha = cs->opacityF(layerIt->rawData());
qreal sel = selCs->opacityF(selectionIt->oldRawData());
qreal newAlpha = sel * dstAlpha / (1.0 - dstAlpha + sel * dstAlpha);
float mask = newAlpha / dstAlpha;
cs->applyAlphaNormedFloatMask(layerIt->rawData(), &mask, 1);
layerIt->nextPixel();
selectionIt->nextPixel();
}
layerIt->nextRow();
selectionIt->nextRow();
}
KisClipboard::instance()->setClip(clip, rc.topLeft());
}
void Selection::cut(Node* node)
{
if (!node) return;
if (!d->selection) return;
if (node->node()->exactBounds().isEmpty()) return;
if (!node->node()->hasEditablePaintDevice()) return;
KisPaintDeviceSP dev = node->node()->paintDevice();
copy(node);
dev->clearSelection(d->selection);
node->node()->setDirty(d->selection->selectedExactRect());
}
void Selection::paste(Node *destination, int x, int y)
{
if (!destination) return;
if (!d->selection) return;
if (!KisClipboard::instance()->hasClip()) return;
KisPaintDeviceSP src = KisClipboard::instance()->clip(QRect(), false);
KisPaintDeviceSP dst = destination->node()->paintDevice();
if (!dst) return;
KisPainter::copyAreaOptimized(QPoint(x, y),
src,
dst,
src->exactBounds(),
d->selection);
destination->node()->setDirty();
}
void Selection::erode()
{
if (!d->selection) return;
KisErodeSelectionFilter esf;
QRect rc = esf.changeRect(d->selection->selectedExactRect(), d->selection->pixelSelection()->defaultBounds());
esf.process(d->selection->pixelSelection(), rc);
}
void Selection::dilate()
{
if (!d->selection) return;
KisDilateSelectionFilter dsf;
QRect rc = dsf.changeRect(d->selection->selectedExactRect(), d->selection->pixelSelection()->defaultBounds());
dsf.process(d->selection->pixelSelection(), rc);
}
void Selection::border(int xRadius, int yRadius)
{
if (!d->selection) return;
KisBorderSelectionFilter sf(xRadius, yRadius);
QRect rc = sf.changeRect(d->selection->selectedExactRect(), d->selection->pixelSelection()->defaultBounds());
sf.process(d->selection->pixelSelection(), rc);
}
void Selection::feather(int radius)
{
if (!d->selection) return;
KisFeatherSelectionFilter fsf(radius);
QRect rc = fsf.changeRect(d->selection->selectedExactRect(), d->selection->pixelSelection()->defaultBounds());
fsf.process(d->selection->pixelSelection(), rc);
}
void Selection::grow(int xradius, int yradius)
{
if (!d->selection) return;
KisGrowSelectionFilter gsf(xradius, yradius);
QRect rc = gsf.changeRect(d->selection->selectedExactRect(), d->selection->pixelSelection()->defaultBounds());
gsf.process(d->selection->pixelSelection(), rc);
}
void Selection::shrink(int xRadius, int yRadius, bool edgeLock)
{
if (!d->selection) return;
KisShrinkSelectionFilter sf(xRadius, yRadius, edgeLock);
QRect rc = sf.changeRect(d->selection->selectedExactRect(), d->selection->pixelSelection()->defaultBounds());
sf.process(d->selection->pixelSelection(), rc);
}
void Selection::smooth()
{
if (!d->selection) return;
KisSmoothSelectionFilter sf;
QRect rc = sf.changeRect(d->selection->selectedExactRect(), d->selection->pixelSelection()->defaultBounds());
sf.process(d->selection->pixelSelection(), rc);
}
void Selection::invert()
{
if (!d->selection) return;
KisInvertSelectionFilter sf;
QRect rc = sf.changeRect(d->selection->selectedExactRect(), d->selection->pixelSelection()->defaultBounds());
sf.process(d->selection->pixelSelection(), rc);
}
void Selection::resize(int w, int h)
{
if (!d->selection) return;
d->selection->pixelSelection()->select(QRect(x(), y(), w, h));
}
void Selection::select(int x, int y, int w, int h, int value)
{
if (!d->selection) return;
d->selection->pixelSelection()->select(QRect(x, y, w, h), value);
}
void Selection::selectAll(Node *node, int value)
{
if (!d->selection) return;
d->selection->pixelSelection()->select(node->node()->exactBounds(), value);
}
void Selection::replace(Selection *selection)
{
if (!d->selection) return;
d->selection->pixelSelection()->applySelection(selection->selection()->pixelSelection(), SELECTION_REPLACE);
}
void Selection::add(Selection *selection)
{
if (!d->selection) return;
d->selection->pixelSelection()->applySelection(selection->selection()->pixelSelection(), SELECTION_ADD);
}
void Selection::subtract(Selection *selection)
{
if (!d->selection) return;
d->selection->pixelSelection()->applySelection(selection->selection()->pixelSelection(), SELECTION_SUBTRACT);
}
void Selection::intersect(Selection *selection)
{
if (!d->selection) return;
d->selection->pixelSelection()->applySelection(selection->selection()->pixelSelection(), SELECTION_INTERSECT);
}
void Selection::symmetricdifference(Selection *selection)
{
if (!d->selection) return;
d->selection->pixelSelection()->applySelection(selection->selection()->pixelSelection(), SELECTION_SYMMETRICDIFFERENCE);
}
QByteArray Selection::pixelData(int x, int y, int w, int h) const
{
QByteArray ba;
if (!d->selection) return ba;
KisPaintDeviceSP dev = d->selection->projection();
quint8 *data = new quint8[w * h];
dev->readBytes(data, x, y, w, h);
ba = QByteArray((const char*)data, (int)(w * h));
delete[] data;
return ba;
}
void Selection::setPixelData(QByteArray value, int x, int y, int w, int h)
{
if (!d->selection) return;
KisPixelSelectionSP dev = d->selection->pixelSelection();
if (!dev) return;
dev->writeBytes((const quint8*)value.constData(), x, y, w, h);
}
KisSelectionSP Selection::selection() const
{
return d->selection;
}
diff --git a/libs/libkis/View.cpp b/libs/libkis/View.cpp
index c72221585e..6152d92113 100644
--- a/libs/libkis/View.cpp
+++ b/libs/libkis/View.cpp
@@ -1,279 +1,298 @@
/*
* Copyright (c) 2016 Boudewijn Rempt <boud@valdyas.org>
*
* This program 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 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 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 "View.h"
#include <QPointer>
#include <KoPattern.h>
#include <KoAbstractGradient.h>
#include <kis_paintop_preset.h>
#include <KisView.h>
#include <KisViewManager.h>
#include <kis_node_manager.h>
#include <kis_selection_manager.h>
#include <kis_canvas_resource_provider.h>
#include <kis_paintop_box.h>
#include <KisMainWindow.h>
#include <KoCanvasBase.h>
#include <kis_canvas2.h>
#include <KisResourceTypes.h>
#include <KisDocument.h>
#include "Document.h"
#include "Canvas.h"
+#include "Scratchpad.h"
#include "Window.h"
#include "Resource.h"
#include "ManagedColor.h"
#include "LibKisUtils.h"
struct View::Private {
Private() {}
QPointer<KisView> view;
+
+ QList<Scratchpad *> scratchpads;
};
View::View(KisView* view, QObject *parent)
: QObject(parent)
, d(new Private)
{
d->view = view;
}
View::~View()
{
delete d;
}
bool View::operator==(const View &other) const
{
return (d->view == other.d->view);
}
bool View::operator!=(const View &other) const
{
return !(operator==(other));
}
Window* View::window() const
{
if (!d->view) return 0;
KisMainWindow *mainwin = d->view->mainWindow();
Window *win = new Window(mainwin);
return win;
}
Document* View::document() const
{
if (!d->view) return 0;
Document *doc = new Document(d->view->document(), false);
return doc;
}
void View::setDocument(Document *document)
{
if (!d->view || !document || !document->document()) return;
d->view = d->view->replaceBy(document->document());
}
bool View::visible() const
{
if (!d->view) return false;
return d->view->isVisible();
}
void View::setVisible()
{
if (!d->view) return;
KisMainWindow *mainwin = d->view->mainWindow();
mainwin->setActiveView(d->view);
mainwin->subWindowActivated();
}
Canvas* View::canvas() const
{
if (!d->view) return 0;
Canvas *c = new Canvas(d->view->canvasBase());
return c;
}
KisView *View::view()
{
return d->view;
}
void View::activateResource(Resource *resource)
{
if (!d->view) return;
if (!resource) return;
KoResourceSP r = resource->resource();
if (!r) return;
if (r.dynamicCast<KoPattern>()) {
QVariant v;
v.setValue<KoResourceSP>(r);
d->view->canvasBase()->resourceManager()->setResource(KisCanvasResourceProvider::CurrentPattern, v);
}
else if (r.dynamicCast<KoAbstractGradient>()) {
QVariant v;
v.setValue<KoResourceSP>(r);
d->view->canvasBase()->resourceManager()->setResource(KisCanvasResourceProvider::CurrentGradient, v);
}
else if (r.dynamicCast<KisPaintOpPreset>()) {
d->view->viewManager()->paintOpBox()->resourceSelected(r);
}
}
+Scratchpad *View::createScratchpad(QColor bgColor)
+{
+ if(view()) {
+ d->scratchpads.append(new Scratchpad(this->canvas()->view(), bgColor));
+ }
+ return d->scratchpads.last();
+}
+
ManagedColor *View::foregroundColor() const
{
if (!d->view) return 0;
return new ManagedColor(d->view->resourceProvider()->fgColor());
}
void View::setForeGroundColor(ManagedColor *color)
{
if (!d->view) return;
d->view->resourceProvider()->setFGColor(color->color());
}
ManagedColor *View::backgroundColor() const
{
if (!d->view) return 0;
return new ManagedColor(d->view->resourceProvider()->bgColor());
}
void View::setBackGroundColor(ManagedColor *color)
{
if (!d->view) return;
d->view->resourceProvider()->setBGColor(color->color());
}
Resource *View::currentBrushPreset() const
{
if (!d->view) return 0;
return new Resource(d->view->resourceProvider()->currentPreset(), ResourceType::PaintOpPresets);
}
void View::setCurrentBrushPreset(Resource *resource)
{
activateResource(resource);
}
Resource *View::currentPattern() const
{
if (!d->view) return 0;
return new Resource(d->view->resourceProvider()->currentPattern(), ResourceType::Patterns);
}
void View::setCurrentPattern(Resource *resource)
{
activateResource(resource);
}
Resource *View::currentGradient() const
{
if (!d->view) return 0;
return new Resource(d->view->resourceProvider()->currentGradient(), ResourceType::Gradients);
}
void View::setCurrentGradient(Resource *resource)
{
activateResource(resource);
}
QString View::currentBlendingMode() const
{
if (!d->view) return "";
return d->view->resourceProvider()->currentCompositeOp();
}
void View::setCurrentBlendingMode(const QString &blendingMode)
{
if (!d->view) return;
d->view->resourceProvider()->setCurrentCompositeOp(blendingMode);
}
float View::HDRExposure() const
{
if (!d->view) return 0.0;
return d->view->resourceProvider()->HDRExposure();
}
void View::setHDRExposure(float exposure)
{
if (!d->view) return;
d->view->resourceProvider()->setHDRExposure(exposure);
}
float View::HDRGamma() const
{
if (!d->view) return 0.0;
return d->view->resourceProvider()->HDRGamma();
}
void View::setHDRGamma(float gamma)
{
if (!d->view) return;
d->view->resourceProvider()->setHDRGamma(gamma);
}
qreal View::paintingOpacity() const
{
if (!d->view) return 0.0;
return d->view->resourceProvider()->opacity();
}
void View::setPaintingOpacity(qreal opacity)
{
if (!d->view) return;
d->view->resourceProvider()->setOpacity(opacity);
}
qreal View::brushSize() const
{
if (!d->view) return 0.0;
return d->view->resourceProvider()->size();
}
void View::setBrushSize(qreal brushSize)
{
if (!d->view) return;
d->view->resourceProvider()->setSize(brushSize);
}
qreal View::paintingFlow() const
{
if (!d->view) return 0.0;
return d->view->resourceProvider()->flow();
}
void View::setPaintingFlow(qreal flow)
{
if (!d->view) return;
d->view->resourceProvider()->setFlow(flow);
}
QList<Node *> View::selectedNodes() const
{
if (!d->view) return QList<Node *>();
if (!d->view->viewManager()) return QList<Node *>();
if (!d->view->viewManager()->nodeManager()) return QList<Node *>();
KisNodeList selectedNodes = d->view->viewManager()->nodeManager()->selectedNodes();
return LibKisUtils::createNodeList(selectedNodes, d->view->image());
}
+
+QList<Scratchpad *> View::scratchpads() const
+{
+ if (!d->view) return QList<Scratchpad *>();
+ if (!d->view->viewManager()) return QList<Scratchpad *>();
+
+ return d->scratchpads;
+}
diff --git a/libs/libkis/View.h b/libs/libkis/View.h
index 964aed2fee..a70950d5c7 100644
--- a/libs/libkis/View.h
+++ b/libs/libkis/View.h
@@ -1,159 +1,173 @@
/*
* Copyright (c) 2016 Boudewijn Rempt <boud@valdyas.org>
*
* This program 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 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 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 LIBKIS_VIEW_H
#define LIBKIS_VIEW_H
#include <QObject>
#include "kritalibkis_export.h"
#include "libkis.h"
class ManagedColor;
class Resource;
+class Scratchpad;
class Node;
class KisView;
/**
* View represents one view on a document. A document can be
* shown in more than one view at a time.
*/
class KRITALIBKIS_EXPORT View : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(View)
public:
explicit View(KisView *view, QObject *parent = 0);
~View() override;
bool operator==(const View &other) const;
bool operator!=(const View &other) const;
public Q_SLOTS:
/**
* @return the window this view is shown in.
*/
Window* window() const;
/**
* @return the document this view is showing.
*/
Document* document() const;
/**
* Reset the view to show @p document.
*/
void setDocument(Document *document);
/**
* @return true if the current view is visible, false if not.
*/
bool visible() const;
/**
* Make the current view visible.
*/
void setVisible();
/**
* @return the canvas this view is showing. The canvas controls
* things like zoom and rotation.
*/
Canvas* canvas() const;
/**
* @brief activateResource activates the given resource.
* @param resource: a pattern, gradient or paintop preset
*/
void activateResource(Resource *resource);
+ /**
+ * @brief creates a scratchpad widget to draw on.
+ * It is stored in the scratchpad list for reference
+ */
+ Scratchpad *createScratchpad(QColor bgColor);
+
/**
* @brief foregroundColor allows access to the currently active color.
* This is nominally per canvas/view, but in practice per mainwindow.
* @code
color = Application.activeWindow().activeView().foregroundColor()
components = color.components()
components[0] = 1.0
components[1] = 0.6
components[2] = 0.7
color.setComponents(components)
Application.activeWindow().activeView().setForeGroundColor(color)
* @endcode
*/
ManagedColor *foregroundColor() const;
void setForeGroundColor(ManagedColor *color);
ManagedColor *backgroundColor() const;
void setBackGroundColor(ManagedColor *color);
Resource *currentBrushPreset() const;
void setCurrentBrushPreset(Resource *resource);
Resource *currentPattern() const;
void setCurrentPattern(Resource *resource);
Resource *currentGradient() const;
void setCurrentGradient(Resource *resource);
QString currentBlendingMode() const;
void setCurrentBlendingMode(const QString &blendingMode);
float HDRExposure() const;
void setHDRExposure(float exposure);
float HDRGamma() const;
void setHDRGamma(float gamma);
qreal paintingOpacity() const;
void setPaintingOpacity(qreal opacity);
qreal brushSize() const;
void setBrushSize(qreal brushSize);
qreal paintingFlow() const;
void setPaintingFlow(qreal flow);
/**
* @brief selectedNodes returns a list of Nodes that are selected in this view.
*
*
@code
from krita import *
w = Krita.instance().activeWindow()
v = w.activeView()
selected_nodes = v.selectedNodes()
print(selected_nodes)
@endcode
*
*
* @return a list of Node objects which may be empty.
*/
QList<Node *> selectedNodes() const;
+
+ /**
+ * @brief Stores scratchpad widgets to draw on
+ */
+ QList<Scratchpad *> scratchpads() const;
+
private:
friend class Window;
+ friend class Scratchpad;
KisView *view();
struct Private;
Private *const d;
};
#endif // LIBKIS_VIEW_H
diff --git a/libs/libkis/libkis.h b/libs/libkis/libkis.h
index fba3852456..b665944af7 100644
--- a/libs/libkis/libkis.h
+++ b/libs/libkis/libkis.h
@@ -1,36 +1,37 @@
#include <QList>
#include <QString>
#include <QVariant>
#include <QMap>
#include <QByteArray>
#include <QAction>
class Canvas;
class Channel;
class ColorDepth;
class ColorManager;
class ColorModel;
class ColorProfile;
class DockWidget;
class DockWidgetFactoryBase;
class Document;
class Filter;
class InfoObject;
class Krita;
class Node;
class Notifier;
class Resource;
+class Scratchpad;
class Selection;
class View;
class Extension;
class Window;
class Shape;
class GroupShape;
class PaintLayer;
class CloneLayer;
class GroupLayer;
class FilterLayer;
class FillLayer;
class FileLayer;
class VectorLayer;
diff --git a/libs/libqml/plugins/kritasketchplugin/models/LayerModel.cpp b/libs/libqml/plugins/kritasketchplugin/models/LayerModel.cpp
index c9fe7bc192..b061f065c6 100644
--- a/libs/libqml/plugins/kritasketchplugin/models/LayerModel.cpp
+++ b/libs/libqml/plugins/kritasketchplugin/models/LayerModel.cpp
@@ -1,977 +1,977 @@
/* This file is part of the KDE project
* Copyright (C) 2012 Dan Leinir Turthra Jensen <admin@leinir.dk>
*
* 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 "LayerModel.h"
#include "LayerThumbProvider.h"
#include <PropertyContainer.h>
#include <kis_node_model.h>
#include <KisViewManager.h>
#include <kis_canvas2.h>
#include <kis_node_manager.h>
#include <kis_dummies_facade_base.h>
#include <KisDocument.h>
#include <kis_composite_ops_model.h>
#include <kis_node.h>
#include <kis_image.h>
#include <kis_layer.h>
#include <kis_group_layer.h>
#include <kis_paint_layer.h>
#include <kis_filter_mask.h>
#include <kis_shape_controller.h>
#include <kis_adjustment_layer.h>
#include <kis_selection_manager.h>
#include <filter/kis_filter.h>
#include <filter/kis_filter_configuration.h>
#include <filter/kis_filter_registry.h>
#include <KoShapeControllerBase.h>
#include <KoProperties.h>
#include <QQmlEngine>
#include <kis_base_node.h>
#include "KisSelectionActionsAdapter.h"
#include <KisGlobalResourcesInterface.h>
struct LayerModelMetaInfo {
LayerModelMetaInfo()
: canMoveUp(false)
, canMoveRight(false)
, canMoveDown(false)
, canMoveLeft(false)
, depth(-1)
{}
bool canMoveUp;
bool canMoveRight;
bool canMoveDown;
bool canMoveLeft;
int depth;
};
class LayerModel::Private {
public:
Private(LayerModel* qq)
: q(qq)
, nodeModel(new KisNodeModel(qq))
, aboutToRemoveRoots(false)
, canvas(0)
, nodeManager(0)
, image(0)
, activeNode(0)
, declarativeEngine(0)
, thumbProvider(0)
, updateActiveLayerWithNewFilterConfigTimer(new QTimer(qq))
, imageChangedTimer(new QTimer(qq))
{
QList<KisFilterSP> tmpFilters = KisFilterRegistry::instance()->values();
Q_FOREACH (const KisFilterSP& filter, tmpFilters)
{
filters[filter.data()->id()] = filter.data();
}
updateActiveLayerWithNewFilterConfigTimer->setInterval(0);
updateActiveLayerWithNewFilterConfigTimer->setSingleShot(true);
connect(updateActiveLayerWithNewFilterConfigTimer, SIGNAL(timeout()), qq, SLOT(updateActiveLayerWithNewFilterConfig()));
imageChangedTimer->setInterval(250);
imageChangedTimer->setSingleShot(true);
connect(imageChangedTimer, SIGNAL(timeout()), qq, SLOT(imageHasChanged()));
}
LayerModel* q;
QList<KisNodeSP> layers;
QHash<const KisNode*, LayerModelMetaInfo> layerMeta;
KisNodeModel* nodeModel;
bool aboutToRemoveRoots;
KisViewManager* view;
KisCanvas2* canvas;
QScopedPointer<KisSelectionActionsAdapter> selectionActionsAdapter;
QPointer<KisNodeManager> nodeManager;
KisImageWSP image;
KisNodeSP activeNode;
QQmlEngine* declarativeEngine;
LayerThumbProvider* thumbProvider;
QHash<QString, const KisFilter*> filters;
KisFilterConfigurationSP newConfig;
QTimer* updateActiveLayerWithNewFilterConfigTimer;
QTimer* imageChangedTimer;
static int counter()
{
static int count = 0;
return count++;
}
static QStringList layerClassNames()
{
QStringList list;
list << "KisGroupLayer";
list << "KisPaintLayer";
list << "KisFilterMask";
list << "KisAdjustmentLayer";
return list;
}
int deepChildCount(KisNodeSP layer)
{
quint32 childCount = layer->childCount();
QList<KisNodeSP> children = layer->childNodes(layerClassNames(), KoProperties());
for(quint32 i = 0; i < childCount; ++i)
childCount += deepChildCount(children.at(i));
return childCount;
}
void rebuildLayerList(KisNodeSP layer = 0)
{
bool refreshingFromRoot = false;
if (!image)
{
layers.clear();
return;
}
if (layer == 0)
{
refreshingFromRoot = true;
layers.clear();
layer = image->rootLayer();
}
// implementation node: The root node is not a visible node, and so
// is never added to the list of layers
QList<KisNodeSP> children = layer->childNodes(layerClassNames(), KoProperties());
if (children.count() == 0)
return;
for(quint32 i = children.count(); i > 0; --i)
{
layers << children.at(i-1);
rebuildLayerList(children.at(i-1));
}
if (refreshingFromRoot)
refreshLayerMovementAbilities();
}
void refreshLayerMovementAbilities()
{
layerMeta.clear();
if (layers.count() == 0)
return;
for(int i = 0; i < layers.count(); ++i)
{
const KisNodeSP layer = layers.at(i);
LayerModelMetaInfo ability;
if (i > 0)
ability.canMoveUp = true;
if (i < layers.count() - 1)
ability.canMoveDown = true;
KisNodeSP parent = layer;
while(parent)
{
++ability.depth;
parent = parent->parent();
}
if (ability.depth > 1)
ability.canMoveLeft = true;
if (i < layers.count() - 1 && qobject_cast<const KisGroupLayer*>(layers.at(i + 1).constData()))
ability.canMoveRight = true;
layerMeta[layer] = ability;
}
}
};
LayerModel::LayerModel(QObject* parent)
: QAbstractListModel(parent)
, d(new Private(this))
{
connect(d->nodeModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
this, SLOT(source_rowsAboutToBeInserted(QModelIndex,int,int)));
connect(d->nodeModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(source_rowsInserted(QModelIndex,int,int)));
connect(d->nodeModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
this, SLOT(source_rowsAboutToBeRemoved(QModelIndex,int,int)));
connect(d->nodeModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
this, SLOT(source_rowsRemoved(QModelIndex,int,int)));
connect(d->nodeModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
this, SLOT(source_dataChanged(QModelIndex,QModelIndex)));
connect(d->nodeModel, SIGNAL(modelReset()),
this, SLOT(source_modelReset()));
connect(d->nodeModel, SIGNAL(layoutAboutToBeChanged()), this, SIGNAL(layoutAboutToBeChanged()));
connect(d->nodeModel, SIGNAL(layoutChanged()), this, SIGNAL(layoutChanged()));
}
LayerModel::~LayerModel()
{
delete d;
}
QHash<int, QByteArray> LayerModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[IconRole] = "icon";
roles[NameRole] = "name";
roles[ActiveLayerRole] = "activeLayer";
roles[OpacityRole] = "opacity";
roles[PercentOpacityRole] = "percentOpacity";
roles[VisibleRole] = "visible";
roles[CompositeDetailsRole] = "compositeDetails";
roles[FilterRole] = "filter";
roles[ChildCountRole] = "childCount";
roles[DeepChildCountRole] = "deepChildCount";
roles[DepthRole] = "depth";
roles[PreviousItemDepthRole] = "previousItemDepth";
roles[NextItemDepthRole] = "nextItemDepth";
roles[CanMoveDownRole] = "canMoveDown";
roles[CanMoveLeftRole] = "canMoveLeft";
roles[CanMoveRightRole] = "canMoveRight";
roles[CanMoveUpRole] = "canMoveUp";
return roles;
}
QObject* LayerModel::view() const
{
return d->view;
}
void LayerModel::setView(QObject *newView)
{
KisViewManager* view = qobject_cast<KisViewManager*>(newView);
// This has to happen very early, and we will be filling it back up again soon anyway...
if (d->canvas) {
d->canvas->disconnectCanvasObserver(this);
disconnect(d->image, 0, this, 0);
disconnect(d->nodeManager, 0, this, 0);
disconnect(d->nodeModel, 0, d->nodeManager, 0);
disconnect(d->nodeModel, SIGNAL(nodeActivated(KisNodeSP)), this, SLOT(currentNodeChanged(KisNodeSP)));
d->image = 0;
d->nodeManager = 0;
d->layers.clear();
d->activeNode.clear();
d->canvas = 0;
d->nodeModel->setDummiesFacade(0, 0, 0, 0, 0);
d->selectionActionsAdapter.reset();
}
d->view = view;
if (!d->view) {
return;
}
d->canvas = view->canvasBase();
d->thumbProvider = new LayerThumbProvider();
d->thumbProvider->setLayerModel(this);
d->thumbProvider->setLayerID(Private::counter());
// QT5TODO: results in a crash
d->declarativeEngine->addImageProvider(QString("layerthumb%1").arg(d->thumbProvider->layerID()), d->thumbProvider);
if (d->canvas) {
d->image = d->canvas->imageView()->image();
d->nodeManager = d->canvas->viewManager()->nodeManager();
KisDummiesFacadeBase *kritaDummiesFacade = dynamic_cast<KisDummiesFacadeBase*>(d->canvas->imageView()->document()->shapeController());
KisShapeController *shapeController = dynamic_cast<KisShapeController*>(d->canvas->imageView()->document()->shapeController());
d->selectionActionsAdapter.reset(new KisSelectionActionsAdapter(d->canvas->viewManager()->selectionManager()));
d->nodeModel->setDummiesFacade(kritaDummiesFacade,
d->image,
shapeController,
d->selectionActionsAdapter.data(),
d->nodeManager);
connect(d->image, SIGNAL(sigAboutToBeDeleted()), SLOT(notifyImageDeleted()));
connect(d->image, SIGNAL(sigNodeChanged(KisNodeSP)), SLOT(nodeChanged(KisNodeSP)));
connect(d->image, SIGNAL(sigImageUpdated(QRect)), SLOT(imageChanged()));
connect(d->image, SIGNAL(sigRemoveNodeAsync(KisNodeSP)), SLOT(aboutToRemoveNode(KisNodeSP)));
// cold start
currentNodeChanged(d->nodeManager->activeNode());
// Connection KisNodeManager -> KisLayerBox
connect(d->nodeManager, SIGNAL(sigUiNeedChangeActiveNode(KisNodeSP)), this, SLOT(currentNodeChanged(KisNodeSP)));
d->rebuildLayerList();
beginResetModel();
endResetModel();
}
}
QObject* LayerModel::engine() const
{
return d->declarativeEngine;
}
void LayerModel::setEngine(QObject* newEngine)
{
d->declarativeEngine = qobject_cast<QQmlEngine*>(newEngine);
emit engineChanged();
}
QString LayerModel::fullImageThumbUrl() const
{
return QString("image://layerthumb%1/fullimage/%2").arg(d->thumbProvider->layerID()).arg(QDateTime::currentMSecsSinceEpoch());
}
void LayerModel::currentNodeChanged(KisNodeSP newActiveNode)
{
if (!d->activeNode.isNull()) {
QModelIndex oldIndex = d->nodeModel->indexFromNode(d->activeNode);
source_dataChanged(oldIndex, oldIndex);
}
d->activeNode = newActiveNode;
emitActiveChanges();
if (!d->activeNode.isNull()) {
QModelIndex oldIndex = d->nodeModel->indexFromNode(d->activeNode);
source_dataChanged(oldIndex, oldIndex);
}
}
QVariant LayerModel::data(const QModelIndex& index, int role) const
{
QVariant data;
if (index.isValid()) {
index.internalPointer();
KisNodeSP node = d->layers.at(index.row());
if (node.isNull())
return data;
KisNodeSP parent;
switch(role)
{
case IconRole:
if (dynamic_cast<const KisGroupLayer*>(node.constData()))
data = QLatin1String("../images/svg/icon-layer_group-black.svg");
else if (dynamic_cast<const KisFilterMask*>(node.constData()))
data = QLatin1String("../images/svg/icon-layer_filter-black.svg");
else if (dynamic_cast<const KisAdjustmentLayer*>(node.constData()))
data = QLatin1String("../images/svg/icon-layer_filter-black.svg");
else
// We add the currentMSecsSinceEpoch to ensure we force an update (even with cache turned
// off, we still apparently get some caching behaviour on delegates in QML)
data = QString("image://layerthumb%1/%2/%3").arg(d->thumbProvider->layerID()).arg(index.row()).arg(QDateTime::currentMSecsSinceEpoch());
break;
case NameRole:
data = node->name();
break;
case ActiveLayerRole:
data = (node == d->activeNode);
break;
case OpacityRole:
data = node->opacity();
break;
case PercentOpacityRole:
data = node->percentOpacity();
break;
case VisibleRole:
data = node->visible();
break;
case CompositeDetailsRole:
// composite op goes here...
if (node->compositeOp())
data = node->compositeOp()->description();
break;
case FilterRole:
break;
case ChildCountRole:
data = node->childNodes(d->layerClassNames(), KoProperties()).count();
break;
case DeepChildCountRole:
data = d->deepChildCount(d->layers.at(index.row()));
break;
case DepthRole:
data = d->layerMeta[node.data()].depth;
break;
case PreviousItemDepthRole:
if (index.row() == 0)
data = -1;
else
data = d->layerMeta[d->layers[index.row() - 1].data()].depth;
break;
case NextItemDepthRole:
if (index.row() == d->layers.count() - 1)
data = -1;
else
data = d->layerMeta[d->layers[index.row() + 1].data()].depth;
break;
case CanMoveDownRole:
data = (node == d->activeNode) && d->layerMeta[node.data()].canMoveDown;
break;
case CanMoveLeftRole:
data = (node == d->activeNode) && d->layerMeta[node.data()].canMoveLeft;
break;
case CanMoveRightRole:
data = (node == d->activeNode) && d->layerMeta[node.data()].canMoveRight;
break;
case CanMoveUpRole:
data = (node == d->activeNode) && d->layerMeta[node.data()].canMoveUp;
break;
default:
break;
}
}
return data;
}
int LayerModel::rowCount(const QModelIndex& parent) const
{
if ( parent.isValid() ) {
return 0;
}
return d->layers.count();
}
QVariant LayerModel::headerData(int section, Qt::Orientation orientation, int role) const
{
return QAbstractItemModel::headerData(section, orientation, role);
}
void LayerModel::setActive(int index)
{
if (index > -1 && index < d->layers.count()) {
KisNodeSP newNode = d->layers.at(index);
d->nodeManager->slotUiActivatedNode(newNode);
currentNodeChanged(newNode);
}
}
void LayerModel::moveUp()
{
KisNodeSP node = d->nodeManager->activeNode();
KisNodeSP parent = node->parent();
KisNodeSP grandParent = parent->parent();
if (!d->nodeManager->activeNode()->nextSibling()) {
//dbgKrita << "Active node apparently has no next sibling, however that has happened...";
if (!grandParent)
return;
//dbgKrita << "Node has grandparent";
if (!grandParent->parent() && node->inherits("KisMask"))
return;
//dbgKrita << "Node isn't a mask";
d->nodeManager->moveNodeAt(node, grandParent, grandParent->index(parent) + 1);
}
else {
//dbgKrita << "Move node directly";
d->nodeManager->lowerNode();
}
}
void LayerModel::moveDown()
{
KisNodeSP node = d->nodeManager->activeNode();
KisNodeSP parent = node->parent();
KisNodeSP grandParent = parent->parent();
if (!d->nodeManager->activeNode()->prevSibling()) {
//dbgKrita << "Active node apparently has no previous sibling, however that has happened...";
if (!grandParent)
return;
//dbgKrita << "Node has grandparent";
if (!grandParent->parent() && node->inherits("KisMask"))
return;
//dbgKrita << "Node isn't a mask";
d->nodeManager->moveNodeAt(node, grandParent, grandParent->index(parent));
} else
{
//dbgKrita << "Move node directly";
d->nodeManager->raiseNode();
}
}
void LayerModel::moveLeft()
{
KisNodeSP node = d->nodeManager->activeNode();
KisNodeSP parent = node->parent();
KisNodeSP grandParent = parent->parent();
quint16 nodeIndex = parent->index(node);
if (!grandParent)
return;
if (!grandParent->parent() && node->inherits("KisMask"))
return;
if (nodeIndex <= parent->childCount() / 2) {
d->nodeManager->moveNodeAt(node, grandParent, grandParent->index(parent));
}
else {
d->nodeManager->moveNodeAt(node, grandParent, grandParent->index(parent) + 1);
}
}
void LayerModel::moveRight()
{
KisNodeSP node = d->nodeManager->activeNode();
KisNodeSP parent = d->nodeManager->activeNode()->parent();
KisNodeSP newParent;
int nodeIndex = parent->index(node);
int indexAbove = nodeIndex + 1;
int indexBelow = nodeIndex - 1;
if (parent->at(indexBelow) && parent->at(indexBelow)->allowAsChild(node)) {
newParent = parent->at(indexBelow);
d->nodeManager->moveNodeAt(node, newParent, newParent->childCount());
}
else if (parent->at(indexAbove) && parent->at(indexAbove)->allowAsChild(node)) {
newParent = parent->at(indexAbove);
d->nodeManager->moveNodeAt(node, newParent, 0);
}
else {
return;
}
}
void LayerModel::clear()
{
d->canvas->viewManager()->selectionManager()->clear();
}
void LayerModel::clone()
{
d->nodeManager->duplicateActiveNode();
}
void LayerModel::setLocked(int index, bool newLocked)
{
if (index > -1 && index < d->layers.count()) {
if(d->layers[index]->userLocked() == newLocked)
return;
d->layers[index]->setUserLocked(newLocked);
QModelIndex idx = createIndex(index, 0);
dataChanged(idx, idx);
}
}
void LayerModel::setOpacity(int index, float newOpacity)
{
if (index > -1 && index < d->layers.count()) {
if(qFuzzyCompare(d->layers[index]->opacity() + 1, newOpacity + 1))
return;
d->layers[index]->setOpacity(newOpacity);
d->layers[index]->setDirty();
QModelIndex idx = createIndex(index, 0);
dataChanged(idx, idx);
}
}
void LayerModel::setVisible(int index, bool newVisible)
{
if (index > -1 && index < d->layers.count()) {
KisBaseNode::PropertyList props = d->layers[index]->sectionModelProperties();
if(props[0].state == newVisible)
return;
KisBaseNode::Property prop = props[0];
prop.state = newVisible;
props[0] = prop;
d->nodeModel->setData( d->nodeModel->indexFromNode(d->layers[index]), QVariant::fromValue<KisBaseNode::PropertyList>(props), KisNodeModel::PropertiesRole );
d->layers[index]->setDirty(d->layers[index]->extent());
QModelIndex idx = createIndex(index, 0);
dataChanged(idx, idx);
}
}
QImage LayerModel::layerThumbnail(QString layerID) const
{
// So, yeah, this is a complete cheatery hack. However, it ensures
// we actually get updates when we want them (every time the image is supposed
// to be changed). Had hoped we could avoid it, but apparently not.
int index = layerID.section(QChar('/'), 0, 0).toInt();
QImage thumb;
if (index > -1 && index < d->layers.count()) {
if (d->thumbProvider)
- thumb = d->layers[index]->createThumbnail(120, 120);
+ thumb = d->layers[index]->createThumbnail(120, 120, Qt::KeepAspectRatio);
}
return thumb;
}
void LayerModel::deleteCurrentLayer()
{
d->activeNode.clear();
d->nodeManager->removeNode();
}
void LayerModel::deleteLayer(int index)
{
if (index > -1 && index < d->layers.count()) {
if (d->activeNode == d->layers.at(index))
d->activeNode.clear();
d->nodeManager->slotUiActivatedNode(d->layers.at(index));
d->nodeManager->removeNode();
d->rebuildLayerList();
beginResetModel();
endResetModel();
}
}
void LayerModel::addLayer(int layerType)
{
switch(layerType) {
case 0:
d->nodeManager->createNode("KisPaintLayer");
break;
case 1:
d->nodeManager->createNode("KisGroupLayer");
break;
case 2:
d->nodeManager->createNode("KisFilterMask", true);
break;
default:
break;
}
}
void LayerModel::source_rowsAboutToBeInserted(QModelIndex /*p*/, int /*from*/, int /*to*/)
{
beginResetModel();
}
void LayerModel::source_rowsInserted(QModelIndex /*p*/, int, int)
{
d->rebuildLayerList();
emit countChanged();
endResetModel();
}
void LayerModel::source_rowsAboutToBeRemoved(QModelIndex /*p*/, int /*from*/, int /*to*/)
{
beginResetModel();
}
void LayerModel::source_rowsRemoved(QModelIndex, int, int)
{
d->rebuildLayerList();
emit countChanged();
endResetModel();
}
void LayerModel::source_dataChanged(QModelIndex /*tl*/, QModelIndex /*br*/)
{
QModelIndex top = createIndex(0, 0);
QModelIndex bottom = createIndex(d->layers.count() - 1, 0);
dataChanged(top, bottom);
}
void LayerModel::source_modelReset()
{
beginResetModel();
d->rebuildLayerList();
d->activeNode.clear();
if (d->layers.count() > 0)
{
d->nodeManager->slotUiActivatedNode(d->layers.at(0));
currentNodeChanged(d->layers.at(0));
}
emit countChanged();
endResetModel();
}
void LayerModel::notifyImageDeleted()
{
}
void LayerModel::nodeChanged(KisNodeSP node)
{
QModelIndex index = createIndex(d->layers.indexOf(node), 0);
dataChanged(index, index);
}
void LayerModel::imageChanged()
{
d->imageChangedTimer->start();
}
void LayerModel::imageHasChanged()
{
QModelIndex top = createIndex(0, 0);
QModelIndex bottom = createIndex(d->layers.count() - 1, 0);
dataChanged(top, bottom);
}
void LayerModel::aboutToRemoveNode(KisNodeSP node)
{
Q_UNUSED(node)
QTimer::singleShot(0, this, SLOT(source_modelReset()));
}
void LayerModel::emitActiveChanges()
{
emit activeFilterConfigChanged();
emit activeNameChanged();
emit activeTypeChanged();
emit activeCompositeOpChanged();
emit activeOpacityChanged();
emit activeVisibleChanged();
emit activeLockedChanged();
emit activeRChannelActiveChanged();
emit activeGChannelActiveChanged();
emit activeBChannelActiveChanged();
emit activeAChannelActiveChanged();
}
QString LayerModel::activeName() const
{
if (d->activeNode.isNull())
return QString();
return d->activeNode->name();
}
void LayerModel::setActiveName(QString newName)
{
if (d->activeNode.isNull())
return;
d->activeNode->setName(newName);
emit activeNameChanged();
}
QString LayerModel::activeType() const
{
return d->activeNode->metaObject()->className();
}
int LayerModel::activeCompositeOp() const
{
if (d->activeNode.isNull())
return 0;
KoID entry(d->activeNode->compositeOp()->id());
QModelIndex idx = KisCompositeOpListModel::sharedInstance()->indexOf(entry);
if (idx.isValid())
return idx.row();
return 0;
}
void LayerModel::setActiveCompositeOp(int newOp)
{
if (d->activeNode.isNull())
return;
KoID entry;
if (KisCompositeOpListModel::sharedInstance()->entryAt(entry, KisCompositeOpListModel::sharedInstance()->index(newOp)))
{
d->activeNode->setCompositeOpId(entry.id());
d->activeNode->setDirty();
emit activeCompositeOpChanged();
}
}
int LayerModel::activeOpacity() const
{
if (d->activeNode.isNull())
return 0;
return d->activeNode->opacity();
}
void LayerModel::setActiveOpacity(int newOpacity)
{
d->activeNode->setOpacity(newOpacity);
d->activeNode->setDirty();
emit activeOpacityChanged();
}
bool LayerModel::activeVisible() const
{ if (d->activeNode.isNull())
return false;
return d->activeNode->visible();
}
void LayerModel::setActiveVisible(bool newVisible)
{
if (d->activeNode.isNull())
return;
setVisible(d->layers.indexOf(d->activeNode), newVisible);
emit activeVisibleChanged();
}
bool LayerModel::activeLocked() const
{
if (d->activeNode.isNull())
return false;
return d->activeNode->userLocked();
}
void LayerModel::setActiveLocked(bool newLocked)
{
if (d->activeNode.isNull())
return;
d->activeNode->setUserLocked(newLocked);
emit activeLockedChanged();
}
bool LayerModel::activeAChannelActive() const
{
KisLayer* layer = qobject_cast<KisLayer*>(d->activeNode.data());
bool state = false;
if (layer)
state = !layer->alphaChannelDisabled();
return state;
}
void LayerModel::setActiveAChannelActive(bool newActive)
{
KisLayer* layer = qobject_cast<KisLayer*>(d->activeNode.data());
if (layer)
{
layer->disableAlphaChannel(!newActive);
layer->setDirty();
emit activeAChannelActiveChanged();
}
}
bool getActiveChannel(KisNodeSP node, int channelIndex)
{
KisLayer* layer = qobject_cast<KisLayer*>(node.data());
bool flag = false;
if (layer)
{
QBitArray flags = layer->channelFlags();
if (channelIndex < flags.size()) {
flag = flags[channelIndex];
}
}
return flag;
}
void setChannelActive(KisNodeSP node, int channelIndex, bool newActive)
{
KisLayer* layer = qobject_cast<KisLayer*>(node.data());
if (layer) {
QBitArray flags = layer->channelFlags();
flags.setBit(channelIndex, newActive);
layer->setChannelFlags(flags);
layer->setDirty();
}
}
bool LayerModel::activeBChannelActive() const
{
return getActiveChannel(d->activeNode, 2);
}
void LayerModel::setActiveBChannelActive(bool newActive)
{
setChannelActive(d->activeNode, 2, newActive);
emit activeBChannelActiveChanged();
}
bool LayerModel::activeGChannelActive() const
{
return getActiveChannel(d->activeNode, 1);
}
void LayerModel::setActiveGChannelActive(bool newActive)
{
setChannelActive(d->activeNode, 1, newActive);
emit activeGChannelActiveChanged();
}
bool LayerModel::activeRChannelActive() const
{
return getActiveChannel(d->activeNode, 0);
}
void LayerModel::setActiveRChannelActive(bool newActive)
{
setChannelActive(d->activeNode, 0, newActive);
emit activeRChannelActiveChanged();
}
QObject* LayerModel::activeFilterConfig() const
{
QMap<QString, QVariant> props;
QString filterId;
KisFilterMask* filterMask = qobject_cast<KisFilterMask*>(d->activeNode.data());
if (filterMask) {
props = filterMask->filter()->getProperties();
filterId = filterMask->filter()->name();
}
else {
KisAdjustmentLayer* adjustmentLayer = qobject_cast<KisAdjustmentLayer*>(d->activeNode.data());
if (adjustmentLayer)
{
props = adjustmentLayer->filter()->getProperties();
filterId = adjustmentLayer->filter()->name();
}
}
PropertyContainer* config = new PropertyContainer(filterId, 0);
QMap<QString, QVariant>::const_iterator i;
for(i = props.constBegin(); i != props.constEnd(); ++i) {
config->setProperty(i.key().toLatin1(), i.value());
//dbgKrita << "Getting active config..." << i.key() << i.value();
}
return config;
}
void LayerModel::setActiveFilterConfig(QObject* newConfig)
{
if (d->activeNode.isNull())
return;
PropertyContainer* config = qobject_cast<PropertyContainer*>(newConfig);
if (!config)
return;
//dbgKrita << "Attempting to set new config" << config->name();
KisFilterConfigurationSP realConfig = d->filters.value(config->name())->factoryConfiguration(KisGlobalResourcesInterface::instance());
QMap<QString, QVariant>::const_iterator i;
for(i = realConfig->getProperties().constBegin(); i != realConfig->getProperties().constEnd(); ++i)
{
realConfig->setProperty(i.key(), config->property(i.key().toLatin1()));
//dbgKrita << "Creating config..." << i.key() << i.value();
}
// The following code causes sporadic crashes, and disabling causes leaks. So, leaks it must be, for now.
// The cause is the lack of a smart pointer interface for passing filter configs around
// Must be remedied, but for now...
// if (d->newConfig)
// delete(d->newConfig);
d->newConfig = realConfig;
//d->updateActiveLayerWithNewFilterConfigTimer->start();
updateActiveLayerWithNewFilterConfig();
}
void LayerModel::updateActiveLayerWithNewFilterConfig()
{
if (!d->newConfig)
return;
//dbgKrita << "Setting new config..." << d->newConfig->name();
KisFilterMask* filterMask = qobject_cast<KisFilterMask*>(d->activeNode.data());
if (filterMask)
{
//dbgKrita << "Setting filter mask";
filterMask->setFilter(d->newConfig->cloneWithResourcesSnapshot());
}
else
{
KisAdjustmentLayer* adjustmentLayer = qobject_cast<KisAdjustmentLayer*>(d->activeNode.data());
if (adjustmentLayer)
{
//dbgKrita << "Setting filter on adjustment layer";
adjustmentLayer->setFilter(d->newConfig->cloneWithResourcesSnapshot());
}
else
{
//dbgKrita << "UNKNOWN, BAIL OUT!";
}
}
d->newConfig = 0;
d->activeNode->setDirty(d->activeNode->extent());
d->image->setModified();
QTimer::singleShot(100, this, SIGNAL(activeFilterConfigChanged()));
}
diff --git a/libs/odf/CMakeLists.txt b/libs/odf/CMakeLists.txt
deleted file mode 100644
index 6acbf4d1a5..0000000000
--- a/libs/odf/CMakeLists.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-add_subdirectory( tests )
-
-set(kritaodf_LIB_SRCS
- KoOdf.cpp
- KoOdfManifestEntry.cpp
- KoDocumentInfo.cpp
- KoGenStyle.cpp
- KoGenStyles.cpp
- KoFontFace.cpp
- KoOdfLoadingContext.cpp
- KoOasisSettings.cpp
- KoOdfStylesReader.cpp
- KoOdfNumberStyles.cpp
- KoOdfReadStore.cpp
- KoOdfWriteStore.cpp
- KoStyleStack.cpp
- KoOdfGraphicStyles.cpp
- KoGenChange.cpp
- KoGenChanges.cpp
- KoDocumentBase.cpp
- KoEmbeddedDocumentSaver.cpp
- KoBorder.cpp
- KoShadowStyle.cpp
- KoPageLayout.cpp
- KoPageFormat.cpp
- KoColumns.cpp
- KoUnit.cpp
- KoOdfNotesConfiguration.cpp
- KoOdfBibliographyConfiguration.cpp
- KoOdfNumberDefinition.cpp
- KoOdfLineNumberingConfiguration.cpp
- KoElementReference.cpp
-
- OdfDebug.cpp
-)
-
-add_library(kritaodf SHARED ${kritaodf_LIB_SRCS})
-generate_export_header(kritaodf BASE_NAME kritaodf)
-
-target_link_libraries(kritaodf kritaversion kritaplugin kritastore KF5::CoreAddons KF5::ConfigCore KF5::I18n Qt5::PrintSupport Qt5::Gui Qt5::Xml)
-
-set_target_properties(kritaodf PROPERTIES
- VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION}
-)
-install(TARGETS kritaodf ${INSTALL_TARGETS_DEFAULT_ARGS} )
diff --git a/libs/odf/KoBorder.cpp b/libs/odf/KoBorder.cpp
deleted file mode 100644
index c546abe8ff..0000000000
--- a/libs/odf/KoBorder.cpp
+++ /dev/null
@@ -1,1164 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2009 Inge Wallin <inge@lysator.liu.se>
- * Copyright (C) 2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
- *
- * 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 "KoBorder.h"
-
-#include <QPainter>
-
-#include <OdfDebug.h>
-
-#include <KoUnit.h>
-#include <KoXmlNS.h>
-#include <KoXmlReader.h>
-#include <KoStyleStack.h>
-
-
-class KoBorderPrivate : public QSharedData
-{
-public:
- KoBorderPrivate();
- ~KoBorderPrivate();
-
- QMap<KoBorder::BorderSide, KoBorder::BorderData> data;
-};
-
-KoBorderPrivate::KoBorderPrivate()
-{
-}
-
-KoBorderPrivate::~KoBorderPrivate()
-{
-}
-
-KoBorder::BorderData::BorderData()
- : style(KoBorder::BorderNone)
- , outerPen(QPen())
- , innerPen(QPen())
- , spacing(0)
-{
- outerPen.setWidthF(0.0f);
- innerPen.setWidthF(0.0f);
-}
-
-bool KoBorder::BorderData::operator==(const KoBorder::BorderData& other) const
-{
- // Left Borders
- if (style == BorderNone && other.style == BorderNone) {
- // If both styles are None, then the rest of the values don't
- // need to be compared.
- ;
- }
- else if (style != other.style) {
- // If any of them are non-None, and they are different, the
- // borders are also different.
- return false;
- }
- else {
- // Here we know that the border styles are the same, now
- // compare the rest of the values.
- if (outerPen != other.outerPen)
- return false;
-
- // If the border style == BorderDouble, then compare a couple
- // of other values too.
- if (style == BorderDouble) {
- if (innerPen != other.innerPen)
- return false;
- if (spacing != other.spacing)
- return false;
- }
- }
-
- return true;
-}
-
-// ----------------------------------------------------------------
-
-KoBorder::KoBorder()
- : d(new KoBorderPrivate)
-{
-}
-
-KoBorder::KoBorder(const KoBorder &kb)
- : d(kb.d)
-{
-}
-
-KoBorder::~KoBorder()
-{
- // No delete because d is a QSharedDataPointer.
-}
-
-
-// ----------------------------------------------------------------
-// operators
-
-KoBorder &KoBorder::operator=(const KoBorder &other)
-{
- d = other.d;
-
- return *this;
-}
-
-bool KoBorder::operator==(const KoBorder &other) const
-{
- if (d.data() == other.d.data())
- return true;
-
-
- if (d->data.size() != other.d->data.size())
- return false;
-
- KoBorder::BorderSide key;
-
- foreach (key, d->data.keys()) {
- if (!other.d->data.contains(key))
- return false;
- if (!(other.d->data[key] == d->data[key]))
- return false;
- }
-
- return true;
-}
-
-
-// ----------------------------------------------------------------
-// public, non-class functions
-
-KoBorder::BorderStyle KoBorder::odfBorderStyle(const QString &borderstyle, bool *converted)
-{
- // Note: the styles marked "Not odf compatible" below are legacies
- // from the old words format. There are also lots of border
- // styles in the MS DOC that we may have to handle at some point.
- if (converted)
- *converted = true;
- if (borderstyle == "none")
- return BorderNone;
- if (borderstyle == "solid")
- return BorderSolid;
- if (borderstyle == "dashed")
- return BorderDashed;
- if (borderstyle == "dotted")
- return BorderDotted;
- if (borderstyle == "dot-dash")
- return BorderDashDot;
- if (borderstyle == "dot-dot-dash")
- return BorderDashDotDot;
- if (borderstyle == "double")
- return BorderDouble;
- if (borderstyle == "groove") // Not odf compatible -- see above
- return BorderGroove;
- if (borderstyle == "ridge") // Not odf compatible -- see above
- return BorderRidge;
- if (borderstyle == "inset") // Not odf compatible -- see above
- return BorderInset;
- if (borderstyle == "outset") // Not odf compatible -- see above
- return BorderOutset;
- if (borderstyle == "dash-largegap")
- return KoBorder::BorderDashedLong;
- if (borderstyle == "slash") // not officially odf, but we support it anyway
- return KoBorder::BorderSlash;
- if (borderstyle == "wave") // not officially odf, but we support it anyway
- return KoBorder::BorderWave;
- if (borderstyle == "double-wave") // not officially odf, but we support it anyway
- return KoBorder::BorderDoubleWave;
-
- if (converted)
- *converted = false;
-
- return BorderSolid;
-}
-
-QString KoBorder::odfBorderStyleString(BorderStyle borderstyle)
-{
- switch (borderstyle) {
- case BorderDashed:
- return QString("dashed");
- case BorderDotted:
- return QString("dotted");
- case BorderDashDot:
- return QString("dot-dash");
- case BorderDashDotDot:
- return QString("dot-dot-dash");
- case BorderDouble:
- return QString("double");
- case BorderGroove:
- return QString("groove"); // not odf -- see above
- case BorderRidge:
- return QString("ridge"); // not odf -- see above
- case BorderInset:
- return QString("inset"); // not odf -- see above
- case BorderOutset:
- return QString("outset"); // not odf -- see above
- case BorderSolid:
- return QString("solid");
- case BorderNone:
- return QString("none");
-
- default:
- // Handle unknown types as solid.
- return QString("solid");
- }
-}
-
-QString KoBorder::msoBorderStyleString(BorderStyle borderstyle)
-{
- switch (borderstyle) {
- case KoBorder::BorderDashedLong:
- return QString("dash-largegap");
- case KoBorder::BorderSlash:
- return QString("slash"); // not officially odf, but we support it anyway
- case KoBorder::BorderWave:
- return QString("wave"); // not officially odf, but we support it anyway
- case KoBorder::BorderDoubleWave:
- return QString("double-wave"); // not officially odf, but we support it anyway
-
- default:
- // Handle remaining styles as odf type style.
- return odfBorderStyleString(borderstyle);
- }
-}
-
-
-// ----------------------------------------------------------------
-// Getters and Setters
-
-
-void KoBorder::setBorderStyle(BorderSide side, BorderStyle style)
-{
- if (d->data[side].style == style) {
- return;
- }
-
- if (!d->data.contains(side)) {
- BorderData data;
- data.style = style;
- d->data[side] = data;
- } else {
- d->data[side].style = style;
- }
-
- // Make a best effort to create the best possible dash pattern for the chosen style.
- // FIXME: KoTableCellStyle::setEdge() should call this function.
- BorderData &edge = d->data[side];
- qreal width = edge.outerPen.widthF();
- qreal innerWidth = 0;
- qreal middleWidth = 0;
- qreal space = 0;
- QVector<qreal> dashes;
- switch (style) {
- case KoBorder::BorderNone:
- width = 0.0;
- break;
- case KoBorder::BorderDouble:
- innerWidth = space = edge.outerPen.width() / 3; //some nice default look
- width -= (space + innerWidth);
- edge.outerPen.setStyle(Qt::SolidLine);
- break;
- case KoBorder::BorderDotted:
- dashes << 1 << 1;
- edge.outerPen.setDashPattern(dashes);
- break;
- case KoBorder::BorderDashed:
- dashes << 4 << 1;
- edge.outerPen.setDashPattern(dashes);
- break;
- case KoBorder::BorderDashedLong: {
- dashes << 4 << 4;
- edge.outerPen.setDashPattern(dashes);
- break;
- }
- case KoBorder::BorderTriple:
- innerWidth = middleWidth = space = width/6;
- width -= (space + innerWidth);
- edge.outerPen.setStyle(Qt::SolidLine);
- break;
- case KoBorder::BorderDashDot:
- dashes << 3 << 3<< 7 << 3;
- edge.outerPen.setDashPattern(dashes);
- break;
- case KoBorder::BorderDashDotDot:
- dashes << 2 << 2<< 6 << 2 << 2 << 2;
- edge.outerPen.setDashPattern(dashes);
- break;
- case KoBorder::BorderWave:
- edge.outerPen.setStyle(Qt::SolidLine);
- break;
- case KoBorder::BorderSlash:
- edge.outerPen.setStyle(Qt::SolidLine);
- break;
- case KoBorder::BorderDoubleWave:
- innerWidth = space = width/3; //some nice default look
- width -= (space + innerWidth);
- edge.outerPen.setStyle(Qt::SolidLine);
- break;
- default:
- edge.outerPen.setStyle(Qt::SolidLine);
- break;
- }
- edge.outerPen.setJoinStyle(Qt::MiterJoin);
- edge.outerPen.setCapStyle(Qt::FlatCap);
- edge.outerPen.setWidthF(width);
-
- edge.spacing = space;
- edge.innerPen = edge.outerPen;
- edge.innerPen.setWidthF(innerWidth);
-}
-
-KoBorder::BorderStyle KoBorder::borderStyle(BorderSide side) const
-{
- if (!d->data.contains(side)) {
- return BorderNone;
- } else {
- return d->data[side].style;
- }
-}
-
-void KoBorder::setBorderColor(BorderSide side, const QColor &color)
-{
- if (!d->data.contains(side)) {
- BorderData data;
- data.outerPen.setColor(color);
- d->data[side] = data;
- } else {
- d->data[side].outerPen.setColor(color);
- }
-}
-
-QColor KoBorder::borderColor(BorderSide side) const
-{
- if (!d->data.contains(side)) {
- return QColor();
- } else {
- return d->data[side].outerPen.color();
- }
-}
-
-void KoBorder::setBorderWidth(BorderSide side, qreal width)
-{
- if (!d->data.contains(side)) {
- BorderData data;
- data.outerPen.setWidthF(width);
- d->data[side] = data;
- } else {
- d->data[side].outerPen.setWidthF(width);
- }
-}
-
-qreal KoBorder::borderWidth(BorderSide side) const
-{
- if (!d->data.contains(side)) {
- return 0;
- } else {
- if (d->data[side].style == BorderDouble)
- return (d->data[side].outerPen.widthF() + d->data[side].innerPen.widthF()
- + d->data[side].spacing);
- else
- return d->data[side].outerPen.widthF();
- }
-}
-
-void KoBorder::setOuterBorderWidth(BorderSide side, qreal width)
-{
- if (!d->data.contains(side)) {
- BorderData data;
- data.outerPen.setWidthF(width);
- d->data[side] = data;
- } else {
- d->data[side].outerPen.setWidthF(width);
- }
-}
-
-qreal KoBorder::outerBorderWidth(BorderSide side) const
-{
- if (!d->data.contains(side)) {
- return 0;
- } else {
- return d->data[side].outerPen.widthF();
- }
-}
-
-void KoBorder::setInnerBorderWidth(BorderSide side, qreal width)
-{
- if (!d->data.contains(side)) {
- BorderData data;
- data.innerPen.setWidthF(width);
- d->data[side] = data;
- } else {
- d->data[side].innerPen.setWidthF(width);
- }
-}
-
-qreal KoBorder::innerBorderWidth(BorderSide side) const
-{
- if (!d->data.contains(side)) {
- return 0;
- } else {
- return d->data[side].innerPen.widthF();
- }
-}
-
-void KoBorder::setBorderSpacing(BorderSide side, qreal width)
-{
- if (!d->data.contains(side)) {
- BorderData data;
- data.spacing = width;
- d->data[side] = data;
- } else {
- d->data[side].spacing = width;
- }
-}
-
-qreal KoBorder::borderSpacing(BorderSide side) const
-{
- if (!d->data.contains(side)) {
- return 0;
- } else {
- return d->data[side].spacing;
- }
-}
-
-
-KoBorder::BorderData KoBorder::borderData(BorderSide side) const
-{
- return d->data.value(side, BorderData());
-}
-
-void KoBorder::setBorderData(BorderSide side, const BorderData &data)
-{
- d->data[side] = data;
-}
-
-
-// -------------------------------
-
-bool KoBorder::hasBorder() const
-{
- if (borderStyle(LeftBorder) != BorderNone && borderWidth(LeftBorder) > 0.0)
- return true;
- if (borderStyle(RightBorder) != BorderNone && borderWidth(RightBorder) > 0.0)
- return true;
- if (borderStyle(TopBorder) != BorderNone && borderWidth(TopBorder) > 0.0)
- return true;
- if (borderStyle(BottomBorder) != BorderNone && borderWidth(BottomBorder) > 0.0)
- return true;
- if (borderStyle(TlbrBorder) != BorderNone && borderWidth(TlbrBorder) > 0.0)
- return true;
- if (borderStyle(BltrBorder) != BorderNone && borderWidth(BltrBorder) > 0.0)
- return true;
- return false;
-}
-
-bool KoBorder::hasBorder(KoBorder::BorderSide side) const
-{
- return borderStyle(side) != BorderNone && borderWidth(side) > 0.0;
-}
-
-
-// ----------------------------------------------------------------
-// painting
-
-
-void KoBorder::paint(QPainter &painter, const QRectF &borderRect,
- BorderPaintArea whereToPaint) const
-{
- Q_UNUSED(whereToPaint);
- // In tables it is apparently best practice to paint the
- // horizontal lines over the vertical ones. So let's use the same
- // strategy here.
-
- QPointF start;
- QPointF end;
-
- // FIXME: Make KoBorder store pointers to BorderData instead. This is very inefficient.
- BorderData leftEdge = borderData(KoBorder::LeftBorder);
- BorderData rightEdge = borderData(KoBorder::RightBorder);
- BorderData topEdge = borderData(KoBorder::TopBorder);
- BorderData bottomEdge = borderData(KoBorder::BottomBorder);
-
- // Left border
- if (hasBorder(LeftBorder)) {
- start = borderRect.topLeft();
- end = borderRect.bottomLeft();
- paintBorderSide(painter, start, end, &leftEdge, true,
- hasBorder(TopBorder) ? &topEdge : 0,
- hasBorder(BottomBorder) ? &bottomEdge : 0,
- 1);
- }
-
- // Right border
- if (hasBorder(RightBorder)) {
- start = borderRect.topRight();
- end = borderRect.bottomRight();
- paintBorderSide(painter, start, end, &rightEdge, true,
- hasBorder(TopBorder) ? &topEdge : 0,
- hasBorder(BottomBorder) ? &bottomEdge : 0,
- -1);
- }
-
- // Top border
- if (hasBorder(TopBorder)) {
- start = borderRect.topLeft();
- end = borderRect.topRight();
- paintBorderSide(painter, start, end, &topEdge, false,
- hasBorder(LeftBorder) ? &leftEdge : 0,
- hasBorder(RightBorder) ? &rightEdge : 0,
- 1);
- }
-
- // Bottom border
- if (hasBorder(BottomBorder)) {
- start = borderRect.bottomLeft();
- end = borderRect.bottomRight();
- paintBorderSide(painter, start, end, &bottomEdge, false,
- hasBorder(LeftBorder) ? &leftEdge : 0,
- hasBorder(RightBorder) ? &rightEdge : 0,
- -1);
- }
-
- // FIXME: Diagonal borders
-}
-
-void KoBorder::paintBorderSide(QPainter &painter, QPointF lineStart, QPointF lineEnd,
- BorderData *borderData, bool isVertical,
- BorderData *neighbour1, BorderData *neighbour2,
- int inwardsAcross) const
-{
- // Adjust the outer line so that it is inside the boundary.
- qreal displacement = borderData->outerPen.widthF() / qreal(2.0);
- if (isVertical) {
- lineStart.setX(lineStart.x() + inwardsAcross * displacement);
- lineEnd.setX(lineEnd.x() + inwardsAcross * displacement);
- }
- else {
- lineStart.setY(lineStart.y() + inwardsAcross * displacement);
- lineEnd.setY(lineEnd.y() + inwardsAcross * displacement);
- }
-
- painter.setPen(borderData->outerPen);
- painter.drawLine(lineStart, lineEnd);
-
- if (borderData->style == BorderDouble) {
- displacement = (borderData->outerPen.widthF() / qreal(2.0)
- + borderData->spacing
- + borderData->innerPen.widthF() / qreal(2.0));
- if (isVertical) {
- lineStart.setX(lineStart.x() + inwardsAcross * displacement);
- lineEnd.setX(lineEnd.x() + inwardsAcross * displacement);
- }
- else {
- lineStart.setY(lineStart.y() + inwardsAcross * displacement);
- lineEnd.setY(lineEnd.y() + inwardsAcross * displacement);
- }
-
- // Adjust for neighboring inner lines.
- if (neighbour1 && neighbour1->style == BorderDouble) {
- displacement = neighbour1->outerPen.widthF() + neighbour1->spacing;
- if (isVertical) {
- lineStart.setY(lineStart.y() + displacement);
- }
- else {
- lineStart.setX(lineStart.x() + displacement);
- }
- }
- if (neighbour2 && neighbour2->style == BorderDouble) {
- displacement = neighbour2->outerPen.widthF() + neighbour2->spacing;
- if (isVertical) {
- lineEnd.setY(lineEnd.y() - displacement);
- }
- else {
- lineEnd.setX(lineEnd.x() - displacement);
- }
- }
-
- // Draw the inner line.
- painter.setPen(borderData->innerPen);
- painter.drawLine(lineStart, lineEnd);
- }
-}
-
-
-// ----------------------------------------------------------------
-// static functions
-
-
-void parseOdfBorder(const QString &border, QColor *color,
- KoBorder::BorderStyle *borderStyle, bool *hasBorderStyle,
- qreal *borderWidth, bool *hasBorderWidth)
-{
- *hasBorderStyle = false;
- *hasBorderWidth = false;
-
- if (!border.isEmpty() && border != "none" && border != "hidden") {
- QStringList borderData = border.split(' ', QString::SkipEmptyParts);
- if (borderData.length() > 0)
- {
- const QColor borderColor = QColor(borderData.last());
- if (borderColor.isValid()) {
- *color = borderColor;
- borderData.removeLast();
- }
-
- bool converted = false;
- const KoBorder::BorderStyle parsedBorderStyle = KoBorder::odfBorderStyle(borderData.last(), &converted);
- if (converted) {
- *hasBorderStyle = true;
- borderData.removeLast();
- *borderStyle = parsedBorderStyle;
- }
-
- if (!borderData.isEmpty()) {
- const qreal parsedBorderWidth = KoUnit::parseValue(borderData[0], 1.0);
- *borderWidth = parsedBorderWidth;
- *hasBorderWidth = true;
- }
- }
- }
-}
-
-// ----------------------------------------------------------------
-// load and save
-
-bool KoBorder::loadOdf(const KoXmlElement &style)
-{
- bool result = false;
-
- QString borderString;
- bool hasSpecialBorder;
- QString specialBorderString;
- if (style.hasAttributeNS(KoXmlNS::fo, "border")) {
- borderString = style.attributeNS(KoXmlNS::fo, "border");
- if (borderString == "none") {
- // We use the "false" to indicate that there is no border
- // rather than that the parsing has failed.
- return false;
- }
-
- result = true;
- if ((hasSpecialBorder = style.hasAttributeNS(KoXmlNS::calligra, "specialborder"))) {
- specialBorderString = style.attributeNS(KoXmlNS::calligra, "specialborder");
- }
- parseAndSetBorder(borderString, hasSpecialBorder, specialBorderString);
- }
- else {
- // No common border attributes, check for the individual ones.
- if (style.hasAttributeNS(KoXmlNS::fo, "border-left")) {
- result = true;
- borderString = style.attributeNS(KoXmlNS::fo, "border-left");
- if ((hasSpecialBorder = style.hasAttributeNS(KoXmlNS::calligra, "specialborder-left"))) {
- specialBorderString = style.attributeNS(KoXmlNS::calligra, "specialborder-left");
- }
- parseAndSetBorder(LeftBorder, borderString, hasSpecialBorder, specialBorderString);
- }
- if (style.hasAttributeNS(KoXmlNS::fo, "border-top")) {
- result = true;
- borderString = style.attributeNS(KoXmlNS::fo, "border-top");
- if ((hasSpecialBorder = style.hasAttributeNS(KoXmlNS::calligra, "specialborder-top"))) {
- specialBorderString = style.attributeNS(KoXmlNS::calligra, "specialborder-top");
- }
- parseAndSetBorder(TopBorder, borderString, hasSpecialBorder, specialBorderString);
- }
- if (style.hasAttributeNS(KoXmlNS::fo, "border-right")) {
- result = true;
- borderString = style.attributeNS(KoXmlNS::fo, "border-right");
- if ((hasSpecialBorder = style.hasAttributeNS(KoXmlNS::calligra, "specialborder-right"))) {
- specialBorderString = style.attributeNS(KoXmlNS::calligra, "specialborder-right");
- }
- parseAndSetBorder(RightBorder, borderString, hasSpecialBorder, specialBorderString);
- }
- if (style.hasAttributeNS(KoXmlNS::fo, "border-bottom")) {
- result = true;
- borderString = style.attributeNS(KoXmlNS::fo, "border-bottom");
- if ((hasSpecialBorder = style.hasAttributeNS(KoXmlNS::calligra, "specialborder-bottom"))) {
- specialBorderString = style.attributeNS(KoXmlNS::calligra, "specialborder-bottom");
- }
- parseAndSetBorder(BottomBorder, borderString, hasSpecialBorder, specialBorderString);
- }
- }
-
- // Diagonals are treated individually and are NOT part of <style:border>.
- if (style.hasAttributeNS(KoXmlNS::style, "diagonal-tl-br")) {
- result = true;
- borderString = style.attributeNS(KoXmlNS::fo, "border-tl-br");
- if ((hasSpecialBorder = style.hasAttributeNS(KoXmlNS::calligra, "specialborder-tl-br"))) {
- specialBorderString = style.attributeNS(KoXmlNS::calligra, "specialborder-tl-br");
- }
- parseAndSetBorder(TlbrBorder, borderString, hasSpecialBorder, specialBorderString);
- }
- if (style.hasAttributeNS(KoXmlNS::style, "diagonal-bl-tr")) {
- result = true;
- borderString = style.attributeNS(KoXmlNS::fo, "border-bl-tr");
- if ((hasSpecialBorder = style.hasAttributeNS(KoXmlNS::calligra, "specialborder-bl-tr"))) {
- specialBorderString = style.attributeNS(KoXmlNS::calligra, "specialborder-bl-tr");
- }
- parseAndSetBorder(BltrBorder, borderString, hasSpecialBorder, specialBorderString);
- }
-
- // Handle double borders.
- if (style.hasAttributeNS(KoXmlNS::style, "border-line-width")) {
- result = true;
- QString borderLineWidth = style.attributeNS(KoXmlNS::style, "border-line-width");
- if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
- QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
- setInnerBorderWidth(LeftBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(LeftBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(LeftBorder, KoUnit::parseValue(blw[2], 0.1));
-
- setInnerBorderWidth(TopBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(TopBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(TopBorder, KoUnit::parseValue(blw[2], 0.1));
-
- setInnerBorderWidth(RightBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(RightBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(RightBorder, KoUnit::parseValue(blw[2], 0.1));
-
- setInnerBorderWidth(BottomBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(BottomBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(BottomBorder, KoUnit::parseValue(blw[2], 0.1));
- }
- }
- else {
- if (style.hasAttributeNS(KoXmlNS::style, "border-line-width-left")) {
- result = true;
- QString borderLineWidth = style.attributeNS(KoXmlNS::style, "border-line-width-left");
- if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
- QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
- setInnerBorderWidth(LeftBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(LeftBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(LeftBorder, KoUnit::parseValue(blw[2], 0.1));
- }
- }
- if (style.hasAttributeNS(KoXmlNS::style, "border-line-width-top")) {
- result = true;
- QString borderLineWidth = style.attributeNS(KoXmlNS::style, "border-line-width-top");
- if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
- QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
- setInnerBorderWidth(TopBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(TopBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(TopBorder, KoUnit::parseValue(blw[2], 0.1));
- }
- }
- if (style.hasAttributeNS(KoXmlNS::style, "border-line-width-right")) {
- result = true;
- QString borderLineWidth = style.attributeNS(KoXmlNS::style, "border-line-width-right");
- if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
- QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
- setInnerBorderWidth(RightBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(RightBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(RightBorder, KoUnit::parseValue(blw[2], 0.1));
- }
- }
- if (style.hasAttributeNS(KoXmlNS::style, "border-line-width-bottom")) {
- result = true;
- QString borderLineWidth = style.attributeNS(KoXmlNS::style, "border-line-width-bottom");
- if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
- QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
- setInnerBorderWidth(BottomBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(BottomBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(BottomBorder, KoUnit::parseValue(blw[2], 0.1));
- }
- }
- }
-
- if (style.hasAttributeNS(KoXmlNS::style, "diagonal-tl-br-widths")) {
- result = true;
- QString borderLineWidth = style.attributeNS(KoXmlNS::style, "diagonal-tl-br-widths");
- if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
- QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
- setInnerBorderWidth(TlbrBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(TlbrBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(TlbrBorder, KoUnit::parseValue(blw[2], 0.1));
- }
- }
- if (style.hasAttributeNS(KoXmlNS::style, "diagonal-bl-tr-widths")) {
- result = true;
- QString borderLineWidth = style.attributeNS(KoXmlNS::style, "diagonal-bl-tr-widths");
- if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
- QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
- setInnerBorderWidth(BltrBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(BltrBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(BltrBorder, KoUnit::parseValue(blw[2], 0.1));
- }
- }
- return result;
-}
-
-bool KoBorder::loadOdf(const KoStyleStack &styleStack)
-{
- bool result = false;
-
- QString borderString;
- bool hasSpecialBorder;
- QString specialBorderString;
- if (styleStack.hasProperty(KoXmlNS::fo, "border")) {
- result = true;
- borderString = styleStack.property(KoXmlNS::fo, "border");
- if ((hasSpecialBorder = styleStack.hasProperty(KoXmlNS::calligra, "specialborder"))) {
- specialBorderString = styleStack.property(KoXmlNS::calligra, "specialborder");
- }
- parseAndSetBorder(borderString, hasSpecialBorder, specialBorderString);
- }
-
- // Even if there are common border attributes, check for the
- // individual ones since they have precedence.
-
- if (styleStack.hasProperty(KoXmlNS::fo, "border-left")) {
- result = true;
- borderString = styleStack.property(KoXmlNS::fo, "border-left");
- if ((hasSpecialBorder = styleStack.hasProperty(KoXmlNS::calligra, "specialborder-left"))) {
- specialBorderString = styleStack.property(KoXmlNS::calligra, "specialborder-left");
- }
- parseAndSetBorder(LeftBorder, borderString, hasSpecialBorder, specialBorderString);
- }
- if (styleStack.hasProperty(KoXmlNS::fo, "border-top")) {
- result = true;
- borderString = styleStack.property(KoXmlNS::fo, "border-top");
- if ((hasSpecialBorder = styleStack.hasProperty(KoXmlNS::calligra, "specialborder-top"))) {
- specialBorderString = styleStack.property(KoXmlNS::calligra, "specialborder-top");
- }
- parseAndSetBorder(TopBorder, borderString, hasSpecialBorder, specialBorderString);
- }
- if (styleStack.hasProperty(KoXmlNS::fo, "border-right")) {
- result = true;
- borderString = styleStack.property(KoXmlNS::fo, "border-right");
- if ((hasSpecialBorder = styleStack.hasProperty(KoXmlNS::calligra, "specialborder-right"))) {
- specialBorderString = styleStack.property(KoXmlNS::calligra, "specialborder-right");
- }
- parseAndSetBorder(RightBorder, borderString, hasSpecialBorder, specialBorderString);
-
- }
- if (styleStack.hasProperty(KoXmlNS::fo, "border-bottom")) {
- result = true;
- borderString = styleStack.property(KoXmlNS::fo, "border-bottom");
- if ((hasSpecialBorder = styleStack.hasProperty(KoXmlNS::calligra, "specialborder-bottom"))) {
- specialBorderString = styleStack.property(KoXmlNS::calligra, "specialborder-bottom");
- }
- parseAndSetBorder(BottomBorder, borderString, hasSpecialBorder, specialBorderString);
- }
-
- // Diagonals are treated individually and are NOT part of <style:border>.
- if (styleStack.hasProperty(KoXmlNS::style, "diagonal-tl-br")) {
- result = true;
- borderString = styleStack.property(KoXmlNS::fo, "border-tl-br");
- if ((hasSpecialBorder = styleStack.hasProperty(KoXmlNS::calligra, "specialborder-tl-br"))) {
- specialBorderString = styleStack.property(KoXmlNS::calligra, "specialborder-tl-br");
- }
- parseAndSetBorder(TlbrBorder, borderString, hasSpecialBorder, specialBorderString);
- }
- if (styleStack.hasProperty(KoXmlNS::style, "diagonal-bl-tr")) {
- result = true;
- borderString = styleStack.property(KoXmlNS::fo, "border-bl-tr");
- if ((hasSpecialBorder = styleStack.hasProperty(KoXmlNS::calligra, "specialborder-bl-tr"))) {
- specialBorderString = styleStack.property(KoXmlNS::calligra, "specialborder-bl-tr");
- }
- parseAndSetBorder(BltrBorder, borderString, hasSpecialBorder, specialBorderString);
- }
-
- // Handle double borders.
- if (styleStack.hasProperty(KoXmlNS::style, "border-line-width")) {
- result = true;
- QString borderLineWidth = styleStack.property(KoXmlNS::style, "border-line-width");
- if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
- QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
- setInnerBorderWidth(LeftBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(LeftBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(LeftBorder, KoUnit::parseValue(blw[2], 0.1));
-
- setInnerBorderWidth(TopBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(TopBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(TopBorder, KoUnit::parseValue(blw[2], 0.1));
-
- setInnerBorderWidth(RightBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(RightBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(RightBorder, KoUnit::parseValue(blw[2], 0.1));
-
- setInnerBorderWidth(BottomBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(BottomBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(BottomBorder, KoUnit::parseValue(blw[2], 0.1));
- }
- }
- // Even if there are common border attributes, check for the
- // individual ones since they have precedence.
-
- if (styleStack.hasProperty(KoXmlNS::style, "border-line-width-left")) {
- result = true;
- QString borderLineWidth = styleStack.property(KoXmlNS::style, "border-line-width-left");
- if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
- QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
- setInnerBorderWidth(LeftBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(LeftBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(LeftBorder, KoUnit::parseValue(blw[2], 0.1));
- }
- }
- if (styleStack.hasProperty(KoXmlNS::style, "border-line-width-top")) {
- result = true;
- QString borderLineWidth = styleStack.property(KoXmlNS::style, "border-line-width-top");
- if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
- QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
- setInnerBorderWidth(TopBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(TopBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(TopBorder, KoUnit::parseValue(blw[2], 0.1));
- }
- }
- if (styleStack.hasProperty(KoXmlNS::style, "border-line-width-right")) {
- result = true;
- QString borderLineWidth = styleStack.property(KoXmlNS::style, "border-line-width-right");
- if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
- QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
- setInnerBorderWidth(RightBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(RightBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(RightBorder, KoUnit::parseValue(blw[2], 0.1));
- }
- }
- if (styleStack.hasProperty(KoXmlNS::style, "border-line-width-bottom")) {
- result = true;
- QString borderLineWidth = styleStack.property(KoXmlNS::style, "border-line-width-bottom");
- if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
- QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
- setInnerBorderWidth(BottomBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(BottomBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(BottomBorder, KoUnit::parseValue(blw[2], 0.1));
- }
- }
-
- // Diagonals are treated individually and are NOT part of <style:border>.
- if (styleStack.hasProperty(KoXmlNS::style, "diagonal-tl-br-widths")) {
- result = true;
- QString borderLineWidth = styleStack.property(KoXmlNS::style, "diagonal-tl-br-widths");
- if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
- QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
- setInnerBorderWidth(TlbrBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(TlbrBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(TlbrBorder, KoUnit::parseValue(blw[2], 0.1));
- }
- }
- if (styleStack.hasProperty(KoXmlNS::style, "diagonal-bl-tr-widths")) {
- result = true;
- QString borderLineWidth = styleStack.property(KoXmlNS::style, "diagonal-bl-tr-widths");
- if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
- QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
- setInnerBorderWidth(BltrBorder, KoUnit::parseValue(blw[0], 0.1));
- setBorderSpacing(BltrBorder, KoUnit::parseValue(blw[1], 1.0));
- setBorderWidth(BltrBorder, KoUnit::parseValue(blw[2], 0.1));
- }
- }
-
- return result;
-}
-
-
-// Private
-void KoBorder::parseAndSetBorder(const QString &borderString,
- bool hasSpecialBorder, const QString &specialBorderString)
-{
- if (borderString == "none") {
- return;
- }
-
- //debugOdf << "*** *** Found border: " << border;
- QColor bordersColor;
- BorderStyle bordersStyle;
- qreal bordersWidth;
- bool foundStyle;
- bool foundWidth;
- parseOdfBorder(borderString, &bordersColor, &bordersStyle, &foundStyle,
- &bordersWidth, &foundWidth);
- if (bordersColor.isValid()) {
- setBorderColor(LeftBorder, bordersColor);
- setBorderColor(TopBorder, bordersColor);
- setBorderColor(RightBorder, bordersColor);
- setBorderColor(BottomBorder, bordersColor);
- }
- if (hasSpecialBorder) {
- bordersStyle = KoBorder::odfBorderStyle(specialBorderString, &foundStyle);
- }
-
- if (foundStyle) {
- setBorderStyle(LeftBorder, bordersStyle);
- setBorderStyle(TopBorder, bordersStyle);
- setBorderStyle(RightBorder, bordersStyle);
- setBorderStyle(BottomBorder, bordersStyle);
- }
- if (foundWidth) {
- setBorderWidth(LeftBorder, bordersWidth);
- setBorderWidth(TopBorder, bordersWidth);
- setBorderWidth(RightBorder, bordersWidth);
- setBorderWidth(BottomBorder, bordersWidth);
- }
-}
-
-// Private
-void KoBorder::parseAndSetBorder(const BorderSide borderSide, const QString &borderString,
- bool hasSpecialBorder, const QString &specialBorderString)
-{
- QColor borderColor;
- BorderStyle borderStyle;
- qreal borderWidth;
- bool foundStyle;
- bool foundWidth;
-
- parseOdfBorder(borderString, &borderColor, &borderStyle, &foundStyle,
- &borderWidth, &foundWidth);
- if (borderColor.isValid()) {
- setBorderColor(borderSide, borderColor);
- }
- if (hasSpecialBorder) {
- borderStyle = KoBorder::odfBorderStyle(specialBorderString, &foundStyle);
- }
-
- if (foundStyle) {
- setBorderStyle( borderSide, borderStyle);
- }
- if (foundWidth) {
- setBorderWidth( borderSide, borderWidth);
- }
-}
-
-void KoBorder::saveOdf(KoGenStyle &style, KoGenStyle::PropertyType type) const
-{
- // Get the strings that describe respective borders.
- QString leftBorderString = QString("%1pt %2 %3")
- .arg(QString::number(borderWidth(LeftBorder)),
- odfBorderStyleString(borderStyle(LeftBorder)),
- borderColor(LeftBorder).name());
- QString rightBorderString = QString("%1pt %2 %3")
- .arg(QString::number(borderWidth(RightBorder)),
- odfBorderStyleString(borderStyle(RightBorder)),
- borderColor(RightBorder).name());
- QString topBorderString = QString("%1pt %2 %3")
- .arg(QString::number(borderWidth(TopBorder)),
- odfBorderStyleString(borderStyle(TopBorder)),
- borderColor(TopBorder).name());
- QString bottomBorderString = QString("%1pt %2 %3")
- .arg(QString::number(borderWidth(BottomBorder)),
- odfBorderStyleString(borderStyle(BottomBorder)),
- borderColor(BottomBorder).name());
-
- QString tlbrBorderString = QString("%1pt %2 %3")
- .arg(QString::number(borderWidth(TlbrBorder)),
- odfBorderStyleString(borderStyle(TlbrBorder)),
- borderColor(TlbrBorder).name());
- QString trblBorderString = QString("%1pt %2 %3")
- .arg(QString::number(borderWidth(BltrBorder)),
- odfBorderStyleString(borderStyle(BltrBorder)),
- borderColor(BltrBorder).name());
-
- // Get the strings that describe respective special borders (for special mso support).
- QString leftBorderSpecialString = msoBorderStyleString(borderStyle(LeftBorder));
- QString rightBorderSpecialString = msoBorderStyleString(borderStyle(RightBorder));
- QString topBorderSpecialString = msoBorderStyleString(borderStyle(TopBorder));
- QString bottomBorderSpecialString = msoBorderStyleString(borderStyle(BottomBorder));
- QString tlbrBorderSpecialString = msoBorderStyleString(borderStyle(TlbrBorder));
- QString trblBorderSpecialString = msoBorderStyleString(borderStyle(BltrBorder));
-
- // Check if we can save all borders in one fo:border attribute, or
- // if we have to use several different ones like fo:border-left, etc.
- if (leftBorderString == rightBorderString
- && leftBorderString == topBorderString
- && leftBorderString == bottomBorderString) {
-
- // Yes, they were all the same, so use only fo:border
- style.addProperty("fo:border", leftBorderString, type);
- style.addProperty("calligra:specialborder-left", leftBorderSpecialString, type);
- style.addProperty("calligra:specialborder-right", rightBorderSpecialString, type);
- style.addProperty("calligra:specialborder-top", topBorderSpecialString, type);
- style.addProperty("calligra:specialborder-bottom", bottomBorderSpecialString, type);
- } else {
- // No, they were different, so use the individual borders.
- //if (leftBorderStyle() != BorderNone)
- style.addProperty("fo:border-left", leftBorderString, type);
- style.addProperty("calligra:specialborder-left", leftBorderSpecialString, type);
- //if (rightBorderStyle() != BorderNone)
- style.addProperty("fo:border-right", rightBorderString, type);
- style.addProperty("calligra:specialborder-right", rightBorderSpecialString, type);
- //if (topBorderStyle() != BorderNone)
- style.addProperty("fo:border-top", topBorderString, type);
- style.addProperty("calligra:specialborder-top", topBorderSpecialString, type);
- //if (bottomBorderStyle() != BorderNone)
- style.addProperty("fo:border-bottom", bottomBorderString, type);
- style.addProperty("calligra:specialborder-bottom", bottomBorderSpecialString, type);
- }
-
- if (style.type() != KoGenStyle::PageLayoutStyle) {
- //if (tlbrBorderStyle() != BorderNone) {
- style.addProperty("style:diagonal-tl-br", tlbrBorderString, type);
- //}
- //if (trblBorderStyle() != BorderNone) {
- style.addProperty("style:diagonal-bl-tr", trblBorderString, type);
- //}
- }
-
- // Handle double borders
- QString leftBorderLineWidth = QString("%1pt %2pt %3pt")
- .arg(QString::number(innerBorderWidth(LeftBorder)),
- QString::number(borderSpacing(LeftBorder)),
- QString::number(borderWidth(LeftBorder)));
- QString rightBorderLineWidth = QString("%1pt %2pt %3pt")
- .arg(QString::number(innerBorderWidth(RightBorder)),
- QString::number(borderSpacing(RightBorder)),
- QString::number(borderWidth(RightBorder)));
- QString topBorderLineWidth = QString("%1pt %2pt %3pt")
- .arg(QString::number(innerBorderWidth(TopBorder)),
- QString::number(borderSpacing(TopBorder)),
- QString::number(borderWidth(TopBorder)));
- QString bottomBorderLineWidth = QString("%1pt %2pt %3pt")
- .arg(QString::number(innerBorderWidth(BottomBorder)),
- QString::number(borderSpacing(BottomBorder)),
- QString::number(borderWidth(BottomBorder)));
-
- QString tlbrBorderLineWidth = QString("%1pt %2pt %3pt")
- .arg(QString::number(innerBorderWidth(TlbrBorder)),
- QString::number(borderSpacing(TlbrBorder)),
- QString::number(borderWidth(TlbrBorder)));
- QString trblBorderLineWidth = QString("%1pt %2pt %3pt")
- .arg(QString::number(innerBorderWidth(BltrBorder)),
- QString::number(borderSpacing(BltrBorder)),
- QString::number(borderWidth(BltrBorder)));
-
- if (leftBorderLineWidth == rightBorderLineWidth
- && leftBorderLineWidth == topBorderLineWidth
- && leftBorderLineWidth == bottomBorderLineWidth
- && borderStyle(LeftBorder) == borderStyle(RightBorder)
- && borderStyle(TopBorder) == borderStyle(BottomBorder)
- && borderStyle(TopBorder) == borderStyle(LeftBorder)
- && (borderStyle(LeftBorder) == BorderDouble || borderStyle(LeftBorder) == BorderDoubleWave)) {
- style.addProperty("style:border-line-width", leftBorderLineWidth, type);
- } else {
- if (borderStyle(LeftBorder) == BorderDouble || borderStyle(LeftBorder) == BorderDoubleWave)
- style.addProperty("style:border-line-width-left", leftBorderLineWidth, type);
- if (borderStyle(RightBorder) == BorderDouble || borderStyle(RightBorder) == BorderDoubleWave)
- style.addProperty("style:border-line-width-right", rightBorderLineWidth, type);
- if (borderStyle(TopBorder) == BorderDouble || borderStyle(TopBorder) == BorderDoubleWave)
- style.addProperty("style:border-line-width-top", topBorderLineWidth, type);
- if (borderStyle(BottomBorder) == BorderDouble || borderStyle(BottomBorder) == BorderDoubleWave)
- style.addProperty("style:border-line-width-bottom", bottomBorderLineWidth, type);
- }
-
- if (style.type() != KoGenStyle::PageLayoutStyle) {
- if (borderStyle(TlbrBorder) == BorderDouble || borderStyle(TlbrBorder) == BorderDoubleWave) {
- style.addProperty("style:diagonal-tl-br-widths", tlbrBorderLineWidth, type);
- }
- if (borderStyle(BltrBorder) == BorderDouble || borderStyle(BltrBorder) == BorderDoubleWave) {
- style.addProperty("style:diagonal-bl-tr-widths", trblBorderLineWidth, type);
- }
- }
-}
diff --git a/libs/odf/KoBorder.h b/libs/odf/KoBorder.h
deleted file mode 100644
index bcabbf8dec..0000000000
--- a/libs/odf/KoBorder.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2009 Inge wallin <inge@lysator.liu.se>
- * Copyright (C) 2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
- *
- * 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 KOBORDER_H
-#define KOBORDER_H
-
-#include "kritaodf_export.h"
-
-#include <QPen>
-#include <QSharedData>
-#include <QMetaType>
-
-#include "KoXmlReaderForward.h"
-#include "KoGenStyle.h"
-
-class QPainter;
-class KoStyleStack;
-class KoBorderPrivate;
-
-class QColor;
-
-/**
- * A container for all properties of a generic border as defined by ODF.
- *
- * A border is used in at least the following contexts:
- * - paragraph
- * - page
- * - table
- * - table cell
- *
- */
-
-class KRITAODF_EXPORT KoBorder
-{
-public:
-
- // Names of the border sides.
- //
- // The "rect" we refer to below is the rectangle around the object
- // with the border. This could be a page, a cell, a paragraph, etc.
- enum BorderSide {
- TopBorder = 0, ///< References the border at the top of the rect
- LeftBorder, ///< References the border at the left side of the rect
- BottomBorder, ///< References the border at the bottom of the rect
- RightBorder, ///< References the border at the right side of the rect
- TlbrBorder, ///< References the border from top left corner to bottom right corner of cell
- BltrBorder ///< References the border from bottom left corner to top right corner of cell
- };
-
- /// Names of the different types of borders.
- //
- // Note that some of the border types are legacies from the old Words format.
- enum BorderStyle {
- BorderNone, ///< no border. This value forces the computed value of 'border-width' to be '0'.
- BorderDotted, ///< The border is a series of dots.
- BorderDashed, ///< The border is a series of short line segments.
- BorderSolid, ///< The border is a single line segment.
- BorderDouble, ///< The border is two solid lines. The sum of the two lines and the space between them equals the value of 'border-width'.
- BorderGroove, ///< The border looks as though it were carved into the canvas. (old words type)
- BorderRidge, ///< The opposite of 'groove': the border looks as though it were coming out of the canvas. (old words type)
- BorderInset, ///< The border makes the entire box look as though it were embedded in the canvas. (old words type)
- BorderOutset, ///< The opposite of 'inset': the border makes the entire box look as though it were coming out of the canvas. (old words type)
-
- BorderDashedLong, ///< Dashed single border with long spaces
- BorderTriple, ///< Triple lined border
- BorderSlash, ///< slash border
- BorderWave, ///< wave border
- BorderDoubleWave, ///< double wave border
-
- // words legacy
- BorderDashDot,
- BorderDashDotDot
- };
-
- /// Holds data about one border line.
- struct KRITAODF_EXPORT BorderData {
- BorderData();
-
- /// Compare the border data with another one
- bool operator==(const BorderData &other) const;
-
- BorderStyle style; ///< The border style. (see KoBorder::BorderStyle)
- QPen outerPen; ///< Holds the outer line when borderstyle is double and the whole line otherwise
- QPen innerPen; ///< Holds the inner line when borderstyle is double
- qreal spacing; ///< Holds the spacing between the outer and inner lines.
- };
-
-
- /// Constructor
- KoBorder();
- KoBorder(const KoBorder &kb);
-
- /// Destructor
- ~KoBorder();
-
- /// Assignment
- KoBorder &operator=(const KoBorder &other);
-
- /// Compare the border with another one
- bool operator==(const KoBorder &other) const;
- bool operator!=(const KoBorder &other) const { return !operator==(other); }
-
- void setBorderStyle(BorderSide side, BorderStyle style);
- BorderStyle borderStyle(BorderSide side) const;
- void setBorderColor(BorderSide side, const QColor &color);
- QColor borderColor(BorderSide side) const;
- void setBorderWidth(BorderSide side, qreal width);
- qreal borderWidth(BorderSide side) const;
- void setOuterBorderWidth(BorderSide side, qreal width);
- qreal outerBorderWidth(BorderSide side) const;
- void setInnerBorderWidth(BorderSide side, qreal width);
- qreal innerBorderWidth(BorderSide side) const;
- void setBorderSpacing(BorderSide side, qreal width);
- qreal borderSpacing(BorderSide side) const;
-
- BorderData borderData(BorderSide side) const;
- void setBorderData(BorderSide side, const BorderData &data);
-
- bool hasBorder() const;
- bool hasBorder(BorderSide side) const;
-
- enum BorderPaintArea {
- PaintOnLine,
- PaintInsideLine
- };
- void paint(QPainter &painter, const QRectF &borderRect,
- BorderPaintArea whereToPaint = PaintInsideLine) const;
-
- /**
- * Load the style from the element
- *
- * @param style the element containing the style to read from
- * @return true when border attributes were found
- */
- bool loadOdf(const KoXmlElement &style);
- bool loadOdf(const KoStyleStack &styleStack);
- void saveOdf(KoGenStyle &style, KoGenStyle::PropertyType type = KoGenStyle::DefaultType) const;
-
-
- // Some public functions used in other places where borders are handled.
- // Example: KoParagraphStyle
- // FIXME: These places should be made to use KoBorder instead.
- static BorderStyle odfBorderStyle(const QString &borderstyle, bool *converted = 0);
- static QString odfBorderStyleString(BorderStyle borderstyle);
- static QString msoBorderStyleString(BorderStyle borderstyle);
-
- private:
- void paintBorderSide(QPainter &painter, QPointF lineStart, QPointF lineEnd,
- BorderData *borderData, bool isVertical,
- BorderData *neighbour1, BorderData *neighbor2,
- int inwardsAcross) const;
-
- void parseAndSetBorder(const QString &border,
- bool hasSpecialBorder, const QString &specialBorderString);
- void parseAndSetBorder(const BorderSide borderSide, const QString &border,
- bool hasSpecialBorder, const QString &specialBorderString);
-
-private:
- QSharedDataPointer<KoBorderPrivate> d;
-};
-
-Q_DECLARE_METATYPE(KoBorder)
-
-
-#endif
diff --git a/libs/odf/KoColumns.cpp b/libs/odf/KoColumns.cpp
deleted file mode 100644
index 6307056ca5..0000000000
--- a/libs/odf/KoColumns.cpp
+++ /dev/null
@@ -1,283 +0,0 @@
-/* This file is part of the KDE project
- Copyright 2012 Friedrich W. H. Kossebau <kossebau@kde.org>
-
- 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 "KoColumns.h"
-
-#include <QBuffer>
-
-#include "KoXmlWriter.h"
-#include "KoGenStyle.h"
-#include "KoXmlReader.h"
-#include "KoXmlNS.h"
-#include "KoUnit.h"
-// KDE
-#include <OdfDebug.h>
-
-static const int defaultColumnCount = 1;
-static const KoColumns::SeparatorStyle defaultSeparatorStyle = KoColumns::None;
-static const int defaultSeparatorHeight = 100;
-static const Qt::GlobalColor defaultSeparatorColor = Qt::black;
-static const KoColumns::SeparatorVerticalAlignment defaultSeparatorVerticalAlignment = KoColumns::AlignTop;
-static const int defaultColumnGapWidth = 17; // in pt, ~ 6mm
-
-
-
-const char * KoColumns::separatorStyleString(KoColumns::SeparatorStyle separatorStyle)
-{
- const char * result;
-
- // skip KoColumns::None, is default
- if (separatorStyle == Solid) {
- result = "solid";
- } else if (separatorStyle == Dotted) {
- result = "dotted";
- } else if (separatorStyle == Dashed) {
- result = "dashed";
- } else if (separatorStyle == DotDashed) {
- result = "dot-dashed";
- } else {
- result = "none";
- }
-
- return result;
-}
-
-const char * KoColumns::separatorVerticalAlignmentString(KoColumns::SeparatorVerticalAlignment separatorVerticalAlignment)
-{
- const char * result;
-
- // skip KoColumns::AlignTop, is default
- if (separatorVerticalAlignment == AlignVCenter) {
- result = "middle";
- } else if (separatorVerticalAlignment == AlignBottom) {
- result = "bottom";
- } else {
- result = "top";
- }
-
- return result;
-}
-
-KoColumns::SeparatorVerticalAlignment KoColumns::parseSeparatorVerticalAlignment(const QString &value)
-{
- // default to AlignTop
- SeparatorVerticalAlignment result = defaultSeparatorVerticalAlignment;
-
- if (! value.isEmpty()) {
- // skip "top", is default
- if (value == QLatin1String("middle")) {
- result = AlignVCenter;
- } else if (value == QLatin1String("bottom")) {
- result = AlignBottom;
- }
- }
-
- return result;
-}
-
-QColor KoColumns::parseSeparatorColor(const QString &value)
-{
- QColor result(value);
-
- if (! result.isValid())
- // default is black, cmp. ODF 1.2 §19.467
- result = QColor(defaultSeparatorColor);
-
- return result;
-}
-
-// TODO: see if there is another parse method somewhere which can be used here
-int KoColumns::parseSeparatorHeight(const QString &value)
-{
- int result = defaultSeparatorHeight;
-
- // only try to convert if it ends with a %, so is also not empty
- if (value.endsWith(QLatin1Char('%'))) {
- bool ok = false;
- // try to convert
- result = value.left(value.length()-1).toInt(&ok);
- // reset to 100% if conversion failed (which sets result to 0)
- if (! ok) {
- result = defaultSeparatorHeight;
- }
- }
-
- return result;
-}
-
-KoColumns::SeparatorStyle KoColumns::parseSeparatorStyle(const QString &value)
-{
- SeparatorStyle result = None;
- if (! value.isEmpty()) {
- // skip "none", is default
- if (value == QLatin1String("solid")) {
- result = Solid;
- } else if (value == QLatin1String("dotted")) {
- result = Dotted;
- } else if (value == QLatin1String("dashed")) {
- result = Dashed;
- } else if (value == QLatin1String("dot-dashed")) {
- result = DotDashed;
- }
- }
-
- return result;
-}
-
-int KoColumns::parseRelativeWidth(const QString &value)
-{
- int result = 0;
-
- // only try to convert if it ends with a *, so is also not empty
- if (value.endsWith(QLatin1Char('*'))) {
- bool ok = false;
- // try to convert
- result = value.left(value.length()-1).toInt(&ok);
- if (! ok) {
- result = 0;
- }
- }
-
- return result;
-}
-
-KoColumns::KoColumns()
- : count(defaultColumnCount)
- , gapWidth(defaultColumnGapWidth)
- , separatorStyle(defaultSeparatorStyle)
- , separatorColor(defaultSeparatorColor)
- , separatorVerticalAlignment(defaultSeparatorVerticalAlignment)
- , separatorHeight(defaultSeparatorHeight)
-{
-}
-
-void KoColumns::reset()
-{
- count = defaultColumnCount;
- gapWidth = defaultColumnGapWidth;
- separatorStyle = defaultSeparatorStyle;
- separatorColor = QColor(defaultSeparatorColor);
- separatorVerticalAlignment = defaultSeparatorVerticalAlignment;
- separatorHeight = defaultSeparatorHeight;
-}
-
-bool KoColumns::operator==(const KoColumns& rhs) const {
- return
- count == rhs.count &&
- (columnData.isEmpty() && rhs.columnData.isEmpty() ?
- (qAbs(gapWidth - rhs.gapWidth) <= 1E-10) :
- (columnData == rhs.columnData));
-}
-
-bool KoColumns::operator!=(const KoColumns& rhs) const {
- return
- count != rhs.count ||
- (columnData.isEmpty() && rhs.columnData.isEmpty() ?
- qAbs(gapWidth - rhs.gapWidth) > 1E-10 :
- ! (columnData == rhs.columnData));
-}
-
-void KoColumns::loadOdf(const KoXmlElement &style)
-{
- KoXmlElement columnsElement = KoXml::namedItemNS(style, KoXmlNS::style, "columns");
- if (!columnsElement.isNull()) {
- count = columnsElement.attributeNS(KoXmlNS::fo, "column-count").toInt();
- if (count < 1)
- count = 1;
- gapWidth = KoUnit::parseValue(columnsElement.attributeNS(KoXmlNS::fo, "column-gap"));
-
- KoXmlElement columnSep = KoXml::namedItemNS(columnsElement, KoXmlNS::style, "column-sep");
- if (! columnSep.isNull()) {
- separatorStyle = parseSeparatorStyle(columnSep.attributeNS(KoXmlNS::style, "style"));
- separatorWidth = KoUnit::parseValue(columnSep.attributeNS(KoXmlNS::style, "width"));
- separatorHeight = parseSeparatorHeight(columnSep.attributeNS(KoXmlNS::style, "height"));
- separatorColor = parseSeparatorColor(columnSep.attributeNS(KoXmlNS::style, "color"));
- separatorVerticalAlignment =
- parseSeparatorVerticalAlignment(columnSep.attributeNS(KoXmlNS::style, "vertical-align"));
- }
-
- KoXmlElement columnElement;
- forEachElement(columnElement, columnsElement) {
- if(columnElement.localName() != QLatin1String("column") ||
- columnElement.namespaceURI() != KoXmlNS::style)
- continue;
-
- ColumnDatum datum;
- datum.leftMargin = KoUnit::parseValue(columnElement.attributeNS(KoXmlNS::fo, "start-indent"), 0.0);
- datum.rightMargin = KoUnit::parseValue(columnElement.attributeNS(KoXmlNS::fo, "end-indent"), 0.0);
- datum.topMargin = KoUnit::parseValue(columnElement.attributeNS(KoXmlNS::fo, "space-before"), 0.0);
- datum.bottomMargin = KoUnit::parseValue(columnElement.attributeNS(KoXmlNS::fo, "space-after"), 0.0);
- datum.relativeWidth = parseRelativeWidth(columnElement.attributeNS(KoXmlNS::style, "rel-width"));
- // on a bad relativeWidth just drop all data
- if (datum.relativeWidth <= 0) {
- columnData.clear();
- break;
- }
-
- columnData.append(datum);
- }
-
- if (! columnData.isEmpty() && count != columnData.count()) {
- warnOdf << "Found not as many <style:column> elements as attribute fo:column-count has set:"<< count;
- columnData.clear();
- }
- } else {
- reset();
- }
-}
-
-void KoColumns::saveOdf(KoGenStyle &style) const
-{
- if (count > 1) {
- QBuffer buffer;
- buffer.open(QIODevice::WriteOnly);
- KoXmlWriter writer(&buffer);
-
- writer.startElement("style:columns");
- writer.addAttribute("fo:column-count", count);
- if (columnData.isEmpty()) {
- writer.addAttribute("fo:column-gap", gapWidth);
- }
-
- if (separatorStyle != KoColumns::None) {
- writer.startElement("style:column-sep");
- writer.addAttribute("style:style", separatorStyleString(separatorStyle));
- writer.addAttribute("style:width", separatorWidth);
- writer.addAttribute("style:height", QString::number(separatorHeight)+QLatin1Char('%'));
- writer.addAttribute("style:color", separatorColor.name());
- writer.addAttribute("style:vertical-align", separatorVerticalAlignmentString(separatorVerticalAlignment));
- writer.endElement(); // style:column-sep
- }
-
- Q_FOREACH (const ColumnDatum &cd, columnData) {
- writer.startElement("style:column");
- writer.addAttribute("fo:start-indent", cd.leftMargin);
- writer.addAttribute("fo:end-indent", cd.rightMargin);
- writer.addAttribute("fo:space-before", cd.topMargin);
- writer.addAttribute("fo:space-after", cd.bottomMargin);
- writer.addAttribute("style:rel-width", QString::number(cd.relativeWidth)+QLatin1Char('*'));
- writer.endElement(); // style:column
- }
-
- writer.endElement(); // style:columns
-
- QString contentElement = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
- style.addChildElement("style:columns", contentElement);
- }
-}
diff --git a/libs/odf/KoColumns.h b/libs/odf/KoColumns.h
deleted file mode 100644
index cf068a0cf9..0000000000
--- a/libs/odf/KoColumns.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
- Copyright 2002, 2003 David Faure <faure@kde.org>
- Copyright 2003 Nicolas GOUTTE <goutte@kde.org>
- Copyright 2007 Thomas Zander <zander@kde.org>
- Copyright 2012 Friedrich W. H. Kossebau <kossebau@kde.org>
-
- 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 KOCOLUMNS_H
-#define KOCOLUMNS_H
-
-#include "kritaodf_export.h"
-
-#include <QtGlobal>
-#include <QColor>
-
-#include <KoXmlReaderForward.h>
-
-class KoGenStyle;
-
-
-/** structure for columns */
-struct KoColumns {
- enum SeparatorVerticalAlignment {
- AlignTop = Qt::AlignTop,
- AlignVCenter = Qt::AlignVCenter,
- AlignBottom = Qt::AlignBottom
- };
-
- enum SeparatorStyle {
- None = Qt::NoPen,
- Solid = Qt::SolidLine,
- Dashed = Qt::DashLine,
- Dotted = Qt::DotLine,
- DotDashed = Qt::DashDotLine
- };
-
- struct ColumnDatum
- {
- /** Left indent in points */
- qreal leftMargin;
- /** Right indent in points */
- qreal rightMargin;
- /** Top indent in points */
- qreal topMargin;
- /** Bottom indent in points */
- qreal bottomMargin;
-
- /** The relative width */
- int relativeWidth;
-
- ColumnDatum() {}
- ColumnDatum(qreal lm, qreal rm, qreal tm, qreal bm, int rw)
- : leftMargin(lm), rightMargin(rm), topMargin(tm), bottomMargin(bm), relativeWidth(rw) {}
-
- bool operator==(const KoColumns::ColumnDatum &rhs) const
- {
- return
- (leftMargin == rhs.leftMargin) &&
- (rightMargin == rhs.rightMargin) &&
- (topMargin == rhs.topMargin) &&
- (bottomMargin == rhs.bottomMargin) &&
- (relativeWidth == rhs.relativeWidth);
- }
- };
-
- /** Number of columns */
- int count;
-
- /** Spacing between columns in points */
- qreal gapWidth;
-
- SeparatorStyle separatorStyle;
- QColor separatorColor;
- SeparatorVerticalAlignment separatorVerticalAlignment;
- /** Width in pt */
- qreal separatorWidth;
- /** Height in percent. Default is 100% */
- unsigned int separatorHeight;
-
- /** data about the individual columns if there */
- QList<ColumnDatum> columnData;
-
- /**
- * Construct a columns with the default column count 1,
- * default margins (2 cm), and portrait orientation.
- */
- KRITAODF_EXPORT KoColumns();
-
- KRITAODF_EXPORT void reset();
- KRITAODF_EXPORT bool operator==(const KoColumns &l) const;
- KRITAODF_EXPORT bool operator!=(const KoColumns &l) const;
-
- /**
- * Save this columns to ODF.
- */
- KRITAODF_EXPORT void saveOdf(KoGenStyle &style) const;
-
- /**
- * Load this columns from ODF
- */
- KRITAODF_EXPORT void loadOdf(const KoXmlElement &style);
-
- qreal totalRelativeWidth() const
- {
- qreal result = 0.0;
- Q_FOREACH (const ColumnDatum &c, columnData) {
- result += c.relativeWidth;
- }
- return result;
- }
-
- KRITAODF_EXPORT static const char * separatorStyleString(KoColumns::SeparatorStyle separatorStyle);
- KRITAODF_EXPORT static const char * separatorVerticalAlignmentString(KoColumns::SeparatorVerticalAlignment separatorVerticalAlignment);
- KRITAODF_EXPORT static KoColumns::SeparatorVerticalAlignment parseSeparatorVerticalAlignment(const QString &value);
- KRITAODF_EXPORT static QColor parseSeparatorColor(const QString &value);
- KRITAODF_EXPORT static int parseSeparatorHeight(const QString &value);
- KRITAODF_EXPORT static KoColumns::SeparatorStyle parseSeparatorStyle(const QString &value);
- KRITAODF_EXPORT static int parseRelativeWidth(const QString &value);
-};
-
-#endif /* KOCOLUMNS_H */
-
diff --git a/libs/odf/KoDocumentBase.cpp b/libs/odf/KoDocumentBase.cpp
deleted file mode 100644
index cfd4e59ce1..0000000000
--- a/libs/odf/KoDocumentBase.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
- Copyright (C) 2000-2005 David Faure <faure@kde.org>
- Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
- Copyright (C) 2009 Boudewijn Rempt <boud@valdyas.org>
-
- 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 "KoDocumentBase.h"
-
-#include <QtGlobal>
-
-class Q_DECL_HIDDEN KoDocumentBase::Private {
-public:
-};
-
-KoDocumentBase::KoDocumentBase()
- : d( new Private )
-{
-}
-
-
-KoDocumentBase::~KoDocumentBase()
-{
- delete d;
-}
diff --git a/libs/odf/KoDocumentBase.h b/libs/odf/KoDocumentBase.h
deleted file mode 100644
index 570b72534b..0000000000
--- a/libs/odf/KoDocumentBase.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/* This file is part of the KDE project
-
- Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
- Copyright (C) 2000-2005 David Faure <faure@kde.org>
- Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
- Copyright (C) 2009 Boudewijn Rempt <boud@valdyas.org>
-
- 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 KODOCUMENTBASE_H
-#define KODOCUMENTBASE_H
-
-class KoStore;
-class KoOdfReadStore;
-class KoOdfWriteStore;
-class KoEmbeddedDocumentSaver;
-
-class QUrl;
-class QByteArray;
-class QString;
-
-#include "kritaodf_export.h"
-
-/**
- * Base class for documents that can load and save ODF. Most of the
- * implementation is still in KoDocument, though that should probably
- * change.
- */
-class KRITAODF_EXPORT KoDocumentBase
-{
-public:
-
- // context passed on saving to saveOdf
- struct SavingContext {
- SavingContext(KoOdfWriteStore &odfStore, KoEmbeddedDocumentSaver &embeddedSaver)
- : odfStore(odfStore)
- , embeddedSaver(embeddedSaver) {}
-
- KoOdfWriteStore &odfStore;
- KoEmbeddedDocumentSaver &embeddedSaver;
- };
-
- /**
- * create a new KoDocumentBase
- */
- KoDocumentBase();
-
- /**
- * delete this document
- */
- virtual ~KoDocumentBase();
-
- /**
- * @return the current URL
- */
- virtual QUrl url() const = 0;
-
- virtual void setUrl(const QUrl &url) = 0;
-
- /**
- * Checks whether the document is currently in the process of autosaving
- */
- virtual bool isAutosaving() const = 0;
-
- /**
- * Returns true if this document or any of its internal child documents are modified.
- */
- virtual bool isModified() const = 0;
-
- /**
- * Returns the actual mimetype of the document
- */
- virtual QByteArray mimeType() const = 0;
-
- /**
- * @brief Sets the mime type for the document.
- *
- * When choosing "save as" this is also the mime type
- * selected by default.
- */
- virtual void setMimeType(const QByteArray & mimeType) = 0;
-
- virtual QString localFilePath() const = 0;
-
-private:
- class Private;
- Private *const d;
-};
-
-
-#endif
diff --git a/libs/odf/KoElementReference.cpp b/libs/odf/KoElementReference.cpp
deleted file mode 100644
index d8b3982407..0000000000
--- a/libs/odf/KoElementReference.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2011 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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 "KoElementReference.h"
-
-#include "KoXmlReader.h"
-#include "KoXmlWriter.h"
-#include <KoXmlNS.h>
-
-KoElementReference::KoElementReference()
- : d(new KoElementReferenceData())
-{
- d->xmlid = "id-" + d->xmlid;
-}
-
-KoElementReference::KoElementReference(const QString &prefix)
- : d(new KoElementReferenceData)
-{
- d->xmlid = prefix + "-" + d->xmlid;
-}
-
-KoElementReference::KoElementReference(const QString &prefix, int counter)
- : d(new KoElementReferenceData)
-{
- d->xmlid = QString("%1-%2").arg(prefix).arg(counter);
-}
-
-KoElementReference::KoElementReference(const KoElementReference &other)
- : d(other.d)
-{
-}
-
-KoElementReference &KoElementReference::operator=(const KoElementReference &rhs)
-{
- if (this == &rhs) return *this;
- d = rhs.d;
-
- return *this;
-}
-
-bool KoElementReference::operator==(const KoElementReference &other) const
-{
- return d->xmlid == other.d->xmlid;
-}
-
-bool KoElementReference::operator!=(const KoElementReference &other) const
-{
- return !(*this == other);
-}
-
-bool KoElementReference::isValid() const
-{
- return (!d->xmlid.isEmpty());
-}
-
-void KoElementReference::saveOdf(KoXmlWriter *writer, SaveOption saveOptions) const
-{
- if (d->xmlid.isEmpty()) return;
-
- writer->addAttribute("xml:id", d->xmlid);
-
- if (saveOptions & DrawId) {
- writer->addAttribute("draw:id", d->xmlid);
- }
- if (saveOptions & TextId) {
- writer->addAttribute("text:id", d->xmlid);
- }
-}
-
-QString KoElementReference::toString() const
-{
- return d->xmlid;
-}
-
-
-KoElementReference KoElementReference::loadOdf(const KoXmlElement &element)
-{
- QString xmlid;
-
- if (element.hasAttributeNS(KoXmlNS::xml, "id")) {
- xmlid = element.attributeNS(KoXmlNS::xml, "id");
- }
- else if (element.hasAttributeNS(KoXmlNS::draw, "id")) {
- xmlid = element.attributeNS(KoXmlNS::draw, "id");
- }
- else if (element.hasAttributeNS(KoXmlNS::text, "id")) {
- xmlid = element.attributeNS(KoXmlNS::text, "id");
- }
-
- d->xmlid = xmlid;
-
- return *this;
-}
-
-void KoElementReference::invalidate()
-{
- d->xmlid.clear();
-}
diff --git a/libs/odf/KoElementReference.h b/libs/odf/KoElementReference.h
deleted file mode 100644
index 750c3406cf..0000000000
--- a/libs/odf/KoElementReference.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (c) 2011-2012 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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.
- */
-
-#ifndef KOELEMENTREFERENCE_H
-#define KOELEMENTREFERENCE_H
-
-#include <QSharedDataPointer>
-#include <QSharedData>
-#include <QUuid>
-
-#include "KoXmlReaderForward.h"
-
-#include "kritaodf_export.h"
-
-class KoXmlWriter;
-
-class KoElementReferenceData : public QSharedData
-{
-public:
-
- KoElementReferenceData()
- {
- xmlid = QUuid::createUuid().toString();
- xmlid.remove('{');
- xmlid.remove('}');
- }
-
- KoElementReferenceData(const KoElementReferenceData &other)
- : QSharedData(other)
- , xmlid(other.xmlid)
- {
- }
-
- ~KoElementReferenceData() {}
-
- QString xmlid;
-};
-
-/**
- * KoElementReference is used to store unique identifiers for elements in an odf document.
- * Element references are saved as xml:id and optionally for compatibility also as draw:id
- * and text:id.
- *
- * You can use element references wherever you would have used a QString to refer to the id
- * of an object.
- *
- * Element references are implicitly shared, so you can and should pass them along by value.
- */
-class KRITAODF_EXPORT KoElementReference
-{
-public:
-
- enum GenerationOption {
- UUID = 0,
- Counter = 1
- };
-
- enum SaveOption {
- XmlId = 0x0,
- DrawId = 0x1,
- TextId = 0x2
- };
- Q_DECLARE_FLAGS(SaveOptions, SaveOption)
-
- KoElementReference();
- explicit KoElementReference(const QString &prefix);
- KoElementReference(const QString &prefix, int counter);
- KoElementReference(const KoElementReference &other);
- KoElementReference &operator=(const KoElementReference &rhs);
- bool operator==(const KoElementReference &other) const;
- bool operator!=(const KoElementReference &other) const;
-
- /**
- * @return true if the xmlid is valid, i.e., not null
- */
- bool isValid() const;
-
- /**
- * @brief loadOdf creates a new KoElementReference from the given element. If the element
- * does not have an xml:id, draw:id or text:id attribute, and invalid element reference
- * is returned.
- * @param element the element that may contain xml:id, text:id or draw:id. xml:id has
- * priority.
- * @return a new element reference
- */
- KoElementReference loadOdf(const KoXmlElement &element);
-
- /**
- * @brief saveOdf saves this element reference into the currently open element in the xml writer.
- * @param writer the writer we save to
- * @param saveOption determines which attributes we save. We always save the xml:id.
- */
- void saveOdf(KoXmlWriter *writer, SaveOption saveOption = XmlId) const;
-
- /**
- * @brief toString creates a QString from the element reference
- * @return a string that represents the element. Can be used in maps etc.
- */
- QString toString() const;
-
- /**
- * Invalidate the reference
- */
- void invalidate();
-
-
-private:
-
- QSharedDataPointer<KoElementReferenceData> d;
-};
-
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(KoElementReference::SaveOptions)
-
-#endif // KOELEMENTREFERENCE_H
diff --git a/libs/odf/KoEmbeddedDocumentSaver.cpp b/libs/odf/KoEmbeddedDocumentSaver.cpp
deleted file mode 100644
index f947700efa..0000000000
--- a/libs/odf/KoEmbeddedDocumentSaver.cpp
+++ /dev/null
@@ -1,189 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2004-2006 David Faure <faure@kde.org>
- Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
- Copyright (C) 2010 Thomas Zander <zander@kde.org>
- Copyright (C) 2011 Inge Wallin <inge@lysator.liu.se>
-
- 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 "KoEmbeddedDocumentSaver.h"
-
-#include <QList>
-
-#include <OdfDebug.h>
-#include <QUrl>
-
-#include <KoStore.h>
-#include <KoXmlWriter.h>
-#include <KoOdfWriteStore.h>
-
-#include "KoDocumentBase.h"
-#include <KoOdfManifestEntry.h>
-
-
-#define INTERNAL_PROTOCOL "intern"
-
-struct FileEntry {
- QString path;
- QByteArray mimeType; // QBA because this is what addManifestEntry wants
- QByteArray contents;
-};
-
-
-class Q_DECL_HIDDEN KoEmbeddedDocumentSaver::Private
-{
-public:
- Private() {}
-
- QHash<QString, int> prefixes; // Used in getFilename();
-
- // These will be saved when saveEmbeddedDocuments() is called.
- QList<FileEntry*> files; // Embedded files.
- QList<KoOdfManifestEntry*> manifestEntries;
-};
-
-KoEmbeddedDocumentSaver::KoEmbeddedDocumentSaver()
- : d(new Private())
-{
-}
-
-KoEmbeddedDocumentSaver::~KoEmbeddedDocumentSaver()
-{
- qDeleteAll(d->files);
- qDeleteAll(d->manifestEntries);
- delete d;
-}
-
-
-QString KoEmbeddedDocumentSaver::getFilename(const QString &prefix)
-{
- int index = 1;
- if (d->prefixes.contains(prefix)) {
- index = d->prefixes.value(prefix);
- }
-
- // This inserts prefix into the map if it's not there.
- d->prefixes[prefix] = index + 1;
-
- //return prefix + QString("%1").arg(index, 4, 10, QChar('0'));
- return prefix + QString("%1").arg(index);
-}
-
-
-// Examples:
-// Videos/Video1.mov ← the number is autogenerated
-// Videos/Video2.mov
-// Object1/foo ← the number is autogenerated
-// Object1/bar
-
-// Note: The contents QByteArray is implicitly shared. It needs to be
-// copied since otherwise the actual array may disappear before
-// the real saving is done.
-//
-void KoEmbeddedDocumentSaver::embedFile(KoXmlWriter &writer, const char *element,
- const QString &path, const QByteArray &mimeType,
- const QByteArray &contents)
-{
- // Put the file in the list of files to be written to the store later.
- FileEntry *entry = new FileEntry;
- entry->mimeType = mimeType;
- entry->path = path;
- entry->contents = contents;
- d->files.append(entry);
-
- writer.startElement(element);
- // Write the attributes that refer to the file.
-
- //<draw:object xlink:href="#./Object 1" xlink:type="simple" xlink:show="embed"
- // xlink:actuate="onLoad"/>
- writer.addAttribute("xlink:type", "simple");
- writer.addAttribute("xlink:show", "embed");
- writer.addAttribute("xlink:actuate", "onLoad");
-
- debugOdf << "saving reference to embedded file as" << path;
- writer.addAttribute("xlink:href", path);
- writer.endElement();
-}
-
-void KoEmbeddedDocumentSaver::saveFile(const QString &path, const QByteArray &mimeType,
- const QByteArray &contents)
-{
- // Put the file in the list of files to be written to the store later.
- FileEntry *entry = new FileEntry;
- entry->mimeType = mimeType;
- entry->path = path;
- entry->contents = contents;
- d->files.append(entry);
-
- debugOdf << "saving reference to embedded file as" << path;
-}
-
-/**
- *
- */
-void KoEmbeddedDocumentSaver::saveManifestEntry(const QString &fullPath, const QString &mediaType,
- const QString &version)
-{
- d->manifestEntries.append(new KoOdfManifestEntry(fullPath, mediaType, version));
-}
-
-
-bool KoEmbeddedDocumentSaver::saveEmbeddedDocuments(KoDocumentBase::SavingContext & documentContext)
-{
- KoStore *store = documentContext.odfStore.store();
-
- // Write the embedded files.
- Q_FOREACH (FileEntry *entry, d->files) {
- QString path = entry->path;
- debugOdf << "saving" << path;
-
- // To make the children happy cd to the correct directory
- store->pushDirectory();
-
- int index = path.lastIndexOf('/');
- const QString dirPath = path.left(index);
- const QString fileName = path.right(path.size() - index - 1);
- store->enterDirectory(dirPath);
-
- if (!store->open(fileName)) {
- return false;
- }
- store->write(entry->contents);
- store->close();
-
- // Now that we're done leave the directory again
- store->popDirectory();
-
- // Create the manifest entry.
- if (path.startsWith(QLatin1String("./"))) {
- path.remove(0, 2); // remove leading './', not wanted in manifest
- }
- documentContext.odfStore.manifestWriter()->addManifestEntry(path, entry->mimeType);
- }
-
- // Write the manifest entries.
- KoXmlWriter *manifestWriter = documentContext.odfStore.manifestWriter();
- Q_FOREACH (KoOdfManifestEntry *entry, d->manifestEntries) {
- manifestWriter->startElement("manifest:file-entry");
- manifestWriter->addAttribute("manifest:version", entry->version());
- manifestWriter->addAttribute("manifest:media-type", entry->mediaType());
- manifestWriter->addAttribute("manifest:full-path", entry->fullPath());
- manifestWriter->endElement(); // manifest:file-entry
- }
-
- return true;
-}
diff --git a/libs/odf/KoEmbeddedDocumentSaver.h b/libs/odf/KoEmbeddedDocumentSaver.h
deleted file mode 100644
index 015d37dfd1..0000000000
--- a/libs/odf/KoEmbeddedDocumentSaver.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
- Copyright (C) 2011 Inge Wallin <inge@lysator.liu.se>
-
- 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 KOEMBEDDEDDOCUMENTSAVER_H
-#define KOEMBEDDEDDOCUMENTSAVER_H
-
-#include "KoDocumentBase.h"
-#include "kritaodf_export.h"
-
-#include <QString>
-
-class KoXmlWriter;
-
-/**
- * This class is used to save embedded objects in ODF documents.
- *
- * @see KoEmbeddedFileSaver
- */
-class KRITAODF_EXPORT KoEmbeddedDocumentSaver
-{
-public:
- KoEmbeddedDocumentSaver();
- ~KoEmbeddedDocumentSaver();
-
- /**
- * Get a unique file name with the given prefix, to be used as a name for an embedded file in the ODF store.
- * @param the prefix of the filename to be created.
- * return a unique file name for use in the odf store.
- */
- QString getFilename(const QString &prefix);
-
- /**
- * Adds the object specific attributes to the tag, and queues the
- * file for saving into the store.
- *
- * However, it does NOT write the content of the embedded document
- * to the store. Saving of the embedded files themselves is done
- * in @ref saveEmbeddedFiles. This function should be called from
- * within saveOdf in a shape or a document.
- */
- void embedFile(KoXmlWriter &writer, const char *element,
- const QString &path, const QByteArray &mimeType,
- const QByteArray &contents);
-
- /**
- * Queues the file for saving into the store.
- *
- * Saving of the embedded files themselves is done in @ref
- * saveEmbeddedFiles. This function should be called from within
- * saveOdf in a shape or a document if you don't wish to have a
- * reference to the file within content.xml, e.g. when the file is
- * part of an embedded object with embedded files within it.
- */
- void saveFile(const QString &path, const QByteArray &mimeType,
- const QByteArray &contents);
-
- /**
- *
- */
- void saveManifestEntry(const QString &fullPath, const QString &mediaType,
- const QString &version = QString());
-
- /**
- * Save all embedded documents to the store.
- */
- bool saveEmbeddedDocuments(KoDocumentBase::SavingContext &documentContext);
-
-private:
- class Private;
- Private * const d;
- Q_DISABLE_COPY(KoEmbeddedDocumentSaver)
-};
-
-#endif /* KOEMBEDDEDDOCUMENTSAVER_H */
diff --git a/libs/odf/KoEncryptionChecker.cpp b/libs/odf/KoEncryptionChecker.cpp
deleted file mode 100644
index 6900976ef4..0000000000
--- a/libs/odf/KoEncryptionChecker.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2009 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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 "KoEncryptionChecker.h"
-
-#ifdef QCA2
-
-// QCA headers have "slots" and "signals", which QT_NO_SIGNALS_SLOTS_KEYWORDS does not like
-#define slots Q_SLOTS
-#define signals Q_SIGNALS
-#include <QtCrypto>
-#undef slots
-#undef signals
-#include <OdfDebug.h>
-
-bool KoEncryptionChecker::isEncryptionSupported()
-{
- QCA::Initializer* initializer = new QCA::Initializer();
- bool supported = QCA::isSupported("sha1") && QCA::isSupported("pbkdf2(sha1)") && QCA::isSupported("blowfish-cfb");
- if (!supported) {
- warnOdf << "QCA is enabled but sha1, pbkdf2(sha1) or blowfish-cfb are not supported. Encryption is disabled.";
- }
- delete initializer;
- return supported;
-}
-#else
-bool KoEncryptionChecker::isEncryptionSupported()
-{
-
- return false;
-}
-#endif
diff --git a/libs/odf/KoEncryptionChecker.h b/libs/odf/KoEncryptionChecker.h
deleted file mode 100644
index a31f9bbe44..0000000000
--- a/libs/odf/KoEncryptionChecker.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2009 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 KO_ENCRYPTION_CHECKER
-#define KO_ENCRYPTION_CHECKER
-
-#include "kritaodf_export.h"
-
-namespace KoEncryptionChecker
-{
-
-KRITAODF_EXPORT bool isEncryptionSupported();
-
-}
-
-#endif
diff --git a/libs/odf/KoFontFace.cpp b/libs/odf/KoFontFace.cpp
deleted file mode 100644
index c71bfe5816..0000000000
--- a/libs/odf/KoFontFace.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-
- Contact: Suresh Chande suresh.chande@nokia.com
-
- 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 "KoFontFace.h"
-#include <KoXmlWriter.h>
-#include <OdfDebug.h>
-
-class KoFontFacePrivate : public QSharedData
-{
-public:
- KoFontFacePrivate(const QString &_name)
- : name(_name), pitch(KoFontFace::VariablePitch)
- {
- }
-
- ~KoFontFacePrivate()
- {
- }
-
- void saveOdf(KoXmlWriter* xmlWriter) const
- {
- xmlWriter->startElement("style:font-face");
- xmlWriter->addAttribute("style:name", name);
- xmlWriter->addAttribute("svg:font-family", family.isEmpty() ? name : family);
- if (!familyGeneric.isEmpty())
- xmlWriter->addAttribute("style:font-family-generic", familyGeneric);
- if (!style.isEmpty())
- xmlWriter->addAttribute("svg:font-style", style);
- xmlWriter->addAttribute("style:font-pitch", pitch == KoFontFace::FixedPitch ? "fixed" : "variable");
- xmlWriter->endElement(); // style:font-face
- }
-
- QString name; //!< for style:name attribute
- QString family; //!< for svg:font-family attribute
- QString familyGeneric; //!< for style:font-family-generic attribute
- QString style; //!< for svg:font-style attribute
- KoFontFace::Pitch pitch; //!< for style:font-pitch attribute
-};
-
-
-KoFontFace::KoFontFace(const QString &_name)
- : d(new KoFontFacePrivate(_name))
-{
-}
-
-KoFontFace::KoFontFace(const KoFontFace &other)
- : d(other.d)
-{
-}
-
-KoFontFace::~KoFontFace()
-{
-}
-
-KoFontFace &KoFontFace::operator=(const KoFontFace &other)
-{
- d = other.d;
- return *this;
-}
-
-bool KoFontFace::operator==(const KoFontFace &other) const
-{
- if (isNull() && other.isNull())
- return true;
- return d.data() == other.d.data();
-}
-
-bool KoFontFace::isNull() const
-{
- return d->name.isEmpty();
-}
-
-QString KoFontFace::name() const
-{
- return d->name;
-}
-
-void KoFontFace::setName(const QString &name)
-{
- d->name = name;
-}
-
-QString KoFontFace::family() const
-{
- return d->family;
-}
-
-void KoFontFace::setFamily(const QString &family)
-{
- d->family = family;
-}
-
-QString KoFontFace::familyGeneric() const
-{
- return d->familyGeneric;
-}
-
-void KoFontFace::setFamilyGeneric(const QString &familyGeneric)
-{
- if (familyGeneric == "decorative" || familyGeneric == "modern"
- || familyGeneric == "roman" || familyGeneric == "script"
- || familyGeneric == "swiss" || familyGeneric == "system") {
- d->familyGeneric = familyGeneric;
- }
-}
-
-QString KoFontFace::style() const
-{
- return d->style;
-}
-
-void KoFontFace::setStyle(const QString &style)
-{
- d->style = style;
-}
-
-KoFontFace::Pitch KoFontFace::pitch() const
-{
- return d->pitch;
-}
-
-void KoFontFace::setPitch(KoFontFace::Pitch pitch)
-{
- d->pitch = pitch;
-}
-
-void KoFontFace::saveOdf(KoXmlWriter* xmlWriter) const
-{
- Q_ASSERT(!isNull());
- if (isNull()) {
- warnOdf << "This font face is null and will not be saved: set at least the name";
- return;
- }
- d->saveOdf(xmlWriter);
-}
diff --git a/libs/odf/KoFontFace.h b/libs/odf/KoFontFace.h
index 2fea70f100..2e82fc1222 100644
--- a/libs/odf/KoFontFace.h
+++ b/libs/odf/KoFontFace.h
@@ -1,95 +1,89 @@
/* This file is part of the KDE project
Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
Contact: Suresh Chande suresh.chande@nokia.com
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 KOFONTFACE_H
#define KOFONTFACE_H
#include <QString>
#include <QSharedData>
#include "kritaodf_export.h"
class KoXmlWriter;
class KoFontFacePrivate;
/**
* @brief Represents font style.
* Font style is defined by the style:font-face element.
- * @todo add more parameters.
- * @todo add class KoFontFaceDeclarations instead of adding methods to KoGenStyle?
*/
class KRITAODF_EXPORT KoFontFace
{
public:
/**
* Constructor. Creates font face definition with empty parameters.
*
* @param name the font name.
*
* The other are empty. If you don't pass the name, the font face will be considered null.
* @see isEmpty()
*/
explicit KoFontFace(const QString &name = QString());
/**
* Copy constructor.
*/
KoFontFace(const KoFontFace &other);
/**
* Destructor.
*/
~KoFontFace();
/**
* @return true if the font face object is null, i.e. has no name assigned.
*/
bool isNull() const;
KoFontFace& operator=(const KoFontFace &other);
bool operator==(const KoFontFace &other) const;
enum Pitch {
FixedPitch,
VariablePitch
};
//! @todo add enum FamilyGeneric?
QString name() const;
void setName(const QString &name);
QString family() const;
void setFamily(const QString &family);
QString familyGeneric() const;
void setFamilyGeneric(const QString &familyGeneric);
QString style() const;
void setStyle(const QString &style);
KoFontFace::Pitch pitch() const;
void setPitch(KoFontFace::Pitch pitch);
- /** Saves font face definition into @a xmlWriter as a style:font-face element.
- */
- void saveOdf(KoXmlWriter *xmlWriter) const;
-
private:
QSharedDataPointer<KoFontFacePrivate> d;
};
#endif /* KOFONTFACE_H */
diff --git a/libs/odf/KoGenChange.cpp b/libs/odf/KoGenChange.cpp
deleted file mode 100644
index 9926611e2d..0000000000
--- a/libs/odf/KoGenChange.cpp
+++ /dev/null
@@ -1,146 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2008 Pierre Stirnweiss <pierre.stirnweiss_calligra@gadz.org>
-
- 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 "KoGenChange.h"
-
-#include <KoXmlWriter.h>
-#include <QDateTime>
-
-#include <OdfDebug.h>
-
-// Returns -1, 0 (equal) or 1
-static int compareMap(const QMap<QString, QString> &map1, const QMap<QString, QString> &map2)
-{
- QMap<QString, QString>::const_iterator it = map1.begin();
- QMap<QString, QString>::const_iterator oit = map2.begin();
- for (; it != map1.end(); ++it, ++oit) { // both maps have been checked for size already
- if (it.key() != oit.key())
- return it.key() < oit.key() ? -1 : + 1;
- if (it.value() != oit.value())
- return it.value() < oit.value() ? -1 : + 1;
- }
- return 0; // equal
-}
-
-
-KoGenChange::KoGenChange(KoGenChange::ChangeFormat changeFormat)
- : m_changeFormat(changeFormat)
- , m_type(UNKNOWN)
-{
-}
-
-KoGenChange::~KoGenChange()
-{
-}
-
-void KoGenChange::writeChangeMetaData(KoXmlWriter* writer) const
-{
- QMap<QString, QString>::const_iterator it = m_changeMetaData.begin();
- const QMap<QString, QString>::const_iterator end = m_changeMetaData.end();
- for (; it != end; ++it) {
- //FIXME: if the propName is passed directly as it.key().toUtf8(), the opening tag is correct but the closing tag becomes undefined
- //FIXME: example: <dc-creator>.......</`ok>
-
- if (it.key() == "dc-creator") {
- writer->startElement("dc:creator");
- writer->addTextNode(it.value());
- writer->endElement();
- }
- if (it.key() == "dc-date") {
- writer->startElement("dc:date");
- writer->addTextNode(it.value());
- writer->endElement();
- }
- }
-}
-
-void KoGenChange::writeChange(KoXmlWriter *writer, const QString &name) const
-{
- if (m_changeFormat == KoGenChange::ODF_1_2) {
- writeODF12Change(writer, name);
- } else {
- writeDeltaXmlChange(writer, name);
- }
-}
-
-void KoGenChange::writeODF12Change(KoXmlWriter *writer, const QString &name) const
-{
- writer->startElement("text:changed-region");
- writer->addAttribute("text:id", name);
- writer->addAttribute("xml:id", name);
-
- const char* elementName;
- switch (m_type) {
- case KoGenChange::DeleteChange:
- elementName = "text:deletion";
- break;
- case KoGenChange::FormatChange:
- elementName = "text:format-change";
- break;
- case KoGenChange::InsertChange:
- elementName = "text:insertion";
- break;
- default:
- elementName = "text:format-change"; //should not happen, format-change is probably the most harmless of the three.
- }
- writer->startElement(elementName);
- if (!m_changeMetaData.isEmpty()) {
- writer->startElement("office:change-info");
- writeChangeMetaData(writer);
- if (m_literalData.contains("changeMetaData"))
- writer->addCompleteElement(m_literalData.value("changeMetaData").toUtf8());
- writer->endElement(); // office:change-info
- }
- if ((m_type == KoGenChange::DeleteChange) && m_literalData.contains("deleteChangeXml"))
- writer->addCompleteElement(m_literalData.value("deleteChangeXml").toUtf8());
-
- writer->endElement(); // text:insertion/format/deletion
- writer->endElement(); // text:change
-}
-
-void KoGenChange::writeDeltaXmlChange(KoXmlWriter *writer, const QString &name) const
-{
- writer->startElement("delta:change-transaction");
- writer->addAttribute("delta:change-id", name);
- if (!m_changeMetaData.isEmpty()) {
- writer->startElement("delta:change-info");
- writeChangeMetaData(writer);
- writer->endElement(); // delta:change-info
- }
- writer->endElement(); // delta:change-transaction
-}
-
-bool KoGenChange::operator<(const KoGenChange &other) const
-{
- Q_UNUSED(other);
-// if (m_changeMetaData.value("dc-date") != other.m_changeMetaData.value("dc-date")) return QDateTime::fromString(m_changeMetaData.value("dc-date"), Qt::ISODate) < QDateTime::fromString(other.m_changeMetaData.value("dc-date"), Qt::ISODate);
-
-
- return true;
-}
-
-bool KoGenChange::operator==(const KoGenChange &other) const
-{
- if (m_type != other.m_type) return false;
- if (m_changeMetaData.count() != other.m_changeMetaData.count()) return false;
- if (m_literalData.count() != other.m_literalData.count()) return false;
- int comp = compareMap(m_changeMetaData, other.m_changeMetaData);
- if (comp != 0) return false;
- return (compareMap(m_literalData, other.m_literalData) == 0);
-}
diff --git a/libs/odf/KoGenChange.h b/libs/odf/KoGenChange.h
deleted file mode 100644
index bc98f881f4..0000000000
--- a/libs/odf/KoGenChange.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2008 Pierre Stirnweiss <pierre.stirnweiss_calligra@gadz.org>
-
- 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 KOGENCHANGE_H
-#define KOGENCHANGE_H
-
-#include <QMap>
-#include <QString>
-#include "kritaodf_export.h"
-
-#include <OdfDebug.h>
-
-class KoGenChanges;
-class KoXmlWriter;
-
-/**
- * A generic change, i.e. basically a collection of properties and a name.
- * Instances of KoGenChange can either be held in the KoGenChanges collection,
- * or created (e.g. on the stack) and given to KoGenChanges::insert.
- *
- * Derived from code from KoGenStyle
- */
-class KRITAODF_EXPORT KoGenChange
-{
-public:
- /**
- * Possible values for the "type" of the KoGenChange.
- * If there is a still missing add it here so that it is possible to use the same
- * saving code in all applications.
- */
- enum Type {
- InsertChange,
- FormatChange,
- DeleteChange,
- UNKNOWN = 9999
- };
-
- enum ChangeFormat {
- ODF_1_2,
- DELTAXML
- };
-
- /**
- * Start the definition of a new change. Its name will be set later by KoGenChanges::insert(),
- * but first you must define its properties and attributes.
- *
- */
- explicit KoGenChange(KoGenChange::ChangeFormat changeFormat = KoGenChange::ODF_1_2);
- ~KoGenChange();
-
- /// Set the type of this change
- void setType(KoGenChange::Type type) {
- m_type = type;
- }
-
- /// set the format to be used to save changes
- void setChangeFormat(KoGenChange::ChangeFormat changeFormat) {
- m_changeFormat = changeFormat;
- }
-
- /// Return the type of this style
- Type type() const {
- return m_type;
- }
-
- /// Return the format to be used to save changes
- KoGenChange::ChangeFormat changeFormat() const {
- return m_changeFormat;
- }
-
- /// Add a property to the style
- void addChangeMetaData(const QString &propName, const QString &propValue) {
- m_changeMetaData.insert(propName, propValue);
- }
-
- /// Overloaded version of addProperty that takes a char*, usually for "..."
- void addChangeMetaData(const QString &propName, const char *propValue) {
- m_changeMetaData.insert(propName, propValue);
- }
- /// Overloaded version of addProperty that converts an int to a string
- void addChangeMetaData(const QString &propName, int propValue) {
- m_changeMetaData.insert(propName, QString::number(propValue));
- }
- /// Overloaded version of addProperty that converts a bool to a string (false/true)
- void addChangeMetaData(const QString &propName, bool propValue) {
- m_changeMetaData.insert(propName, propValue ? "true" : "false");
- }
-
- /**
- * @brief Add a child element to the properties.
- *
- * What is meant here is that the contents of the QString
- * will be written out literally. This means you should use
- * KoXmlWriter to generate it:
- * @code
- * QBuffer buffer;
- * buffer.open( QIODevice::WriteOnly );
- * KoXmlWriter elementWriter( &buffer ); // TODO pass indentation level
- * elementWriter.startElement( "..." );
- * ...
- * elementWriter.endElement();
- * QString elementContents = QString::fromUtf8( buffer.buffer(), buffer.buffer().size() );
- * gs.addChildElement( "...", elementContents );
- * @endcode
- *
- * The value of @p elementName isn't used, except that it must be unique.
- */
- void addChildElement(const QString &elementName, const QString &elementContents) {
- m_literalData.insert(elementName, elementContents);
- }
-
- /**
- * Write the definition of this change to @p writer, using the OASIS format.
- * @param writer the KoXmlWriter in which the element will be created and filled in
- * @param name must come from the collection.
- */
- void writeChange(KoXmlWriter *writer, const QString &name) const;
-
- /**
- * QMap requires a complete sorting order.
- * Another solution would have been a qdict and a key() here, a la KoTextFormat,
- * but the key was difficult to generate.
- * Solutions with only a hash value (not representative of the whole data)
- * require us to write a hashtable by hand....
- */
- bool operator<(const KoGenChange &other) const;
-
- /// Not needed for QMap, but can still be useful
- bool operator==(const KoGenChange &other) const;
-
-private:
- QString changeMetaData(const QString &propName) const {
- QMap<QString, QString>::const_iterator it = m_changeMetaData.find(propName);
- if (it != m_changeMetaData.end())
- return it.value();
- return QString();
- }
-
- void writeChangeMetaData(KoXmlWriter *writer) const;
-
- void writeODF12Change(KoXmlWriter *writer, const QString &name) const;
-
- void writeDeltaXmlChange(KoXmlWriter *writer, const QString &name) const;
-
-private:
- // Note that the copy constructor and assignment operator are allowed.
- // Better not use pointers below!
- ChangeFormat m_changeFormat;
- Type m_type;
- /// We use QMaps since they provide automatic sorting on the key (important for unicity!)
- QMap<QString, QString> m_changeMetaData;
- QMap<QString, QString> m_literalData;
-};
-
-#endif /* KOGENCHANGE_H */
diff --git a/libs/odf/KoGenChanges.cpp b/libs/odf/KoGenChanges.cpp
deleted file mode 100644
index 0b2f7599ee..0000000000
--- a/libs/odf/KoGenChanges.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2008 Pierre Stirnweiss <pierre.stirnweiss_calligra@gadz.org>
- Copyright (C) 2010 Thomas Zander <zander@kde.org>
-
- 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 "KoGenChanges.h"
-#include <KoXmlWriter.h>
-#include <KoElementReference.h>
-
-#include <QList>
-#include <QMap>
-#include <QString>
-
-#include <OdfDebug.h>
-
-class Q_DECL_HIDDEN KoGenChanges::Private
-{
-public:
- Private(KoGenChanges *q)
- : q(q)
- { }
-
-
- struct NamedChange {
- const KoGenChange* change; ///< @note owned by the collection
- QString name;
- };
-
- /// style definition -> name
- QMap<KoGenChange, QString> changeMap;
-
- /// List of styles (used to preserve ordering)
- QList<NamedChange> changeArray;
-
- QMap<KoGenChange, QString> ::iterator insertChange(const KoGenChange &change);
-
- KoGenChanges *q;
-};
-
-KoGenChanges::KoGenChanges()
- : d(new Private(this))
-{
-}
-
-KoGenChanges::~KoGenChanges()
-{
- delete d;
-}
-
-QString KoGenChanges::insert(const KoGenChange& change)
-{
- QMap<KoGenChange, QString> ::iterator it = d->changeMap.find(change);
- if (it == d->changeMap.end()) {
- it = d->insertChange(change);
- }
- return it.value();
-}
-
-QMap<KoGenChange, QString>::iterator KoGenChanges::Private::insertChange(const KoGenChange &change)
-{
- QString changeName;
- switch (change.type()) {
- case KoGenChange::InsertChange: changeName = 'I'; break;
- case KoGenChange::FormatChange: changeName = 'F'; break;
- case KoGenChange::DeleteChange: changeName = 'D'; break;
- default:
- changeName = 'C';
- }
- KoElementReference ref(changeName);
- changeName = ref.toString();
-
- QMap<KoGenChange, QString>::iterator it = changeMap.insert(change, changeName);
- NamedChange s;
- s.change = &it.key();
- s.name = changeName;
- changeArray.append(s);
-
- return it;
-}
-
-void KoGenChanges::saveOdfChanges(KoXmlWriter* xmlWriter, bool trackChanges) const
-{
- QMap<KoGenChange, QString>::const_iterator it = d->changeMap.constBegin();
-
- if ((it != d->changeMap.constEnd()) && (it.key().changeFormat() == KoGenChange::DELTAXML)) {
- xmlWriter->startElement("delta:tracked-changes");
- } else {
- xmlWriter->startElement("text:tracked-changes");
- xmlWriter->addAttribute("text:track-changes", trackChanges);
- }
-
- for (; it != d->changeMap.constEnd() ; ++it) {
- KoGenChange change = it.key();
- change.writeChange(xmlWriter, it.value());
- }
-
- xmlWriter->endElement(); // text:tracked-changes
-}
diff --git a/libs/odf/KoGenChanges.h b/libs/odf/KoGenChanges.h
deleted file mode 100644
index a0400f786d..0000000000
--- a/libs/odf/KoGenChanges.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2008 Pierre Stirnweiss <pierre.stirnweiss_calligra@gadz.org>
- Copyright (C) 2010 Thomas Zander <zander@kde.org>
-
- 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 KOGENCHANGES_H
-#define KOGENCHANGES_H
-
-#include "kritaodf_export.h"
-
-#include <KoGenChange.h>
-
-class KoXmlWriter;
-
-/**
- * @brief Repository of changes used during saving of OASIS/OOo file.
- *
- * Inspired from KoGenStyles.h
- *
- * Is used to store all the change regions, which will be saved at the beginning of <office:body><office:text> elements
- * We use a container outside the changeTracker, as the change tracker is linked to the document of a TextShapeData and is then not aware of the other TextShapeData.
- *
- */
-class KRITAODF_EXPORT KoGenChanges
-{
-public:
- KoGenChanges();
- ~KoGenChanges();
-
- /**
- * Look up a change in the collection, inserting it if necessary. If the change already
- * exists, return the existing name. If not, assign a name to the change and returns it.
- *
- * @param change the change to look up.
- * @param name proposed internal name for the change. It will be modified to be guaranteed unique.
- * @return the name for this change
- */
- QString insert(const KoGenChange &change);
-
- /**
- * Save changes.
- *
- * This creates the text:changed-region tag containing all
- * changes.
- *
- * @param xmlWriter
- * @param stylesDotXml
- */
- void saveOdfChanges(KoXmlWriter *xmlWriter, bool trackChanges) const;
-
-private:
- class Private;
- Private * const d;
-};
-
-#endif /* KOGENCHANGES_H */
diff --git a/libs/odf/KoGenStyle.cpp b/libs/odf/KoGenStyle.cpp
deleted file mode 100644
index d26f9cacce..0000000000
--- a/libs/odf/KoGenStyle.cpp
+++ /dev/null
@@ -1,523 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2004-2006 David Faure <faure@kde.org>
- Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
- Copyright (C) 2010 Jarosław Staniek <staniek@kde.org>
- Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
-
- 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 "KoGenStyle.h"
-#include "KoGenStyles.h"
-
-#include <QTextLength>
-
-#include <KoXmlWriter.h>
-
-#include <float.h>
-
-#include <OdfDebug.h>
-
-// Returns -1, 0 (equal) or 1
-static int compareMap(const QMap<QString, QString>& map1, const QMap<QString, QString>& map2)
-{
- QMap<QString, QString>::const_iterator it = map1.constBegin();
- QMap<QString, QString>::const_iterator oit = map2.constBegin();
- for (; it != map1.constEnd(); ++it, ++oit) { // both maps have been checked for size already
- if (it.key() != oit.key())
- return it.key() < oit.key() ? -1 : + 1;
- if (it.value() != oit.value())
- return it.value() < oit.value() ? -1 : + 1;
- }
- return 0; // equal
-}
-
-
-KoGenStyle::KoGenStyle(Type type, const char* familyName,
- const QString& parentName)
- : m_type(type), m_familyName(familyName), m_parentName(parentName),
- m_autoStyleInStylesDotXml(false), m_defaultStyle(false)
-{
- switch (type) {
- case TextStyle:
- case TextAutoStyle:
- m_propertyType = TextType;
- break;
- case ParagraphStyle:
- case ParagraphAutoStyle:
- m_propertyType = ParagraphType;
- break;
- case GraphicStyle:
- case GraphicAutoStyle:
- m_propertyType = GraphicType;
- break;
- case SectionStyle:
- case SectionAutoStyle:
- m_propertyType = SectionType;
- break;
- case RubyStyle:
- case RubyAutoStyle:
- m_propertyType = RubyType;
- break;
- case TableStyle:
- case TableAutoStyle:
- m_propertyType = TableType;
- break;
- case TableColumnStyle:
- case TableColumnAutoStyle:
- m_propertyType = TableColumnType;
- break;
- case TableRowStyle:
- case TableRowAutoStyle:
- m_propertyType = TableRowType;
- break;
- case TableCellStyle:
- case TableCellAutoStyle:
- m_propertyType = TableCellType;
- break;
- case PresentationStyle:
- case PresentationAutoStyle:
- m_propertyType = PresentationType;
- break;
- case DrawingPageStyle:
- case DrawingPageAutoStyle:
- m_propertyType = DrawingPageType;
- break;
- case ChartStyle:
- case ChartAutoStyle:
- m_propertyType = ChartType;
- break;
- default:
- m_propertyType = DefaultType;
- break;
- }
-}
-
-KoGenStyle::~KoGenStyle()
-{
-}
-
-/*
- * The order of this list is important; e.g. a graphic-properties must
- * precede a text-properties always. See the Relax NG to check the order.
- */
-static const KoGenStyle::PropertyType s_propertyTypes[] = {
- KoGenStyle::DefaultType,
- KoGenStyle::SectionType,
- KoGenStyle::RubyType,
- KoGenStyle::TableType,
- KoGenStyle::TableColumnType,
- KoGenStyle::TableRowType,
- KoGenStyle::TableCellType,
- KoGenStyle::DrawingPageType,
- KoGenStyle::ChartType,
- KoGenStyle::GraphicType,
- KoGenStyle::ParagraphType,
- KoGenStyle::TextType,
-};
-
-static const char* const s_propertyNames[] = {
- 0,
- "style:section-properties",
- "style:ruby-properties",
- "style:table-properties",
- "style:table-column-properties",
- "style:table-row-properties",
- "style:table-cell-properties",
- "style:drawing-page-properties",
- "style:chart-properties",
- "style:graphic-properties",
- "style:paragraph-properties",
- "style:text-properties"
-};
-
-static const int s_propertyNamesCount = sizeof(s_propertyNames) / sizeof(*s_propertyNames);
-
-static KoGenStyle::PropertyType propertyTypeByElementName(const char* propertiesElementName)
-{
- for (int i = 0; i < s_propertyNamesCount; ++i) {
- if (qstrcmp(s_propertyNames[i], propertiesElementName) == 0) {
- return s_propertyTypes[i];
- }
- }
- return KoGenStyle::DefaultType;
-}
-
-void KoGenStyle::writeStyleProperties(KoXmlWriter* writer, PropertyType type,
- const KoGenStyle* parentStyle) const
-{
- const char* elementName = 0;
- for (int i=0; i<s_propertyNamesCount; ++i) {
- if (s_propertyTypes[i] == type) {
- elementName = s_propertyNames[i];
- }
- }
- Q_ASSERT(elementName);
- const StyleMap& map = m_properties[type];
- const StyleMap& mapChild = m_childProperties[type];
- if (!map.isEmpty() || !mapChild.isEmpty()) {
- writer->startElement(elementName);
- QMap<QString, QString>::const_iterator it = map.constBegin();
- const QMap<QString, QString>::const_iterator end = map.constEnd();
- for (; it != end; ++it) {
- if (!parentStyle || parentStyle->property(it.key(), type) != it.value())
- writer->addAttribute(it.key().toUtf8(), it.value().toUtf8());
- }
- QMap<QString, QString>::const_iterator itChild = mapChild.constBegin();
- const QMap<QString, QString>::const_iterator endChild = mapChild.constEnd();
- for (; itChild != endChild; ++itChild) {
- if (!parentStyle || parentStyle->childProperty(itChild.key(), type) != itChild.value())
- writer->addCompleteElement(itChild.value().toUtf8());
- }
- writer->endElement();
- }
-}
-
-void KoGenStyle::writeStyle(KoXmlWriter* writer, const KoGenStyles& styles, const char* elementName, const QString& name, const char* propertiesElementName, bool closeElement, bool drawElement) const
-{
- //debugOdf <<"writing out style" << name <<" display-name=" << m_attributes["style:display-name"] <<" family=" << m_familyName;
- writer->startElement(elementName);
- const KoGenStyle* parentStyle = 0;
- if (!m_defaultStyle) {
- if (!drawElement)
- writer->addAttribute("style:name", name);
- else
- writer->addAttribute("draw:name", name);
- if (!m_parentName.isEmpty()) {
- Q_ASSERT(!m_familyName.isEmpty());
- parentStyle = styles.style(m_parentName, m_familyName);
- if (parentStyle && m_familyName.isEmpty()) {
- // get family from parent style, just in case
- // Note: this is saving code, don't convert to attributeNS!
- const_cast<KoGenStyle *>(this)->
- m_familyName = parentStyle->attribute("style:family").toLatin1();
- //debugOdf <<"Got familyname" << m_familyName <<" from parent";
- }
- if (parentStyle && !parentStyle->isDefaultStyle())
- writer->addAttribute("style:parent-style-name", m_parentName);
- }
- } else { // default-style
- Q_ASSERT(qstrcmp(elementName, "style:default-style") == 0);
- Q_ASSERT(m_parentName.isEmpty());
- }
- if (!m_familyName.isEmpty())
- const_cast<KoGenStyle *>(this)->
- addAttribute("style:family", QString::fromLatin1(m_familyName));
- else {
- if (qstrcmp(elementName, "style:style") == 0)
- warnOdf << "User style " << name << " is without family - invalid. m_type=" << m_type;
- }
-
-#if 0 // #ifndef NDEBUG
- debugOdf << "style:" << name;
- printDebug();
- if (parentStyle) {
- debugOdf << " parent:" << m_parentName;
- parentStyle->printDebug();
- }
-#endif
-
- // Write attributes [which differ from the parent style]
- // We only look at the direct parent style because we assume
- // that styles are fully specified, i.e. the inheritance is
- // only in the final file, not in the caller's code.
- QMap<QString, QString>::const_iterator it = m_attributes.constBegin();
- for (; it != m_attributes.constEnd(); ++it) {
- bool writeit = true;
- if (parentStyle && it.key() != "style:family" // always write the family out
- && parentStyle->attribute(it.key()) == it.value())
- writeit = false;
- if (writeit)
- writer->addAttribute(it.key().toUtf8(), it.value().toUtf8());
- }
- bool createPropertiesTag = propertiesElementName && propertiesElementName[0] != '\0';
- KoGenStyle::PropertyType i = KoGenStyle::DefaultType;
- KoGenStyle::PropertyType defaultPropertyType = KoGenStyle::DefaultType;
- if (createPropertiesTag)
- defaultPropertyType = propertyTypeByElementName(propertiesElementName);
- if (!m_properties[i].isEmpty() ||
- !m_childProperties[defaultPropertyType].isEmpty() ||
- !m_properties[defaultPropertyType].isEmpty()) {
- if (createPropertiesTag)
- writer->startElement(propertiesElementName); // e.g. paragraph-properties
- it = m_properties[i].constBegin();
- for (; it != m_properties[i].constEnd(); ++it) {
- if (!parentStyle || parentStyle->property(it.key(), i) != it.value())
- writer->addAttribute(it.key().toUtf8(), it.value().toUtf8());
- }
- //write the explicitly-defined properties that are the same type as the default,
- //but only if defaultPropertyType is Text, Paragraph, or GraphicType
- if (defaultPropertyType != 0) {
- it = m_properties[defaultPropertyType].constBegin();
- for (; it != m_properties[defaultPropertyType].constEnd(); ++it) {
- if (!parentStyle || parentStyle->property(it .key(), defaultPropertyType) != it.value())
- writer->addAttribute(it.key().toUtf8(), it.value().toUtf8());
- }
- }
- //write child elements of the properties elements
- it = m_childProperties[defaultPropertyType].constBegin();
- for (; it != m_childProperties[defaultPropertyType].constEnd(); ++it) {
- if (!parentStyle || parentStyle->childProperty(it.key(), defaultPropertyType) != it.value()) {
- writer->addCompleteElement(it.value().toUtf8());
- }
- }
- if (createPropertiesTag)
- writer->endElement();
- }
-
- // now write out any other properties elements
- //start with i=1 to skip the defaultType that we already took care of
- for (int i = 1; i < s_propertyNamesCount; ++i) {
- //skip any properties that are the same as the defaultType
- if (s_propertyTypes[i] != defaultPropertyType) {
- writeStyleProperties(writer, s_propertyTypes[i], parentStyle);
- }
- }
-
- //write child elements that aren't in any of the properties elements
- i = KoGenStyle::StyleChildElement;
- it = m_properties[i].constBegin();
- for (; it != m_properties[i].constEnd(); ++it) {
- if (!parentStyle || parentStyle->property(it.key(), i) != it.value()) {
- writer->addCompleteElement(it.value().toUtf8());
- }
- }
-
- // And now the style maps
- for (int i = 0; i < m_maps.count(); ++i) {
- bool writeit = true;
- if (parentStyle && compareMap(m_maps[i], parentStyle->m_maps[i]) == 0)
- writeit = false;
- if (writeit) {
- writer->startElement("style:map");
- QMap<QString, QString>::const_iterator it = m_maps[i].constBegin();
- for (; it != m_maps[i].constEnd(); ++it) {
- writer->addAttribute(it.key().toUtf8(), it.value().toUtf8());
- }
- writer->endElement(); // style:map
- }
- }
- if (closeElement)
- writer->endElement();
-}
-
-void KoGenStyle::addPropertyPt(const QString& propName, qreal propValue, PropertyType type)
-{
- if (type == DefaultType) {
- type = m_propertyType;
- }
- QString str;
- str.setNum(propValue, 'f', DBL_DIG);
- str += "pt";
- m_properties[type].insert(propName, str);
-}
-
-void KoGenStyle::addPropertyLength(const QString& propName, const QTextLength &propValue, PropertyType type)
-{
- if (type == DefaultType) {
- type = m_propertyType;
- }
- if (propValue.type() == QTextLength::FixedLength) {
- return addPropertyPt(propName, propValue.rawValue(), type);
- } else {
- QString str;
- str.setNum((int) propValue.rawValue());
- str += '%';
- m_properties[type].insert(propName, str);
- }
-}
-
-void KoGenStyle::addAttribute(const QString& attrName, qreal attrValue)
-{
- QString str;
- str.setNum(attrValue, 'f', DBL_DIG);
- str += "pt";
- m_attributes.insert(attrName, str);
-}
-
-void KoGenStyle::addAttributePercent(const QString &attrName, qreal value)
-{
- QByteArray str;
- str.setNum(value, 'f', FLT_DIG);
- str += '%';
- addAttribute(attrName, str.data());
-}
-
-void KoGenStyle::addAttributePercent(const QString &attrName, int value)
-{
- QByteArray str;
- str.setNum(value);
- str += '%';
- addAttribute(attrName, str.data());
-}
-
-void KoGenStyle::addStyleMap(const QMap<QString, QString>& styleMap)
-{
- // check, if already present
- for (int i = 0 ; i < m_maps.count() ; ++i) {
- if (m_maps[i].count() == styleMap.count()) {
- int comp = compareMap(m_maps[i], styleMap);
- if (comp == 0)
- return;
- }
- }
- m_maps.append(styleMap);
-}
-
-
-#ifndef NDEBUG
-void KoGenStyle::printDebug() const
-{
- int i = DefaultType;
- debugOdf << m_properties[i].count() << " properties.";
- for (QMap<QString, QString>::ConstIterator it = m_properties[i].constBegin(); it != m_properties[i].constEnd(); ++it) {
- debugOdf << "" << it.key() << " =" << it.value();
- }
- i = TextType;
- debugOdf << m_properties[i].count() << " text properties.";
- for (QMap<QString, QString>::ConstIterator it = m_properties[i].constBegin(); it != m_properties[i].constEnd(); ++it) {
- debugOdf << "" << it.key() << " =" << it.value();
- }
- i = ParagraphType;
- debugOdf << m_properties[i].count() << " paragraph properties.";
- for (QMap<QString, QString>::ConstIterator it = m_properties[i].constBegin(); it != m_properties[i].constEnd(); ++it) {
- debugOdf << "" << it.key() << " =" << it.value();
- }
- i = TextType;
- debugOdf << m_childProperties[i].count() << " text child elements.";
- for (QMap<QString, QString>::ConstIterator it = m_childProperties[i].constBegin(); it != m_childProperties[i].constEnd(); ++it) {
- debugOdf << "" << it.key() << " =" << it.value();
- }
- i = ParagraphType;
- debugOdf << m_childProperties[i].count() << " paragraph child elements.";
- for (QMap<QString, QString>::ConstIterator it = m_childProperties[i].constBegin(); it != m_childProperties[i].constEnd(); ++it) {
- debugOdf << "" << it.key() << " =" << it.value();
- }
- debugOdf << m_attributes.count() << " attributes.";
- for (QMap<QString, QString>::ConstIterator it = m_attributes.constBegin(); it != m_attributes.constEnd(); ++it) {
- debugOdf << "" << it.key() << " =" << it.value();
- }
- debugOdf << m_maps.count() << " maps.";
- for (int i = 0; i < m_maps.count(); ++i) {
- debugOdf << "map" << i << ":";
- for (QMap<QString, QString>::ConstIterator it = m_maps[i].constBegin(); it != m_maps[i].constEnd(); ++it) {
- debugOdf << "" << it.key() << " =" << it.value();
- }
- }
- debugOdf;
-}
-#endif
-
-bool KoGenStyle::operator<(const KoGenStyle &other) const
-{
- if (m_type != other.m_type) return m_type < other.m_type;
- if (m_parentName != other.m_parentName) return m_parentName < other.m_parentName;
- if (m_familyName != other.m_familyName) return m_familyName < other.m_familyName;
- if (m_autoStyleInStylesDotXml != other.m_autoStyleInStylesDotXml) return m_autoStyleInStylesDotXml;
- for (uint i = 0 ; i <= LastPropertyType; ++i) {
- if (m_properties[i].count() != other.m_properties[i].count()) {
- return m_properties[i].count() < other.m_properties[i].count();
- }
- if (m_childProperties[i].count() != other.m_childProperties[i].count()) {
- return m_childProperties[i].count() < other.m_childProperties[i].count();
- }
- }
- if (m_attributes.count() != other.m_attributes.count()) return m_attributes.count() < other.m_attributes.count();
- if (m_maps.count() != other.m_maps.count()) return m_maps.count() < other.m_maps.count();
- // Same number of properties and attributes, no other choice than iterating
- for (uint i = 0 ; i <= LastPropertyType; ++i) {
- int comp = compareMap(m_properties[i], other.m_properties[i]);
- if (comp != 0)
- return comp < 0;
- }
- for (uint i = 0 ; i <= LastPropertyType; ++i) {
- int comp = compareMap(m_childProperties[i], other.m_childProperties[i]);
- if (comp != 0)
- return comp < 0;
- }
- int comp = compareMap(m_attributes, other.m_attributes);
- if (comp != 0)
- return comp < 0;
- for (int i = 0 ; i < m_maps.count() ; ++i) {
- int comp = compareMap(m_maps[i], other.m_maps[i]);
- if (comp != 0)
- return comp < 0;
- }
- return false;
-}
-
-bool KoGenStyle::operator==(const KoGenStyle &other) const
-{
- if (m_type != other.m_type) return false;
- if (m_parentName != other.m_parentName) return false;
- if (m_familyName != other.m_familyName) return false;
- if (m_autoStyleInStylesDotXml != other.m_autoStyleInStylesDotXml) return false;
- for (uint i = 0 ; i <= LastPropertyType; ++i) {
- if (m_properties[i].count() != other.m_properties[i].count()) {
- return false;
- }
- if (m_childProperties[i].count() != other.m_childProperties[i].count()) {
- return false;
- }
- }
- if (m_attributes.count() != other.m_attributes.count()) return false;
- if (m_maps.count() != other.m_maps.count()) return false;
- // Same number of properties and attributes, no other choice than iterating
- for (uint i = 0 ; i <= LastPropertyType; ++i) {
- int comp = compareMap(m_properties[i], other.m_properties[i]);
- if (comp != 0)
- return false;
- }
- for (uint i = 0 ; i <= LastPropertyType; ++i) {
- int comp = compareMap(m_childProperties[i], other.m_childProperties[i]);
- if (comp != 0)
- return false;
- }
- int comp = compareMap(m_attributes, other.m_attributes);
- if (comp != 0)
- return false;
- for (int i = 0 ; i < m_maps.count() ; ++i) {
- int comp = compareMap(m_maps[i], other.m_maps[i]);
- if (comp != 0)
- return false;
- }
- return true;
-}
-
-bool KoGenStyle::isEmpty() const
-{
- if (!m_attributes.isEmpty() || ! m_maps.isEmpty())
- return false;
- for (uint i = 0 ; i <= LastPropertyType; ++i)
- if (! m_properties[i].isEmpty())
- return false;
- return true;
-}
-
-void KoGenStyle::copyPropertiesFromStyle(const KoGenStyle &sourceStyle, KoGenStyle &targetStyle, PropertyType type)
-{
- if (type == DefaultType) {
- type = sourceStyle.m_propertyType;
- }
-
- const StyleMap& map = sourceStyle.m_properties[type];
- if (!map.isEmpty()) {
- QMap<QString, QString>::const_iterator it = map.constBegin();
- const QMap<QString, QString>::const_iterator end = map.constEnd();
- for (; it != end; ++it) {
- targetStyle.addProperty(it.key(), it.value(), type);
- }
- }
-}
diff --git a/libs/odf/KoGenStyle.h b/libs/odf/KoGenStyle.h
deleted file mode 100644
index 0c86eda16f..0000000000
--- a/libs/odf/KoGenStyle.h
+++ /dev/null
@@ -1,549 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2004-2006 David Faure <faure@kde.org>
- Copyright (C) 2007-2008 Thorsten Zachmann <zachmann@kde.org>
- Copyright (C) 2009 Inge Wallin <inge@lysator.liu.se>
- Copyright (C) 2010 KO GmbH <jos.van.den.oever@kogmbh.com>
- Copyright (C) 2010 Jarosław Staniek <staniek@kde.org>
- Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
-
- 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 KOGENSTYLE_H
-#define KOGENSTYLE_H
-
-#include <QList>
-#include <QMap>
-#include <QString>
-#include "kritaodf_export.h"
-
-class QTextLength;
-class KoGenStyles;
-class KoXmlWriter;
-
-/**
- * A generic style, i.e. basically a collection of properties and a name.
- * Instances of KoGenStyle can either be held in the KoGenStyles collection,
- * or created (e.g. on the stack) and given to KoGenStyles::insert().
- *
- * @author David Faure <faure@kde.org>
- */
-class KRITAODF_EXPORT KoGenStyle
-{
-public:
- /**
- * Possible values for the "type" argument of the KoGenStyle constructor.
- * @note If there is still something missing, add it here so that it is possible to use the same
- * saving code in all applications.
- */
- enum Type {
- PageLayoutStyle, ///< style:page-layout as in odf 14.3 Page Layout
- TextStyle, ///< style:style from family "text" as in odf 14.8.1 Text Styles
- ///< (office:styles)
- TextAutoStyle, ///< style:style from family "text" as in odf 14.8.1 Text Styles
- ///< (office:automatic-styles)
- ParagraphStyle, ///< style:style from family "paragraph" as in odf 14.1 Style Element
- ///< (office:styles)
- ParagraphAutoStyle, ///< style:style from family "paragraph" as in odf 14.1 Style Element
- ///< (office:automatic-styles)
- SectionStyle, ///< style:style from family "section" as in odf 14.8.3 Section Styles
- ///< (office:styles)
- SectionAutoStyle, ///< style:style from family "section" as in odf 14.8.3 Section Styles
- ///< (office:automatic-styles)
- RubyStyle, ///< style:style from family "ruby" as in odf 14.8.4 Ruby Style
- ///< (office:styles)
- RubyAutoStyle, ///< style:style from family "ruby" as in odf 14.8.4 Ruby Style
- ///< (office:automatic-styles)
- TableStyle, ///< style:style from family "table" as in odf 14.12 Table Formatting
- ///< Properties (office:styles)
- TableAutoStyle, ///< style:style from family "table" as in odf 14.12 Table Formatting Properties
- ///< (office:automatic-styles)
- TableColumnStyle, ///< style:style from family "table-column" as in odf 15.9 Column Formatting
- ///< Properties (office:styles)
- TableColumnAutoStyle, ///< style:style from family "table-column" as in odf 15.9 Column Formatting
- ///< Properties (office:automatic-styles)
- TableRowStyle, ///< style:style from family "table-row" as in odf 15.10 Table Row Formatting
- ///< Properties (office:styles)
- TableRowAutoStyle, ///< style:style from family "table-row" as in odf 15.10 Table Row Formatting
- ///< Properties (office:automatic-styles)
- TableCellStyle, ///< style:style from family "table-cell" as in odf 15.11 Table Cell Formatting
- ///< Properties (office:styles)
- TableCellAutoStyle, ///< style:style from family "table-cell" as in odf 15.11 Table Cell Formatting
- ///< Properties (office:automatic-styles)
- GraphicStyle, ///< style:style from family "graphic" as in 14.13.1 Graphic and Presentation
- ///< Styles (office:automatic-styles)
- GraphicAutoStyle, ///< style:style from family "graphic" as in 14.13.1 Graphic and Presentation
- ///< Styles (office:automatic-styles)
- PresentationStyle, ///< style:style from family "presentation" as in 14.13.1 Graphic and
- ///< Presentation Styles (office:styles)
- PresentationAutoStyle, ///< style:style from family "presentation" as in 14.13.1 Graphic and
- ///< Presentation Styles (office:automatic-styles)
- DrawingPageStyle, ///< style:style from family "drawing-page" as in odf 14.13.2 Drawing Page Style
- ///< (office:styles)
- DrawingPageAutoStyle, ///< style:style from family "drawing-page" as in odf 14.13.2 Drawing Page Style
- ///< (office:automatic-styles)
- ChartStyle, ///< style:style from family "chart" as in odf 14.16 Chart Styles
- ///< (office:styles)
- ChartAutoStyle, ///< style:style from family "chart" as in odf 14.16 Chart Styles
- ///< (office:automatic-styles)
-
- ListStyle, ///< text:list-style as in odf 14.10 List Style (office:styles)
- ListAutoStyle, ///< text:list-style as in odf 14.10 List Style (office:automatic-styles)
- NumericNumberStyle, ///< number:number-style as in odf 14.7.1 Number Style
- NumericDateStyle, ///< number:date-style as in odf 14.7.4 Date Style
- NumericTimeStyle, ///< number:time-style as in odf 14.7.5 Time Style
- NumericFractionStyle, ///< number:number-style as in odf 14.7.1 Number Style
- NumericPercentageStyle, ///< number:percentage-style as in odf 14.7.3 Percentage Style
- NumericScientificStyle, ///< number:number-style as in odf 14.7.1 Number Style
- NumericCurrencyStyle, ///< number:currency-style as in odf 14.7.2 Currency Style
- NumericTextStyle, ///< number:text-style 14.7.7 Text Style
- ///< @note unused
- HatchStyle, ///< draw:hatch as in odf 14.14.3 Hatch (office:styles)
- StrokeDashStyle, ///< draw:stroke-dash as in odf 14.14.7 Stroke Dash (office:styles)
- GradientStyle, ///< draw:gradient as in odf 14.14.1 Gradient (office:styles)
- LinearGradientStyle, ///< svg:linearGradient as in odf 14.14.2 SVG Gradients (office:styles)
- RadialGradientStyle, ///< svg:radialGradient as in odf 14.14.2 SVG Gradients (office:styles)
- ConicalGradientStyle, ///< calligra:conicalGradient calligra extension for conical gradients
- FillImageStyle, ///< draw:fill-image as in odf 14.14.4 Fill Image (office:styles)
- NumericBooleanStyle, ///< number:boolean 14.7.6 Boolean Style
- ///< @note unused
- OpacityStyle, ///< draw:opacity as in odf 14.14.5 Opacity Gradient
- ///< @note unused
- MarkerStyle, ///< draw:marker as in odf 14.14.6 Marker
- PresentationPageLayoutStyle, ///< style:presentation-page-layout as in odf 14.15 Presentation Page Layouts
- OutlineLevelStyle, ///< text:outline-style as in odf 1.2 section 16.34
- // TODO differently
- MasterPageStyle, ///< style:master-page as in odf 14.4 14.4 Master Pages (office:master-styles)
- // style:default-style as in odf 14.2 Default Styles
- // 14.5 Table Templates
- /// @internal @note always update when adding values to this enum
- LastStyle = MasterPageStyle
- };
-
- /**
- * Start the definition of a new style. Its name will be set later by KoGenStyles::insert(),
- * but first you must define its properties and attributes.
- *
- * @param type this is a hook for the application to categorize styles
- * See the Style* enum. Ignored when writing out the style.
- *
- * @param familyName The value for style:family, e.g. text, paragraph, graphic etc.
- * The family is for style:style elements only; number styles and list styles don't have one.
- *
- * @param parentName If set, name of the parent style from which this one inherits.
- */
- explicit KoGenStyle(Type type = PageLayoutStyle, const char *familyName = 0,
- const QString &parentName = QString());
- ~KoGenStyle();
-
- /**
- * setAutoStyleInStylesDotXml(true) marks a given automatic style as being needed in styles.xml.
- * For instance styles used by headers and footers need to go there, since
- * they are saved in styles.xml, and styles.xml must be independent from content.xml.
- *
- * The application should use KoGenStyles::styles( type, true ) in order to retrieve
- * those styles and save them separately.
- */
- void setAutoStyleInStylesDotXml(bool b) {
- m_autoStyleInStylesDotXml = b;
- }
- /// @return the value passed to setAutoStyleInStylesDotXml; false by default
- bool autoStyleInStylesDotXml() const {
- return m_autoStyleInStylesDotXml;
- }
-
- /**
- * setDefaultStyle(true) marks a given style as being the default style.
- * This means we expect that you will call writeStyle( ...,"style:default-style"),
- * and its name will be omitted in the output.
- */
- void setDefaultStyle(bool b) {
- m_defaultStyle = b;
- }
- /// @return the value passed to setDefaultStyle; false by default
- bool isDefaultStyle() const {
- return m_defaultStyle;
- }
-
- /// Return the type of this style, as set in the constructor
- Type type() const {
- return m_type;
- }
-
- /// Return the family name
- const char* familyName() const {
- return m_familyName.data();
- }
-
- /// Sets the name of style's parent.
- void setParentName(const QString &name) {
- m_parentName = name;
- }
-
- /// Return the name of style's parent, if set
- QString parentName() const {
- return m_parentName;
- }
-
- /**
- * @brief The types of properties
- *
- * Simple styles only write one foo-properties tag, in which case they can just use DefaultType.
- * However a given style might want to write several kinds of properties, in which case it would
- * need to use other property types than the default one.
- *
- * For instance this style:
- * @code
- * <style:style style:family="chart">
- * <style:chart-properties .../>
- * <style:graphic-properties .../>
- * <style:text-properties .../>
- * </style:style>
- * @endcode
- * would use DefaultType for chart-properties (and would pass "style:chart-properties" to writeStyle(),
- * and would use GraphicType and TextType.
- */
- enum PropertyType {
- /**
- * DefaultType depends on family: e.g. paragraph-properties if family=paragraph
- * or on the type of style (e.g. page-layout -> page-layout-properties).
- * (In fact that tag name is the one passed to writeStyle)
- */
- DefaultType,
- /// TextType is always text-properties.
- TextType,
- /// ParagraphType is always paragraph-properties.
- ParagraphType,
- /// GraphicType is always graphic-properties.
- GraphicType,
- /// SectionType is always section-properties.
- SectionType,
- /// RubyType is always ruby-properties.
- RubyType,
- /// TableType is always table-properties.
- TableType,
- /// TableColumnType is always table-column-properties
- TableColumnType,
- /// TableRowType is always table-row-properties.
- TableRowType,
- /// TableCellType is always for table-cell-properties.
- TableCellType,
- /// PresentationType is always for presentation-properties.
- PresentationType,
- /// DrawingPageType is always for drawing-page-properties.
- DrawingPageType,
- /// ChartType is always for chart-properties.
- ChartType,
- Reserved1, ///< @internal for binary compatible extensions
- /// For elements that are children of the style itself, not any of the properties
- StyleChildElement,
- /// @internal @note always update when adding values to this enum
- LastPropertyType = StyleChildElement
- };
-
- /// Add a property to the style. Passing DefaultType as property type uses a style-type specific property type.
- void addProperty(const QString &propName, const QString &propValue, PropertyType type = DefaultType) {
- if (type == DefaultType) {
- type = m_propertyType;
- }
- m_properties[type].insert(propName, propValue);
- }
- /// Overloaded version of addProperty that takes a char*, usually for "..."
- void addProperty(const QString &propName, const char *propValue, PropertyType type = DefaultType) {
- if (type == DefaultType) {
- type = m_propertyType;
- }
- m_properties[type].insert(propName, QString::fromUtf8(propValue));
- }
- /// Overloaded version of addProperty that converts an int to a string
- void addProperty(const QString &propName, int propValue, PropertyType type = DefaultType) {
- if (type == DefaultType) {
- type = m_propertyType;
- }
- m_properties[type].insert(propName, QString::number(propValue));
- }
- /// Overloaded version of addProperty that converts a bool to a string (false/true)
- void addProperty(const QString &propName, bool propValue, PropertyType type = DefaultType) {
- if (type == DefaultType) {
- type = m_propertyType;
- }
- m_properties[type].insert(propName, propValue ? "true" : "false");
- }
-
- /**
- * Add a property which represents a distance, measured in pt
- * The number is written out with the highest possible precision
- * (unlike QString::number and setNum, which default to 6 digits),
- * and the unit name ("pt") is appended to it.
- */
- void addPropertyPt(const QString &propName, qreal propValue, PropertyType type = DefaultType);
-
- /**
- * Add a property which represents a length, measured in pt, or in percent
- * The number is written out with the highest possible precision
- * (unlike QString::number and setNum, which default to 6 digits) or as integer (for percents),
- * and the unit name ("pt" or "%") is appended to it.
- */
- void addPropertyLength(const QString &propName, const QTextLength &propValue, PropertyType type = DefaultType);
-
- /**
- * Remove a property from the style. Passing DefaultType as property type
- * uses a style-type specific property type.
- */
- void removeProperty(const QString &propName, PropertyType type = DefaultType) {
- if (type == DefaultType) {
- type = m_propertyType;
- }
- m_properties[type].remove(propName);
- }
-
- /**
- * Remove properties of defined type from the style. Passing DefaultType
- * as property type uses a style-type specific property type.
- */
- void removeAllProperties(PropertyType type = DefaultType) {
- if (type == DefaultType) {
- type = m_propertyType;
- }
- m_properties[type].clear();
- }
-
- /**
- * Add an attribute to the style
- * The difference between property and attributes is a bit oasis-format-specific:
- * attributes are for the style element itself, and properties are in the style:properties child element
- */
- void addAttribute(const QString &attrName, const QString& attrValue) {
- m_attributes.insert(attrName, attrValue);
- }
- /// Overloaded version of addAttribute that takes a char*, usually for "..."
- void addAttribute(const QString &attrName, const char* attrValue) {
- m_attributes.insert(attrName, QString::fromUtf8(attrValue));
- }
- /// Overloaded version of addAttribute that converts an int to a string
- void addAttribute(const QString &attrName, int attrValue) {
- m_attributes.insert(attrName, QString::number(attrValue));
- }
-
- /// Overloaded version of addAttribute that converts a bool to a string
- void addAttribute(const QString &attrName, bool attrValue) {
- m_attributes.insert(attrName, attrValue ? "true" : "false");
- }
-
- /**
- * Add an attribute which represents a distance, measured in pt
- * The number is written out with the highest possible precision
- * (unlike QString::number and setNum, which default to 6 digits),
- * and the unit name ("pt") is appended to it.
- */
- void addAttribute(const QString &attrName, qreal attrValue);
-
- /**
- * Add an attribute that represents a percentage value as defined in ODF
- */
- void addAttributePercent(const QString &attrName, qreal value);
-
- /**
- * Add an attribute that represents a percentage value as defined in ODF
- */
- void addAttributePercent(const QString &attrName, int value);
-
- /**
- * Remove an attribute from the style.
- */
- void removeAttribute(const QString &attrName) {
- m_attributes.remove(attrName);
- }
-
-
- /**
- * @brief Add a child element to the style properties.
- *
- * What is meant here is that the contents of the QString
- * will be written out literally. This means you should use
- * KoXmlWriter to generate it:
- * @code
- * QBuffer buffer;
- * buffer.open( QIODevice::WriteOnly );
- * KoXmlWriter elementWriter( &buffer ); // TODO pass indentation level
- * elementWriter.startElement( "..." );
- * ...
- * elementWriter.endElement();
- * QString elementContents = QString::fromUtf8( buffer.buffer(), buffer.buffer().size() );
- * gs.addChildElement( "...", elementContents );
- * @endcode
- *
- * The value of @p elementName is only used to set the order on how the child elements are written out.
- */
- void addChildElement(const QString &elementName, const QString& elementContents, PropertyType type = DefaultType) {
- if (type == DefaultType) {
- type = m_propertyType;
- }
- m_childProperties[type].insert(elementName, elementContents);
- }
-
- /**
- * Same like \a addChildElement above but with QByteArray to explicit convert from QByteArray
- * to QString using utf8 to prevent a dirty pitfall.
- */
- void addChildElement(const QString &elementName, const QByteArray& elementContents, PropertyType type = DefaultType) {
- if (type == DefaultType) {
- type = m_propertyType;
- }
- m_childProperties[type].insert(elementName, QString::fromUtf8(elementContents));
- }
-
- /**
- * Same like \a addChildElement above but adds a child style which is not child of any of the properties
- * The value of @p elementName is only used to set the order on how the child elements are written out.
- */
- void addStyleChildElement(const QString &elementName, const QString& elementContents) {
- m_properties[StyleChildElement].insertMulti(elementName, elementContents);
- }
-
- /**
- * Same like \a addStyleChildElement above but with QByteArray to explicit convert from QByteArray
- * to QString using utf8 to prevent a dirty pitfall.
- * The value of @p elementName is only used to set the order on how the child elements are written out.
- */
- void addStyleChildElement(const QString &elementName, const QByteArray& elementContents) {
- m_properties[StyleChildElement].insertMulti(elementName, QString::fromUtf8(elementContents));
- }
-
- /**
- * @brief Add a style:map to the style.
- * @param styleMap the attributes for the map, associated as (name,value).
- */
- void addStyleMap(const QMap<QString, QString> &styleMap);
-
- /**
- * @return true if the style has no attributes, no properties, no style map etc.
- * This can be used by applications which do not save all attributes unconditionally,
- * but only those that differ from the parent. But note that KoGenStyles::insert() can't find this out...
- */
- bool isEmpty() const;
-
- /**
- * Write the definition of this style to @p writer, using the OASIS format.
- * @param writer the KoXmlWriter in which @p elementName will be created and filled in
- * @param styles the styles collection, used to look up the parent style
- * @param elementName the name of the XML element, e.g. "style:style". Don't forget to
- * pass style:default-style if isDefaultStyle().
- * @param name must come from the collection. It will be ignored if isDefaultStyle() is true.
- * @param propertiesElementName the name of the XML element with the style properties,
- * e.g. "style:text-properties". Can be 0 in special cases where there should be no such item,
- * in which case the attributes and elements are added under the style itself.
- * @param closeElement set it to false to be able to add more child elements to the style element
- * @param drawElement set it to true to add "draw:name" (used for gradient/hatch style) otherwise add "style:name"
- */
- void writeStyle(KoXmlWriter *writer, const KoGenStyles &styles, const char *elementName, const QString &name,
- const char *propertiesElementName, bool closeElement = true, bool drawElement = false) const;
-
- /**
- * Write the definition of these style properties to @p writer, using the OASIS format.
- * @param writer the KoXmlWriter in which @p elementName will be created and filled in
- * @param type the type of properties to write
- * @param parentStyle the parent to this style
- */
- void writeStyleProperties(KoXmlWriter *writer, PropertyType type,
- const KoGenStyle *parentStyle = 0) const;
-
- /**
- * QMap requires a complete sorting order.
- * Another solution would have been a qdict and a key() here, a la KoTextFormat,
- * but the key was difficult to generate.
- * Solutions with only a hash value (not representative of the whole data)
- * require us to write a hashtable by hand....
- */
- bool operator<(const KoGenStyle &other) const;
-
- /// Not needed for QMap, but can still be useful
- bool operator==(const KoGenStyle &other) const;
-
- /**
- * Returns a property of this style. In prinicpal this class is meant to be write-only, but
- * some exceptional cases having read-support as well is very useful. Passing DefaultType
- * as property type uses a style-type specific property type.
- */
- QString property(const QString &propName, PropertyType type = DefaultType) const {
- if (type == DefaultType) {
- type = m_propertyType;
- }
- const QMap<QString, QString>::const_iterator it = m_properties[type].constFind(propName);
- if (it != m_properties[type].constEnd())
- return it.value();
- return QString();
- }
-
- /**
- * Returns a property of this style. In prinicpal this class is meant to be write-only, but
- * some exceptional cases having read-support as well is very useful. Passing DefaultType
- * as property type uses a style-type specific property type.
- */
- QString childProperty(const QString &propName, PropertyType type = DefaultType) const {
- if (type == DefaultType) {
- type = m_propertyType;
- }
- const QMap<QString, QString>::const_iterator it = m_childProperties[type].constFind(propName);
- if (it != m_childProperties[type].constEnd())
- return it.value();
- return QString();
- }
-
- /// Returns an attribute of this style. In prinicpal this class is meant to be write-only, but some exceptional cases having read-support as well is very useful.
- QString attribute(const QString &propName) const {
- const QMap<QString, QString>::const_iterator it = m_attributes.constFind(propName);
- if (it != m_attributes.constEnd())
- return it.value();
- return QString();
- }
-
- /**
- * Copies properties of defined type from a style to another style.
- * This is needed in rare cases where two styles have properties of different types
- * and we want to merge them to one style.
- */
- static void copyPropertiesFromStyle(const KoGenStyle &sourceStyle, KoGenStyle &targetStyle, PropertyType type = DefaultType);
-
-private:
-#ifndef NDEBUG
- void printDebug() const;
-#endif
-
-private:
- // Note that the copy constructor and assignment operator are allowed.
- // Better not use pointers below!
- // TODO turn this into a QSharedData class
- PropertyType m_propertyType;
- Type m_type;
- QByteArray m_familyName;
- QString m_parentName;
- /// We use QMaps since they provide automatic sorting on the key (important for unicity!)
- typedef QMap<QString, QString> StyleMap;
- StyleMap m_properties[LastPropertyType+1];
- StyleMap m_childProperties[LastPropertyType+1];
- StyleMap m_attributes;
- QList<StyleMap> m_maps; // we can't really sort the maps between themselves...
-
- bool m_autoStyleInStylesDotXml;
- bool m_defaultStyle;
- short m_unused2 {0};
-
- // For insert()
- friend class KoGenStyles;
-};
-
-#endif /* KOGENSTYLE_H */
diff --git a/libs/odf/KoGenStyles.cpp b/libs/odf/KoGenStyles.cpp
deleted file mode 100644
index f3f5b20009..0000000000
--- a/libs/odf/KoGenStyles.cpp
+++ /dev/null
@@ -1,546 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2004-2006 David Faure <faure@kde.org>
- Copyright (C) 2007-2008 Thorsten Zachmann <zachmann@kde.org>
- Copyright (C) 2009 Thomas Zander <zander@kde.org>
- Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- Copyright (C) 2009 Inge Wallin <inge@lysator.liu.se>
- Copyright (C) 2010 KO GmbH <jos.van.den.oever@kogmbh.com>
- Copyright (C) 2010 Jarosław Staniek <staniek@kde.org>
-
- 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 "KoGenStyles.h"
-
-#include <KoStore.h>
-#include <KoStoreDevice.h>
-#include <KoXmlWriter.h>
-#include "KoOdfWriteStore.h"
-#include "KoFontFace.h"
-#include <float.h>
-#include <OdfDebug.h>
-
-static const struct {
- KoGenStyle::Type m_type;
- const char * m_elementName;
- const char * m_propertiesElementName;
- bool m_drawElement;
-} styleData[] = {
- { KoGenStyle::TextStyle, "style:style", "style:text-properties", false },
- { KoGenStyle::ParagraphStyle, "style:style", "style:paragraph-properties", false },
- { KoGenStyle::SectionStyle, "style:style", "style:section-properties", false },
- { KoGenStyle::RubyStyle, "style:style", "style:ruby-properties", false },
- { KoGenStyle::TableStyle, "style:style", "style:table-properties", false },
- { KoGenStyle::TableColumnStyle, "style:style", "style:table-column-properties", false },
- { KoGenStyle::TableRowStyle, "style:style", "style:table-row-properties", false },
- { KoGenStyle::TableCellStyle, "style:style", "style:table-cell-properties", false },
- { KoGenStyle::GraphicStyle, "style:style", "style:graphic-properties", false },
- { KoGenStyle::PresentationStyle, "style:style", "style:graphic-properties", false },
- { KoGenStyle::DrawingPageStyle, "style:style", "style:drawing-page-properties", false },
- { KoGenStyle::ChartStyle, "style:style", "style:chart-properties", false },
- { KoGenStyle::ListStyle, "text:list-style", 0, false },
- { KoGenStyle::LinearGradientStyle, "svg:linearGradient", 0, true },
- { KoGenStyle::RadialGradientStyle, "svg:radialGradient", 0, true },
- { KoGenStyle::ConicalGradientStyle, "calligra:conicalGradient", 0, true },
- { KoGenStyle::StrokeDashStyle, "draw:stroke-dash", 0, true },
- { KoGenStyle::FillImageStyle, "draw:fill-image", 0, true },
- { KoGenStyle::HatchStyle, "draw:hatch", "style:graphic-properties", true },
- { KoGenStyle::GradientStyle, "draw:gradient", "style:graphic-properties", true },
- { KoGenStyle::MarkerStyle, "draw:marker", "style:graphic-properties", true },
- { KoGenStyle::PresentationPageLayoutStyle, "style:presentation-page-layout", 0, false },
- { KoGenStyle::OutlineLevelStyle, "text:outline-style", 0, false }
-};
-
-static const unsigned int numStyleData = sizeof(styleData) / sizeof(*styleData);
-
-static const struct {
- KoGenStyle::Type m_type;
- const char * m_elementName;
- const char * m_propertiesElementName;
- bool m_drawElement;
-} autoStyleData[] = {
- { KoGenStyle::TextAutoStyle, "style:style", "style:text-properties", false },
- { KoGenStyle::ParagraphAutoStyle, "style:style", "style:paragraph-properties", false },
- { KoGenStyle::SectionAutoStyle, "style:style", "style:section-properties", false },
- { KoGenStyle::RubyAutoStyle, "style:style", "style:ruby-properties", false },
- { KoGenStyle::TableAutoStyle, "style:style", "style:table-properties", false },
- { KoGenStyle::TableColumnAutoStyle, "style:style", "style:table-column-properties", false },
- { KoGenStyle::TableRowAutoStyle, "style:style", "style:table-row-properties", false },
- { KoGenStyle::TableCellAutoStyle, "style:style", "style:table-cell-properties", false },
- { KoGenStyle::GraphicAutoStyle, "style:style", "style:graphic-properties", false },
- { KoGenStyle::PresentationAutoStyle, "style:style", "style:graphic-properties", false },
- { KoGenStyle::DrawingPageAutoStyle, "style:style", "style:drawing-page-properties", false },
- { KoGenStyle::ChartAutoStyle, "style:style", "style:chart-properties", false },
- { KoGenStyle::PageLayoutStyle, "style:page-layout", "style:page-layout-properties", false },
- { KoGenStyle::ListAutoStyle, "text:list-style", 0, false },
- { KoGenStyle::NumericNumberStyle, "number:number-style", 0, false },
- { KoGenStyle::NumericFractionStyle, "number:number-style", 0, false },
- { KoGenStyle::NumericScientificStyle, "number:number-style", 0, false },
- { KoGenStyle::NumericDateStyle, "number:date-style", 0, false },
- { KoGenStyle::NumericTimeStyle, "number:time-style", 0, false },
- { KoGenStyle::NumericPercentageStyle, "number:percentage-style", 0, false },
- { KoGenStyle::NumericCurrencyStyle, "number:currency-style", 0, false },
- { KoGenStyle::NumericBooleanStyle, "number:boolean-style", 0, false },
- { KoGenStyle::NumericTextStyle, "number:text-style", 0, false }
-};
-
-static const unsigned int numAutoStyleData = sizeof(autoStyleData) / sizeof(*autoStyleData);
-
-static void insertRawOdfStyles(const QByteArray& xml, QByteArray& styles)
-{
- if (xml.isEmpty())
- return;
- if (!styles.isEmpty() && !styles.endsWith('\n') && !xml.startsWith('\n')) {
- styles.append('\n');
- }
- styles.append(xml);
-}
-
-class Q_DECL_HIDDEN KoGenStyles::Private
-{
-public:
- Private(KoGenStyles *q) : q(q)
- {
- }
-
- ~Private()
- {
- }
-
- QList<KoGenStyles::NamedStyle> styles(bool autoStylesInStylesDotXml, KoGenStyle::Type type) const;
- void saveOdfAutomaticStyles(KoXmlWriter* xmlWriter, bool autoStylesInStylesDotXml,
- const QByteArray& rawOdfAutomaticStyles) const;
- void saveOdfDocumentStyles(KoXmlWriter* xmlWriter) const;
- void saveOdfMasterStyles(KoXmlWriter* xmlWriter) const;
- QString makeUniqueName(const QString& base, const QByteArray &family, InsertionFlags flags) const;
-
- /**
- * Save font face declarations
- *
- * This creates the office:font-face-decls tag containing all font face
- * declarations
- */
- void saveOdfFontFaceDecls(KoXmlWriter* xmlWriter) const;
-
- /// style definition -> name
- StyleMap styleMap;
-
- /// Map with the style name as key.
- /// This map is mainly used to check for name uniqueness
- QMap<QByteArray, QSet<QString> > styleNames;
- QMap<QByteArray, QSet<QString> > autoStylesInStylesDotXml;
-
- /// List of styles (used to preserve ordering)
- QList<KoGenStyles::NamedStyle> styleList;
-
- /// map for saving default styles
- QMap<int, KoGenStyle> defaultStyles;
-
- /// font faces
- QMap<QString, KoFontFace> fontFaces;
-
- StyleMap::iterator insertStyle(const KoGenStyle &style, const QString &name, InsertionFlags flags);
-
- struct RelationTarget {
- QString target; // the style we point to
- QString attribute; // the attribute name used for the relation
- };
- QHash<QString, RelationTarget> relations; // key is the name of the source style
-
- QByteArray rawOdfDocumentStyles;
- QByteArray rawOdfAutomaticStyles_stylesDotXml;
- QByteArray rawOdfAutomaticStyles_contentDotXml;
- QByteArray rawOdfMasterStyles;
- QByteArray rawOdfFontFaceDecls;
-
- KoGenStyles *q;
-};
-
-QList<KoGenStyles::NamedStyle> KoGenStyles::Private::styles(bool autoStylesInStylesDotXml, KoGenStyle::Type type) const
-{
- QList<KoGenStyles::NamedStyle> lst;
- QList<KoGenStyles::NamedStyle>::const_iterator it = styleList.constBegin();
- const QList<KoGenStyles::NamedStyle>::const_iterator end = styleList.constEnd();
- for (; it != end ; ++it) {
- if ((*it).style->type() == type && (*it).style->autoStyleInStylesDotXml() == autoStylesInStylesDotXml) {
- lst.append(*it);
- }
- }
- return lst;
-}
-
-void KoGenStyles::Private::saveOdfAutomaticStyles(KoXmlWriter* xmlWriter, bool autoStylesInStylesDotXml,
- const QByteArray& rawOdfAutomaticStyles) const
-{
- xmlWriter->startElement("office:automatic-styles");
-
- for (uint i = 0; i < numAutoStyleData; ++i) {
- QList<KoGenStyles::NamedStyle> stylesList = styles(autoStylesInStylesDotXml, autoStyleData[i].m_type);
- QList<KoGenStyles::NamedStyle>::const_iterator it = stylesList.constBegin();
- for (; it != stylesList.constEnd() ; ++it) {
- (*it).style->writeStyle(xmlWriter, *q, autoStyleData[i].m_elementName, (*it).name,
- autoStyleData[i].m_propertiesElementName, true, autoStyleData[i].m_drawElement);
- }
- }
-
- if (!rawOdfAutomaticStyles.isEmpty()) {
- xmlWriter->addCompleteElement(rawOdfAutomaticStyles.constData());
- }
-
- xmlWriter->endElement(); // office:automatic-styles
-}
-
-void KoGenStyles::Private::saveOdfDocumentStyles(KoXmlWriter* xmlWriter) const
-{
- xmlWriter->startElement("office:styles");
-
- for (uint i = 0; i < numStyleData; ++i) {
- const QMap<int, KoGenStyle>::const_iterator it(defaultStyles.constFind(styleData[i].m_type));
- if (it != defaultStyles.constEnd()) {
- it.value().writeStyle(xmlWriter, *q, "style:default-style", "",
- styleData[i].m_propertiesElementName, true, styleData[i].m_drawElement);
- }
- }
-
- for (uint i = 0; i < numStyleData; ++i) {
- QList<KoGenStyles::NamedStyle> stylesList(styles(false, styleData[i].m_type));
- QList<KoGenStyles::NamedStyle>::const_iterator it = stylesList.constBegin();
- for (; it != stylesList.constEnd() ; ++it) {
- if (relations.contains(it->name)) {
- KoGenStyles::Private::RelationTarget relation = relations.value(it->name);
- KoGenStyle styleCopy = *(*it).style;
- styleCopy.addAttribute(relation.attribute, relation.target);
- styleCopy.writeStyle(xmlWriter, *q, styleData[i].m_elementName, (*it).name,
- styleData[i].m_propertiesElementName, true, styleData[i].m_drawElement);
- } else {
- (*it).style->writeStyle(xmlWriter, *q, styleData[i].m_elementName, (*it).name,
- styleData[i].m_propertiesElementName, true, styleData[i].m_drawElement);
- }
- }
- }
-
- if (!rawOdfDocumentStyles.isEmpty()) {
- xmlWriter->addCompleteElement(rawOdfDocumentStyles.constData());
- }
-
- xmlWriter->endElement(); // office:styles
-}
-
-void KoGenStyles::Private::saveOdfMasterStyles(KoXmlWriter* xmlWriter) const
-{
- xmlWriter->startElement("office:master-styles");
-
- QList<KoGenStyles::NamedStyle> stylesList = styles(false, KoGenStyle::MasterPageStyle);
- QList<KoGenStyles::NamedStyle>::const_iterator it = stylesList.constBegin();
- for (; it != stylesList.constEnd() ; ++it) {
- (*it).style->writeStyle(xmlWriter, *q, "style:master-page", (*it).name, 0);
- }
-
- if (!rawOdfMasterStyles.isEmpty()) {
- xmlWriter->addCompleteElement(rawOdfMasterStyles.constData());
- }
-
- xmlWriter->endElement(); // office:master-styles
-}
-
-void KoGenStyles::Private::saveOdfFontFaceDecls(KoXmlWriter* xmlWriter) const
-{
- if (fontFaces.isEmpty())
- return;
-
- xmlWriter->startElement("office:font-face-decls");
- for (QMap<QString, KoFontFace>::ConstIterator it(fontFaces.constBegin());
- it != fontFaces.constEnd(); ++it)
- {
- it.value().saveOdf(xmlWriter);
- }
-
- if (!rawOdfFontFaceDecls.isEmpty()) {
- xmlWriter->addCompleteElement(rawOdfFontFaceDecls.constData());
- }
-
- xmlWriter->endElement(); // office:font-face-decls
-}
-
-QString KoGenStyles::Private::makeUniqueName(const QString& base, const QByteArray &family, InsertionFlags flags) const
-{
- // If this name is not used yet, and numbering isn't forced, then the given name is ok.
- if ((flags & DontAddNumberToName)
- && !autoStylesInStylesDotXml[family].contains(base)
- && !styleNames[family].contains(base))
- return base;
- int num = 1;
- QString name;
- do {
- name = base + QString::number(num++);
- } while (autoStylesInStylesDotXml[family].contains(name)
- || styleNames[family].contains(name));
- return name;
-}
-
-//------------------------
-
-KoGenStyles::KoGenStyles()
- : d(new Private(this))
-{
-}
-
-KoGenStyles::~KoGenStyles()
-{
- delete d;
-}
-
-QString KoGenStyles::insert(const KoGenStyle& style, const QString& baseName, InsertionFlags flags)
-{
- // if it is a default style it has to be saved differently
- if (style.isDefaultStyle()) {
- // we can have only one default style per type
- Q_ASSERT(!d->defaultStyles.contains(style.type()));
- // default style is only possible for style:style in office:style types
- Q_ASSERT(style.type() == KoGenStyle::TextStyle ||
- style.type() == KoGenStyle::ParagraphStyle ||
- style.type() == KoGenStyle::SectionStyle ||
- style.type() == KoGenStyle::RubyStyle ||
- style.type() == KoGenStyle::TableStyle ||
- style.type() == KoGenStyle::TableColumnStyle ||
- style.type() == KoGenStyle::TableRowStyle ||
- style.type() == KoGenStyle::TableCellStyle ||
- style.type() == KoGenStyle::GraphicStyle ||
- style.type() == KoGenStyle::PresentationStyle ||
- style.type() == KoGenStyle::DrawingPageStyle ||
- style.type() == KoGenStyle::ChartStyle);
-
- d->defaultStyles.insert(style.type(), style);
- // default styles don't have a name
- return QString();
- }
-
- if (flags & AllowDuplicates) {
- StyleMap::iterator it = d->insertStyle(style, baseName, flags);
- return it.value();
- }
-
- StyleMap::iterator it = d->styleMap.find(style);
- if (it == d->styleMap.end()) {
- // Not found, try if this style is in fact equal to its parent (the find above
- // wouldn't have found it, due to m_parentName being set).
- if (!style.parentName().isEmpty()) {
- KoGenStyle testStyle(style);
- const KoGenStyle* parentStyle = this->style(style.parentName(), style.familyName()); // ## linear search
- if (!parentStyle) {
- debugOdf << "baseName=" << baseName << "parent style" << style.parentName()
- << "not found in collection";
- } else {
- // TODO remove
- if (testStyle.m_familyName != parentStyle->m_familyName) {
- warnOdf << "baseName=" << baseName << "family=" << testStyle.m_familyName
- << "parent style" << style.parentName() << "has a different family:"
- << parentStyle->m_familyName;
- }
-
- testStyle.m_parentName = parentStyle->m_parentName;
- // Exclude the type from the comparison. It's ok for an auto style
- // to have a user style as parent; they can still be identical
- testStyle.m_type = parentStyle->m_type;
- // Also it's ok to not have the display name of the parent style
- // in the auto style
- QMap<QString, QString>::const_iterator it = parentStyle->m_attributes.find("style:display-name");
- if (it != parentStyle->m_attributes.end())
- testStyle.addAttribute("style:display-name", *it);
-
- if (*parentStyle == testStyle)
- return style.parentName();
- }
- }
-
- it = d->insertStyle(style, baseName, flags);
- }
- return it.value();
-}
-
-KoGenStyles::StyleMap::iterator KoGenStyles::Private::insertStyle(const KoGenStyle &style,
- const QString& baseName, InsertionFlags flags)
-{
- QString styleName(baseName);
- if (styleName.isEmpty()) {
- switch (style.type()) {
- case KoGenStyle::ParagraphAutoStyle: styleName = 'P'; break;
- case KoGenStyle::ListAutoStyle: styleName = 'L'; break;
- case KoGenStyle::TextAutoStyle: styleName = 'T'; break;
- default:
- styleName = 'A'; // for "auto".
- }
- flags &= ~DontAddNumberToName; // i.e. force numbering
- }
- styleName = makeUniqueName(styleName, style.m_familyName, flags);
- if (style.autoStyleInStylesDotXml())
- autoStylesInStylesDotXml[style.m_familyName].insert(styleName);
- else
- styleNames[style.m_familyName].insert(styleName);
- KoGenStyles::StyleMap::iterator it = styleMap.insert(style, styleName);
- NamedStyle s;
- s.style = &it.key();
- s.name = styleName;
- styleList.append(s);
- return it;
-}
-
-KoGenStyles::StyleMap KoGenStyles::styles() const
-{
- return d->styleMap;
-}
-
-QList<KoGenStyles::NamedStyle> KoGenStyles::styles(KoGenStyle::Type type) const
-{
- return d->styles(false, type);
-}
-
-const KoGenStyle* KoGenStyles::style(const QString &name, const QByteArray &family) const
-{
- QList<KoGenStyles::NamedStyle>::const_iterator it = d->styleList.constBegin();
- const QList<KoGenStyles::NamedStyle>::const_iterator end = d->styleList.constEnd();
- for (; it != end ; ++it) {
- if ((*it).name == name && (*it).style->familyName() == family) {
- return (*it).style;
- }
- }
- return 0;
-}
-
-KoGenStyle* KoGenStyles::styleForModification(const QString &name, const QByteArray &family)
-{
- return const_cast<KoGenStyle *>(style(name, family));
-}
-
-void KoGenStyles::markStyleForStylesXml(const QString &name, const QByteArray &family)
-{
- Q_ASSERT(d->styleNames[family].contains(name));
- d->styleNames[family].remove(name);
- d->autoStylesInStylesDotXml[family].insert(name);
- styleForModification(name, family)->setAutoStyleInStylesDotXml(true);
-}
-
-void KoGenStyles::insertFontFace(const KoFontFace &face)
-{
- Q_ASSERT(!face.isNull());
- if (face.isNull()) {
- warnOdf << "This font face is null and will not be added to styles: set at least the name";
- return;
- }
- d->fontFaces.insert(face.name(), face); // replaces prev item
-}
-
-KoFontFace KoGenStyles::fontFace(const QString& name) const
-{
- return d->fontFaces.value(name);
-}
-
-bool KoGenStyles::saveOdfStylesDotXml(KoStore* store, KoXmlWriter* manifestWriter) const
-{
- if (!store->open("styles.xml"))
- return false;
-
- manifestWriter->addManifestEntry("styles.xml", "text/xml");
-
- KoStoreDevice stylesDev(store);
- KoXmlWriter* stylesWriter = KoOdfWriteStore::createOasisXmlWriter(&stylesDev, "office:document-styles");
-
- d->saveOdfFontFaceDecls(stylesWriter);
- d->saveOdfDocumentStyles(stylesWriter);
- d->saveOdfAutomaticStyles(stylesWriter, true, d->rawOdfAutomaticStyles_stylesDotXml);
- d->saveOdfMasterStyles(stylesWriter);
-
- stylesWriter->endElement(); // root element (office:document-styles)
- stylesWriter->endDocument();
- delete stylesWriter;
-
- if (!store->close()) // done with styles.xml
- return false;
-
- return true;
-}
-
-void KoGenStyles::saveOdfStyles(StylesPlacement placement, KoXmlWriter* xmlWriter) const
-{
- switch (placement) {
- case DocumentStyles:
- d->saveOdfDocumentStyles(xmlWriter);
- break;
- case MasterStyles:
- d->saveOdfMasterStyles(xmlWriter);
- break;
- case DocumentAutomaticStyles:
- d->saveOdfAutomaticStyles(xmlWriter, false, d->rawOdfAutomaticStyles_contentDotXml);
- break;
- case StylesXmlAutomaticStyles:
- d->saveOdfAutomaticStyles(xmlWriter, true, d->rawOdfAutomaticStyles_stylesDotXml);
- break;
- case FontFaceDecls:
- d->saveOdfFontFaceDecls(xmlWriter);
- break;
- }
-}
-
-void KoGenStyles::insertRawOdfStyles(StylesPlacement placement, const QByteArray& xml)
-{
- switch (placement) {
- case DocumentStyles:
- ::insertRawOdfStyles(xml, d->rawOdfDocumentStyles);
- break;
- case MasterStyles:
- ::insertRawOdfStyles(xml, d->rawOdfMasterStyles);
- break;
- case DocumentAutomaticStyles:
- ::insertRawOdfStyles(xml, d->rawOdfAutomaticStyles_contentDotXml);
- break;
- case StylesXmlAutomaticStyles:
- ::insertRawOdfStyles(xml, d->rawOdfAutomaticStyles_stylesDotXml);
- break;
- case FontFaceDecls:
- ::insertRawOdfStyles(xml, d->rawOdfFontFaceDecls);
- break;
- }
-}
-
-void KoGenStyles::insertStyleRelation(const QString &source, const QString &target, const char *tagName)
-{
- KoGenStyles::Private::RelationTarget relation;
- relation.target = target;
- relation.attribute = QString(tagName);
- d->relations.insert(source, relation);
-}
-
-QDebug operator<<(QDebug dbg, const KoGenStyles& styles)
-{
- dbg.nospace() << "KoGenStyles:";
- QList<KoGenStyles::NamedStyle>::const_iterator it = styles.d->styleList.constBegin();
- const QList<KoGenStyles::NamedStyle>::const_iterator end = styles.d->styleList.constEnd();
- for (; it != end ; ++it) {
- dbg.nospace() << (*it).name;
- }
- for (QMap<QByteArray, QSet<QString> >::const_iterator familyIt(styles.d->styleNames.constBegin()); familyIt != styles.d->styleNames.constEnd(); ++familyIt) {
- for (QSet<QString>::const_iterator it(familyIt.value().constBegin()); it != familyIt.value().constEnd(); ++it) {
- dbg.space() << "style:" << *it;
- }
- }
-#ifndef NDEBUG
- for (QMap<QByteArray, QSet<QString> >::const_iterator familyIt(styles.d->autoStylesInStylesDotXml.constBegin()); familyIt != styles.d->autoStylesInStylesDotXml.constEnd(); ++familyIt) {
- for (QSet<QString>::const_iterator it(familyIt.value().constBegin()); it != familyIt.value().constEnd(); ++it) {
- dbg.space() << "auto style for style.xml:" << *it;
- }
- }
-#endif
- return dbg.space();
-}
diff --git a/libs/odf/KoGenStyles.h b/libs/odf/KoGenStyles.h
deleted file mode 100644
index 57a5e84b3d..0000000000
--- a/libs/odf/KoGenStyles.h
+++ /dev/null
@@ -1,258 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2004-2006 David Faure <faure@kde.org>
- Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
- Copyright (C) 2009 Thomas Zander <zander@kde.org>
- Copyright (C) 2010 Jarosław Staniek <staniek@kde.org>
-
- 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 KOGENSTYLES_H
-#define KOGENSTYLES_H
-
-#include <QList>
-#include <QMultiMap>
-#include <QString>
-
-#include "KoGenStyle.h"
-
-class KoStore;
-class KoFontFace;
-
-/**
- * @brief Repository of styles used during saving ODF documents.
- *
- * Each instance of KoGenStyles is a collection of styles whose names
- * are in the same "namespace".
- * This means there should be one instance for all styles in &lt;office:styles&gt;,
- * and &lt;office:automatic-styles&gt;, another instance for number formats, another
- * one for draw styles, and another one for list styles.
- *
- * "Style" in this context only means "a collection of properties".
- * The "Gen" means both "Generic" and "Generated" :)
- *
- * The basic design principle is the flyweight pattern: if you need
- * a style with the same properties from two different places, you
- * get the same object. Here it means rather you get the same name for the style,
- * and it will get saved only once to the file.
- *
- * KoGenStyles features sharing, creation on demand, and name generation.
- * Since this is used for saving only, it doesn't feature refcounting, nor
- * removal of individual styles.
- *
- * @note The use of KoGenStyles isn't mandatory, of course. If the application
- * is already designed with user and automatic styles in mind for a given
- * set of properties, it can go ahead and save all styles directly (after
- * ensuring they have unique names).
- *
- * @author David Faure <faure@kde.org>
- */
-class KRITAODF_EXPORT KoGenStyles
-{
-public:
- /// Single style with assigned name
- struct NamedStyle {
- const KoGenStyle* style; ///< @note owned by the collection
- QString name;
- };
-
- typedef QMultiMap<KoGenStyle, QString> StyleMap;
-
- KoGenStyles();
- ~KoGenStyles();
-
- /**
- * Those are flags for the insert() call.
- *
- * By default (NoFlag), the generated style names will look like "name1", "name2".
- * If DontAddNumberToName is set, the first name that will be tried is "name", and only if
- * that one exists, then "name1" is tried. Set DontAddNumberToName if the name given as
- * argument is supposed to be the full style name.
- * If AllowDuplicates is set, a unique style name is generated even if a similar KoGenStyle
- * already exists. In other words, the collection will now contain two equal KoGenStyle
- * and generate them with different style names.
- */
- enum InsertionFlag {
- NoFlag = 0,
- DontAddNumberToName = 1,
- AllowDuplicates = 2
- };
- Q_DECLARE_FLAGS(InsertionFlags, InsertionFlag)
-
- /**
- * Look up a style in the collection, inserting it if necessary.
- * This assigns a name to the style and returns it.
- *
- * @param style the style to look up.
- * @param baseName proposed (base) name for the style. Note that with the ODF,
- * the style name is never shown to the user (there's a separate display-name
- * attribute for that). So there are little reasons to use named styles anyway.
- * But this attribute can be used for clarity of the files.
- * If this name is already in use (for another style), then a number is appended
- * to it until unused name is found.
- * @param flags see Flags
- *
- * @return the name that has been assigned for the inserted style
- */
- QString insert(const KoGenStyle &style, const QString &baseName = QString(), InsertionFlags flags = NoFlag);
-
- /**
- * Return the entire collection of styles
- * Use this for saving the styles
- */
- StyleMap styles() const;
-
- /**
- * Return all styles of a given type (NOT marked for styles.xml).
- *
- * Use this only if you have special needs.
- *
- * @param type the style type, see the KoGenStyle constructor
- * @see insert()
- */
- QList<KoGenStyles::NamedStyle> styles(KoGenStyle::Type type) const;
-
- /**
- * @return an existing style by name. If no such style exists, 0 is returned.
- */
- const KoGenStyle *style(const QString &name, const QByteArray &family) const;
-
- /**
- * @return an existing style by name, which can be modified.
- * If no such style exists, 0 is returned.
- * @warning This is DANGEROUS.
- * It basically defeats the purpose of insert()!
- * Only do this if you know for sure no other 'user' of that style will
- * be affected.
- */
- KoGenStyle* styleForModification(const QString &name, const QByteArray &family);
-
- /**
- * Mark a given automatic style as being needed in styles.xml.
- * For instance styles used by headers and footers need to go there, since
- * they are saved in styles.xml, and styles.xml must be independent from content.xml.
- *
- * Equivalent to using KoGenStyle::setAutoStyleInStylesDotXml() but this can be done after insert().
- *
- * This operation can't be undone; once styles are promoted they can't go back
- * to being content.xml-only.
- *
- * @see styles, KoGenStyle::setAutoStyleInStylesDotXml
- */
- void markStyleForStylesXml(const QString &name, const QByteArray &family);
-
- /**
- * Insert a font face declaration.
- * @a face should have non-empty "name" parameter, i.e. should not be null.
- *
- * Declaration with given name replaces previously inserted declaration with the same name.
- *
- * See odf 2.6 Font Face Declarations
- * and odf 14.6 Font Face Declaration.
- */
- void insertFontFace(const KoFontFace &face);
-
- /**
- * @return font face declaration for name @a name
- * or null font face (see KoFontFace::isNull()) if there is no such font face.
- *
- * See odf 2.6 Font Face Declarations
- * and odf 14.6 Font Face Declaration.
- */
- KoFontFace fontFace(const QString &name) const;
-
- /**
- * Save the styles into the styles.xml file
- *
- * This saves all styles and font face declarations to the styles.xml file which
- * belong there. This creates the file and creates an entry in the manifest.
- *
- * @param store
- * @param mainfestwriter
- * @return true on success
- */
- bool saveOdfStylesDotXml(KoStore *store, KoXmlWriter *manifestWriter) const;
-
- /**
- * Placement of styles saved in saveOdfStyles() or inserted in insertRawOdfStyles().
- */
- enum StylesPlacement {
- /**
- * Creates document's office:styles tag and saves all document styles there
- * or inserts raw styles into document's office:styles.
- */
- DocumentStyles,
- /**
- * Creates styles.xml's office:master-styles tag and saves all master styles there
- * or inserts raw styles into styles.xml's office:automatic-styles.
- */
- MasterStyles,
- /**
- * Creates document's office:automatic-styles tag and saves all automatic styles there
- * or inserts raw styles into document's office:automatic-styles.
- */
- DocumentAutomaticStyles,
- /**
- * Creates styles.xml's office:automatic-styles tag and saves all automatic styles there
- * or inserts raw styles into style.xml's office:automatic-styles.
- */
- StylesXmlAutomaticStyles,
- /**
- * Creates document's office:font-face-decls tag and saves all document styles there
- * or inserts raw styles into document's office:font-face-decls.
- */
- FontFaceDecls
- };
-
- /**
- * Save styles of given type.
- *
- * @param placement see StylesPlacement
- * @param xmlWriter target writer
- */
- void saveOdfStyles(StylesPlacement placement, KoXmlWriter *xmlWriter) const;
-
- /**
- * Insert extra styles of given type.
- *
- * This inserts extra styles as raw xml into a given placement.
- * The information is collected and written back when saveOdfStyles() is called.
- * This method is useful for testing purposes.
- *
- * @param placement see StylesPlacement
- * @param xml the raw xml string
- */
- void insertRawOdfStyles(StylesPlacement placement, const QByteArray &xml);
-
- /**
- * register a relation for a previously inserted style to a previously inserted target style.
- * This allows you to insert a style relation based on generated names.
- */
- void insertStyleRelation(const QString &source, const QString &target, const char *tagName);
-
-private:
- friend KRITAODF_EXPORT QDebug operator<<(QDebug dbg, const KoGenStyles& styles);
-
- class Private;
- Private * const d;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(KoGenStyles::InsertionFlags)
-
-//! Debug stream operator.
-KRITAODF_EXPORT QDebug operator<<(QDebug dbg, const KoGenStyles& styles);
-
-#endif /* KOGENSTYLES_H */
diff --git a/libs/odf/KoOasisSettings.cpp b/libs/odf/KoOasisSettings.cpp
deleted file mode 100644
index 31095afe58..0000000000
--- a/libs/odf/KoOasisSettings.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2004 Laurent Montel <montel@kde.org>
-
- 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 "KoOasisSettings.h"
-#include "KoXmlNS.h"
-#include <OdfDebug.h>
-
-class Q_DECL_HIDDEN KoOasisSettings::Private
-{
-};
-
-KoOasisSettings::KoOasisSettings(const KoXmlDocument& doc)
- : m_settingsElement(KoXml::namedItemNS(doc.documentElement(), KoXmlNS::office, "settings")),
- m_configNsUri(KoXmlNS::config)
- , d(0)
-{
- const KoXmlElement contents = doc.documentElement();
- if (m_settingsElement.isNull())
- debugOdf << " document doesn't have tag 'office:settings'";
-}
-
-KoOasisSettings::KoOasisSettings(const KoXmlDocument& doc, const char* officeNSURI, const char* configNSURI)
- : m_settingsElement(KoXml::namedItemNS(doc.documentElement(), officeNSURI, "settings")),
- m_configNsUri(configNSURI)
- , d(0)
-{
- const KoXmlElement contents = doc.documentElement();
- if (m_settingsElement.isNull())
- debugOdf << " document doesn't have tag 'office:settings'";
-}
-
-KoOasisSettings::~KoOasisSettings()
-{
- delete d;
-}
-
-KoOasisSettings::Items KoOasisSettings::itemSet(const QString& itemSetName) const
-{
- KoXmlElement e;
- forEachElement(e, m_settingsElement) {
- if (e.localName() == "config-item-set" &&
- e.namespaceURI() == m_configNsUri &&
- e.attributeNS(m_configNsUri, "name", QString()) == itemSetName) {
- return Items(e, this);
- }
- }
-
- return Items(KoXmlElement(), this);
-}
-
-KoOasisSettings::IndexedMap KoOasisSettings::Items::indexedMap(const QString& itemMapName) const
-{
- KoXmlElement configItem;
- forEachElement(configItem, m_element) {
- if (configItem.localName() == "config-item-map-indexed" &&
- configItem.namespaceURI() == m_settings->m_configNsUri &&
- configItem.attributeNS(m_settings->m_configNsUri, "name", QString()) == itemMapName) {
- return IndexedMap(configItem, m_settings);
- }
- }
- return IndexedMap(KoXmlElement(), m_settings);
-}
-
-KoOasisSettings::NamedMap KoOasisSettings::Items::namedMap(const QString& itemMapName) const
-{
- KoXmlElement configItem;
- forEachElement(configItem, m_element) {
- if (configItem.localName() == "config-item-map-named" &&
- configItem.namespaceURI() == m_settings->m_configNsUri &&
- configItem.attributeNS(m_settings->m_configNsUri, "name", QString()) == itemMapName) {
- return NamedMap(configItem, m_settings);
- }
- }
- return NamedMap(KoXmlElement(), m_settings);
-}
-
-KoOasisSettings::Items KoOasisSettings::IndexedMap::entry(int entryIndex) const
-{
- int i = 0;
- KoXmlElement entry;
- forEachElement(entry, m_element) {
- if (entry.localName() == "config-item-map-entry" &&
- entry.namespaceURI() == m_settings->m_configNsUri) {
- if (i == entryIndex)
- return Items(entry, m_settings);
- else
- ++i;
- }
- }
- return Items(KoXmlElement(), m_settings);
-}
-
-KoOasisSettings::Items KoOasisSettings::NamedMap::entry(const QString& entryName) const
-{
- KoXmlElement entry;
- forEachElement(entry, m_element) {
- if (entry.localName() == "config-item-map-entry" &&
- entry.namespaceURI() == m_settings->m_configNsUri &&
- entry.attributeNS(m_settings->m_configNsUri, "name", QString()) == entryName) {
- return Items(entry, m_settings);
- }
- }
- return Items(KoXmlElement(), m_settings);
-}
-
-// helper method
-QString KoOasisSettings::Items::findConfigItem(const KoXmlElement& element,
- const QString& item, bool* ok) const
-{
- KoXmlElement it;
- forEachElement(it, element) {
- if (it.localName() == "config-item" &&
- it.namespaceURI() == m_settings->m_configNsUri &&
- it.attributeNS(m_settings->m_configNsUri, "name", QString()) == item) {
- *ok = true;
- return it.text();
- }
- }
- *ok = false;
- return QString();
-}
-
-
-QString KoOasisSettings::Items::findConfigItem(const QString& item, bool* ok) const
-{
- return findConfigItem(m_element, item, ok);
-}
-
-#if 0 // does anyone need this one? passing a default value does the job, too
-bool KoOasisSettings::Items::hasConfigItem(const QString& configName) const
-{
- bool ok;
- (void)findConfigItem(configName, &ok);
- return ok;
-}
-#endif
-
-QString KoOasisSettings::Items::parseConfigItemString(const QString& configName, const QString& defValue) const
-{
- bool ok;
- const QString str = findConfigItem(configName, &ok);
- return ok ? str : defValue;
-}
-
-int KoOasisSettings::Items::parseConfigItemInt(const QString& configName, int defValue) const
-{
- bool ok;
- const QString str = findConfigItem(configName, &ok);
- int value;
- if (ok) {
- value = str.toInt(&ok);
- if (ok)
- return value;
- }
- return defValue;
-}
-
-qreal KoOasisSettings::Items::parseConfigItemDouble(const QString& configName, qreal defValue) const
-{
- bool ok;
- const QString str = findConfigItem(configName, &ok);
- qreal value;
- if (ok) {
- value = str.toDouble(&ok);
- if (ok)
- return value;
- }
- return defValue;
-}
-
-bool KoOasisSettings::Items::parseConfigItemBool(const QString& configName, bool defValue) const
-{
- bool ok;
- const QString str = findConfigItem(configName, &ok);
- if (! ok)
- return defValue;
- if (str == "true")
- return true;
- else if (str == "false")
- return false;
- return defValue;
-}
-
-short KoOasisSettings::Items::parseConfigItemShort(const QString& configName, short defValue) const
-{
- bool ok;
- const QString str = findConfigItem(configName, &ok);
- short value;
- if (ok) {
- value = str.toShort(&ok);
- if (ok)
- return value;
- }
- return defValue;
-}
-
-long KoOasisSettings::Items::parseConfigItemLong(const QString& configName, long defValue) const
-{
- bool ok;
- const QString str = findConfigItem(configName, &ok);
- long value;
- if (ok) {
- value = str.toLong(&ok);
- if (ok)
- return value;
- }
- return defValue;
-}
diff --git a/libs/odf/KoOasisSettings.h b/libs/odf/KoOasisSettings.h
deleted file mode 100644
index 22978c878a..0000000000
--- a/libs/odf/KoOasisSettings.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2004 Laurent Montel <montel@kde.org>
- David Faure <faure@kde.org>
-
- 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 KOOASISSETTINGS_H
-#define KOOASISSETTINGS_H
-
-#include <QDomDocument>
-#include "kritaodf_export.h"
-#include "KoXmlReader.h"
-
-/**
- * @brief Parse settings.xml file.
- *
- * This class helps parsing the settings.xml file of an OASIS document.
- *
- * For reference, the structure of settings.xml looks like:
- * <pre>
- * \<office:settings\>
- * \<config:config-item-set config:name="configure-settings"\>
- * ....
- * \</config:config-item-set\>
- * \<config:config-item-set config:name="view-settings"\>
- * \<config:config-item-map-indexed config:name="Views"\>
- * \<config:config-item-map-entry\>
- * \<config:config-item config:name="SnapLinesDrawing" config:type="string"\>value\</config:config-item\>
- * ....
- * \<config:config-item-map-named config:name="Tables"\>
- * \<config:config-item-map-entry config:name="Sheet1"\>
- * \<config:config-item config:name="CursorPositionX"\>
- * ......
- * \</config:config-item-map-entry\>
- * \<config:config-item-map-entry config:name="Sheet2"\>
- * ....
- * \</config:config-item-map-entry\>
- * \</config:config-item-map-named\>
- * .....
- * \</config:config-item-map-entry\>
- * \</config:config-item-map-indexed\>
- * \<config:config-item-map-indexed config:name="Interface"\>
- * .......
- * \</config:config-item-map-indexed\>
- * \</config:config-item-set\>
- * \</office:settings\>
- * </pre>
- * Basically, an item-set is a set of named \<config-item\>s and/or maps.
- * There are two kinds of maps (by-index or by-name), and entries in the
- * maps contain \<config-item\>s too, or nested maps.
- *
- * The API of KoOasisSettings allows the caller to look for a given item-set
- * or item-map once, and then lookup multiple items inside it.
- * It also allows "drilling down" inside the tree in case of nesting.
- */
-class KRITAODF_EXPORT KoOasisSettings
-{
-public:
- /**
- * Normal KoOasisSettings constructor, for an OASIS settings.xml
- */
- explicit KoOasisSettings(const KoXmlDocument &doc);
-
- /**
- * KoOasisSettings constructor for an OpenOffice-1.1 file
- */
- KoOasisSettings(const KoXmlDocument &doc, const char *officeNsUri, const char *configNsUri);
-
- ~KoOasisSettings();
-
- class Items;
- /**
- * Returns the toplevel item-set named @p itemSetName.
- * If not found, the returned items instance is null.
- */
- Items itemSet(const QString &itemSetName) const;
-
- class IndexedMap;
- class NamedMap;
- /// Represents a collection of items (config-item or maps).
- class KRITAODF_EXPORT Items
- {
- friend class KoOasisSettings;
- friend class IndexedMap;
- friend class NamedMap;
- Items(const KoXmlElement& elem, const KoOasisSettings* settings)
- : m_element(elem), m_settings(settings) {}
- public:
- bool isNull() const {
- return m_element.isNull();
- }
-
- /**
- * Look for the config-item-map-indexed named @p itemMapName and return it.
- *
- * An indexed map is an array (or sequence), i.e. items are supposed to
- * be retrieved by index. This is useful for e.g. "view 0", "view 1" etc.
- */
- IndexedMap indexedMap(const QString &itemMapName) const;
-
- /**
- * Look for the config-item-map-named named @p mapItemName and return it.
- *
- * A named map is a map where items are retrieved by entry name, @see selectItemMapEntry
- * @return false if no such map was found
- */
- NamedMap namedMap(const QString &itemMapName) const;
-
- int parseConfigItemInt(const QString &configName, int defaultValue = 0) const;
- qreal parseConfigItemDouble(const QString &configName, qreal defaultValue = 0) const;
- QString parseConfigItemString(const QString &configName, const QString &defaultValue = QString()) const;
- bool parseConfigItemBool(const QString &configName, bool defaultValue = false) const;
- short parseConfigItemShort(const QString &configName, short defaultValue = 0) const;
- long parseConfigItemLong(const QString &configName, long defaultValue = 0) const;
- private:
- /// @internal
- QString findConfigItem(const QString &item, bool *ok) const;
- /// @internal
- QString findConfigItem(const KoXmlElement &element, const QString &item, bool *ok) const;
-
- KoXmlElement m_element;
- const KoOasisSettings* m_settings;
- };
-
- /// Internal base class for IndexedMap and NamedMap
- class Map
- {
- public:
- bool isNull() const {
- return m_element.isNull();
- }
- protected:
- Map(const KoXmlElement &elem, const KoOasisSettings *settings)
- : m_element(elem), m_settings(settings) {}
- const KoXmlElement m_element;
- const KoOasisSettings *m_settings;
- };
-
- class KRITAODF_EXPORT IndexedMap : public Map
- {
- friend class Items;
- IndexedMap(const KoXmlElement& elem, const KoOasisSettings* settings)
- : Map(elem, settings) {}
- public:
- /// Returns an entry in an indexed map
- Items entry(int entryIndex) const;
- };
-
- class KRITAODF_EXPORT NamedMap : public Map
- {
- friend class Items;
- NamedMap(const KoXmlElement &elem, const KoOasisSettings *settings)
- : Map(elem, settings) {}
- public:
- /// Returns an entry in a named map
- Items entry(const QString& entryName) const;
- };
-
-private:
- friend class Items;
- friend class IndexedMap;
- friend class NamedMap;
- const KoXmlElement m_settingsElement;
- const QString m_configNsUri;
-
- class Private;
- Private * const d;
-};
-
-#endif
diff --git a/libs/odf/KoOdf.cpp b/libs/odf/KoOdf.cpp
deleted file mode 100644
index 409a8e18b0..0000000000
--- a/libs/odf/KoOdf.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
- Copyright (C) 2010 Thomas Zander <zander@kde.org>
-
- 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 "KoOdf.h"
-
-namespace KoOdf
-{
-struct DocumentData {
- const char * mimeType;
- const char * templateMimeType;
- const char * bodyContentElement;
-};
-
-const DocumentData s_documentData[] = {
- { "application/vnd.oasis.opendocument.text", "application/vnd.oasis.opendocument.text-template", "office:text" },
- { "application/vnd.oasis.opendocument.graphics", "application/vnd.oasis.opendocument.graphics-template", "office:drawing" },
- { "application/vnd.oasis.opendocument.presentation", "application/vnd.oasis.opendocument.presentation-template", "office:presentation" },
- { "application/vnd.oasis.opendocument.spreadsheet", "application/vnd.oasis.opendocument.spreadsheet-template", "office:spreadsheet" },
- { "application/vnd.oasis.opendocument.chart", "application/vnd.oasis.opendocument.chart-template", "office:chart" },
- { "application/vnd.oasis.opendocument.image", "application/vnd.oasis.opendocument.image-template", "office:image" },
- // TODO what is the element for a formula check if bodyContentElement is ok
- { "application/vnd.oasis.opendocument.formula", "application/vnd.oasis.opendocument.formula-template", "office:XXX" },
- { "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"", "", "office:text" }
-};
-//"application/vnd.oasis.opendocument.text-master"
-//"application/vnd.oasis.opendocument.text-web"
-
-const char * mimeType(DocumentType documentType)
-{
- return s_documentData[documentType].mimeType;
-}
-
-const char * templateMimeType(DocumentType documentType)
-{
- return s_documentData[documentType].templateMimeType;
-}
-
-const char * bodyContentElement(DocumentType documentType, bool withNamespace)
-{
- return withNamespace ? s_documentData[documentType].bodyContentElement : s_documentData[documentType].bodyContentElement + 7;
-}
-
-}
diff --git a/libs/odf/KoOdf.h b/libs/odf/KoOdf.h
deleted file mode 100644
index 37f99825ce..0000000000
--- a/libs/odf/KoOdf.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
-
- 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 KOODF_H
-#define KOODF_H
-
-#include "kritaodf_export.h"
-
-namespace KoOdf
-{
- enum DocumentType {
- Text,
- Graphics,
- Presentation,
- Spreadsheet,
- Chart,
- Image,
- Formula,
- OpenOfficeClipboard
- };
-
- /**
- * Get the mime type
- *
- * @param documentType the document type
- * @return the mime type used for the given document type
- */
- KRITAODF_EXPORT const char * mimeType(DocumentType documentType);
-
- /**
- * Get the mime type
- *
- * @param documentType the document type
- * @return the mime type used for templates of the given document type
- */
- KRITAODF_EXPORT const char * templateMimeType(DocumentType documentType);
-
- /**
- * Get the mime type
- *
- * @param documentType the document type
- * @param withNamespace if true the namespace before the element is also returned
- * if false only the element is returned
- * @return the body element name for the given document type
- */
- KRITAODF_EXPORT const char * bodyContentElement(DocumentType documentType, bool withNamespace);
-}
-
-#endif /* KOODF_H */
diff --git a/libs/odf/KoOdfBibliographyConfiguration.cpp b/libs/odf/KoOdfBibliographyConfiguration.cpp
deleted file mode 100644
index 8781ffe22b..0000000000
--- a/libs/odf/KoOdfBibliographyConfiguration.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Smit Patel <smitpatel24@gmail.com>
- *
- * 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 "KoOdfBibliographyConfiguration.h"
-
-#include <OdfDebug.h>
-#include "KoXmlNS.h"
-#include "KoXmlWriter.h"
-#include "KoXmlReader.h"
-
-#include <QList>
-
-const QList<QString> KoOdfBibliographyConfiguration::bibTypes = QList<QString>() << "article" << "book" << "booklet" << "conference"
- << "email" << "inbook" << "incollection"
- << "inproceedings" << "journal" << "manual"
- << "mastersthesis" << "misc" << "phdthesis"
- << "proceedings" << "techreport" << "unpublished"
- << "www" << "custom1" << "custom2"
- << "custom3" << "custom4" << "custom5";
-
-const QList<QString> KoOdfBibliographyConfiguration::bibDataFields = QList<QString>() << "address" << "annote" << "author"
- << "bibliography-type" << "booktitle"
- << "chapter" << "custom1" << "custom2"
- << "custom3" << "custom4" << "custom5"
- << "edition" << "editor" << "howpublished"
- << "identifier" << "institution" << "isbn"
- << "issn" << "journal" << "month" << "note"
- << "number" << "organizations" << "pages"
- << "publisher" << "report-type" << "school"
- << "series" << "title" << "url" << "volume"
- << "year";
-
-class Q_DECL_HIDDEN KoOdfBibliographyConfiguration::Private
-{
-public:
- QString prefix;
- QString suffix;
- bool numberedEntries;
- bool sortByPosition;
- QString sortAlgorithm;
- QList<SortKeyPair> sortKeys;
-};
-
-KoOdfBibliographyConfiguration::KoOdfBibliographyConfiguration()
- : d(new Private())
-{
- d->prefix = "[";
- d->suffix = "]";
- d->numberedEntries = false;
- d->sortByPosition = true;
-}
-
-KoOdfBibliographyConfiguration::~KoOdfBibliographyConfiguration()
-{
- delete d;
-}
-
-KoOdfBibliographyConfiguration::KoOdfBibliographyConfiguration(const KoOdfBibliographyConfiguration &other)
- : QObject(), d(new Private())
-{
- *this = other;
-}
-
-KoOdfBibliographyConfiguration &KoOdfBibliographyConfiguration::operator=(const KoOdfBibliographyConfiguration &other)
-{
- d->prefix = other.d->prefix;
- d->suffix = other.d->suffix;
- d->numberedEntries = other.d->numberedEntries;
- d->sortAlgorithm = other.d->sortAlgorithm;
- d->sortByPosition = other.d->sortByPosition;
- d->sortKeys = other.d->sortKeys;
-
- return *this;
-}
-
-
-void KoOdfBibliographyConfiguration::loadOdf(const KoXmlElement &element)
-{
- d->prefix = element.attributeNS(KoXmlNS::text, "prefix", QString());
- d->suffix = element.attributeNS(KoXmlNS::text, "suffix", QString());
- d->numberedEntries = (element.attributeNS(KoXmlNS::text, "numbered-entries", QString("false")) == "true")
- ? true : false;
- d->sortByPosition = (element.attributeNS(KoXmlNS::text, "sort-by-position", QString("true")) == "true")
- ? true : false;
- d->sortAlgorithm = element.attributeNS(KoXmlNS::text, "sort-algorithm", QString());
-
- for (KoXmlNode node = element.firstChild(); !node.isNull(); node = node.nextSibling())
- {
- KoXmlElement child = node.toElement();
-
- if (child.namespaceURI() == KoXmlNS::text && child.localName() == "sort-key") {
- QString key = child.attributeNS(KoXmlNS::text, "key", QString());
- Qt::SortOrder order = (child.attributeNS(KoXmlNS::text, "sort-ascending", "true") == "true")
- ? (Qt::AscendingOrder): (Qt::DescendingOrder);
- if(!key.isNull() && KoOdfBibliographyConfiguration::bibDataFields.contains(key)) {
- d->sortKeys << QPair<QString, Qt::SortOrder>(key,order);
- }
- }
- }
-}
-
-void KoOdfBibliographyConfiguration::saveOdf(KoXmlWriter *writer) const
-{
- writer->startElement("text:bibliography-configuration");
-
- if (!d->prefix.isNull()) {
- writer->addAttribute("text:prefix", d->prefix);
- }
-
- if (!d->suffix.isNull()) {
- writer->addAttribute("text:suffix", d->suffix);
- }
-
- if (!d->sortAlgorithm.isNull()) {
- writer->addAttribute("text:sort-algorithm", d->sortAlgorithm);
- }
-
- writer->addAttribute("text:numbered-entries", d->numberedEntries ? "true" : "false");
- writer->addAttribute("text:sort-by-position", d->sortByPosition ? "true" : "false");
-
- foreach (const SortKeyPair &key, d->sortKeys) {
- writer->startElement("text:sort-key");
- writer->addAttribute("text:key", key.first);
- writer->addAttribute("text:sort-ascending",key.second);
- writer->endElement();
- }
- writer->endElement();
-}
-
-QString KoOdfBibliographyConfiguration::prefix() const
-{
- return d->prefix;
-}
-
-QString KoOdfBibliographyConfiguration::suffix() const
-{
- return d->suffix;
-}
-
-QString KoOdfBibliographyConfiguration::sortAlgorithm() const
-{
- return d->sortAlgorithm;
-}
-
-bool KoOdfBibliographyConfiguration::sortByPosition() const
-{
- return d->sortByPosition;
-}
-
-QList<SortKeyPair> KoOdfBibliographyConfiguration::sortKeys() const
-{
- return d->sortKeys;
-}
-
-bool KoOdfBibliographyConfiguration::numberedEntries() const
-{
- return d->numberedEntries;
-}
-
-void KoOdfBibliographyConfiguration::setNumberedEntries(bool enable)
-{
- d->numberedEntries = enable;
-}
-
-void KoOdfBibliographyConfiguration::setPrefix(const QString &prefixValue)
-{
- d->prefix = prefixValue;
-}
-
-void KoOdfBibliographyConfiguration::setSuffix(const QString &suffixValue)
-{
- d->suffix = suffixValue;
-}
-
-void KoOdfBibliographyConfiguration::setSortAlgorithm(const QString &algorithm)
-{
- d->sortAlgorithm = algorithm;
-}
-
-void KoOdfBibliographyConfiguration::setSortByPosition(bool enable)
-{
- d->sortByPosition = enable;
-}
-
-void KoOdfBibliographyConfiguration::setSortKeys(const QList<SortKeyPair> &sortKeys)
-{
- d->sortKeys = sortKeys;
-}
diff --git a/libs/odf/KoOdfBibliographyConfiguration.h b/libs/odf/KoOdfBibliographyConfiguration.h
deleted file mode 100644
index d7dca92020..0000000000
--- a/libs/odf/KoOdfBibliographyConfiguration.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Smit Patel <smitpatel24@gmail.com>
- *
- * 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 KOODFBIBLIOGRAPHYCONFIGURATION_H
-#define KOODFBIBLIOGRAPHYCONFIGURATION_H
-
-#include <QString>
-#include <QMetaType>
-#include <QObject>
-
-#include "KoXmlReaderForward.h"
-#include "kritaodf_export.h"
-
-class KoXmlWriter;
-
-typedef QPair<QString, Qt::SortOrder> SortKeyPair;
-
-/**
- * load and save the bibliography-configuration element from the text: namespace.
- * • Prefix
- * • Suffix
- * • Numbered entries
- * • Sort by position
- * • Sort algorithm
- */
-class KRITAODF_EXPORT KoOdfBibliographyConfiguration : public QObject
-{
- Q_OBJECT
-public:
-
- KoOdfBibliographyConfiguration();
- ~KoOdfBibliographyConfiguration() override;
- KoOdfBibliographyConfiguration(const KoOdfBibliographyConfiguration &other);
- KoOdfBibliographyConfiguration &operator=(const KoOdfBibliographyConfiguration &other);
-
- static const QList<QString> bibTypes;
- static const QList<QString> bibDataFields;
-
- /**
- * load the bibliography-configuration element
- */
- void loadOdf(const KoXmlElement &element);
-
- /**
- * save the bibliography-configuration element
- */
- void saveOdf(KoXmlWriter * writer) const;
-
- /**
- * Sort by position
- * If text:sort-by-position attribute is true then bibliography entries or citations will be
- * sorted according to their position in document.
- */
- bool sortByPosition() const;
- void setSortByPosition(bool enable);
-
- /**
- * Numbered entries
- * If text:numbered-entries attribute is true then bibliography entries or citations will be numbered.
- */
- bool numberedEntries() const;
- void setNumberedEntries(bool enable);
-
- /**
- * Prefix
- * The text:prefix attribute specifies prefix of bibliography entry or citation(text:bibliography-mark)
- */
- QString prefix() const;
- void setPrefix(const QString &prefixValue);
-
- /**
- * Suffix
- * The text:suffix attribute specifies suffix of bibliography entry or citation(text:bibliography-mark)
- */
- QString suffix() const;
- void setSuffix(const QString &suffixValue);
-
- /**
- * Sort algorithm
- * The text:sort-algorithm attribute specifies sorting algorithm for bibliography entry
- */
- QString sortAlgorithm() const;
- void setSortAlgorithm(const QString &algorithm);
-
- /**
- * Sort Keys
- * The text:sort-key attribute specifies sort key for bibliography entry
- */
- QList<SortKeyPair> sortKeys() const;
- void setSortKeys(const QList<SortKeyPair> &sortKeys);
-
-private:
-
- class Private;
- Private * const d;
-
-};
-
-Q_DECLARE_METATYPE(KoOdfBibliographyConfiguration*)
-
-#endif // KOODFBIBLIOGRAPHYCONFIGURATION_H
diff --git a/libs/odf/KoOdfGraphicStyles.cpp b/libs/odf/KoOdfGraphicStyles.cpp
deleted file mode 100644
index 1b6ebb1179..0000000000
--- a/libs/odf/KoOdfGraphicStyles.cpp
+++ /dev/null
@@ -1,783 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2004-2006 David Faure <faure@kde.org>
- Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- Copyright (C) 2007-2008,2010-2011 Thorsten Zachmann <zachmann@kde.org>
- Copyright (C) 2011 Lukáš Tvrdý <lukas.tvrdy@ixonos.com>
-
- 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 "KoOdfGraphicStyles.h"
-
-#include <QBrush>
-#include <QBuffer>
-#include <QPen>
-
-#include <OdfDebug.h>
-
-#include <KoGenStyles.h>
-#include <KoStyleStack.h>
-#include <KoUnit.h>
-#include <KoXmlNS.h>
-#include <KoXmlWriter.h>
-#include <KoXmlReader.h>
-
-#include "KoOdfStylesReader.h"
-
-void KoOdfGraphicStyles::saveOdfFillStyle(KoGenStyle &styleFill, KoGenStyles& mainStyles, const QBrush & brush)
-{
- KoGenStyle::Type type = styleFill.type();
- KoGenStyle::PropertyType propertyType = (type == KoGenStyle::GraphicStyle || type == KoGenStyle::GraphicAutoStyle ||
- type == KoGenStyle::DrawingPageStyle || type == KoGenStyle::DrawingPageAutoStyle )
- ? KoGenStyle::DefaultType : KoGenStyle::GraphicType;
- switch (brush.style()) {
- case Qt::Dense1Pattern:
- styleFill.addProperty("draw:opacity", "6%", propertyType);
- styleFill.addProperty("draw:fill", "solid", propertyType);
- styleFill.addProperty("draw:fill-color", brush.color().name(), propertyType);
- break;
- case Qt::Dense2Pattern:
- styleFill.addProperty("draw:opacity", "12%", propertyType);
- styleFill.addProperty("draw:fill", "solid", propertyType);
- styleFill.addProperty("draw:fill-color", brush.color().name(), propertyType);
- break;
- case Qt::Dense3Pattern:
- styleFill.addProperty("draw:opacity", "37%", propertyType);
- styleFill.addProperty("draw:fill", "solid", propertyType);
- styleFill.addProperty("draw:fill-color", brush.color().name(), propertyType);
- break;
- case Qt::Dense4Pattern:
- styleFill.addProperty("draw:opacity", "50%", propertyType);
- styleFill.addProperty("draw:fill", "solid", propertyType);
- styleFill.addProperty("draw:fill-color", brush.color().name(), propertyType);
- break;
- case Qt::Dense5Pattern:
- styleFill.addProperty("draw:opacity", "63%", propertyType);
- styleFill.addProperty("draw:fill", "solid", propertyType);
- styleFill.addProperty("draw:fill-color", brush.color().name(), propertyType);
- break;
- case Qt::Dense6Pattern:
- styleFill.addProperty("draw:opacity", "88%", propertyType);
- styleFill.addProperty("draw:fill", "solid", propertyType);
- styleFill.addProperty("draw:fill-color", brush.color().name(), propertyType);
- break;
- case Qt::Dense7Pattern:
- styleFill.addProperty("draw:opacity", "94%", propertyType);
- styleFill.addProperty("draw:fill", "solid", propertyType);
- styleFill.addProperty("draw:fill-color", brush.color().name(), propertyType);
- break;
- case Qt::LinearGradientPattern:
- case Qt::RadialGradientPattern:
- case Qt::ConicalGradientPattern:
- styleFill.addProperty("draw:fill", "gradient", propertyType);
- styleFill.addProperty("draw:fill-gradient-name", saveOdfGradientStyle(mainStyles, brush), propertyType);
- break;
- case Qt::HorPattern:
- case Qt::VerPattern:
- case Qt::CrossPattern:
- case Qt::BDiagPattern:
- case Qt::FDiagPattern:
- case Qt::DiagCrossPattern:
- styleFill.addProperty("draw:fill", "hatch", propertyType);
- styleFill.addProperty("draw:fill-hatch-name", saveOdfHatchStyle(mainStyles, brush), propertyType);
- break;
- case Qt::SolidPattern:
- styleFill.addProperty("draw:fill", "solid", propertyType);
- styleFill.addProperty("draw:fill-color", brush.color().name(), propertyType);
- if (! brush.isOpaque())
- styleFill.addProperty("draw:opacity", QString("%1%").arg(brush.color().alphaF() * 100.0), propertyType);
- break;
- case Qt::NoBrush:
- default:
- styleFill.addProperty("draw:fill", "none", propertyType);
- break;
- }
-}
-
-void KoOdfGraphicStyles::saveOdfStrokeStyle(KoGenStyle &styleStroke, KoGenStyles &mainStyles, const QPen &pen)
-{
- // TODO implement all possibilities
- switch (pen.style()) {
- case Qt::NoPen:
- styleStroke.addProperty("draw:stroke", "none", KoGenStyle::GraphicType);
- return;
- case Qt::SolidLine:
- styleStroke.addProperty("draw:stroke", "solid", KoGenStyle::GraphicType);
- break;
- default: { // must be a dashed line
- styleStroke.addProperty("draw:stroke", "dash", KoGenStyle::GraphicType);
- // save stroke dash (14.14.7) which is severely limited, but still
- KoGenStyle dashStyle(KoGenStyle::StrokeDashStyle);
- dashStyle.addAttribute("draw:style", "rect");
- QVector<qreal> dashes = pen.dashPattern();
- dashStyle.addAttribute("draw:dots1", static_cast<int>(1));
- dashStyle.addAttribute("draw:dots1-length", dashes[0]*pen.widthF());
- dashStyle.addAttribute("draw:distance", dashes[1]*pen.widthF());
- if (dashes.size() > 2) {
- dashStyle.addAttribute("draw:dots2", static_cast<int>(1));
- dashStyle.addAttribute("draw:dots2-length", dashes[2]*pen.widthF());
- }
- QString dashStyleName = mainStyles.insert(dashStyle, "dash");
- styleStroke.addProperty("draw:stroke-dash", dashStyleName, KoGenStyle::GraphicType);
- break;
- }
- }
-
- if (pen.brush().gradient()) {
- styleStroke.addProperty("calligra:stroke-gradient", saveOdfGradientStyle(mainStyles, pen.brush()), KoGenStyle::GraphicType);
- }
- else {
- styleStroke.addProperty("svg:stroke-color", pen.color().name(), KoGenStyle::GraphicType);
- styleStroke.addProperty("svg:stroke-opacity", QString("%1").arg(pen.color().alphaF()), KoGenStyle::GraphicType);
- }
- styleStroke.addPropertyPt("svg:stroke-width", pen.widthF(), KoGenStyle::GraphicType);
-
- switch (pen.joinStyle()) {
- case Qt::MiterJoin:
- styleStroke.addProperty("draw:stroke-linejoin", "miter", KoGenStyle::GraphicType);
- break;
- case Qt::BevelJoin:
- styleStroke.addProperty("draw:stroke-linejoin", "bevel", KoGenStyle::GraphicType);
- break;
- case Qt::RoundJoin:
- styleStroke.addProperty("draw:stroke-linejoin", "round", KoGenStyle::GraphicType);
- break;
- default:
- styleStroke.addProperty("draw:stroke-linejoin", "miter", KoGenStyle::GraphicType);
- styleStroke.addProperty("calligra:stroke-miterlimit", QString("%1").arg(pen.miterLimit()), KoGenStyle::GraphicType);
- break;
- }
- switch (pen.capStyle()) {
- case Qt::RoundCap:
- styleStroke.addProperty("svg:stroke-linecap", "round", KoGenStyle::GraphicType);
- break;
- case Qt::SquareCap:
- styleStroke.addProperty("svg:stroke-linecap", "square", KoGenStyle::GraphicType);
- break;
- default:
- styleStroke.addProperty("svg:stroke-linecap", "butt", KoGenStyle::GraphicType);
- break;
- }
-}
-
-QString KoOdfGraphicStyles::saveOdfHatchStyle(KoGenStyles& mainStyles, const QBrush &brush)
-{
- KoGenStyle hatchStyle(KoGenStyle::HatchStyle /*no family name*/);
- hatchStyle.addAttribute("draw:color", brush.color().name());
- //hatchStyle.addAttribute( "draw:distance", m_distance ); not implemented into kpresenter
- switch (brush.style()) {
- case Qt::HorPattern:
- hatchStyle.addAttribute("draw:style", "single");
- hatchStyle.addAttribute("draw:rotation", 0);
- break;
- case Qt::BDiagPattern:
- hatchStyle.addAttribute("draw:style", "single");
- hatchStyle.addAttribute("draw:rotation", 450);
- break;
- case Qt::VerPattern:
- hatchStyle.addAttribute("draw:style", "single");
- hatchStyle.addAttribute("draw:rotation", 900);
- break;
- case Qt::FDiagPattern:
- hatchStyle.addAttribute("draw:style", "single");
- hatchStyle.addAttribute("draw:rotation", 1350);
- break;
- case Qt::CrossPattern:
- hatchStyle.addAttribute("draw:style", "double");
- hatchStyle.addAttribute("draw:rotation", 0);
- break;
- case Qt::DiagCrossPattern:
- hatchStyle.addAttribute("draw:style", "double");
- hatchStyle.addAttribute("draw:rotation", 450);
- break;
- default:
- break;
- }
-
- return mainStyles.insert(hatchStyle, "hatch");
-}
-
-QString KoOdfGraphicStyles::saveOdfGradientStyle(KoGenStyles &mainStyles, const QBrush &brush)
-{
- KoGenStyle gradientStyle;
- if (brush.style() == Qt::RadialGradientPattern) {
- const QRadialGradient *gradient = static_cast<const QRadialGradient*>(brush.gradient());
- gradientStyle = KoGenStyle(KoGenStyle::RadialGradientStyle /*no family name*/);
- gradientStyle.addAttributePercent("svg:cx", gradient->center().x() * 100);
- gradientStyle.addAttributePercent("svg:cy", gradient->center().y() * 100);
- gradientStyle.addAttributePercent("svg:r", gradient->radius() * 100);
- gradientStyle.addAttributePercent("svg:fx", gradient->focalPoint().x() * 100);
- gradientStyle.addAttributePercent("svg:fy", gradient->focalPoint().y() * 100);
- } else if (brush.style() == Qt::LinearGradientPattern) {
- const QLinearGradient *gradient = static_cast<const QLinearGradient*>(brush.gradient());
- gradientStyle = KoGenStyle(KoGenStyle::LinearGradientStyle /*no family name*/);
- gradientStyle.addAttributePercent("svg:x1", gradient->start().x() * 100);
- gradientStyle.addAttributePercent("svg:y1", gradient->start().y() * 100);
- gradientStyle.addAttributePercent("svg:x2", gradient->finalStop().x() * 100);
- gradientStyle.addAttributePercent("svg:y2", gradient->finalStop().y() * 100);
- } else if (brush.style() == Qt::ConicalGradientPattern) {
- const QConicalGradient * gradient = static_cast<const QConicalGradient*>(brush.gradient());
- gradientStyle = KoGenStyle(KoGenStyle::ConicalGradientStyle /*no family name*/);
- gradientStyle.addAttributePercent("svg:cx", gradient->center().x() * 100);
- gradientStyle.addAttributePercent("svg:cy", gradient->center().y() * 100);
- gradientStyle.addAttribute("draw:angle", QString("%1").arg(gradient->angle()));
- }
- const QGradient * gradient = brush.gradient();
- if (gradient->spread() == QGradient::RepeatSpread)
- gradientStyle.addAttribute("svg:spreadMethod", "repeat");
- else if (gradient->spread() == QGradient::ReflectSpread)
- gradientStyle.addAttribute("svg:spreadMethod", "reflect");
- else
- gradientStyle.addAttribute("svg:spreadMethod", "pad");
-
- if (! brush.transform().isIdentity()) {
- gradientStyle.addAttribute("svg:gradientTransform", saveTransformation(brush.transform()));
- }
-
- QBuffer buffer;
- buffer.open(QIODevice::WriteOnly);
- KoXmlWriter elementWriter(&buffer); // TODO pass indentation level
-
- // save stops
- QGradientStops stops = gradient->stops();
- Q_FOREACH (const QGradientStop & stop, stops) {
- elementWriter.startElement("svg:stop");
- elementWriter.addAttribute("svg:offset", QString("%1").arg(stop.first));
- elementWriter.addAttribute("svg:stop-color", stop.second.name());
- if (stop.second.alphaF() < 1.0)
- elementWriter.addAttribute("svg:stop-opacity", QString("%1").arg(stop.second.alphaF()));
- elementWriter.endElement();
- }
-
- QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
- gradientStyle.addChildElement("svg:stop", elementContents);
-
- return mainStyles.insert(gradientStyle, "gradient");
-}
-
-QBrush KoOdfGraphicStyles::loadOdfGradientStyle(const KoStyleStack &styleStack, const KoOdfStylesReader & stylesReader, const QSizeF &size)
-{
- QString styleName = styleStack.property(KoXmlNS::draw, "fill-gradient-name");
- return loadOdfGradientStyleByName(stylesReader, styleName, size);
-}
-
-qreal percent(const KoXmlElement &element, const QString &ns, const QString &type, const QString &defaultValue, qreal absolute)
-{
- qreal tmp = 0.0;
- QString value = element.attributeNS(ns, type, defaultValue);
- if (value.indexOf('%') > -1) { // percent value
- tmp = value.remove('%').toDouble() / 100.0;
- }
- else { // fixed value
- tmp = KoUnit::parseValue(value) / absolute;
- // The following is done so that we get the same data as when we save/load.
- // This is needed that we get the same values due to rounding differences
- // of absolute and relative values.
- QString value = QString("%1").arg(tmp * 100.0);
- tmp = value.toDouble() / 100;
- }
-
- return tmp;
-}
-
-QBrush KoOdfGraphicStyles::loadOdfGradientStyleByName(const KoOdfStylesReader &stylesReader, const QString &styleName, const QSizeF &size)
-{
- KoXmlElement* e = stylesReader.drawStyles("gradient")[styleName];
- if (! e)
- return QBrush();
-
- QGradient * gradient = 0;
- QTransform transform;
-
- if (e->namespaceURI() == KoXmlNS::draw && e->localName() == "gradient") {
- // FIXME seems like oo renders the gradient start stop color at the center of the
- // radial gradient, and the start color at the radius of the radial gradient
- // whereas it is not mentioned in the spec how it should be rendered
- // note that svg defines that exactly as the opposite as oo does
- // so what should we do?
- QString type = e->attributeNS(KoXmlNS::draw, "style", QString());
- if (type == "radial") {
- // Zagge: at the moment the only objectBoundingBox is supported:
- // 18.539 svg:gradientUnits
- // See §13.2.2 and §13.2.3 of [SVG].
- // The default value for this attribute is objectBoundingBox.
- // The only value of the svg:gradientUnits attribute is objectBoundingBox.
-
- qreal cx = KoUnit::parseValue(e->attributeNS(KoXmlNS::draw, "cx", QString()).remove('%'));
- qreal cy = KoUnit::parseValue(e->attributeNS(KoXmlNS::draw, "cy", QString()).remove('%'));
- gradient = new QRadialGradient(QPointF(cx * 0.01, cy * 0.01), sqrt(0.5));
- gradient->setCoordinateMode(QGradient::ObjectBoundingMode);
- } else if (type == "linear" || type == "axial") {
- QLinearGradient * lg = new QLinearGradient();
- lg->setCoordinateMode(QGradient::ObjectBoundingMode);
- // Dividing by 10 here because OOo saves as degree * 10
- qreal angle = 90 + e->attributeNS(KoXmlNS::draw, "angle", "0").toDouble() / 10;
- qreal radius = sqrt(0.5);
-
- qreal sx = cos(angle * M_PI / 180) * radius;
- qreal sy = sin(angle * M_PI / 180) * radius;
- lg->setStart(QPointF(0.5 + sx, 0.5 - sy));
- lg->setFinalStop(QPointF(0.5 - sx, 0.5 + sy));
- gradient = lg;
- } else
- return QBrush();
-
- qreal border = 0.01 * e->attributeNS(KoXmlNS::draw, "border", "0").remove('%').toDouble();
- QGradientStops stops;
- if (type != "axial") {
- // In case of radial gradients the colors are reversed, because OOo saves them as the opposite of the SVG direction
- // see bug 137639
- QGradientStop start;
- start.first = (type != "radial") ? border : 1.0 - border;
- start.second = QColor(e->attributeNS(KoXmlNS::draw, "start-color", QString()));
- start.second.setAlphaF(0.01 * e->attributeNS(KoXmlNS::draw, "start-intensity", "100").remove('%').toDouble());
-
- QGradientStop end;
- end.first = (type != "radial") ? 1.0 : 0.0;
- end.second = QColor(e->attributeNS(KoXmlNS::draw, "end-color", QString()));
- end.second.setAlphaF(0.01 * e->attributeNS(KoXmlNS::draw, "end-intensity", "100").remove('%').toDouble());
-
- stops << start << end;
- } else {
- QGradientStop start;
- start.first = 0.5 * border;
- start.second = QColor(e->attributeNS(KoXmlNS::draw, "end-color", QString()));
- start.second.setAlphaF(0.01 * e->attributeNS(KoXmlNS::draw, "end-intensity", "100").remove('%').toDouble());
-
- QGradientStop middle;
- middle.first = 0.5;
- middle.second = QColor(e->attributeNS(KoXmlNS::draw, "start-color", QString()));
- middle.second.setAlphaF(0.01 * e->attributeNS(KoXmlNS::draw, "start-intensity", "100").remove('%').toDouble());
-
- QGradientStop end;
- end.first = 1.0 - 0.5 * border;
- end.second = QColor(e->attributeNS(KoXmlNS::draw, "end-color", QString()));
- end.second.setAlphaF(0.01 * e->attributeNS(KoXmlNS::draw, "end-intensity", "100").remove('%').toDouble());
-
- stops << start << middle << end;
- }
-
- gradient->setStops(stops);
- } else if (e->namespaceURI() == KoXmlNS::svg) {
- if (e->localName() == "linearGradient") {
- QPointF start, stop;
- start.setX(percent(*e, KoXmlNS::svg, "x1", "0%", size.width()));
- start.setY(percent(*e, KoXmlNS::svg, "y1", "0%", size.height()));
- stop.setX(percent(*e, KoXmlNS::svg, "x2", "100%", size.width()));
- stop.setY(percent(*e, KoXmlNS::svg, "y2", "100%", size.height()));
- gradient = new QLinearGradient(start, stop);
- } else if (e->localName() == "radialGradient") {
- QPointF center, focalPoint;
- center.setX(percent(*e, KoXmlNS::svg, "cx", "50%", size.width()));
- center.setY(percent(*e, KoXmlNS::svg, "cy", "50%", size.height()));
- qreal r = percent(*e, KoXmlNS::svg, "r", "50%", sqrt(size.width() * size.width() + size.height() * size.height()));
- focalPoint.setX(percent(*e, KoXmlNS::svg, "fx", QString(), size.width()));
- focalPoint.setY(percent(*e, KoXmlNS::svg, "fy", QString(), size.height()));
- gradient = new QRadialGradient(center, r, focalPoint );
- }
- if (! gradient)
- return QBrush();
-
- gradient->setCoordinateMode(QGradient::ObjectBoundingMode);
-
- QString strSpread(e->attributeNS(KoXmlNS::svg, "spreadMethod", "pad"));
- if (strSpread == "repeat")
- gradient->setSpread(QGradient::RepeatSpread);
- else if (strSpread == "reflect")
- gradient->setSpread(QGradient::ReflectSpread);
- else
- gradient->setSpread(QGradient::PadSpread);
-
- if (e->hasAttributeNS(KoXmlNS::svg, "gradientTransform"))
- transform = loadTransformation(e->attributeNS(KoXmlNS::svg, "gradientTransform", QString()));
-
- QGradientStops stops;
-
- // load stops
- KoXmlElement colorstop;
- forEachElement(colorstop, (*e)) {
- if (colorstop.namespaceURI() == KoXmlNS::svg && colorstop.localName() == "stop") {
- QGradientStop stop;
- stop.second = QColor(colorstop.attributeNS(KoXmlNS::svg, "stop-color", QString()));
- stop.second.setAlphaF(colorstop.attributeNS(KoXmlNS::svg, "stop-opacity", "1.0").toDouble());
- stop.first = colorstop.attributeNS(KoXmlNS::svg, "offset", "0.0").toDouble();
- stops.append(stop);
- }
- }
- gradient->setStops(stops);
- } else if (e->namespaceURI() == KoXmlNS::calligra) {
- if (e->localName() == "conicalGradient") {
- QPointF center;
- center.setX(percent(*e, KoXmlNS::svg, "cx", "50%", size.width()));
- center.setY(percent(*e, KoXmlNS::svg, "cy", "50%", size.height()));
- qreal angle = KoUnit::parseValue(e->attributeNS(KoXmlNS::draw, "angle", QString()));
- gradient = new QConicalGradient(center, angle);
- gradient->setCoordinateMode(QGradient::ObjectBoundingMode);
-
- QString strSpread(e->attributeNS(KoXmlNS::svg, "spreadMethod", "pad"));
- if (strSpread == "repeat")
- gradient->setSpread(QGradient::RepeatSpread);
- else if (strSpread == "reflect")
- gradient->setSpread(QGradient::ReflectSpread);
- else
- gradient->setSpread(QGradient::PadSpread);
-
- if (e->hasAttributeNS(KoXmlNS::svg, "gradientTransform"))
- transform = loadTransformation(e->attributeNS(KoXmlNS::svg, "gradientTransform", QString()));
-
- QGradientStops stops;
-
- // load stops
- KoXmlElement colorstop;
- forEachElement(colorstop, (*e)) {
- if (colorstop.namespaceURI() == KoXmlNS::svg && colorstop.localName() == "stop") {
- QGradientStop stop;
- stop.second = QColor(colorstop.attributeNS(KoXmlNS::svg, "stop-color", QString()));
- stop.second.setAlphaF(colorstop.attributeNS(KoXmlNS::svg, "stop-opacity", "1.0").toDouble());
- stop.first = colorstop.attributeNS(KoXmlNS::svg, "offset", "0.0").toDouble();
- stops.append(stop);
- }
- }
- gradient->setStops(stops);
- }
- }
-
- if (! gradient)
- return QBrush();
-
- QBrush resultBrush(*gradient);
- resultBrush.setTransform(transform);
-
- delete gradient;
- return resultBrush;
-}
-
-QBrush KoOdfGraphicStyles::loadOdfFillStyle(const KoStyleStack &styleStack, const QString & fill, const KoOdfStylesReader & stylesReader)
-{
- QBrush tmpBrush; // default brush for "none" is a Qt::NoBrush
-
- if (fill == "solid") {
- tmpBrush.setStyle(Qt::SolidPattern);
- if (styleStack.hasProperty(KoXmlNS::draw, "fill-color"))
- tmpBrush.setColor(styleStack.property(KoXmlNS::draw, "fill-color"));
- if (styleStack.hasProperty(KoXmlNS::draw, "opacity")) {
- QString opacity = styleStack.property(KoXmlNS::draw, "opacity");
- if (! opacity.isEmpty() && opacity.right(1) == "%") {
- float percent = opacity.left(opacity.length() - 1).toFloat();
- QColor color = tmpBrush.color();
- color.setAlphaF(percent / 100.0);
- tmpBrush.setColor(color);
- }
- }
- //TODO
- if (styleStack.hasProperty(KoXmlNS::draw, "transparency")) {
- QString transparency = styleStack.property(KoXmlNS::draw, "transparency");
- if (transparency == "94%") {
- tmpBrush.setStyle(Qt::Dense1Pattern);
- } else if (transparency == "88%") {
- tmpBrush.setStyle(Qt::Dense2Pattern);
- } else if (transparency == "63%") {
- tmpBrush.setStyle(Qt::Dense3Pattern);
-
- } else if (transparency == "50%") {
- tmpBrush.setStyle(Qt::Dense4Pattern);
-
- } else if (transparency == "37%") {
- tmpBrush.setStyle(Qt::Dense5Pattern);
-
- } else if (transparency == "12%") {
- tmpBrush.setStyle(Qt::Dense6Pattern);
-
- } else if (transparency == "6%") {
- tmpBrush.setStyle(Qt::Dense7Pattern);
-
- } else
- debugOdf << " transparency is not defined into kpresenter :" << transparency;
- }
- } else if (fill == "hatch") {
- QString style = styleStack.property(KoXmlNS::draw, "fill-hatch-name");
- debugOdf << " hatch style is :" << style;
-
- //type not defined by default
- //try to use style.
- KoXmlElement* draw = stylesReader.drawStyles("hatch")[style];
- if (draw) {
- debugOdf << "We have a style";
- int angle = 0;
- if (draw->hasAttributeNS(KoXmlNS::draw, "rotation")) {
- angle = (draw->attributeNS(KoXmlNS::draw, "rotation", QString()).toInt()) / 10;
- debugOdf << "angle :" << angle;
- }
- if (draw->hasAttributeNS(KoXmlNS::draw, "color")) {
- //debugOdf<<" draw:color :"<<draw->attributeNS( KoXmlNS::draw,"color", QString() );
- tmpBrush.setColor(draw->attributeNS(KoXmlNS::draw, "color", QString()));
- }
- if (draw->hasAttributeNS(KoXmlNS::draw, "distance")) {
- //todo implement it into kpresenter
- }
- if (draw->hasAttributeNS(KoXmlNS::draw, "display-name")) {
- //todo implement it into kpresenter
- }
- if (draw->hasAttributeNS(KoXmlNS::draw, "style")) {
- //todo implement it into kpresenter
- QString styleHash = draw->attributeNS(KoXmlNS::draw, "style", QString());
- if (styleHash == "single") {
- switch (angle) {
- case 0:
- case 180:
- tmpBrush.setStyle(Qt::HorPattern);
- break;
- case 45:
- case 225:
- tmpBrush.setStyle(Qt::BDiagPattern);
- break;
- case 90:
- case 270:
- tmpBrush.setStyle(Qt::VerPattern);
- break;
- case 135:
- case 315:
- tmpBrush.setStyle(Qt::FDiagPattern);
- break;
- default:
- //todo fixme when we will have a kopaint
- debugOdf << " draw:rotation 'angle' :" << angle;
- break;
- }
- } else if (styleHash == "double") {
- switch (angle) {
- case 0:
- case 180:
- case 90:
- case 270:
- tmpBrush.setStyle(Qt::CrossPattern);
- break;
- case 45:
- case 135:
- case 225:
- case 315:
- tmpBrush.setStyle(Qt::DiagCrossPattern);
- break;
- default:
- //todo fixme when we will have a kopaint
- debugOdf << " draw:rotation 'angle' :" << angle;
- break;
- }
-
- } else if (styleHash == "triple") {
- debugOdf << " it is not implemented :(";
- }
- }
- }
- }
-
- return tmpBrush;
-}
-
-static qreal parseDashEntrySize(QString& attr, qreal penWidth, qreal defaultValue = 0.0){
- qreal result = defaultValue;
- if (attr.endsWith('%')) {
- bool ok;
- const int percent = attr.remove('%').toInt(&ok);
- if (ok && percent >= 0) {
- result = percent / 100.0;
- }
- } else {
- result = KoUnit::parseValue(attr) / penWidth;
- }
- return result;
-}
-
-QPen KoOdfGraphicStyles::loadOdfStrokeStyle(const KoStyleStack &styleStack, const QString & stroke, const KoOdfStylesReader & stylesReader)
-{
- QPen tmpPen(Qt::NoPen); // default pen for "none" is a Qt::NoPen
-
- if (stroke == "solid" || stroke == "dash") {
- // If solid or dash is set then we assume that the color is black and the penWidth
- // is zero till defined otherwise with the following attributes.
- tmpPen = QPen();
-
- if (styleStack.hasProperty(KoXmlNS::svg, "stroke-color"))
- tmpPen.setColor(styleStack.property(KoXmlNS::svg, "stroke-color"));
- if (styleStack.hasProperty(KoXmlNS::svg, "stroke-opacity")) {
- QColor color = tmpPen.color();
- QString opacity = styleStack.property(KoXmlNS::svg, "stroke-opacity");
- if (opacity.endsWith('%'))
- color.setAlphaF(0.01 * opacity.remove('%').toDouble());
- else
- color.setAlphaF(opacity.toDouble());
- tmpPen.setColor(color);
- }
- if (styleStack.hasProperty(KoXmlNS::svg, "stroke-width"))
- tmpPen.setWidthF(KoUnit::parseValue(styleStack.property(KoXmlNS::svg, "stroke-width")));
- if (styleStack.hasProperty(KoXmlNS::draw, "stroke-linejoin")) {
- QString join = styleStack.property(KoXmlNS::draw, "stroke-linejoin");
- if (join == "bevel")
- tmpPen.setJoinStyle(Qt::BevelJoin);
- else if (join == "round")
- tmpPen.setJoinStyle(Qt::RoundJoin);
- else {
- tmpPen.setJoinStyle(Qt::MiterJoin);
- if (styleStack.hasProperty(KoXmlNS::calligra, "stroke-miterlimit")) {
- QString miterLimit = styleStack.property(KoXmlNS::calligra, "stroke-miterlimit");
- tmpPen.setMiterLimit(miterLimit.toDouble());
- }
- }
- }
- if (styleStack.hasProperty(KoXmlNS::svg, "stroke-linecap")) {
- const QString cap = styleStack.property(KoXmlNS::svg, "stroke-linecap");
- if (cap == "round")
- tmpPen.setCapStyle(Qt::RoundCap);
- else if (cap == "square")
- tmpPen.setCapStyle(Qt::SquareCap);
- else
- tmpPen.setCapStyle(Qt::FlatCap);
- } else {
- // default as per svg specification
- tmpPen.setCapStyle(Qt::FlatCap);
- }
-
- if (stroke == "dash" && styleStack.hasProperty(KoXmlNS::draw, "stroke-dash")) {
- QString dashStyleName = styleStack.property(KoXmlNS::draw, "stroke-dash");
-
- // set width to 1 in case it is 0 as dividing by 0 gives infinity
- qreal width = tmpPen.widthF();
- if ( width == 0 ) {
- width = 1;
- }
-
- KoXmlElement * dashElement = stylesReader.drawStyles("stroke-dash")[ dashStyleName ];
- if (dashElement) {
- QVector<qreal> dashes;
- if (dashElement->hasAttributeNS(KoXmlNS::draw, "dots1")) {
- QString distance( dashElement->attributeNS(KoXmlNS::draw, "distance", QString()) );
- qreal space = parseDashEntrySize(distance, width, 0.0);
-
- QString dots1Length(dashElement->attributeNS(KoXmlNS::draw, "dots1-length", QString()));
- qreal dot1Length = parseDashEntrySize(dots1Length,width,1.0);
-
- bool ok;
- int dots1 = dashElement->attributeNS(KoXmlNS::draw, "dots1").toInt(&ok);
- if (!ok) {
- dots1 = 1;
- }
-
- for (int i = 0; i < dots1; i++) {
- dashes.append(dot1Length);
- dashes.append(space);
- }
-
- if (dashElement->hasAttributeNS(KoXmlNS::draw, "dots2")) {
- QString dots2Length(dashElement->attributeNS(KoXmlNS::draw, "dots2-length", QString()));
- qreal dot2Length = parseDashEntrySize(dots2Length,width,1.0);
-
- int dots2 = dashElement->attributeNS(KoXmlNS::draw, "dots2").toInt(&ok);
- if (!ok) {
- dots2 = 1;
- }
-
- for (int i = 0; i < dots2; i++) {
- dashes.append(dot2Length);
- dashes.append(space);
- }
- }
- tmpPen.setDashPattern(dashes);
- }
- }
- }
- }
-
- return tmpPen;
-}
-
-QTransform KoOdfGraphicStyles::loadTransformation(const QString &transformation)
-{
- QTransform transform;
-
- // Split string for handling 1 transform statement at a time
- QStringList subtransforms = transformation.split(')', QString::SkipEmptyParts);
- QStringList::ConstIterator it = subtransforms.constBegin();
- QStringList::ConstIterator end = subtransforms.constEnd();
- for (; it != end; ++it) {
- QStringList subtransform = (*it).split('(', QString::SkipEmptyParts);
-
- subtransform[0] = subtransform[0].trimmed().toLower();
- subtransform[1] = subtransform[1].simplified();
- QRegExp reg("[,( ]");
- QStringList params = subtransform[1].split(reg, QString::SkipEmptyParts);
-
- if (subtransform[0].startsWith(';') || subtransform[0].startsWith(','))
- subtransform[0] = subtransform[0].right(subtransform[0].length() - 1);
-
- if (subtransform[0] == "rotate") {
- // TODO find out what oo2 really does when rotating, it seems severely broken
- if (params.count() == 3) {
- qreal x = KoUnit::parseValue(params[1]);
- qreal y = KoUnit::parseValue(params[2]);
-
- transform.translate(x, y);
- // oo2 rotates by radians
- transform.rotate(params[0].toDouble()*180.0 / M_PI);
- transform.translate(-x, -y);
- } else {
- // oo2 rotates by radians
- transform.rotate(params[0].toDouble()*180.0 / M_PI);
- }
- } else if (subtransform[0] == "translate") {
- if (params.count() == 2) {
- qreal x = KoUnit::parseValue(params[0]);
- qreal y = KoUnit::parseValue(params[1]);
- transform.translate(x, y);
- } else // Spec : if only one param given, assume 2nd param to be 0
- transform.translate(KoUnit::parseValue(params[0]) , 0);
- } else if (subtransform[0] == "scale") {
- if (params.count() == 2)
- transform.scale(params[0].toDouble(), params[1].toDouble());
- else // Spec : if only one param given, assume uniform scaling
- transform.scale(params[0].toDouble(), params[0].toDouble());
- } else if (subtransform[0] == "skewx")
- transform.shear(tan(params[0].toDouble()), 0.0F);
- else if (subtransform[0] == "skewy")
- transform.shear(tan(params[0].toDouble()), 0.0F);
- else if (subtransform[0] == "matrix") {
- if (params.count() >= 6) {
- transform.setMatrix(params[0].toDouble(), params[1].toDouble(), 0,
- params[2].toDouble(), params[3].toDouble(), 0,
- KoUnit::parseValue(params[4]), KoUnit::parseValue(params[5]), 1);
- }
- }
- }
-
- return transform;
-}
-
-QString KoOdfGraphicStyles::saveTransformation(const QTransform &transformation, bool appendTranslateUnit)
-{
- QString transform;
- if (appendTranslateUnit)
- transform = QString("matrix(%1 %2 %3 %4 %5pt %6pt)")
- .arg(transformation.m11()).arg(transformation.m12())
- .arg(transformation.m21()).arg(transformation.m22())
- .arg(transformation.dx()) .arg(transformation.dy());
- else
- transform = QString("matrix(%1 %2 %3 %4 %5 %6)")
- .arg(transformation.m11()).arg(transformation.m12())
- .arg(transformation.m21()).arg(transformation.m22())
- .arg(transformation.dx()) .arg(transformation.dy());
-
- return transform;
-}
-
diff --git a/libs/odf/KoOdfGraphicStyles.h b/libs/odf/KoOdfGraphicStyles.h
deleted file mode 100644
index 5b6f8846cc..0000000000
--- a/libs/odf/KoOdfGraphicStyles.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2004-2006 David Faure <faure@kde.org>
- Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
-
- 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 KOODFGRAPHICSTYLES_H
-#define KOODFGRAPHICSTYLES_H
-
-#include "kritaodf_export.h"
-
-#include <QTransform>
-
-class QBrush;
-class QPen;
-class QString;
-class QSizeF;
-
-class KoGenStyle;
-class KoGenStyles;
-class KoStyleStack;
-
-class KoOdfStylesReader;
-
-namespace KoOdfGraphicStyles
-{
- KRITAODF_EXPORT void saveOdfFillStyle(KoGenStyle &styleFill, KoGenStyles& mainStyles, const QBrush &brush);
-
- KRITAODF_EXPORT void saveOdfStrokeStyle(KoGenStyle &styleStroke, KoGenStyles &mainStyles, const QPen &pen);
-
- KRITAODF_EXPORT QString saveOdfHatchStyle(KoGenStyles &mainStyles, const QBrush &brush);
-
- /// Saves gradient style of brush into mainStyles and returns the styles name
- KRITAODF_EXPORT QString saveOdfGradientStyle(KoGenStyles &mainStyles, const QBrush &brush);
-
- /// Loads gradient style from style stack and stylesReader adapted to the given size and returns a brush
- KRITAODF_EXPORT QBrush loadOdfGradientStyle(const KoStyleStack &styleStack, const KoOdfStylesReader &stylesReader, const QSizeF &size);
-
- /// Loads gradient style with the given name from style stack and stylesReader adapted to the given size and returns a brush
- KRITAODF_EXPORT QBrush loadOdfGradientStyleByName(const KoOdfStylesReader &stylesReader, const QString &styleName, const QSizeF &size);
-
- KRITAODF_EXPORT QBrush loadOdfFillStyle(const KoStyleStack &styleStack, const QString &fill, const KoOdfStylesReader &stylesReader);
-
- KRITAODF_EXPORT QPen loadOdfStrokeStyle(const KoStyleStack &styleStack, const QString &stroke, const KoOdfStylesReader &stylesReader);
-
- /// Helper function to parse a transformation attribute
- KRITAODF_EXPORT QTransform loadTransformation(const QString &transformation);
-
- /// Helper function to create a transformation attribute
- KRITAODF_EXPORT QString saveTransformation(const QTransform &transformation, bool appendTranslateUnit = true);
-}
-
-#endif /* KOODFGRAPHICSTYLES_H */
diff --git a/libs/odf/KoOdfLineNumberingConfiguration.cpp b/libs/odf/KoOdfLineNumberingConfiguration.cpp
deleted file mode 100644
index 973c611541..0000000000
--- a/libs/odf/KoOdfLineNumberingConfiguration.cpp
+++ /dev/null
@@ -1,281 +0,0 @@
-/* This file is part of the KDE project
-
- Copyright (C) 2010 KO GmbH <boud@valdyas.org>
-
- 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 "KoOdfLineNumberingConfiguration.h"
-
-#include <OdfDebug.h>
-#include "KoXmlNS.h"
-#include "KoUnit.h"
-#include "KoXmlWriter.h"
-#include "KoXmlReader.h"
-#include "KoOdfNumberDefinition.h"
-
-class Q_DECL_HIDDEN KoOdfLineNumberingConfiguration::Private
-{
-public:
- bool lineNumberingEnabled;
- KoOdfNumberDefinition numberFormat;
- QString textStyle;
- int increment;
- Position position;
- int offset;
- bool countEmptyLines;
- bool countLinesInTextBoxes;
- bool restartNumberingOnEveryPage;
- QString separator;
- int separatorIncrement;
-};
-
-KoOdfLineNumberingConfiguration::KoOdfLineNumberingConfiguration()
- : d(new Private())
-{
- d->lineNumberingEnabled = false;
- d->increment = 1;
- d->position = Left;
- d->offset = 10;
- d->countEmptyLines = false;
- d->countLinesInTextBoxes = false;
- d->separatorIncrement = 5;
-}
-
-KoOdfLineNumberingConfiguration::~KoOdfLineNumberingConfiguration()
-{
- delete d;
-}
-
-KoOdfLineNumberingConfiguration::KoOdfLineNumberingConfiguration(const KoOdfLineNumberingConfiguration &other)
- : QObject(), d(new Private())
-{
- d->lineNumberingEnabled = other.d->lineNumberingEnabled;
- d->numberFormat = other.d->numberFormat;
- d->textStyle = other.d->textStyle;
- d->increment = other.d->increment;
- d->position = other.d->position;
- d->offset = other.d->offset;
- d->countEmptyLines = other.d->countEmptyLines;
- d->countLinesInTextBoxes = other.d->countLinesInTextBoxes;
- d->restartNumberingOnEveryPage = other.d->restartNumberingOnEveryPage;
- d->separator = other.d->separator;
- d->separatorIncrement = other.d->separatorIncrement;
-}
-
-KoOdfLineNumberingConfiguration &KoOdfLineNumberingConfiguration::operator=(const KoOdfLineNumberingConfiguration &other)
-{
- d->lineNumberingEnabled = other.d->lineNumberingEnabled;
- d->numberFormat = other.d->numberFormat;
- d->textStyle = other.d->textStyle;
- d->increment = other.d->increment;
- d->position = other.d->position;
- d->offset = other.d->offset;
- d->countEmptyLines = other.d->countEmptyLines;
- d->countLinesInTextBoxes = other.d->countLinesInTextBoxes;
- d->restartNumberingOnEveryPage = other.d->restartNumberingOnEveryPage;
- d->separator = other.d->separator;
- d->separatorIncrement = other.d->separatorIncrement;
-
- return *this;
-}
-
-
-void KoOdfLineNumberingConfiguration::loadOdf(const KoXmlElement &element)
-{
- d->lineNumberingEnabled = element.attributeNS(KoXmlNS::text, "number-lines", "true") == "true";
- d->numberFormat.loadOdf(element);
- d->textStyle = element.attributeNS(KoXmlNS::text, "style-name", QString());
- d->increment = KoUnit::parseValue(element.attributeNS(KoXmlNS::text, "increment", "1"));
-
- QString position = element.attributeNS(KoXmlNS::text, "position", "left");
- if (position == "left") {
- d->position = Left;
- }
- else if (position == "right") {
- d->position = Right;
- }
- else if (position == "inner") {
- d->position = Inner;
- }
- else if (position == "outer") {
- d->position = Outer;
- }
-
- d->offset = KoUnit::parseValue(element.attributeNS(KoXmlNS::text, "offset", "10"));
- d->countEmptyLines = element.attributeNS(KoXmlNS::text, "count-empty-lines", "false") == "true";
- d->countLinesInTextBoxes = element.attributeNS(KoXmlNS::text, "count-in-text-boxes", "false") == "true";
- d->restartNumberingOnEveryPage = element.attributeNS(KoXmlNS::text, "restart-on-page", "false") == "true";
-
- if(element.hasChildNodes()) {
- KoXmlNode node = element.firstChild();
- while(!node.isNull()) {
- if(node.isElement()) {
- KoXmlElement nodeElement = node.toElement();
- if(nodeElement.localName() == "linenumber-separator") {
- d->separator = nodeElement.text();
- d->separatorIncrement = KoUnit::parseValue(element.attributeNS(KoXmlNS::text, "increment", "10"));
- break;
- }
- }
- node = node.nextSibling();
- }
- }
-
-
-}
-
-void KoOdfLineNumberingConfiguration::saveOdf(KoXmlWriter *writer) const
-{
- writer->addAttribute("text:number-lines", "true");
- d->numberFormat.saveOdf(writer);
- if (!d->textStyle.isEmpty()) {
- writer->addAttribute("text:style-name", d->textStyle);
- }
- writer->addAttribute("text:increment", d->increment);
- switch(d->position) {
- case Left:
- break; // this is default, don't save
- case Right:
- writer->addAttribute("text:position", "right");
- break;
- case Inner:
- writer->addAttribute("text:position", "inner");
- break;
- case Outer:
- writer->addAttribute("text:position", "outer");
- break;
- }
- if (d->offset != 10) { writer->addAttribute("text:offset", d->offset); }
- if (d->countEmptyLines) { writer->addAttribute("text:count-empty-lines", d->countEmptyLines); }
- if (d->countLinesInTextBoxes) { writer->addAttribute("text:count-in-text-boxes", d->countLinesInTextBoxes); }
- if (d->restartNumberingOnEveryPage) { writer->addAttribute("text:restart-on-page", d->restartNumberingOnEveryPage); }
- if (!d->separator.isNull()) {
- writer->startElement("txt:linenumber-separator");
- if (d->separatorIncrement != 10) { writer->addAttribute("text:increment", d->separatorIncrement); }
- writer->addTextNode(d->separator);
- writer->endElement();
- }
-}
-
-bool KoOdfLineNumberingConfiguration::enabled() const
-{
- return d->lineNumberingEnabled;
-}
-
-void KoOdfLineNumberingConfiguration::setEnabled(bool enabled)
-{
- d->lineNumberingEnabled = enabled;
-}
-
-KoOdfNumberDefinition KoOdfLineNumberingConfiguration::numberFormat() const
-{
- return d->numberFormat;
-}
-
-void KoOdfLineNumberingConfiguration::setNumberFormat(const KoOdfNumberDefinition &numberFormat)
-{
- d->numberFormat = numberFormat;
-}
-
-QString KoOdfLineNumberingConfiguration::textStyle() const
-{
- return d->textStyle;
-}
-
-void KoOdfLineNumberingConfiguration::setTextStyle(const QString &textStyle)
-{
- d->textStyle = textStyle;
-}
-
-int KoOdfLineNumberingConfiguration::increment() const
-{
- return d->increment;
-}
-
-void KoOdfLineNumberingConfiguration::setIncrement(int increment)
-{
- d->increment = increment;
-}
-
-KoOdfLineNumberingConfiguration::Position KoOdfLineNumberingConfiguration::position() const
-{
- return d->position;
-}
-
-void KoOdfLineNumberingConfiguration::setPosition(KoOdfLineNumberingConfiguration::Position position)
-{
- d->position = position;
-}
-
-int KoOdfLineNumberingConfiguration::offset() const
-{
- return d->offset;
-}
-
-void KoOdfLineNumberingConfiguration::setOffset(int offset)
-{
- d->offset = offset;
-}
-
-bool KoOdfLineNumberingConfiguration::countEmptyLines() const
-{
- return d->countEmptyLines;
-}
-
-void KoOdfLineNumberingConfiguration::setCountEmptyLines(bool countEmptyLines)
-{
- d->countEmptyLines = countEmptyLines;
-}
-
-bool KoOdfLineNumberingConfiguration::countLinesInTextBoxes() const
-{
- return d->countLinesInTextBoxes;
-}
-
-void KoOdfLineNumberingConfiguration::setCountLinesInTextBoxes(bool countLinesInTextBoxes)
-{
- d->countLinesInTextBoxes = countLinesInTextBoxes;
-}
-
-bool KoOdfLineNumberingConfiguration::restartNumberingOnEveryPage() const
-{
- return d->restartNumberingOnEveryPage;
-}
-
-void KoOdfLineNumberingConfiguration::setRestartNumberingOnEveryPage(bool restartNumberingOnEveryPage)
-{
- d->restartNumberingOnEveryPage = restartNumberingOnEveryPage;
-}
-
-QString KoOdfLineNumberingConfiguration::separator() const
-{
- return d->separator;
-}
-
-void KoOdfLineNumberingConfiguration::setSeparator(const QString &separator)
-{
- d->separator = separator;
-}
-
-int KoOdfLineNumberingConfiguration::separatorIncrement() const
-{
- return d->separatorIncrement;
-}
-
-void KoOdfLineNumberingConfiguration::setSeparatorIncrement(int separatorIncrement)
-{
- d->separatorIncrement = separatorIncrement;
-}
-
diff --git a/libs/odf/KoOdfLineNumberingConfiguration.h b/libs/odf/KoOdfLineNumberingConfiguration.h
deleted file mode 100644
index d151c68985..0000000000
--- a/libs/odf/KoOdfLineNumberingConfiguration.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/* This file is part of the KDE project
-
- Copyright (C) 2010 KO GmbH <boud@valdyas.org>
-
- 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.
- */
-#ifndef KOODFLINENUMBERINGCONFIGURATION_H
-#define KOODFLINENUMBERINGCONFIGURATION_H
-
-#include <QMetaType>
-#include <QObject>
-
-#include "KoXmlReaderForward.h"
-#include "kritaodf_export.h"
-
-class KoXmlWriter;
-class KoOdfNumberDefinition;
-
-/**
- * Implement section 14.9.1: Line Numbering Configuration.
- *
- * A document can contain none or one line numbering configuration element
- * <text:linenumbering-configuration> within the <office:styles> element. If the
- * element is not present, a default line numbering configuration is used. The default line numbering
- * may vary on the office application software, but every document saved by an application that
- * supports line numbering should contain a line numbering configuration element.
- *
- * The attributes that may be associated with the <text:linenumbering-configuration>
- * element are:
- * <ul>
- * <li> Line numbering enable
- * <li> Number format
- * <li> Text style
- * <li> Increment
- * <li> Position
- * <li> Offset
- * <li> Count empty lines
- * <li> Count line in text boxes
- * <li> Restart numbering on every page
- * </ul>
- * The following element may be included in the <text:linenumbering-separator> element:
- * <li> Separator
- */
-class KRITAODF_EXPORT KoOdfLineNumberingConfiguration : public QObject
-{
- Q_OBJECT
-public:
-
- KoOdfLineNumberingConfiguration();
- ~KoOdfLineNumberingConfiguration() override;
- KoOdfLineNumberingConfiguration(const KoOdfLineNumberingConfiguration &other);
- KoOdfLineNumberingConfiguration &operator=(const KoOdfLineNumberingConfiguration &other);
-
-
- /**
- * load the line numbering configuration element
- */
- void loadOdf(const KoXmlElement &element);
-
- /**
- * save the line number configuration element
- */
- void saveOdf(KoXmlWriter * writer) const;
-
- /**
- * The text:number-lines attribute controls whether or not lines are numbered.
- */
- bool enabled() const;
- void setEnabled(bool enabled);
-
- /**
- * See section 12.2 for detailed information on number format attributes. The attributes
- * described in section 12.2 can also be associated with the <text:linenumbering-configuration>
- * element.
- */
- KoOdfNumberDefinition numberFormat() const;
- void setNumberFormat(const KoOdfNumberDefinition &numberFormat);
-
- /**
- * The text:style-name attribute specifies the text style for all line numbers. The value
- * of this attribute is the name of the text style that is applied to all line numbers.
- */
- QString textStyle() const;
- void setTextStyle(const QString &textStyle);
-
- /**
- * The text:increment attribute causes line numbers that are a multiple of the given increment to
- * be numbered. For example, if the increment is 5, only lines number 5, 10, 15, and so on are
- * numbered.
- */
- int increment() const;
- void setIncrement(int increment);
-
- /**
- * The text:position attribute determines whether the line numbers are printed on the left, right,
- * inner, or outer margins.
- */
- enum Position {
- Left,
- Right,
- Inner,
- Outer
- };
-
- Position position() const;
- void setPosition(Position position);
-
- /**
- * The text:offset attribute determines the distance between the line number and the margin.
- */
- int offset() const;
- void setOffset(int offset);
-
- /**
- * The text:count-empty-lines attribute determines whether or not empty lines are included in
- * the line count. If the value of this attribute is true, empty lines are included in the line count.
- */
- bool countEmptyLines() const;
- void setCountEmptyLines(bool countEmptyLines);
-
- /**
- * The text:count-in-text-boxes attribute determines whether or not text in text boxes is
- * included in the line count. If the value of this attribute is true, text within text boxes is included in
- * the line count.
- */
- bool countLinesInTextBoxes() const;
- void setCountLinesInTextBoxes(bool countLinesInTextBoxes);
-
- /**
- * The text:restart-on-page attribute determines whether or not the line count is reset to 1 at
- * the start of every page.
- *
- * If the value of this attribute is true, the line count is reset to 1 at the beginning of every page,
- * resulting in page -specific numbering of lines. The default value of this attribute is false,
- * resulting in document-specific numbering of lines.
- */
- bool restartNumberingOnEveryPage() const;
- void setRestartNumberingOnEveryPage(bool restartNumberingOnEveryPage);
-
- /**
- * The <text:linenumbering-separator> element contains the text that is displayed as a
- * separator. A separator is text that is displayed instead of a line number for lines where no number
- * is displayed.
- *
- * This element is contained in the line numbering configuration element. If the element is not
- * present, no separator is displayed.
- *
- * The element's text:increment attribute causes the separator to appear on lines that are a
- * multiple of the given increment. For example, if the increment is 2, only lines 2, 4, 6, and so on get
- * a separator, provided that no number is displayed already.
- */
- QString separator() const;
- void setSeparator(const QString &separator);
-
- int separatorIncrement() const;
- void setSeparatorIncrement(int separatorIncrement);
-
-private:
-
- class Private;
- Private * const d;
-
-};
-
-Q_DECLARE_METATYPE(KoOdfLineNumberingConfiguration*)
-
-#endif // KOODFLINENUMBERINGCONFIGURATION_H
diff --git a/libs/odf/KoOdfLoadingContext.cpp b/libs/odf/KoOdfLoadingContext.cpp
deleted file mode 100644
index 25cf62f83f..0000000000
--- a/libs/odf/KoOdfLoadingContext.cpp
+++ /dev/null
@@ -1,353 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2005 David Faure <faure@kde.org>
- Copyright (C) 2010 Inge Wallin <inge@lysator.liu.se>
-
- 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.
-*/
-
-// Own
-#include "KoOdfLoadingContext.h"
-
-// KDE
-#include <OdfDebug.h>
-
-
-// Calligra
-#include <KoOdfReadStore.h>
-#include <KoOdfStylesReader.h>
-#include <KoStore.h>
-#include <KoStoreDevice.h>
-#include <KoXmlNS.h>
-#include <KoOdfManifestEntry.h>
-#include "KoStyleStack.h"
-#include <KoXmlReader.h>
-
-// Qt
-#include <QStandardPaths>
-#include <KisMimeDatabase.h>
-#include <QFile>
-
-
-class Q_DECL_HIDDEN KoOdfLoadingContext::Private
-{
-public:
- Private(KoOdfStylesReader &sr, KoStore *s)
- : store(s),
- stylesReader(sr),
- generatorType(KoOdfLoadingContext::Unknown),
- metaXmlParsed(false),
- useStylesAutoStyles(false)
- {
- }
-
- ~Private() {
- qDeleteAll(manifestEntries);
- }
-
- KoStore *store;
- KoOdfStylesReader &stylesReader;
- KoStyleStack styleStack;
-
- mutable QString generator;
- GeneratorType generatorType;
- mutable bool metaXmlParsed;
- bool useStylesAutoStyles;
-
- KoXmlDocument manifestDoc;
- QHash<QString, KoOdfManifestEntry *> manifestEntries;
-
-
- KoOdfStylesReader defaultStylesReader;
- KoXmlDocument doc; // the doc needs to be kept around so it is possible to access the styles
-};
-
-KoOdfLoadingContext::KoOdfLoadingContext(KoOdfStylesReader &stylesReader, KoStore* store, const QString &defaultStylesResourcePath)
- : d(new Private(stylesReader, store))
-{
- // Ideally this should be done by KoDocument and passed as argument here...
- KoOdfReadStore oasisStore(store);
- QString dummy;
- (void)oasisStore.loadAndParse("tar:/META-INF/manifest.xml", d->manifestDoc, dummy);
-
- if (!defaultStylesResourcePath.isEmpty()) {
- Q_ASSERT(defaultStylesResourcePath.endsWith(QLatin1Char('/')));
- const QString fileName =
- QStandardPaths::locate(QStandardPaths::AppDataLocation,
- defaultStylesResourcePath + "defaultstyles.xml");
- if ( ! fileName.isEmpty() ) {
- QFile file( fileName );
- QString errorMessage;
- if ( KoOdfReadStore::loadAndParse( &file, d->doc, errorMessage, fileName ) ) {
- d->defaultStylesReader.createStyleMap( d->doc, true );
- }
- else {
- warnOdf << "reading of defaultstyles.xml failed:" << errorMessage;
- }
- }
- else {
- warnOdf << "defaultstyles.xml not found";
- }
- }
-
- if (!parseManifest(d->manifestDoc)) {
- debugOdf << "could not parse manifest document";
- }
-}
-
-KoOdfLoadingContext::~KoOdfLoadingContext()
-{
- delete d;
-}
-
-void KoOdfLoadingContext::setManifestFile(const QString& fileName) {
- KoOdfReadStore oasisStore(d->store);
- QString dummy;
- (void)oasisStore.loadAndParse(fileName, d->manifestDoc, dummy);
- if (!parseManifest(d->manifestDoc)) {
- debugOdf << "could not parse manifest document";
- }
-}
-
-void KoOdfLoadingContext::fillStyleStack(const KoXmlElement& object, const QString &nsURI, const QString &attrName, const QString &family)
-{
- // find all styles associated with an object and push them on the stack
- if (object.hasAttributeNS(nsURI, attrName)) {
- const QString styleName = object.attributeNS(nsURI, attrName, QString());
- const KoXmlElement * style = d->stylesReader.findStyle(styleName, family, d->useStylesAutoStyles);
-
- if (style)
- addStyles(style, family, d->useStylesAutoStyles);
- else
- warnOdf << "style" << styleName << "not found in" << (d->useStylesAutoStyles ? "styles.xml" : "content.xml");
- }
-}
-
-void KoOdfLoadingContext::addStyles(const KoXmlElement* style, const QString &family, bool usingStylesAutoStyles)
-{
- Q_ASSERT(style);
- if (!style) return;
-
- // this recursive function is necessary as parent styles can have parents themselves
- if (style->hasAttributeNS(KoXmlNS::style, "parent-style-name")) {
- const QString parentStyleName = style->attributeNS(KoXmlNS::style, "parent-style-name", QString());
- const KoXmlElement* parentStyle = d->stylesReader.findStyle(parentStyleName, family, usingStylesAutoStyles);
-
- if (parentStyle)
- addStyles(parentStyle, family, usingStylesAutoStyles);
- else {
- warnOdf << "Parent style not found: " << family << parentStyleName << usingStylesAutoStyles;
- //we are handling a non compliant odf file. let's at the very least load the application default, and the eventual odf default
- if (!family.isEmpty()) {
- const KoXmlElement* def = d->stylesReader.defaultStyle(family);
- if (def) { // then, the default style for this family
- d->styleStack.push(*def);
- }
- }
- }
- } else if (!family.isEmpty()) {
- const KoXmlElement* def = d->stylesReader.defaultStyle(family);
- if (def) { // then, the default style for this family
- d->styleStack.push(*def);
- }
- }
-
- //debugOdf <<"pushing style" << style->attributeNS( KoXmlNS::style,"name", QString() );
- d->styleStack.push(*style);
-}
-
-void KoOdfLoadingContext::parseGenerator() const
-{
- // Regardless of whether we cd into the parent directory
- // or not to find a meta.xml, restore the directory that
- // we were in afterwards.
- d->store->pushDirectory();
-
- // Some embedded documents to not contain their own meta.xml
- // Use the parent directory's instead.
- if (!d->store->hasFile("meta.xml"))
- // Only has an effect if there is a parent directory
- d->store->leaveDirectory();
-
- if (d->store->hasFile("meta.xml")) {
- KoXmlDocument metaDoc;
- KoOdfReadStore oasisStore(d->store);
- QString errorMsg;
- if (oasisStore.loadAndParse("meta.xml", metaDoc, errorMsg)) {
- KoXmlNode meta = KoXml::namedItemNS(metaDoc, KoXmlNS::office, "document-meta");
- KoXmlNode office = KoXml::namedItemNS(meta, KoXmlNS::office, "meta");
- KoXmlElement generator = KoXml::namedItemNS(office, KoXmlNS::meta, "generator");
- if (!generator.isNull()) {
- d->generator = generator.text();
- if (d->generator.startsWith("Calligra")) {
- d->generatorType = Calligra;
- }
- // NeoOffice is a port of OpenOffice to Mac OS X
- else if (d->generator.startsWith("OpenOffice.org") || d->generator.startsWith("NeoOffice") ||
- d->generator.startsWith("LibreOffice") || d->generator.startsWith("StarOffice") ||
- d->generator.startsWith("Lotus Symphony")) {
- d->generatorType = OpenOffice;
- }
- else if (d->generator.startsWith("MicrosoftOffice")) {
- d->generatorType = MicrosoftOffice;
- }
- }
- }
- }
- d->metaXmlParsed = true;
-
- d->store->popDirectory();
-}
-
-QString KoOdfLoadingContext::generator() const
-{
- if (!d->metaXmlParsed && d->store) {
- parseGenerator();
- }
- return d->generator;
-}
-
-KoOdfLoadingContext::GeneratorType KoOdfLoadingContext::generatorType() const
-{
- if (!d->metaXmlParsed && d->store) {
- parseGenerator();
- }
- return d->generatorType;
-}
-
-KoStore *KoOdfLoadingContext::store() const
-{
- return d->store;
-}
-
-KoOdfStylesReader &KoOdfLoadingContext::stylesReader()
-{
- return d->stylesReader;
-}
-
-/**
-* Get the application default styles styleReader
-*/
-KoOdfStylesReader &KoOdfLoadingContext::defaultStylesReader()
-{
- return d->defaultStylesReader;
-}
-
-KoStyleStack &KoOdfLoadingContext::styleStack() const
-{
- return d->styleStack;
-}
-
-void KoOdfLoadingContext::setUseStylesAutoStyles(bool useStylesAutoStyles)
-{
- d->useStylesAutoStyles = useStylesAutoStyles;
-}
-
-bool KoOdfLoadingContext::useStylesAutoStyles() const
-{
- return d->useStylesAutoStyles;
-}
-
-QString KoOdfLoadingContext::mimeTypeForPath(const QString& path, bool guess) const
-{
- QHash<QString, KoOdfManifestEntry *>::iterator it(d->manifestEntries.find(path));
- if (it == d->manifestEntries.end()) {
- // try to find it with an added / at the end
- QString dirPath = path + '/';
- it = d->manifestEntries.find(dirPath);
- }
- if (it != d->manifestEntries.end()) {
- QString mimeType = it.value()->mediaType();
-
- // figure out mimetype by content if it is not provided
- if (mimeType.isEmpty() && guess) {
- Q_ASSERT(!d->store->isOpen());
- if (d->store->open(path)) {
- KoStoreDevice device(d->store);
- QByteArray data = device.read(16384);
- d->store->close();
- mimeType = KisMimeDatabase::mimeTypeForData(data);
- if (!mimeType.isEmpty()) {
- it.value()->setMediaType(mimeType);
- }
- }
- }
-
- return mimeType;
- }
- else {
- return QString();
- }
-}
-
-QList<KoOdfManifestEntry*> KoOdfLoadingContext::manifestEntries() const
-{
- return d->manifestEntries.values();
-}
-
-bool KoOdfLoadingContext::parseManifest(const KoXmlDocument &manifestDocument)
-{
- // First find the manifest:manifest node.
- KoXmlNode n = manifestDocument.firstChild();
- debugOdf << "Searching for manifest:manifest " << n.toElement().nodeName();
- for (; !n.isNull(); n = n.nextSibling()) {
- if (!n.isElement()) {
- debugOdf << "NOT element";
- continue;
- } else {
- debugOdf << "element";
- }
-
- debugOdf << "name:" << n.toElement().localName()
- << "namespace:" << n.toElement().namespaceURI();
-
- if (n.toElement().localName() == "manifest"
- && n.toElement().namespaceURI() == KoXmlNS::manifest)
- {
- debugOdf << "found manifest:manifest";
- break;
- }
- }
- if (n.isNull()) {
- debugOdf << "Could not find manifest:manifest";
- return false;
- }
-
- // Now loop through the children of the manifest:manifest and
- // store all the manifest:file-entry elements.
- const KoXmlElement manifestElement = n.toElement();
- for (n = manifestElement.firstChild(); !n.isNull(); n = n.nextSibling()) {
-
- if (!n.isElement())
- continue;
-
- KoXmlElement el = n.toElement();
- if (!(el.localName() == "file-entry" && el.namespaceURI() == KoXmlNS::manifest))
- continue;
-
- QString fullPath = el.attributeNS(KoXmlNS::manifest, "full-path", QString());
- QString mediaType = el.attributeNS(KoXmlNS::manifest, "media-type", QString());
- QString version = el.attributeNS(KoXmlNS::manifest, "version", QString());
-
- // Only if fullPath is valid, should we store this entry.
- // If not, we don't bother to find out exactly what is wrong, we just skip it.
- if (!fullPath.isNull()) {
- d->manifestEntries.insert(fullPath,
- new KoOdfManifestEntry(fullPath, mediaType, version));
- }
- }
-
- return true;
-}
diff --git a/libs/odf/KoOdfLoadingContext.h b/libs/odf/KoOdfLoadingContext.h
deleted file mode 100644
index dd44901cb1..0000000000
--- a/libs/odf/KoOdfLoadingContext.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2005 David Faure <faure@kde.org>
- Copyright (C) 2010 Inge Wallin <inge@lysator.liu.se>
-
- 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 KOODFLOADINGCONTEXT_H
-#define KOODFLOADINGCONTEXT_H
-
-#include "kritaodf_export.h"
-
-#include <QString>
-#include "KoXmlReaderForward.h"
-
-
-class KoStore;
-class KoOdfManifestEntry;
-class KoStyleStack;
-class KoOdfStylesReader;
-
-
-/**
- * Used during loading of Oasis format (and discarded at the end of the loading).
- *
- * @author David Faure <faure@kde.org>
- */
-class KRITAODF_EXPORT KoOdfLoadingContext
-{
-public:
- enum GeneratorType { Unknown, Calligra, OpenOffice, MicrosoftOffice };
- /**
- * Stores reference to the KoOdfStylesReader and stored passed by
- * KoDocument. Make sure that the KoOdfStylesReader instance outlives
- * this KoOdfLoadingContext instance. (This is the case during
- * loading, when using the KoOdfStylesReader given by KoDocument)
- *
- * @param styles reference to the KoOdfStylesReader parsed by KoDocument
- * @param store pointer to store, if available, for e.g. loading images.
- * @param defaultStylesResourcePath resource path to "defaultstyles.xml", empty if none
- */
- explicit KoOdfLoadingContext(KoOdfStylesReader &stylesReader, KoStore *store, const QString &defaultStylesResourcePath = QString());
- virtual ~KoOdfLoadingContext();
-
- /**
- * Set different manifest
- * @param fileName file name of the manifest file
- */
- void setManifestFile(const QString &fileName);
-
- KoStore *store() const;
-
- KoOdfStylesReader &stylesReader();
-
- /**
- * Get the application default styles styleReader
- */
- KoOdfStylesReader &defaultStylesReader();
-
- KoStyleStack &styleStack() const;
-
- /// Return the <meta:generator> of the document, e.g. "Calligra/1.4.0a"
- QString generator() const;
- /// Return the GeneratorType of the document, e.g. Calligra
- GeneratorType generatorType() const;
-
- /**
- * Convenience method for loading the style of an object
- * before loading that object.
- *
- * Read attribute (nsURI,attrName) from the given dom element,
- * treat that attribute as a style name, and load that style
- * including all its parent styles.
- * @param element the dom element to read the attribute from
- * @param nsURI the namespace URI of the attribute to read
- * @param attrName the name of the attribute to read
- * @param family the style family used for this object
- */
- void fillStyleStack(const KoXmlElement &element, const QString &nsURI, const QString &attrName, const QString &family);
-
- /**
- * Add @p style to the stack, as well as all its parent styles
- * and the default style for this style family.
- *
- * @param style the dom element containing the style to add to the stack
- * @param family the family to use when looking up parent styles
- * @param usingStylesAutoStyles if true, the parent styles are looked up
- * in the automatic styles from styles.xml, instead of looking up
- * in the automatic styles from content.xml as we usually do.
- * This is useful for loading headers and footers for instance.
- * See setUseStylesAutoStyles(), which makes fillStyleStack() set this bool.
- *
- * Usually you would call fillStyleStack() instead.
- */
- void addStyles(const KoXmlElement *style, const QString &family, bool usingStylesAutoStyles = false);
-
- /// Set to true while loading headers and footers, to remember to use auto styles
- /// from styles.xml
- void setUseStylesAutoStyles(bool useStylesAutoStyles);
- bool useStylesAutoStyles() const;
-
-
- /**
- * @return the mimetype for the document in the given path using the manifest
- * The mimetype is defined in the manifest.xml document.
- * @param path The path to get the mimetpye for
- * @param guess If set to true it tries to guess the mimetype in case it is not provided in the manifest
- Note: Be sure to call this function with a closed store when guess is set to true as otherwise
- it will fail.
- */
- QString mimeTypeForPath(const QString& path, bool guess = false) const;
-
- /**
- * @return the full list of entries from the manifest file
- */
- QList<KoOdfManifestEntry*> manifestEntries() const;
-
-private:
- class Private;
- Private * const d;
- /// Parse and set generator and generatorType attributes from <meta:generator> attribute of meta.xml file
- void parseGenerator() const;
- bool parseManifest(const KoXmlDocument &manifestDocument);
-};
-
-#endif /* KOODFLOADINGCONTEXT_H */
diff --git a/libs/odf/KoOdfManifestEntry.cpp b/libs/odf/KoOdfManifestEntry.cpp
deleted file mode 100644
index 27ecf23939..0000000000
--- a/libs/odf/KoOdfManifestEntry.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2011 Inge Wallin <inge@lysator.liu.se>
-
- 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.
-*/
-
-
-// Own
-#include "KoOdfManifestEntry.h"
-
-#include <QString>
-
-class Q_DECL_HIDDEN KoOdfManifestEntry::Private
-{
-public:
- Private() {};
-
- QString fullPath; // manifest:full-path
- QString mediaType; // manifest:media-type
- QString version; // manifest:version (isNull==true if not present)
-};
-
-
-// ----------------------------------------------------------------
-
-
-KoOdfManifestEntry::KoOdfManifestEntry(const QString &fullPath, const QString &mediaType,
- const QString &version)
- : d(new Private())
-{
- d->fullPath = fullPath;
- d->mediaType = mediaType;
- d->version = version;
-}
-
-KoOdfManifestEntry::KoOdfManifestEntry(const KoOdfManifestEntry &other)
- : d(new Private())
-{
- d->fullPath = other.d->fullPath;
- d->mediaType = other.d->mediaType;
- d->version = other.d->version;
-}
-
-KoOdfManifestEntry::~KoOdfManifestEntry()
-{
- delete d;
-}
-
-KoOdfManifestEntry &KoOdfManifestEntry::operator=(const KoOdfManifestEntry &other)
-{
- d->fullPath = other.d->fullPath;
- d->mediaType = other.d->mediaType;
- d->version = other.d->version;
-
- return *this;
-}
-
-
-QString KoOdfManifestEntry::fullPath() const
-{
- return d->fullPath;
-}
-
-void KoOdfManifestEntry::setFullPath(const QString &fullPath)
-{
- d->fullPath = fullPath;
-}
-
-QString KoOdfManifestEntry::mediaType() const
-{
- return d->mediaType;
-}
-
-void KoOdfManifestEntry::setMediaType(const QString &mediaType)
-{
- d->mediaType = mediaType;
-}
-
-QString KoOdfManifestEntry::version() const
-{
- return d->version;
-}
-
-void KoOdfManifestEntry::setVersion(const QString &version)
-{
- d->version = version;
-}
-
diff --git a/libs/odf/KoOdfManifestEntry.h b/libs/odf/KoOdfManifestEntry.h
deleted file mode 100644
index d017584440..0000000000
--- a/libs/odf/KoOdfManifestEntry.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2010-2011 Inge Wallin <inge@lysator.liu.se>
-
- 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 KOODFMANIFEST_H
-#define KOODFMANIFEST_H
-
-#include "kritaodf_export.h"
-
-
-class QString;
-
-
-// A class that holds a manifest:file-entry.
-class KRITAODF_EXPORT KoOdfManifestEntry
-{
-public:
- KoOdfManifestEntry(const QString &fullPath, const QString &mediatType, const QString &version);
- KoOdfManifestEntry(const KoOdfManifestEntry &other);
- ~KoOdfManifestEntry();
-
- KoOdfManifestEntry &operator=(const KoOdfManifestEntry &other);
-
- QString fullPath() const;
- void setFullPath(const QString &fullPath);
-
- QString mediaType() const;
- void setMediaType(const QString &mediaType);
-
- QString version() const;
- void setVersion(const QString &version);
-
-private:
- class Private;
- Private * const d;
-};
-
-
-#endif /* KOODFMANIFEST_H */
diff --git a/libs/odf/KoOdfNotesConfiguration.cpp b/libs/odf/KoOdfNotesConfiguration.cpp
deleted file mode 100644
index 4b1f35bcaa..0000000000
--- a/libs/odf/KoOdfNotesConfiguration.cpp
+++ /dev/null
@@ -1,342 +0,0 @@
-/* This file is part of the KDE project
-
- Copyright (C) 2010 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 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 "KoOdfNotesConfiguration.h"
-
-#include <OdfDebug.h>
-#include "KoXmlNS.h"
-#include "KoXmlWriter.h"
-#include "KoXmlReader.h"
-#include "KoOdfNumberDefinition.h"
-
-class Q_DECL_HIDDEN KoOdfNotesConfiguration::Private
-{
-public:
- KoOdfNotesConfiguration::NoteClass noteClass;
- QString citationTextStyleName;
- QString citationBodyTextStyleName;
- QString defaultNoteParagraphStyleName;
- void *citationTextStyle;
- void *citationBodyTextStyle;
- void *defaultNoteParagraphStyle;
- QString masterPageName;
- int startValue;
- KoOdfNumberDefinition numberFormat;
- KoOdfNotesConfiguration::NumberingScheme numberingScheme;
- KoOdfNotesConfiguration::FootnotesPosition footnotesPosition;
- QString footnotesContinuationForward;
- QString footnotesContinuationBackward;
-
-};
-
-KoOdfNotesConfiguration::KoOdfNotesConfiguration(NoteClass noteClass)
- : d(new Private())
-{
- d->noteClass = noteClass;
- d->startValue = 1;
- d->numberingScheme = BeginAtDocument;
- d->footnotesPosition = Page;
-
- d->defaultNoteParagraphStyle = 0;
- d->citationTextStyle = 0;
- d->citationBodyTextStyle = 0;
-
- if (noteClass == KoOdfNotesConfiguration::Footnote) {
- d->numberFormat.setFormatSpecification(KoOdfNumberDefinition::Numeric);
- d->defaultNoteParagraphStyleName = "Footnote";
- d->citationTextStyleName = "Footnote_20_Symbol";
- d->citationBodyTextStyleName = "Footnote_20_anchor";
- } else {
- d->numberFormat.setFormatSpecification(KoOdfNumberDefinition::RomanLowerCase);
- d->defaultNoteParagraphStyleName = "Endnote";
- d->citationTextStyleName = "Endnote_20_Symbol";
- d->citationBodyTextStyleName = "Endnote_20_anchor";
- }
-}
-
-KoOdfNotesConfiguration::~KoOdfNotesConfiguration()
-{
- delete d;
-}
-
-KoOdfNotesConfiguration::KoOdfNotesConfiguration(const KoOdfNotesConfiguration &other)
- : QObject(), d(new Private())
-{
- d->noteClass = other.d->noteClass;
- d->citationTextStyleName = other.d->citationTextStyleName;
- d->citationBodyTextStyleName = other.d->citationBodyTextStyleName;
- d->defaultNoteParagraphStyleName = other.d->defaultNoteParagraphStyleName;
- d->citationTextStyle = other.d->citationTextStyle;
- d->citationBodyTextStyle = other.d->citationBodyTextStyle;
- d->defaultNoteParagraphStyle = other.d->defaultNoteParagraphStyle;
- d->masterPageName = other.d->masterPageName;
- d->startValue = other.d->startValue;
- d->numberFormat = other.d->numberFormat;
- d->numberingScheme = other.d->numberingScheme;
- d->footnotesPosition = other.d->footnotesPosition;
- d->footnotesContinuationForward = other.d->footnotesContinuationForward;
- d->footnotesContinuationBackward = other.d->footnotesContinuationBackward;
-
-}
-
-KoOdfNotesConfiguration &KoOdfNotesConfiguration::operator=(const KoOdfNotesConfiguration &other)
-{
- d->noteClass = other.d->noteClass;
- d->citationTextStyleName = other.d->citationTextStyleName;
- d->citationBodyTextStyleName = other.d->citationBodyTextStyleName;
- d->defaultNoteParagraphStyleName = other.d->defaultNoteParagraphStyleName;
- d->citationTextStyle = other.d->citationTextStyle;
- d->citationBodyTextStyle = other.d->citationBodyTextStyle;
- d->defaultNoteParagraphStyle = other.d->defaultNoteParagraphStyle;
- d->masterPageName = other.d->masterPageName;
- d->startValue = other.d->startValue;
- d->numberFormat = other.d->numberFormat;
- d->numberingScheme = other.d->numberingScheme;
- d->footnotesPosition = other.d->footnotesPosition;
- d->footnotesContinuationForward = other.d->footnotesContinuationForward;
- d->footnotesContinuationBackward = other.d->footnotesContinuationBackward;
-
- return *this;
-}
-
-
-void KoOdfNotesConfiguration::loadOdf(const KoXmlElement &element)
-{
- d->citationTextStyleName = element.attributeNS(KoXmlNS::text, "citation-style-name", d->citationTextStyleName);
- d->citationBodyTextStyleName = element.attributeNS(KoXmlNS::text, "citation-body-style-name", d->citationBodyTextStyleName);
- d->defaultNoteParagraphStyleName = element.attributeNS(KoXmlNS::text, "default-style-name", d->defaultNoteParagraphStyleName);
- d->masterPageName = element.attributeNS(KoXmlNS::text, "master-page-name", d->masterPageName);
- d->startValue = qMax(1, element.attributeNS(KoXmlNS::text, "start-value", QString::number(d->startValue)).toInt());
-
- d->numberFormat.loadOdf(element);
-
- QString numberingScheme = element.attributeNS(KoXmlNS::text, "start-numbering-at", "document");
- if (numberingScheme == "document") {
- d->numberingScheme = BeginAtDocument;
- }
- else if (numberingScheme == "chapter") {
- d->numberingScheme = BeginAtChapter;
- }
- else if (numberingScheme == "page") {
- d->numberingScheme = BeginAtPage;
- }
-
- QString footnotesPosition = element.attributeNS(KoXmlNS::text, "footnotes-position", "page");
- if (footnotesPosition == "text") {
- d->footnotesPosition = Text;
- }
- else if (footnotesPosition == "page") {
- d->footnotesPosition = Page;
- }
- else if (footnotesPosition == "section") {
- d->footnotesPosition = Section;
- }
- else if (footnotesPosition == "document") {
- d->footnotesPosition = Document;
- }
-
- for (KoXmlNode node = element.firstChild(); !node.isNull(); node = node.nextSibling()) {
- KoXmlElement child = node.toElement();
- if (child.namespaceURI() == KoXmlNS::text) {
- if (child.localName() == "note-continuation-notice-forward") {
- d->footnotesContinuationForward = child.text();
- } else if (child.localName() == "note-continuation-notice-backward") {
- d->footnotesContinuationBackward = child.text();
- }
- }
- }
-}
-
-void KoOdfNotesConfiguration::saveOdf(KoXmlWriter *writer) const
-{
- writer->startElement("text:notes-configuration");
-
- if (d->noteClass == Footnote) {
- writer->addAttribute("text:note-class", "footnote");
- }
- else if (d->noteClass == Endnote) {
- writer->addAttribute("text:note-class", "endnote");
- }
- if (!d->citationTextStyleName.isNull()) {writer->addAttribute("text:citation-style-name", d->citationTextStyleName); }
- if (!d->citationBodyTextStyleName.isNull()) {writer->addAttribute("text:citation-body-style-name", d->citationBodyTextStyleName); }
- if (!d->defaultNoteParagraphStyleName.isNull()) {writer->addAttribute("text:default-style-name", d->defaultNoteParagraphStyleName); }
- if (!d->masterPageName.isNull()) {writer->addAttribute("text:master-page-name", d->masterPageName); }
- if (d->startValue != 0) { writer->addAttribute("text:start-value", d->startValue); }
-
- d->numberFormat.saveOdf(writer);
- switch(d->numberingScheme) {
- case BeginAtDocument:
- writer->addAttribute("text:start-numbering-at", "document");
- break;
- case BeginAtChapter:
- writer->addAttribute("text:start-numbering-at", "chapter");
- break;
- case BeginAtPage:
- writer->addAttribute("text:start-numbering-at", "page");
- break;
- }
- switch(d->footnotesPosition) {
- case Text:
- writer->addAttribute("text:footnotes-position", "text");
- break;
- case Page:
- writer->addAttribute("text:footnotes-position", "page");
- break;
- case Section:
- writer->addAttribute("text:footnotes-position", "section");
- break;
- case Document:
- writer->addAttribute("text:footnotes-position", "document");
- break;
- }
- if (!d->footnotesContinuationForward.isNull()) {
- writer->startElement("text:note-continuation-notice-forward", false);
- writer->addTextNode(d->footnotesContinuationForward);
- writer->endElement();
- }
- if (!d->footnotesContinuationBackward.isNull()) {
- writer->startElement("text:note-continuation-notice-backward", false);
- writer->addTextNode(d->footnotesContinuationBackward);
- writer->endElement();
- }
-
- writer->endElement(); //text:notes-configuration
-}
-
-
-KoOdfNotesConfiguration::NoteClass KoOdfNotesConfiguration::noteClass() const
-{
- return d->noteClass;
-}
-
-
-void *KoOdfNotesConfiguration::citationTextStyle() const
-{
- return d->citationTextStyle;
-}
-
-QString KoOdfNotesConfiguration::citationTextStyleName() const
-{
- return d->citationTextStyleName;
-}
-
-void KoOdfNotesConfiguration::setCitationTextStyle(void *citationTextStyle)
-{
- d->citationTextStyle = citationTextStyle;
-}
-
-void *KoOdfNotesConfiguration::citationBodyTextStyle() const
-{
- return d->citationBodyTextStyle;
-}
-
-QString KoOdfNotesConfiguration::citationBodyTextStyleName() const
-{
- return d->citationBodyTextStyleName;
-}
-
-void KoOdfNotesConfiguration::setCitationBodyTextStyle(void *citationBodyTextStyle)
-{
- d->citationBodyTextStyle = citationBodyTextStyle;
-}
-
-void *KoOdfNotesConfiguration::defaultNoteParagraphStyle() const
-{
- return d->defaultNoteParagraphStyle;
-}
-
-QString KoOdfNotesConfiguration::defaultNoteParagraphStyleName() const
-{
- return d->defaultNoteParagraphStyleName;
-}
-
-void KoOdfNotesConfiguration::setDefaultNoteParagraphStyle(void *defaultNoteParagraphStyle)
-{
- d->defaultNoteParagraphStyle = defaultNoteParagraphStyle;
-}
-
-QString KoOdfNotesConfiguration::masterPage() const
-{
- return d->masterPageName;
-}
-
-void KoOdfNotesConfiguration::setMasterPage(const QString &masterPage)
-{
- d->masterPageName = masterPage;
-}
-
-int KoOdfNotesConfiguration::startValue() const
-{
- return d->startValue;
-}
-
-void KoOdfNotesConfiguration::setStartValue(int startValue)
-{
- d->startValue = qMax(1, startValue);
-}
-
-
-KoOdfNumberDefinition KoOdfNotesConfiguration::numberFormat() const
-{
- return d->numberFormat;
-}
-
-void KoOdfNotesConfiguration::setNumberFormat(const KoOdfNumberDefinition &numberFormat)
-{
- d->numberFormat = numberFormat;
-}
-
-KoOdfNotesConfiguration::NumberingScheme KoOdfNotesConfiguration::numberingScheme() const
-{
- return d->numberingScheme;
-}
-
-void KoOdfNotesConfiguration::setNumberingScheme(NumberingScheme numberingScheme)
-{
- d->numberingScheme = numberingScheme;
-}
-
-KoOdfNotesConfiguration::FootnotesPosition KoOdfNotesConfiguration::footnotesPosition() const
-{
- return d->footnotesPosition;
-}
-
-void KoOdfNotesConfiguration::setFootnotesPosition(FootnotesPosition footnotesPosition)
-{
- d->footnotesPosition = footnotesPosition;
-}
-
-QString KoOdfNotesConfiguration::footnoteContinuationForward() const
-{
- return d->footnotesContinuationForward;
-}
-
-void KoOdfNotesConfiguration::setFootnoteContinuationForward(const QString &footnoteContinuationForward)
-{
- d->footnotesContinuationForward = footnoteContinuationForward;
-}
-
-QString KoOdfNotesConfiguration::footnoteContinuationBackward() const
-{
- return d->footnotesContinuationBackward;
-}
-
-void KoOdfNotesConfiguration::setFootnoteContinuationBackward(const QString &footnoteContinuationBackward)
-{
- d->footnotesContinuationBackward = footnoteContinuationBackward;
-}
diff --git a/libs/odf/KoOdfNotesConfiguration.h b/libs/odf/KoOdfNotesConfiguration.h
deleted file mode 100644
index f19d18ccc7..0000000000
--- a/libs/odf/KoOdfNotesConfiguration.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/* This file is part of the KDE project
-
- Copyright (C) 2010 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 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.
- */
-#ifndef KOODFNOTESCONFIGURATION_H
-#define KOODFNOTESCONFIGURATION_H
-
-#include <QMetaType>
-#include <QObject>
-
-#include "KoXmlReaderForward.h"
-#include "kritaodf_export.h"
-
-class KoXmlWriter;
-class KoOdfNumberDefinition;
-
-/**
- * load and save the notes-configuration element from the text: namespace.
- *
- * @see 14.9.2 Notes Configuration Element
- * A document in OpenDocument format contains at most one notes configuration element for every
- * notes class used in the document. If there is no note configuration element, a default note
- * configuration is used.
- * The attributes that may be associated with the <text:notes-configuration> element are:
- *
- * • Note class
- * • Citation text style
- * • Citation body text style
- * • Default footnote paragraph style
- * • Master page
- * • Start value
- * • Number format
- * • Numbering scheme
- * • Footnote position
- *
- * The following element may be included in the <text:footnotes-configuration> element:
- *
- * • Footnote continuation notice (forward and backward)
- */
-class KRITAODF_EXPORT KoOdfNotesConfiguration : public QObject
-{
- Q_OBJECT
-public:
-
- /**
- * Note class
- * The note class attribute determines which note elements this notes configuration applies to.
- */
- enum NoteClass {
- Footnote,
- Endnote
- };
-
- KoOdfNotesConfiguration(NoteClass noteClass);
- ~KoOdfNotesConfiguration() override;
- KoOdfNotesConfiguration(const KoOdfNotesConfiguration &other);
- KoOdfNotesConfiguration &operator=(const KoOdfNotesConfiguration &other);
-
-
- /**
- * load the notes-configuration element
- */
- void loadOdf(const KoXmlElement &element);
-
- /**
- * save the notes-configuration element
- */
- void saveOdf(KoXmlWriter * writer) const;
-
-
- NoteClass noteClass() const;
-
- /**
- * Citation Text Style
- * The text:citation-style attribute specifies the text style to use for the footnote citation
- * within the footnote.
- */
- QString citationTextStyleName() const;
- void *citationTextStyle() const;
- void setCitationTextStyle(void *citationTextStyle);
-
- /**
- * Citation Body Text Style
- * The text:citation-body-style-name attribute specifies the text style to use for the
- * footnote citation in the text flow.
- */
- QString citationBodyTextStyleName() const;
- void *citationBodyTextStyle() const;
- void setCitationBodyTextStyle(void *citationBodyTextStyle);
-
- /**
- * Default Note Paragraph Style
- * The default footnote paragraph style is only used for footnotes that are inserted into an existing
- * document. It is not used for footnotes that already exist.
- */
- QString defaultNoteParagraphStyleName() const;
- void *defaultNoteParagraphStyle() const;
- void setDefaultNoteParagraphStyle(void *defaultNoteParagraphStyle);
-
- /**
- * Master Page
- * To display the footnotes at the end of the document, the pages that contain the footnotes must be
- * instances of the master page specified by the text:master-page-name attribute.
- */
- QString masterPage() const;
- void setMasterPage(const QString &masterPage);
-
- /**
- * Start Value
- * The start:value attribute specifies the value at which the footnote numbering starts.
- */
- int startValue() const;
- void setStartValue(int startValue);
-
- /**
- * Number Format
- * See section 12.2 for information on the number format for footnotes.
- */
- KoOdfNumberDefinition numberFormat() const;
- void setNumberFormat(const KoOdfNumberDefinition &numberFormat);
-
- /**
- * Numbering Scheme
- * The text:start-numbering-at attribute specifies if footnote numbers start with a new
- * number at the beginning of the document or at the beginning of each chapter or page.
- */
- enum NumberingScheme {
- BeginAtDocument,
- BeginAtChapter,
- BeginAtPage
- };
-
- NumberingScheme numberingScheme() const;
- void setNumberingScheme(NumberingScheme numberingScheme);
-
- /**
- * Footnotes Position
- * • The text:footnotes-position attribute specifies one of the following positions for footnotes:
- * • text: At the page where the footnote citation is located, immediately below the page's text.
- * • page: The bottom of the page where the footnote citation is located.
- * • section: The end of the section
- * • document: The end of the document.
- */
- enum FootnotesPosition {
- Text,
- Page,
- Section,
- Document
- };
-
- FootnotesPosition footnotesPosition() const;
- void setFootnotesPosition(FootnotesPosition footnotesPosition);
-
- /**
- * Footnote Continuation
- * The footnote continuation elements specify:
- * • Text displayed at the end of a footnote that is continued on the next page
- * • Text displayed before the continued text
- */
- QString footnoteContinuationForward() const;
- void setFootnoteContinuationForward(const QString &footnoteContinuationForward);
-
- QString footnoteContinuationBackward() const;
- void setFootnoteContinuationBackward(const QString &footnoteContinuationBackward);
-
-private:
-
- class Private;
- Private * const d;
-
-};
-
-Q_DECLARE_METATYPE(KoOdfNotesConfiguration*)
-
-#endif // KOODFNOTESCONFIGURATION_H
diff --git a/libs/odf/KoOdfNumberDefinition.cpp b/libs/odf/KoOdfNumberDefinition.cpp
deleted file mode 100644
index 69c7fdcd4b..0000000000
--- a/libs/odf/KoOdfNumberDefinition.cpp
+++ /dev/null
@@ -1,407 +0,0 @@
-/* This file is part of the KDE project
-
- Copyright (C) 2010 Boudewijn Rempt
- Copyright (C) 2011 Mojtaba Shahi Senobari <mojtaba.shahi3000@gmail.com>
-
- 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 "KoOdfNumberDefinition.h"
-
-#include "KoXmlNS.h"
-#include "KoXmlWriter.h"
-#include "KoXmlReader.h"
-
-class Q_DECL_HIDDEN KoOdfNumberDefinition::Private
-{
-public:
- QString prefix;
- QString suffix;
- KoOdfNumberDefinition::FormatSpecification formatSpecification;
- bool letterSynchronization;
-};
-
-KoOdfNumberDefinition::KoOdfNumberDefinition()
- : d(new Private())
-{
- d->formatSpecification = Numeric;
- d->letterSynchronization = false;
-}
-
-KoOdfNumberDefinition::KoOdfNumberDefinition(const KoOdfNumberDefinition &other)
- : d(new Private())
-{
- d->prefix = other.d->prefix;
- d->suffix = other.d->suffix;
- d->formatSpecification = other.d->formatSpecification;
- d->letterSynchronization = other.d->letterSynchronization;
-}
-
-KoOdfNumberDefinition &KoOdfNumberDefinition::operator=(const KoOdfNumberDefinition &other)
-{
- d->prefix = other.d->prefix;
- d->suffix = other.d->suffix;
- d->formatSpecification = other.d->formatSpecification;
- d->letterSynchronization = other.d->letterSynchronization;
-
- return *this;
-}
-
-KoOdfNumberDefinition::~KoOdfNumberDefinition()
-{
- delete d;
-}
-
-void KoOdfNumberDefinition::loadOdf(const KoXmlElement &element)
-{
- const QString format = element.attributeNS(KoXmlNS::style, "num-format", QString());
- if (format.isEmpty()) {
- //do nothing fall back to what we had.
- }
- else if (format[0] == '1') {
- d->formatSpecification = Numeric;
- }
- else if (format[0] == 'a') {
- d->formatSpecification = AlphabeticLowerCase;
- }
- else if (format[0] == 'A') {
- d->formatSpecification = AlphabeticUpperCase;
- }
- else if (format[0] == 'i') {
- d->formatSpecification = RomanLowerCase;
- }
- else if (format[0] == 'I') {
- d->formatSpecification = RomanUpperCase;
- }
- else if (format == QString::fromUtf8("أ, ب, ت, ...")){
- d->formatSpecification = ArabicAlphabet;
- }
- else if (format == QString::fromUtf8("ก, ข, ค, ...")){
- d->formatSpecification = Thai;
- }
- else if (format == QString::fromUtf8("أ, ب, ج, ...")) {
- d->formatSpecification = Abjad;
- }
- else if (format == QString::fromUtf8("ﺃ,ﺏ, ﺝ, ... ")) {
- d->formatSpecification = AbjadMinor;
- }
- else if (format == QString::fromUtf8("౧, ౨, ౩, ...")) {
- d->formatSpecification = Telugu;
- }
- else if (format == QString::fromUtf8("௧, ௨, ௪, ...")) {
- d->formatSpecification = Tamil;
- }
- else if (format == QString::fromUtf8("୧, ୨, ୩, ...")) {
- d->formatSpecification = Oriya;
- }
- else if (format == QString::fromUtf8("൧, ൨, ൩, ...")) {
- d->formatSpecification = Malayalam;
- }
- else if (format == QString::fromUtf8("೧, ೨, ೩, ...")) {
- d->formatSpecification = Kannada;
- }
- else if (format == QString::fromUtf8("੧, ੨, ੩, ...")) {
- d->formatSpecification = Gurumukhi;
- }
- else if (format == QString::fromUtf8("૧, ૨, ૩, ...")) {
- d->formatSpecification = Gujarati;
- }
- else if (format == QString::fromUtf8("১, ২, ৩, ...")) {
- d->formatSpecification = Bengali;
- }
- else {
- d->formatSpecification = Numeric;
- }
-
- //The style:num-prefix and style:num-suffix attributes specify what to display before and after the number.
- d->prefix = element.attributeNS(KoXmlNS::style, "num-prefix", d->prefix);
- d->suffix = element.attributeNS(KoXmlNS::style, "num-suffix", d->suffix);
-
- d->letterSynchronization = (element.attributeNS(KoXmlNS::style, "num-letter-sync", d->letterSynchronization ? "true" : "false") == "true");
-}
-
-void KoOdfNumberDefinition::saveOdf(KoXmlWriter *writer) const
-{
- if (!d->prefix.isNull()) {
- writer->addAttribute("style:num-prefix", d->prefix);
- }
-
- if (!d->suffix.isNull()) {
- writer->addAttribute("style:num-suffix", d->suffix);
- }
- QByteArray format;
- switch(d->formatSpecification) {
- case Numeric:
- format = "1";
- break;
- case AlphabeticLowerCase:
- format = "a";
- break;
- case AlphabeticUpperCase:
- format = "A";
- break;
- case RomanLowerCase:
- format = "i";
- break;
- case RomanUpperCase:
- format = "I";
- break;
- case ArabicAlphabet:
- format = "أ, ب, ت, ...";
- break;
- case Thai:
- format = "ก, ข, ค, ...";
- break;
- case Telugu:
- format = "౧, ౨, ౩, ...";
- break;
- case Tamil:
- format = "௧, ௨, ௪, ...";
- break;
- case Oriya:
- format = "୧, ୨, ୩, ...";
- break;
- case Malayalam:
- format = "൧, ൨, ൩, ...";
- break;
- case Kannada:
- format = "೧, ೨, ೩, ...";
- break;
- case Gurumukhi:
- format = "੧, ੨, ੩, ...";
- break;
- case Gujarati:
- format = "૧, ૨, ૩, ...";
- break;
- case Bengali:
- format = "১, ২, ৩, ...";
- break;
- case Empty:
- default:
- ;
- };
- if (!format.isNull()) {
- writer->addAttribute("style:num-format", format);
- }
-
- if (d->letterSynchronization) {
- writer->addAttribute("style:num-letter-sync", "true");
- }
-}
-
-QString KoOdfNumberDefinition::formattedNumber(int number, KoOdfNumberDefinition *defaultDefinition) const
-{
- switch(d->formatSpecification) {
- case Numeric:
- return QString::number(number);
- break;
-
- case AlphabeticLowerCase:
- {
- if (d->letterSynchronization) {
- int loop = (number-1)/26;
- int rem = (number-1)%26;
- QChar letter = (char)(rem+97);
- QString alpha;
- for (int i=0; i<=loop; i++) {
- alpha.append(letter);
- }
- return alpha;
- } else {
- int loop = (number-1)/26;
- QChar letter;
- QString alpha;
- if (loop>0) {
- letter = (char)(loop+96);
- alpha.append(letter);
- }
- int rem = (number -1)%26;
- letter = (char)(rem+97);
- alpha.append(letter);
- return alpha;
- }
- break;
- }
- case AlphabeticUpperCase:
- {
- if (d->letterSynchronization) {
- int loop = (number-1)/26;
- int rem = (number-1)%26;
- QChar letter = (char)(rem+65);
- QString alpha;
- for (int i=0; i<=loop; i++) {
- alpha.append(letter);
- }
- return alpha;
- } else {
- int loop = (number-1)/26;
- QChar letter;
- QString alpha;
- if (loop>0) {
- letter = (char)(loop+64);
- alpha.append(letter);
- }
- int rem = (number -1)%26;
- letter = (char)(rem+65);
- alpha.append(letter);
- return alpha;
- }
- break;
- }
- case RomanLowerCase:
- {
- QString roman;
- int loop = number/1000;
- for (int i=1; i<=loop && number/1000!=0; i++) {
- roman.append("m");
- }
- number = number%1000;
- loop = number/500;
- if (loop > 0) {
- roman.append("d");
- }
- number = number%500;
- loop = number/100;
- for (int i=1; i<=loop && number/100!=0; i++) {
- roman.append("c");
- }
- number = number%100;
- loop = number/50;
- if (loop > 0) {
- roman.append("l");
- }
- number = number%50;
- loop = number/10;
- for (int i=1; i<=loop && number/10!=0; i++) {
- roman.append("x");
- }
- number = number%10;
- if (number>=5 && number<=8) {
- loop = number%5;
- roman.append("v");
- for (int i=1;i<=loop;i++)
- roman.append("i");
- }
- else if (number==9) {
- roman.append("ix");
- }
- else if (number>=1 && number<=3) {
- for (int i=1; i<=number; i++)
- roman.append("i");
- }
- else if (number==4)
- roman.append("iv");
-
- return roman;
- break;
- }
- case RomanUpperCase:
- {
- QString roman;
- int loop = number/1000;
- for (int i=1; i<=loop && number/1000!=0; i++) {
- roman.append("M");
- }
- number = number%1000;
- loop = number/500;
- if (loop > 0) {
- roman.append("D");
- }
- number = number%500;
- loop = number/100;
- for (int i=1; i<=loop && number/100!=0; i++) {
- roman.append("C");
- }
- number = number%100;
- loop = number/50;
- if (loop > 0) {
- roman.append("L");
- }
- number = number%50;
- loop = number/10;
- for (int i=1; i<=loop && number/10!=0; i++) {
- roman.append("X");
- }
- number = number%10;
- if (number>=5 && number<=8) {
- loop = number%5;
- roman.append("V");
- for (int i=1; i<=loop; i++)
- roman.append("I");
- }
- else if (number==9) {
- roman.append("IX");
- }
- else if (number>=1 && number<=3) {
- for (int i=1; i<=number; i++)
- roman.append("I");
- }
- else if (number==4)
- roman.append("IV");
-
- return roman;
- }
- case Empty:
- if (defaultDefinition) {
- return defaultDefinition->formattedNumber(number);
- }
-
- break;
- default:
- ;
- };
-
- return "";
-}
-
-
-QString KoOdfNumberDefinition::prefix() const
-{
- return d->prefix;
-}
-
-void KoOdfNumberDefinition::setPrefix(const QString &prefix)
-{
- d->prefix = prefix;
-}
-
-QString KoOdfNumberDefinition::suffix() const
-{
- return d->suffix;
-}
-
-void KoOdfNumberDefinition::setSuffix(const QString &suffix)
-{
- d->suffix = suffix;
-}
-
-KoOdfNumberDefinition::FormatSpecification KoOdfNumberDefinition::formatSpecification() const
-{
- return d->formatSpecification;
-}
-
-void KoOdfNumberDefinition::setFormatSpecification(FormatSpecification formatSpecification)
-{
- d->formatSpecification = formatSpecification;
-}
-
-bool KoOdfNumberDefinition::letterSynchronization() const
-{
- return d->letterSynchronization;
-}
-
-void KoOdfNumberDefinition::setLetterSynchronization(bool letterSynchronization)
-{
- d->letterSynchronization = letterSynchronization;
-}
diff --git a/libs/odf/KoOdfNumberDefinition.h b/libs/odf/KoOdfNumberDefinition.h
deleted file mode 100644
index 8f37740e79..0000000000
--- a/libs/odf/KoOdfNumberDefinition.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/* This file is part of the KDE project
-
- Copyright (C) 2010 Boudewijn Rempt
- Copyright (C) 2011 Mojtaba Shahi Senobari <mojtaba.shahi3000@gmail.com>
-
- 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.
- */
-#ifndef KOODFNUMBERDEFINITION_H
-#define KOODFNUMBERDEFINITION_H
-
-#include <QString>
-
-#include "KoXmlReaderForward.h"
-#include "kritaodf_export.h"
-
-class KoXmlWriter;
-
-/**
- * Load and save the ODF numbering scheme according to section 12.
- *
- * The OpenDocument number format consists of three parts:
- * • Prefix – the text that is displayed before the number
- * • Display format specification, for example, A, B, C, or 1, 2, 3
- * • Suffix – the text that is displayed after the number
- */
-class KRITAODF_EXPORT KoOdfNumberDefinition
-{
-public:
- explicit KoOdfNumberDefinition();
- ~KoOdfNumberDefinition();
- KoOdfNumberDefinition(const KoOdfNumberDefinition &other);
- KoOdfNumberDefinition &operator=(const KoOdfNumberDefinition &other);
-
- /**
- * load the number definition element
- */
- void loadOdf(const KoXmlElement &element);
-
- /**
- * save the number definition element
- */
- void saveOdf(KoXmlWriter *writer) const;
-
- /**
- * create a string representation of the specified number.
- */
- QString formattedNumber(int number, KoOdfNumberDefinition *defaultDefinition = 0) const;
-
- /**
- * The style:num-prefix and style:num-suffix attributes specify what to display before and
- * after the number.
- *
- * If the prefix and suffix do not contain alphanumeric characters, an [XSLT] format attribute can
- * be created from the OpenDocument attributes by concatenating the values of the style:num-
- * prefix, style:num-format, and style:num-suffix attributes.
- */
- QString prefix() const;
- void setPrefix(const QString &prefix);
-
- QString suffix() const;
- void setSuffix(const QString &suffix);
-
-
- /**
- * The style:num-format attribute specifies the format of the number in the same way as the
- * [XSLT] format attribute. The number styles supported are as follows:
- * • Numeric: 1, 2, 3, ...
- * • Alphabetic: a, b, c, ... or A, B, C, ...
- * • Roman: i, ii, iii, iv, ... or I, II, III, IV,...
- *
- * The value of this attribute can be "1", "a", "A", "i", or "I". For some
- * elements, the attribute value also can be empty. In this case, no number
- * is displayed.
- */
- enum FormatSpecification {
- Numeric,
- AlphabeticLowerCase,
- AlphabeticUpperCase,
- RomanLowerCase,
- RomanUpperCase,
- ArabicAlphabet,
- Thai,
- Abjad,
- AbjadMinor,
- Tibetan,
- Telugu,
- Tamil,
- Oriya,
- Malayalam,
- Kannada,
- Gurumukhi,
- Gujarati,
- Bengali,
- Empty
- };
-
- FormatSpecification formatSpecification() const;
- void setFormatSpecification(FormatSpecification formatSpecification);
-
- /**
- * Letter synchronization
- *
- * If letters are used in alphabetical order for numbering, there are two ways to process overflows
- * within a digit, as follows:
- * • A new digit is inserted. Its start value is A, and it is incremented every time an overflow occurs
- * in the following digit. The numbering sequence in this case is something like a,b,c, ..., z, aa,
- * ab, ac, ...,az, ba, ..., and so on.
- * • A new digit is inserted that always has the same value as the following digit. The numbering
- * sequence in this case is something like a, b, c, ..., z, aa, bb, cc, ..., zz, aaa, ..., and so on. This
- * is called letter synchronization.
- *
- * The style:num-letter-sync specifies whether letter synchronization shall take place.
- */
- bool letterSynchronization() const;
- void setLetterSynchronization(bool letterSynchronization);
-
-private:
-
- class Private;
- Private * const d;
-
-
-};
-
-#endif // KOODFNUMBERDEFINITION_H
diff --git a/libs/odf/KoOdfNumberStyles.cpp b/libs/odf/KoOdfNumberStyles.cpp
deleted file mode 100644
index 60fb83838d..0000000000
--- a/libs/odf/KoOdfNumberStyles.cpp
+++ /dev/null
@@ -1,1408 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2004-2006 David Faure <faure@kde.org>
- Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
-
- 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 "KoOdfNumberStyles.h"
-
-#include "KoGenStyles.h"
-#include "KoXmlNS.h"
-
-#include <QBuffer>
-#include <QDateTime>
-#include <QTime>
-
-#include <klocalizedstring.h>
-#include <OdfDebug.h>
-
-#include <KoXmlReader.h>
-#include <KoXmlWriter.h>
-
-#include <math.h>
-
-namespace KoOdfNumberStyles
-{
-
- static bool saveOdfTimeFormat(KoXmlWriter &elementWriter, QString &format, QString &text, bool &antislash);
- static void parseOdfDatelocale(KoXmlWriter &elementWriter, QString &format, QString &text);
- static bool saveOdflocaleTimeFormat(KoXmlWriter &elementWriter, QString &format, QString &text);
- static void parseOdfTimelocale(KoXmlWriter &elementWriter, QString &format, QString &text);
- static void addCalligraNumericStyleExtension(KoXmlWriter &elementWriter, const QString &_suffix, const QString &_prefix);
-
-QString format(const QString &value, const NumericStyleFormat &format)
-{
- switch (format.type) {
- case Number: {
- bool ok;
- qreal v = value.toDouble(&ok);
- return ok ? formatNumber(v, format.formatStr, format.precision) : value;
- } break;
- case Boolean: {
- return formatBoolean(value, format.formatStr);
- } break;
- case Date: {
- bool ok;
- int v = value.toInt(&ok);
- return ok ? formatDate(v, format.formatStr) : value;
- } break;
- case Time: {
- bool ok;
- qreal v = value.toDouble(&ok);
- return ok ? formatTime(v, format.formatStr) : value;
- } break;
- case Percentage: {
- return formatPercent(value, format.formatStr, format.precision);
- } break;
- case Currency: {
- bool ok;
- qreal v = value.toDouble(&ok);
- return ok ? formatCurrency(v, format.formatStr, format.currencySymbol, format.precision) : value;
- } break;
- case Scientific: {
- bool ok;
- qreal v = value.toDouble(&ok);
- return ok ? formatScientific(v, format.formatStr, format.precision) : value;
- } break;
- case Fraction: {
- bool ok;
- qreal v = value.toDouble(&ok);
- return ok ? formatFraction(v, format.formatStr) : value;
- } break;
- case Text: {
- return value;
- } break;
- }
- return value;
-}
-
-QString formatNumber(qreal value, const QString &format, int precision)
-{
- QString result;
- int start = 0;
- bool showNegative = format.startsWith('-');
- if (showNegative)
- start = 1;
- for (int i = start; i < format.length(); ++i) {
- QChar c = format[ i ];
- switch (c.unicode()) {
- case '.':
- case ',':
- case '#':
- case '0':
- case '?': {
-// bool grouping = false;
- bool gotDot = false;
- bool gotE = false;
- bool gotFraction = false;
- int decimalPlaces = 0;
- int integerDigits = 0;
- int optionalDecimalPlaces = 0;
- int optionalIntegerDigits = 0;
- int exponentDigits = 0;
- int numeratorDigits = 0;
- int denominatorDigits = 0;
- char ch = format[ i ].toLatin1();
- do {
- if (ch == '.') {
- gotDot = true;
- } else if (ch == ',') {
- // grouping = true;
- } else if (ch == 'E' || ch == 'e') {
- //SET_TYPE_OR_RETURN(KoGenStyle::NumericScientificStyle);
-
- if (i >= format.length() - 1) break;
- const char chN = format[ i + 1 ].toLatin1();
- if (chN == '-' || chN == '+') {
- gotE = true;
- ++i;
- }
- } else if (ch == '0' && gotE) {
- ++exponentDigits;
- } else if (ch == '0' && !gotDot && !gotFraction) {
- ++integerDigits;
- } else if (ch == '#' && !gotDot && !gotFraction) {
- ++optionalIntegerDigits;
- } else if (ch == '0' && gotDot && !gotFraction) {
- ++decimalPlaces;
- } else if (ch == '#' && gotDot && !gotFraction) {
- ++optionalDecimalPlaces;
- } else if (ch == '?' && !gotFraction) {
- ++numeratorDigits;
- } else if (ch == '?' && gotFraction) {
- ++denominatorDigits;
- } else if (ch == '/') {
- //SET_TYPE_OR_RETURN(KoGenStyle::NumericFractionStyle);
- if (gotDot) return QString(); // invalid
- gotFraction = true;
- }
-
- if (i >= format.length() - 1) break;
- ch = format[ ++i ].toLatin1();
-
- if (ch == ' ') {
- // spaces are not allowed - but there's an exception: if this is a fraction. Let's check for '?' or '/'
- const char c = format[ i + 1 ].toLatin1();
- if (c == '?' || c == '/')
- ch = format[ ++i ].toLatin1();
- }
- } while (i < format.length() && (ch == '.' || ch == ',' || ch == '#' || ch == '0' || ch == 'E' || ch == 'e' || ch == '?' || ch == '/'));
- if (!(ch == '.' || ch == ',' || ch == '#' || ch == '0' || ch == 'E' || ch == 'e' || ch == '?' || ch == '/')) {
- --i;
- }
-
- QString v(QString::number(qAbs(value), 'f', precision >= 0 ? precision : (optionalDecimalPlaces + decimalPlaces)));
- int p = v.indexOf('.');
- QString integerValue = p >= 0 ? v.left(p) : v;
- if (integerValue.length() < integerDigits)
- integerValue.prepend(QString().fill('0', integerDigits - integerValue.length()));
- QString decimalValue = p >= 0 ? v.mid(p + 1) : QString();
- if (decimalValue.length() < decimalPlaces)
- decimalValue.append(QString().fill('0', decimalPlaces - decimalValue.length()));
-
- if (showNegative && value < 0)
- result.append('-');
- result.append(integerValue);
- if (!decimalValue.isEmpty())
- result.append('.' + decimalValue);
- } break;
- case '\\': { // backslash escapes the next char
- if (i < format.length() - 1) {
- result.append(format[ ++i ]);
- }
- } break;
- default:
- result.append(c);
- break;
- }
- }
-
- return result;
-}
-
-QString formatBoolean(const QString &value, const QString &format)
-{
- Q_UNUSED(format);
- bool ok = false;
- int v = value.toInt(&ok);
- return ok && v != 0 ? "TRUE" : "FALSE";
-}
-
-QString formatDate(int value, const QString &format)
-{
- QDateTime dt(QDate(1899, 12, 30)); // reference date
- dt = dt.addDays(value);
- return dt.toString(format);
-}
-
-QString formatTime(qreal value, const QString &format)
-{
- QTime t(0,0,0);
- t = t.addSecs(qRound(value * 86400.0)); // 24 hours
- return t.toString(format);
-}
-
-QString formatCurrency(qreal value, const QString &format, const QString& currencySymbol, int precision)
-{
- if (currencySymbol == "CCC") // undocumented hack, see doc attached to comment 6 at bug 282972
- return QLocale().toCurrencyString(value, "USD");
- if (format.isEmpty()) // no format means use locale format
- return QLocale().toCurrencyString(value, currencySymbol.isEmpty() ? QLocale().currencySymbol(QLocale::CurrencySymbol)
- : currencySymbol);
- return formatNumber(value, format, precision);
-}
-
-QString formatScientific(qreal value, const QString &format, int precision)
-{
- Q_UNUSED(format);
- QString v(QString::number(value, 'E', precision));
- int pos = v.indexOf('.');
- if (pos != -1) {
- v.replace(pos, 1, QLocale().decimalPoint());
- }
- return v;
-}
-
-QString formatFraction(qreal value, const QString &format)
-{
- QString prefix = value < 0 ? "-" : "";
- value = fabs(value);
- qreal result = value - floor(value);
-
- if (result == 0) // return w/o fraction part if not necessary
- return prefix + QString::number(value);
-
- int index = 0;
- int limit = 0;
- if (format.endsWith("/2")) {
- index = 2;
- } else if (format.endsWith("/4")) {
- index = 4;
- } else if (format.endsWith("/8")) {
- index = 8;
- } else if (format.endsWith("/16")) {
- index = 16;
- } else if (format.endsWith("/10")) {
- index = 10;
- } else if (format.endsWith("/100")) {
- index = 100;
- } else if (format.endsWith("/?")) {
- index = 3;
- limit = 9;
- } else if (format.endsWith("/??")) {
- index = 4;
- limit = 99;
- } else if (format.endsWith("/???")) {
- index = 5;
- limit = 999;
- } else { // fallback
- return prefix + QString::number(value);
- }
-
- // handle halves, quarters, tenths, ...
- if (!format.endsWith("/?") && !format.endsWith("/??") && !format.endsWith("/???")) {
- qreal calc = 0;
- int index1 = 0;
- qreal diff = result;
- for (int i = 1; i <= index; i++) {
- calc = i * 1.0 / index;
- if (fabs(result - calc) < diff) {
- index1 = i;
- diff = fabs(result - calc);
- }
- }
- if (index1 == 0)
- return prefix + QString("%1").arg(floor(value));
- if (index1 == index)
- return prefix + QString("%1").arg(floor(value) + 1);
- if (floor(value) == 0)
- return prefix + QString("%1/%2").arg(index1).arg(index);
- return prefix + QString("%1 %2/%3").arg(floor(value)).arg(index1).arg(index);
- }
-
- // handle Format::fraction_one_digit, Format::fraction_two_digit and Format::fraction_three_digit style
- qreal target = result;
- qreal numerator = 1;
- qreal denominator = 1;
- qreal bestNumerator = 0;
- qreal bestDenominator = 1;
- qreal bestDist = target;
-
- // as soon as either numerator or denominator gets above the limit, we're done
- while (numerator <= limit && denominator <= limit) {
- qreal dist = fabs((numerator / denominator) - target);
- if (dist < bestDist) {
- bestDist = dist;
- bestNumerator = numerator;
- bestDenominator = denominator;
- }
- if (numerator / denominator > target) {
- ++denominator;
- } else {
- ++numerator;
- }
- }
-
- if (bestNumerator == 0)
- return prefix + QString().setNum(floor(value));
- if (bestDenominator == bestNumerator)
- return prefix + QString().setNum(floor(value + 1));
- if (floor(value) == 0)
- return prefix + QString("%1/%2").arg(bestNumerator).arg(bestDenominator);
- return prefix + QString("%1 %2/%3").arg(floor(value)).arg(bestNumerator).arg(bestDenominator);
-
-}
-
-QString formatPercent(const QString &value, const QString &/*format*/, int precision)
-{
- if (value.contains('.')) {
- bool ok;
- qreal v = value.toDouble(&ok);
- if (ok)
- return QString::number(v * 100., 'f', precision) + QLatin1String("%");
- }
- return value;
-}
-
-// OO spec 2.5.4. p68. Conversion to Qt format: see qdate.html
-// OpenCalcImport::loadFormat has similar code, but slower, intermixed with other stuff,
-// lacking long-textual forms.
-QPair<QString, NumericStyleFormat> loadOdfNumberStyle(const KoXmlElement &parent)
-{
- NumericStyleFormat dataStyle;
-
- const QString localName = parent.localName();
- if (localName == "number-style")
- dataStyle.type = Number;
- else if (localName == "currency-style")
- dataStyle.type = Currency;
- else if (localName == "percentage-style")
- dataStyle.type = Percentage;
- else if (localName == "boolean-style")
- dataStyle.type = Boolean;
- else if (localName == "text-style")
- dataStyle.type = Text;
- else if (localName == "date-style")
- dataStyle.type = Date;
- else if (localName == "time-style")
- dataStyle.type = Time;
-
- QString format;
- int precision = -1;
- int leadingZ = 1;
-
- bool thousandsSep = false;
- //todo negred
- //bool negRed = false;
- bool ok = false;
- int i = 0;
- KoXmlElement e;
- QString prefix;
- QString suffix;
- forEachElement(e, parent) {
- if (e.namespaceURI() != KoXmlNS::number)
- continue;
- QString localName = e.localName();
- const QString numberStyle = e.attributeNS(KoXmlNS::number, "style", QString());
- const bool shortForm = numberStyle == "short" || numberStyle.isEmpty();
- if (localName == "day") {
- format += shortForm ? "d" : "dd";
- } else if (localName == "day-of-week") {
- format += shortForm ? "ddd" : "dddd";
- } else if (localName == "month") {
- if (e.attributeNS(KoXmlNS::number, "possessive-form", QString()) == "true") {
- format += shortForm ? "PPP" : "PPPP";
- }
- // TODO the spec has a strange mention of number:format-source
- else if (e.attributeNS(KoXmlNS::number, "textual", QString()) == "true") {
- bool isExtraShort = false; // find out if we have to use the extra-short month name (just 1st letter)
- if (e.attributeNS(KoXmlNS::calligra, "number-length", QString()) == "extra-short") {
- isExtraShort = true;
- }
-
- if (!isExtraShort) { // for normal month format (first 3 letters or complete name)
- format += shortForm ? "MMM" : "MMMM";
- } else { // for the extra-short month name use 'X' as a special mark
- format += "X";
- }
- } else { // month number
- format += shortForm ? "M" : "MM";
- }
- } else if (localName == "year") {
- format += shortForm ? "yy" : "yyyy";
- } else if (localName == "era") {
- //TODO I don't know what is it... (define into oo spec)
- } else if (localName == "week-of-year" || localName == "quarter") {
- // ### not supported in Qt
- } else if (localName == "hours") {
- format += shortForm ? "h" : "hh";
- } else if (localName == "minutes") {
- format += shortForm ? "m" : "mm";
- } else if (localName == "seconds") {
- format += shortForm ? "s" : "ss";
- } else if (localName == "am-pm") {
- format += "ap";
- } else if (localName == "text") { // literal
- format += e.text();
- } else if (localName == "suffix") {
- suffix = e.text();
- debugOdf << " suffix :" << suffix;
- } else if (localName == "prefix") {
- prefix = e.text();
- debugOdf << " prefix :" << prefix;
- } else if (localName == "currency-symbol") {
- dataStyle.currencySymbol = e.text();
- debugOdf << " currency-symbol:" << dataStyle.currencySymbol;
- format += e.text();
- //TODO
- // number:language="de" number:country="DE">€</number:currency-symbol>
- // Stefan: localization of the symbol?
- } else if (localName == "number") {
- if (e.hasAttributeNS(KoXmlNS::number, "grouping")) {
- thousandsSep = e.attributeNS(KoXmlNS::number, "grouping", QString()).toLower() == "true";
- }
- if (e.hasAttributeNS(KoXmlNS::number, "decimal-places")) {
- int d = e.attributeNS(KoXmlNS::number, "decimal-places", QString()).toInt(&ok);
- if (ok)
- precision = d;
- }
- if (e.hasAttributeNS(KoXmlNS::number, "min-integer-digits")) {
- int d = e.attributeNS(KoXmlNS::number, "min-integer-digits", QString()).toInt(&ok);
- if (ok)
- leadingZ = d;
- }
- if (thousandsSep && leadingZ <= 3) {
- format += "#,";
- for (i = leadingZ; i <= 3; ++i)
- format += '#';
- }
- for (i = 1; i <= leadingZ; ++i) {
- format += '0';
- if ((i % 3 == 0) && thousandsSep)
- format = + ',' ;
- }
- if (precision > -1) {
- format += '.';
- for (i = 0; i < precision; ++i)
- format += '0';
- }
- } else if (localName == "scientific-number") {
- if (dataStyle.type == Number)
- dataStyle.type = Scientific;
- int exp = 2;
-
- if (e.hasAttributeNS(KoXmlNS::number, "decimal-places")) {
- int d = e.attributeNS(KoXmlNS::number, "decimal-places", QString()).toInt(&ok);
- if (ok)
- precision = d;
- }
-
- if (e.hasAttributeNS(KoXmlNS::number, "min-integer-digits")) {
- int d = e.attributeNS(KoXmlNS::number, "min-integer-digits", QString()).toInt(&ok);
- if (ok)
- leadingZ = d;
- }
-
- if (e.hasAttributeNS(KoXmlNS::number, "min-exponent-digits")) {
- int d = e.attributeNS(KoXmlNS::number, "min-exponent-digits", QString()).toInt(&ok);
- if (ok)
- exp = d;
- if (exp <= 0)
- exp = 1;
- }
-
- if (e.hasAttributeNS(KoXmlNS::number, "grouping")) {
- thousandsSep = e.attributeNS(KoXmlNS::number, "grouping", QString()).toLower() == "true";
- }
-
- if (thousandsSep && leadingZ <= 3) {
- format += "#,";
- for (i = leadingZ; i <= 3; ++i)
- format += '#';
- }
-
- for (i = 1; i <= leadingZ; ++i) {
- format += '0';
- if ((i % 3 == 0) && thousandsSep)
- format += ',';
- }
-
- if (precision > -1) {
- format += '.';
- for (i = 0; i < precision; ++i)
- format += '0';
- }
-
- format += "E+";
- for (i = 0; i < exp; ++i)
- format += '0';
- } else if (localName == "fraction") {
- if (dataStyle.type == Number)
- dataStyle.type = Fraction;
- int integer = 0;
- int numerator = 1;
- int denominator = 1;
- int denominatorValue = 0;
- if (e.hasAttributeNS(KoXmlNS::number, "min-integer-digits")) {
- int d = e.attributeNS(KoXmlNS::number, "min-integer-digits", QString()).toInt(&ok);
- if (ok)
- integer = d;
- }
- if (e.hasAttributeNS(KoXmlNS::number, "min-numerator-digits")) {
- int d = e.attributeNS(KoXmlNS::number, "min-numerator-digits", QString()).toInt(&ok);
- if (ok)
- numerator = d;
- }
- if (e.hasAttributeNS(KoXmlNS::number, "min-denominator-digits")) {
- int d = e.attributeNS(KoXmlNS::number, "min-denominator-digits", QString()).toInt(&ok);
- if (ok)
- denominator = d;
- }
- if (e.hasAttributeNS(KoXmlNS::number, "denominator-value")) {
- int d = e.attributeNS(KoXmlNS::number, "denominator-value", QString()).toInt(&ok);
- if (ok)
- denominatorValue = d;
- }
- if (e.hasAttributeNS(KoXmlNS::number, "grouping")) {
- thousandsSep = e.attributeNS(KoXmlNS::number, "grouping", QString()).toLower() == "true";
- }
-
- for (i = 0; i < integer; ++i)
- format += '#';
-
- format += ' ';
-
- for (i = 0; i < numerator; ++i)
- format += '?';
-
- format += '/';
-
- if (denominatorValue != 0)
- format += QString::number(denominatorValue);
- else {
- for (i = 0; i < denominator; ++i)
- format += '?';
- }
- }
-
- // stylesmap's are embedded into a style and are pointing to another style that
- // should be used insteat ot this style if the defined condition is true. E.g.;
- // <number:number-style style:name="N139P0" style:volatile="true"/>
- // <number:number-style style:name="N139P1" style:volatile="true"/>
- // <number:number-style style:name="N139P2" style:volatile="true"/>
- // <number:text-style style:name="N139">
- // <style:map style:condition="value()&gt;0" style:apply-style-name="N139P0"/>
- // <style:map style:condition="value()&lt;0" style:apply-style-name="N139P1"/>
- // <style:map style:condition="value()=0" style:apply-style-name="N139P2"/>
- // </number:text-style>
- for (KoXmlNode node(e); !node.isNull(); node = node.nextSibling()) {
- KoXmlElement elem = node.toElement();
- if (elem.namespaceURI() == KoXmlNS::style && elem.localName() == "map") {
- QString condition, applyStyleName;
- if (elem.hasAttributeNS(KoXmlNS::style, "condition"))
- condition = elem.attributeNS(KoXmlNS::style, "condition");
- if (elem.hasAttributeNS(KoXmlNS::style, "apply-style-name"))
- applyStyleName = elem.attributeNS(KoXmlNS::style, "apply-style-name");
- dataStyle.styleMaps.append( QPair<QString,QString>(condition,applyStyleName) );
- }
- }
- }
-
- const QString styleName = parent.attributeNS(KoXmlNS::style, "name", QString());
-
-debugOdf<<"99 *****************************************************************************";
-//Q_ASSERT(false);
- debugOdf << "data style:" << styleName << " qt format=" << format;
- if (!prefix.isEmpty()) {
- debugOdf << " format.left( prefix.length() ) :" << format.left(prefix.length()) << " prefix :" << prefix;
- if (format.left(prefix.length()) == prefix) {
- format = format.right(format.length() - prefix.length());
- } else
- prefix.clear();
- }
- if (!suffix.isEmpty()) {
- debugOdf << "format.right( suffix.length() ) :" << format.right(suffix.length()) << " suffix :" << suffix;
- if (format.right(suffix.length()) == suffix) {
- format = format.left(format.length() - suffix.length());
- } else
- suffix.clear();
- }
-
- dataStyle.formatStr = format;
- dataStyle.prefix = prefix;
- dataStyle.suffix = suffix;
- dataStyle.precision = precision;
- dataStyle.thousandsSep = thousandsSep;
- debugOdf << " finish insert format :" << format << " prefix :" << prefix << " suffix :" << suffix;
- return QPair<QString, NumericStyleFormat>(styleName, dataStyle);
-}
-
-QString saveOdfNumberStyle(KoGenStyles &mainStyles, const NumericStyleFormat &format)
-{
- QString styleName;
- switch (format.type) {
- case KoOdfNumberStyles::Number: {
- styleName = KoOdfNumberStyles::saveOdfNumberStyle(mainStyles, format.formatStr, format.prefix, format.suffix, format.thousandsSep);
- } break;
- case KoOdfNumberStyles::Boolean: {
- styleName = KoOdfNumberStyles::saveOdfBooleanStyle(mainStyles, format.formatStr, format.prefix, format.suffix);
- } break;
- case KoOdfNumberStyles::Date: {
- bool localeFormat = format.formatStr.isEmpty();
- styleName = KoOdfNumberStyles::saveOdfDateStyle(mainStyles, format.formatStr, localeFormat, format.prefix, format.suffix);
- } break;
- case KoOdfNumberStyles::Time: {
- bool localeFormat = format.formatStr.isEmpty();
- styleName = KoOdfNumberStyles::saveOdfTimeStyle(mainStyles, format.formatStr, localeFormat, format.prefix, format.suffix);
- } break;
- case KoOdfNumberStyles::Percentage: {
- styleName = KoOdfNumberStyles::saveOdfPercentageStyle(mainStyles, format.formatStr, format.prefix, format.suffix);
- } break;
- case KoOdfNumberStyles::Currency: {
- styleName = KoOdfNumberStyles::saveOdfCurrencyStyle(mainStyles, format.formatStr, format.currencySymbol, format.prefix, format.suffix);
- } break;
- case KoOdfNumberStyles::Scientific: {
- styleName = KoOdfNumberStyles::saveOdfScientificStyle(mainStyles, format.formatStr, format.prefix, format.suffix);
- } break;
- case KoOdfNumberStyles::Fraction: {
- styleName = KoOdfNumberStyles::saveOdfFractionStyle(mainStyles, format.formatStr, format.prefix, format.suffix);
- } break;
- case KoOdfNumberStyles::Text: {
- styleName = KoOdfNumberStyles::saveOdfTextStyle(mainStyles, format.formatStr, format.prefix, format.suffix);
- } break;
- }
- return styleName;
-}
-
-#define addTextNumber( text, elementWriter ) { \
- if ( !text.isEmpty() ) \
- { \
- elementWriter.startElement( "number:text" ); \
- elementWriter.addTextNode( text ); \
- elementWriter.endElement(); \
- text.clear(); \
- } \
- }
-
-void parseOdfTimelocale(KoXmlWriter &elementWriter, QString &format, QString &text)
-{
- debugOdf << "parseOdfTimelocale(KoXmlWriter &elementWriter, QString & format, QString & text ) :" << format;
- do {
- if (!saveOdflocaleTimeFormat(elementWriter, format, text)) {
- text += format[0];
- format.remove(0, 1);
- }
- } while (format.length() > 0);
- addTextNumber(text, elementWriter);
-}
-
-bool saveOdflocaleTimeFormat(KoXmlWriter &elementWriter, QString &format, QString &text)
-{
- bool changed = false;
- if (format.startsWith("%H")) { //hh
- //hour in 24h
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:hours");
- elementWriter.addAttribute("number:style", "long");
- elementWriter.endElement();
- format.remove(0, 2);
- changed = true;
- } else if (format.startsWith("%k")) { //h
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:hours");
- elementWriter.addAttribute("number:style", "short");
- elementWriter.endElement();
- format.remove(0, 2);
- changed = true;
- } else if (format.startsWith("%I")) { // ?????
- //TODO hour in 12h
- changed = true;
- } else if (format.startsWith("%l")) {
- //TODO hour in 12h with 1 digit
- changed = true;
- } else if (format.startsWith("%M")) { // mm
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:minutes");
- elementWriter.addAttribute("number:style", "long");
- elementWriter.endElement();
- format.remove(0, 2);
- changed = true;
-
- } else if (format.startsWith("%S")) { //ss
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:seconds");
- elementWriter.addAttribute("number:style", "long");
- elementWriter.endElement();
- format.remove(0, 2);
- changed = true;
- } else if (format.startsWith("%p")) {
- //TODO am or pm
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:am-pm");
- elementWriter.endElement();
- format.remove(0, 2);
- changed = true;
- }
- return changed;
-}
-
-
-bool saveOdfTimeFormat(KoXmlWriter &elementWriter, QString &format, QString &text, bool &antislash)
-{
- bool changed = false;
- //we can also add time to date.
- if (antislash) {
- text += format[0];
- format.remove(0, 1);
- antislash = false;
- changed = true;
- } else if (format.startsWith("hh")) {
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:hours");
- elementWriter.addAttribute("number:style", "long");
- elementWriter.endElement();
- format.remove(0, 2);
- changed = true;
- } else if (format.startsWith('h')) {
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:hours");
- elementWriter.addAttribute("number:style", "short");
- elementWriter.endElement();
- format.remove(0, 1);
- changed = true;
- } else if (format.startsWith("mm")) {
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:minutes");
- elementWriter.addAttribute("number:style", "long");
- elementWriter.endElement();
- format.remove(0, 2);
- changed = true;
- } else if (format.startsWith('m')) {
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:minutes");
- elementWriter.addAttribute("number:style", "short");
- elementWriter.endElement();
- format.remove(0, 1);
- changed = true;
- } else if (format.startsWith("ss")) {
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:seconds");
- elementWriter.addAttribute("number:style", "long");
- elementWriter.endElement();
- format.remove(0, 2);
- changed = true;
- } else if (format.startsWith('s')) {
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:seconds");
- elementWriter.addAttribute("number:style", "short");
- elementWriter.endElement();
- format.remove(0, 1);
- changed = true;
- } else if (format.startsWith("ap")) {
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:am-pm");
- elementWriter.endElement();
- format.remove(0, 2);
- changed = true;
- }
- return changed;
-}
-
-QString saveOdfTimeStyle(KoGenStyles &mainStyles, const QString &_format, bool localeFormat,
- const QString &_prefix, const QString &_suffix)
-{
- Q_UNUSED(_prefix);
- Q_UNUSED(_suffix);
- //debugOdf << "QString KoOdfNumberStyles::saveOdfTimeStyle( KoGenStyles &mainStyles, const QString & _format ) :" << _format;
- QString format(_format);
- KoGenStyle currentStyle(KoGenStyle::NumericTimeStyle);
- QBuffer buffer;
- buffer.open(QIODevice::WriteOnly);
- KoXmlWriter elementWriter(&buffer); // TODO pass indentation level
- QString text;
- if (localeFormat) {
- parseOdfTimelocale(elementWriter, format, text);
- } else {
- bool antislash = false;
- do {
- if (!saveOdfTimeFormat(elementWriter, format, text, antislash)) {
- QString elem(format[0]);
- format.remove(0, 1);
- if (elem == "\\") {
- antislash = true;
- } else {
- text += elem;
- antislash = false;
- }
- }
- } while (format.length() > 0);
- addTextNumber(text, elementWriter);
- }
- QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
- currentStyle.addChildElement("number", elementContents);
- return mainStyles.insert(currentStyle, "N");
-}
-
-//convert locale string to good format
-void parseOdfDatelocale(KoXmlWriter &elementWriter, QString &format, QString &text)
-{
- debugOdf << format;
- do {
- if (format.startsWith("%Y")) {
- addTextNumber(text, elementWriter);
- elementWriter.startElement("number:year");
- elementWriter.addAttribute("number:style", "long");
- elementWriter.endElement();
- format.remove(0, 2);
- } else if (format.startsWith("%y")) {
-
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:year");
- elementWriter.addAttribute("number:style", "short");
- elementWriter.endElement();
- format.remove(0, 2);
- } else if (format.startsWith("%n")) {
- addTextNumber(text, elementWriter);
- elementWriter.startElement("number:month");
- elementWriter.addAttribute("number:style", "short");
- elementWriter.addAttribute("number:textual", "false");
- elementWriter.endElement();
- format.remove(0, 2);
- } else if (format.startsWith("%m")) {
- addTextNumber(text, elementWriter);
- elementWriter.startElement("number:month");
- elementWriter.addAttribute("number:style", "long");
- elementWriter.addAttribute("number:textual", "false"); //not necessary remove it
- elementWriter.endElement();
- format.remove(0, 2);
- } else if (format.startsWith("%e")) {
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:day");
- elementWriter.addAttribute("number:style", "short");
- elementWriter.endElement();
- format.remove(0, 2);
- } else if (format.startsWith("%d")) {
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:day");
- elementWriter.addAttribute("number:style", "long");
- elementWriter.endElement();
- format.remove(0, 2);
- } else if (format.startsWith("%b")) {
- addTextNumber(text, elementWriter);
- elementWriter.startElement("number:month");
- elementWriter.addAttribute("number:style", "short");
- elementWriter.addAttribute("number:textual", "true");
- elementWriter.endElement();
- format.remove(0, 2);
- } else if (format.startsWith("%B")) {
- addTextNumber(text, elementWriter);
- elementWriter.startElement("number:month");
- elementWriter.addAttribute("number:style", "long");
- elementWriter.addAttribute("number:textual", "true");
- elementWriter.endElement();
- format.remove(0, 2);
- } else if (format.startsWith("%a")) {
- addTextNumber(text, elementWriter);
- elementWriter.startElement("number:day-of-week");
- elementWriter.addAttribute("number:style", "short");
- elementWriter.endElement();
-
- format.remove(0, 2);
- } else if (format.startsWith("%A")) {
- addTextNumber(text, elementWriter);
- elementWriter.startElement("number:day-of-week");
- elementWriter.addAttribute("number:style", "long");
- elementWriter.endElement();
- format.remove(0, 2);
- } else {
- if (!saveOdflocaleTimeFormat(elementWriter, format, text)) {
- text += format[0];
- format.remove(0, 1);
- }
- }
- } while (format.length() > 0);
- addTextNumber(text, elementWriter);
-}
-
-QString saveOdfDateStyle(KoGenStyles &mainStyles, const QString &_format, bool localeFormat,
- const QString &_prefix, const QString &_suffix)
-{
- Q_UNUSED(_prefix);
- Q_UNUSED(_suffix);
- //debugOdf << _format;
- QString format(_format);
-
- // Not supported into Qt: "era" "week-of-year" "quarter"
-
- KoGenStyle currentStyle(KoGenStyle::NumericDateStyle);
- QBuffer buffer;
- buffer.open(QIODevice::WriteOnly);
- KoXmlWriter elementWriter(&buffer); // TODO pass indentation level
- QString text;
- if (localeFormat) {
- parseOdfDatelocale(elementWriter, format, text);
- } else {
- bool antislash = false;
- do {
- if (antislash) {
- text += format[0];
- format.remove(0, 1);
- }
- //TODO implement loading ! What is it ?
- else if (format.startsWith("MMMMM")) { // MMMMM is extra-short month name (only 1st character)
- addTextNumber(text, elementWriter);
- elementWriter.startElement("number:month");
- elementWriter.addAttribute("number:textual", "true");
- elementWriter.addAttribute("calligra:number-length", "extra-short");
- elementWriter.endElement();
- format.remove(0, 5);
- } else if (format.startsWith("MMMM")) {
- addTextNumber(text, elementWriter);
- elementWriter.startElement("number:month");
- elementWriter.addAttribute("number:style", "long");
- elementWriter.addAttribute("number:textual", "true");
- elementWriter.endElement();
- format.remove(0, 4);
- } else if (format.startsWith("MMM")) {
- addTextNumber(text, elementWriter);
- elementWriter.startElement("number:month");
- elementWriter.addAttribute("number:style", "short");
- elementWriter.addAttribute("number:textual", "true");
- elementWriter.endElement();
- format.remove(0, 3);
- } else if (format.startsWith("MM")) {
- addTextNumber(text, elementWriter);
- elementWriter.startElement("number:month");
- elementWriter.addAttribute("number:style", "long");
- elementWriter.addAttribute("number:textual", "false"); //not necessary remove it
- elementWriter.endElement();
- format.remove(0, 2);
- } else if (format.startsWith('M')) {
- addTextNumber(text, elementWriter);
- elementWriter.startElement("number:month");
- elementWriter.addAttribute("number:style", "short");
- elementWriter.addAttribute("number:textual", "false");
- elementWriter.endElement();
- format.remove(0, 1);
- } else if (format.startsWith("PPPP")) {
- addTextNumber(text, elementWriter);
- //<number:month number:possessive-form="true" number:textual="true" number:style="long"/>
- elementWriter.startElement("number:month");
- elementWriter.addAttribute("number:style", "short");
- elementWriter.addAttribute("number:textual", "false");
- elementWriter.addAttribute("number:possessive-form", "true");
- elementWriter.endElement();
- format.remove(0, 4);
- } else if (format.startsWith("PPP")) {
- addTextNumber(text, elementWriter);
- //<number:month number:possessive-form="true" number:textual="true" number:style="short"/>
- elementWriter.startElement("number:month");
- elementWriter.addAttribute("number:possessive-form", "true");
-
- elementWriter.addAttribute("number:style", "short");
- elementWriter.addAttribute("number:textual", "false");
- elementWriter.endElement();
- format.remove(0, 3);
- } else if (format.startsWith("dddd")) {
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:day-of-week");
- elementWriter.addAttribute("number:style", "long");
- elementWriter.endElement();
- format.remove(0, 4);
- } else if (format.startsWith("ddd")) {
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:day-of-week");
- elementWriter.addAttribute("number:style", "short");
- elementWriter.endElement();
- format.remove(0, 3);
- } else if (format.startsWith("dd")) {
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:day");
- elementWriter.addAttribute("number:style", "long");
- elementWriter.endElement();
- format.remove(0, 2);
- } else if (format.startsWith('d')) {
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:day");
- elementWriter.addAttribute("number:style", "short");
- elementWriter.endElement();
- format.remove(0, 1);
- } else if (format.startsWith("yyyy")) {
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:year");
- elementWriter.addAttribute("number:style", "long");
- elementWriter.endElement();
- format.remove(0, 4);
- } else if (format.startsWith("yy")) {
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:year");
- elementWriter.addAttribute("number:style", "short");
- elementWriter.endElement();
- format.remove(0, 2);
- } else {
- if (!saveOdfTimeFormat(elementWriter, format, text, antislash)) {
- QString elem(format[0]);
- format.remove(0, 1);
- if (elem == "\\") {
- antislash = true;
- } else {
- text += elem;
- antislash = false;
- }
- }
- }
- } while (format.length() > 0);
- addTextNumber(text, elementWriter);
- }
-
- QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
- currentStyle.addChildElement("number", elementContents);
- return mainStyles.insert(currentStyle, "N");
-}
-
-
-QString saveOdfFractionStyle(KoGenStyles &mainStyles, const QString &_format,
- const QString &_prefix, const QString &_suffix)
-{
- //debugOdf << "QString saveOdfFractionStyle( KoGenStyles &mainStyles, const QString & _format ) :" << _format;
- QString format(_format);
-
- KoGenStyle currentStyle(KoGenStyle::NumericFractionStyle);
- QBuffer buffer;
- buffer.open(QIODevice::WriteOnly);
- KoXmlWriter elementWriter(&buffer); // TODO pass indentation level
- QString text;
- int integer = 0;
- int numerator = 0;
- int denominator = 0;
- int denominatorValue = 0;
- bool beforeSlash = true;
- do {
- if (format[0] == '#')
- integer++;
- else if (format[0] == '/')
- beforeSlash = false;
- else if (format[0] == '?') {
- if (beforeSlash)
- numerator++;
- else
- denominator++;
- } else {
- bool ok;
- int value = format.toInt(&ok);
- if (ok) {
- denominatorValue = value;
- break;
- }
- }
- format.remove(0, 1);
- } while (format.length() > 0);
-
- text = _prefix;
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:fraction");
- elementWriter.addAttribute("number:min-integer-digits", integer);
- elementWriter.addAttribute("number:min-numerator-digits", numerator);
- elementWriter.addAttribute("number:min-denominator-digits", denominator);
- if (denominatorValue != 0)
- elementWriter.addAttribute("number:denominator-value", denominatorValue);
- elementWriter.endElement();
-
- addCalligraNumericStyleExtension(elementWriter, _suffix, _prefix);
-
- text = _suffix;
- addTextNumber(text, elementWriter);
-
- QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
- currentStyle.addChildElement("number", elementContents);
- return mainStyles.insert(currentStyle, "N");
-}
-
-
-QString saveOdfNumberStyle(KoGenStyles &mainStyles, const QString &_format,
- const QString &_prefix, const QString &_suffix, bool thousandsSep)
-{
- //debugOdf << "QString saveOdfNumberStyle( KoGenStyles &mainStyles, const QString & _format ) :" << _format;
- QString format(_format);
-
- KoGenStyle currentStyle(KoGenStyle::NumericNumberStyle);
- QBuffer buffer;
- buffer.open(QIODevice::WriteOnly);
- KoXmlWriter elementWriter(&buffer); // TODO pass indentation level
- QString text;
- int decimalplaces = 0;
- int integerdigits = 0;
- bool beforeSeparator = true;
- do {
- if (format[0] == '.' || format[0] == ',')
- beforeSeparator = false;
- else if (format[0] == '0' && beforeSeparator)
- integerdigits++;
- else if (format[0] == '0' && !beforeSeparator)
- decimalplaces++;
- else
- debugOdf << " error format 0";
- format.remove(0, 1);
- } while (format.length() > 0);
- text = _prefix ;
- addTextNumber(text, elementWriter);
- elementWriter.startElement("number:number");
- //kDebug(30003) << " decimalplaces :" << decimalplaces << " integerdigits :" << integerdigits;
- if (!beforeSeparator)
- elementWriter.addAttribute("number:decimal-places", decimalplaces);
- elementWriter.addAttribute("number:min-integer-digits", integerdigits);
- if (thousandsSep)
- elementWriter.addAttribute("number:grouping", true);
- elementWriter.endElement();
-
- text = _suffix ;
- addTextNumber(text, elementWriter);
- addCalligraNumericStyleExtension(elementWriter, _suffix, _prefix);
-
- QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
- currentStyle.addChildElement("number", elementContents);
- return mainStyles.insert(currentStyle, "N");
-}
-
-QString saveOdfBooleanStyle(KoGenStyles &mainStyles, const QString &format, const QString &prefix, const QString &suffix)
-{
- Q_UNUSED(format);
-
- KoGenStyle currentStyle(KoGenStyle::NumericBooleanStyle);
-
- QBuffer buffer;
- buffer.open(QIODevice::WriteOnly);
- KoXmlWriter elementWriter(&buffer); // TODO pass indentation level
- QString text = prefix;
- addTextNumber(text, elementWriter);
- elementWriter.startElement("number:boolean");
- elementWriter.endElement();
- text = suffix;
- addTextNumber(text, elementWriter);
-
- QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
- currentStyle.addChildElement("number", elementContents);
- return mainStyles.insert(currentStyle, "N");
-}
-
-QString saveOdfPercentageStyle(KoGenStyles &mainStyles, const QString &_format,
- const QString &_prefix, const QString &_suffix)
-{
- //<number:percentage-style style:name="N11">
- //<number:number number:decimal-places="2" number:min-integer-digits="1"/>
- //<number:text>%</number:text>
- //</number:percentage-style>
-
- //debugOdf << "QString saveOdfPercentageStyle( KoGenStyles &mainStyles, const QString & _format ) :" << _format;
- QString format(_format);
-
- KoGenStyle currentStyle(KoGenStyle::NumericPercentageStyle);
- QBuffer buffer;
- buffer.open(QIODevice::WriteOnly);
- KoXmlWriter elementWriter(&buffer); // TODO pass indentation level
- QString text;
- int decimalplaces = 0;
- int integerdigits = 0;
- bool beforeSeparator = true;
- do {
- if (format[0] == '.' || format[0] == ',')
- beforeSeparator = false;
- else if (format[0] == '0' && beforeSeparator)
- integerdigits++;
- else if (format[0] == '0' && !beforeSeparator)
- decimalplaces++;
- else
- debugOdf << " error format 0";
- format.remove(0, 1);
- } while (format.length() > 0);
- text = _prefix ;
- addTextNumber(text, elementWriter);
- elementWriter.startElement("number:number");
- if (!beforeSeparator)
- elementWriter.addAttribute("number:decimal-places", decimalplaces);
- elementWriter.addAttribute("number:min-integer-digits", integerdigits);
- elementWriter.endElement();
-
- addTextNumber(QString("%"), elementWriter);
-
- text = _suffix ;
- addTextNumber(text, elementWriter);
- addCalligraNumericStyleExtension(elementWriter, _suffix, _prefix);
-
- QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
- currentStyle.addChildElement("number", elementContents);
- return mainStyles.insert(currentStyle, "N");
-
-}
-
-QString saveOdfScientificStyle(KoGenStyles &mainStyles, const QString &_format,
- const QString &_prefix, const QString &_suffix, bool thousandsSep)
-{
- //<number:number-style style:name="N60">
- //<number:scientific-number number:decimal-places="2" number:min-integer-digits="1" number:min-exponent-digits="3"/>
- //</number:number-style>
-
- //example 000,000e+0000
- //debugOdf << "QString saveOdfScientificStyle( KoGenStyles &mainStyles, const QString & _format ) :" << _format;
- QString format(_format);
-
- KoGenStyle currentStyle(KoGenStyle::NumericScientificStyle);
- QBuffer buffer;
- buffer.open(QIODevice::WriteOnly);
- int decimalplace = 0;
- int integerdigits = 0;
- int exponentdigits = 0;
- KoXmlWriter elementWriter(&buffer); // TODO pass indentation level
- QString text;
- bool beforeSeparator = true;
- bool exponential = false;
- bool positive = true;
- do {
- if (!exponential) {
- if (format[0] == '0' && beforeSeparator)
- integerdigits++;
- else if (format[0] == ',' || format[0] == '.')
- beforeSeparator = false;
- else if (format[0] == '0' && !beforeSeparator)
- decimalplace++;
- else if (format[0].toLower() == 'e') {
- format.remove(0, 1);
- if (format[0] == '+')
- positive = true;
- else if (format[0] == '-')
- positive = false;
- else
- debugOdf << "Error into scientific number";
- exponential = true;
- }
- } else {
- if (format[0] == '0' && positive)
- exponentdigits++;
- else if (format[0] == '0' && !positive)
- exponentdigits--;
- else
- debugOdf << " error into scientific number exponential value";
- }
- format.remove(0, 1);
- } while (format.length() > 0);
- text = _prefix ;
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:scientific-number");
- //kDebug(30003) << " decimalplace :" << decimalplace << " integerdigits :" << integerdigits << " exponentdigits :" << exponentdigits;
- if (!beforeSeparator)
- elementWriter.addAttribute("number:decimal-places", decimalplace);
- elementWriter.addAttribute("number:min-integer-digits", integerdigits);
- elementWriter.addAttribute("number:min-exponent-digits", exponentdigits);
- if (thousandsSep)
- elementWriter.addAttribute("number:grouping", true);
- elementWriter.endElement();
-
- text = _suffix;
- addTextNumber(text, elementWriter);
- addCalligraNumericStyleExtension(elementWriter, _suffix, _prefix);
-
- QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
- currentStyle.addChildElement("number", elementContents);
- return mainStyles.insert(currentStyle, "N");
-}
-
-QString saveOdfCurrencyStyle(KoGenStyles &mainStyles,
- const QString &_format, const QString &symbol,
- const QString &_prefix, const QString &_suffix)
-{
-
- //<number:currency-style style:name="N107P0" style:volatile="true">
- //<number:number number:decimal-places="2" number:min-integer-digits="1" number:grouping="true"/>
- //<number:text> </number:text>
- //<number:currency-symbol>VEB</number:currency-symbol>
- //</number:currency-style>
-
- //debugOdf << "QString saveOdfCurrencyStyle( KoGenStyles &mainStyles, const QString & _format ) :" << _format;
- QString format(_format);
-
- KoGenStyle currentStyle(KoGenStyle::NumericCurrencyStyle);
- QBuffer buffer;
- buffer.open(QIODevice::WriteOnly);
- KoXmlWriter elementWriter(&buffer); // TODO pass indentation level
- QString text;
- int decimalplaces = 0;
- int integerdigits = 0;
- bool beforeSeparator = true;
- do {
- if (format[0] == '.' || format[0] == ',')
- beforeSeparator = false;
- else if (format[0] == '0' && beforeSeparator)
- integerdigits++;
- else if (format[0] == '0' && !beforeSeparator)
- decimalplaces++;
- else
- debugOdf << " error format 0";
- format.remove(0, 1);
- } while (format.length() > 0);
-
- text = _prefix ;
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:number");
- //kDebug(30003) << " decimalplaces :" << decimalplaces << " integerdigits :" << integerdigits;
- if (!beforeSeparator)
- elementWriter.addAttribute("number:decimal-places", decimalplaces);
- elementWriter.addAttribute("number:min-integer-digits", integerdigits);
- elementWriter.endElement();
-
- text = _suffix ;
- addTextNumber(text, elementWriter);
- addCalligraNumericStyleExtension(elementWriter, _suffix, _prefix);
-
- elementWriter.startElement("number:currency-symbol");
- //kDebug(30003) << " currency-symbol:" << symbol;
- elementWriter.addTextNode(symbol.toUtf8());
- elementWriter.endElement();
-
- QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
- currentStyle.addChildElement("number", elementContents);
- return mainStyles.insert(currentStyle, "N");
-}
-
-QString saveOdfTextStyle(KoGenStyles &mainStyles, const QString &_format, const QString &_prefix, const QString &_suffix)
-{
- Q_UNUSED(_format);
-
- //<number:text-style style:name="N100">
- //<number:text-content/>
- ///</number:text-style>
-
- //debugOdf << "QString saveOdfTextStyle( KoGenStyles &mainStyles, const QString & _format ) :" << _format;
-
- KoGenStyle currentStyle(KoGenStyle::NumericTextStyle);
- QBuffer buffer;
- buffer.open(QIODevice::WriteOnly);
- KoXmlWriter elementWriter(&buffer); // TODO pass indentation level
- QString text = _prefix ;
- addTextNumber(text, elementWriter);
-
- elementWriter.startElement("number:text-content");
- elementWriter.endElement();
-
- text = _suffix ;
- addTextNumber(text, elementWriter);
- addCalligraNumericStyleExtension(elementWriter, _suffix, _prefix);
-
- QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
- currentStyle.addChildElement("number", elementContents);
- return mainStyles.insert(currentStyle, "N");
-}
-
-//This is an extension of numeric style. For the moment we used namespace of
-//oasis format for specific calligra extension. Change it for the future.
-void addCalligraNumericStyleExtension(KoXmlWriter &elementWriter, const QString &_suffix, const QString &_prefix)
-{
- if (!_suffix.isEmpty()) {
- elementWriter.startElement("number:suffix");
- elementWriter.addTextNode(_suffix);
- elementWriter.endElement();
- }
- if (!_prefix.isEmpty()) {
- elementWriter.startElement("number:prefix");
- elementWriter.addTextNode(_prefix);
- elementWriter.endElement();
- }
-}
-}
diff --git a/libs/odf/KoOdfNumberStyles.h b/libs/odf/KoOdfNumberStyles.h
deleted file mode 100644
index 6416c6251c..0000000000
--- a/libs/odf/KoOdfNumberStyles.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2004-2006 David Faure <faure@kde.org>
- Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
-
- 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.
-*/
-
-#ifndef KOODFNUMBERSTYLES_H
-#define KOODFNUMBERSTYLES_H
-
-#include "kritaodf_export.h"
-#include "KoXmlReaderForward.h"
-
-#include <QPair>
-#include <QString>
-#include <QList>
-
-class KoGenStyles;
-class KoGenStyle;
-
-/**
- * Loading and saving of number styles
- */
-namespace KoOdfNumberStyles
-{
- enum Format {
- Number,
- Scientific,
- Fraction,
- Currency,
- Percentage,
- Date,
- Time,
- Boolean,
- Text
- };
- /// Prefix and suffix are always included into formatStr. Having them as separate fields simply
- /// allows to extract them from formatStr, to display them in separate widgets.
- struct NumericStyleFormat {
- QString formatStr;
- QString prefix;
- QString suffix;
- Format type;
- int precision;
- QString currencySymbol;
- bool thousandsSep;
- QList<QPair<QString,QString> > styleMaps; // conditional formatting, first=condition, second=applyStyleName
- NumericStyleFormat() : type(Text), precision(-1), thousandsSep(false) {}
- };
-
- KRITAODF_EXPORT QString format(const QString &value, const NumericStyleFormat &format);
-
- KRITAODF_EXPORT QString formatNumber(qreal value, const QString &format, int precision = -1);
- KRITAODF_EXPORT QString formatBoolean(const QString &value, const QString &format);
- KRITAODF_EXPORT QString formatDate(int value, const QString &format);
- KRITAODF_EXPORT QString formatTime(qreal value, const QString &format);
- KRITAODF_EXPORT QString formatCurrency(qreal value, const QString &format, const QString& currencySymbol, int precision = -1);
- KRITAODF_EXPORT QString formatScientific(qreal value, const QString &format, int precision = -1);
- KRITAODF_EXPORT QString formatFraction(qreal value, const QString &format);
- KRITAODF_EXPORT QString formatPercent(const QString &value, const QString &format, int precision = -1);
-
- KRITAODF_EXPORT QPair<QString, NumericStyleFormat> loadOdfNumberStyle(const KoXmlElement &parent);
- KRITAODF_EXPORT QString saveOdfNumberStyle(KoGenStyles &mainStyles, const NumericStyleFormat &format);
-
- KRITAODF_EXPORT QString saveOdfDateStyle(KoGenStyles &mainStyles, const QString &format, bool localeFormat, const QString &prefix = QString(), const QString &suffix = QString());
- KRITAODF_EXPORT QString saveOdfTimeStyle(KoGenStyles &mainStyles, const QString &format, bool localeFormat, const QString &prefix = QString(), const QString &suffix = QString());
- KRITAODF_EXPORT QString saveOdfFractionStyle(KoGenStyles &mainStyles, const QString &format, const QString &prefix = QString(), const QString &suffix = QString());
- KRITAODF_EXPORT QString saveOdfScientificStyle(KoGenStyles &mainStyles, const QString &format, const QString &prefix = QString(), const QString &suffix = QString(), bool thousandsSep = false);
- KRITAODF_EXPORT QString saveOdfNumberStyle(KoGenStyles &mainStyles, const QString &format, const QString &prefix = QString(), const QString &suffix = QString(), bool thousandsSep = false);
- KRITAODF_EXPORT QString saveOdfBooleanStyle(KoGenStyles &mainStyles, const QString &format, const QString &prefix = QString(), const QString &suffix = QString());
- KRITAODF_EXPORT QString saveOdfPercentageStyle(KoGenStyles &mainStyles, const QString &format, const QString &prefix = QString(), const QString &suffix = QString());
- KRITAODF_EXPORT QString saveOdfCurrencyStyle(KoGenStyles &mainStyles, const QString &format, const QString &symbol, const QString &prefix = QString(), const QString &suffix = QString());
- KRITAODF_EXPORT QString saveOdfTextStyle(KoGenStyles &mainStyles, const QString &format, const QString &prefix = QString(), const QString &suffix = QString());
-}
-
-#endif // KOODFNUMBERSTYLES_H
diff --git a/libs/odf/KoOdfReadStore.cpp b/libs/odf/KoOdfReadStore.cpp
deleted file mode 100644
index ba8e80badf..0000000000
--- a/libs/odf/KoOdfReadStore.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2005 David Faure <faure@kde.org>
- Copyright (C) 2007 Thorsten Zach3n <zachmann@kde.org>
-
- 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 "KoOdfReadStore.h"
-
-#include <OdfDebug.h>
-#include <klocalizedstring.h>
-
-#include <KoStore.h>
-#include <KoXmlReader.h>
-
-#include "KoOdfStylesReader.h"
-
-class Q_DECL_HIDDEN KoOdfReadStore::Private
-{
-public:
- Private(KoStore *s)
- : store(s)
- {
- }
-
- KoStore * store;
- KoOdfStylesReader stylesReader;
- // it is needed to keep the stylesDoc around so that you can access the styles
- KoXmlDocument stylesDoc;
- KoXmlDocument contentDoc;
- KoXmlDocument settingsDoc;
-};
-
-KoOdfReadStore::KoOdfReadStore(KoStore *store)
- : d(new Private(store))
-{
-}
-
-KoOdfReadStore::~KoOdfReadStore()
-{
- delete d;
-}
-
-KoStore * KoOdfReadStore::store() const
-{
- return d->store;
-}
-
-KoOdfStylesReader &KoOdfReadStore::styles()
-{
- return d->stylesReader;
-}
-
-KoXmlDocument KoOdfReadStore::contentDoc() const
-{
- return d->contentDoc;
-}
-
-KoXmlDocument KoOdfReadStore::settingsDoc() const
-{
- return d->settingsDoc;
-}
-
-bool KoOdfReadStore::loadAndParse(QString &errorMessage)
-{
- if (!loadAndParse("content.xml", d->contentDoc, errorMessage)) {
- return false;
- }
-
- if (d->store->hasFile("styles.xml")) {
- if (!loadAndParse("styles.xml", d->stylesDoc, errorMessage)) {
- return false;
- }
- }
- // Load styles from style.xml
- d->stylesReader.createStyleMap(d->stylesDoc, true);
- // Also load styles from content.xml
- d->stylesReader.createStyleMap(d->contentDoc, false);
-
- if (d->store->hasFile("settings.xml")) {
- loadAndParse("settings.xml", d->settingsDoc, errorMessage);
- }
- return true;
-}
-
-bool KoOdfReadStore::loadAndParse(const QString &fileName, KoXmlDocument &doc, QString &errorMessage)
-{
- if (!d->store) {
- errorMessage = i18n("No store backend");
- return false;
- }
-
- if (!d->store->isOpen()) {
- if (!d->store->open(fileName)) {
- debugOdf << "Entry " << fileName << " not found!"; // not a warning as embedded stores don't have to have all files
- errorMessage = i18n("Could not find %1", fileName);
- return false;
- }
- }
-
- bool ok = loadAndParse(d->store->device(), doc, errorMessage, fileName);
- d->store->close();
- return ok;
-}
-
-bool KoOdfReadStore::loadAndParse(QIODevice *fileDevice, KoXmlDocument &doc, QString &errorMessage, const QString &fileName)
-{
- // Error variables for QDomDocument::setContent
- QString errorMsg;
- int errorLine, errorColumn;
-
- if (!fileDevice->isOpen()) {
- fileDevice->open(QIODevice::ReadOnly);
- }
- bool ok = doc.setContent(fileDevice, true, &errorMsg, &errorLine, &errorColumn);
- if (!ok) {
- errorOdf << "Parsing error in " << fileName << "! Aborting!" << endl
- << " In line: " << errorLine << ", column: " << errorColumn << endl
- << " Error message: " << errorMsg << endl;
- errorMessage = i18n("Parsing error in the main document at line %1, column %2\nError message: %3"
- , errorLine , errorColumn , errorMsg);
- } else {
- debugOdf << "File" << fileName << " loaded and parsed";
- }
- return ok;
-}
diff --git a/libs/odf/KoOdfReadStore.h b/libs/odf/KoOdfReadStore.h
deleted file mode 100644
index 45377eb843..0000000000
--- a/libs/odf/KoOdfReadStore.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2005 David Faure <faure@kde.org>
- Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
-
- 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 KOODFREADSTORE_H
-#define KOODFREADSTORE_H
-
-#include "KoXmlReaderForward.h"
-#include "kritaodf_export.h"
-
-class QString;
-class QIODevice;
-class KoStore;
-class KoOdfStylesReader;
-
-/**
- * Helper class around KoStore for reading out ODF files.
- *
- * The class loads and parses files from the KoStore.
- *
- * @author: David Faure <faure@kde.org>
- */
-class KRITAODF_EXPORT KoOdfReadStore
-{
-public:
- /// @param store recontents the property of the caller
- explicit KoOdfReadStore(KoStore* store);
-
- ~KoOdfReadStore();
-
- /**
- * Get the store
- */
- KoStore* store() const;
-
- /**
- * Get the styles
- *
- * To get a usable result loadAndParse( QString ) has to be called first.
- *
- * @return styles
- */
- KoOdfStylesReader &styles();
-
- /**
- * Get the content document
- *
- * To get a usable result loadAndParse( QString ) has to be called first.
- *
- * This gives you the content of the content.xml file
- */
- KoXmlDocument contentDoc() const;
-
- /**
- * Get the settings document
- *
- * To get a usable result loadAndParse( QString ) has to be called first.
- *
- * This gives you the content of the settings.xml file
- */
- KoXmlDocument settingsDoc() const;
-
- /**
- * Load and parse
- *
- * This function loads and parses the content.xml, styles.xml and the settings.xml
- * file in the store. The styles are already parsed.
- *
- * After this function is called you can access the data via
- * styles()
- * contentDoc()
- * settingsDoc()
- *
- * @param errorMessage The errorMessage is set in case an error is encountered.
- * @return true if loading and parsing was successful, false otherwise. In case of an error
- * the errorMessage is updated accordingly.
- */
- bool loadAndParse(QString &errorMessage);
-
- /**
- * Load a file from an odf store
- */
- bool loadAndParse(const QString &fileName, KoXmlDocument &doc, QString &errorMessage);
-
- /**
- * Load a file and parse from a QIODevice
- * filename argument is just used for debug message
- */
- static bool loadAndParse(QIODevice *fileDevice, KoXmlDocument &doc, QString &errorMessage, const QString& fileName);
-
-private:
- class Private;
- Private * const d;
-};
-
-#endif /* KOODFREADSTORE_H */
diff --git a/libs/odf/KoOdfStylesReader.cpp b/libs/odf/KoOdfStylesReader.cpp
deleted file mode 100644
index 81420b4800..0000000000
--- a/libs/odf/KoOdfStylesReader.cpp
+++ /dev/null
@@ -1,414 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2004-2006 David Faure <faure@kde.org>
- Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
-
- 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 "KoOdfStylesReader.h"
-
-#include "KoXmlNS.h"
-#include "KoOdfNotesConfiguration.h"
-#include "KoOdfNumberDefinition.h"
-#include "KoOdfLineNumberingConfiguration.h"
-#include "KoOdfBibliographyConfiguration.h"
-#include "KoXmlReader.h"
-
-#include <OdfDebug.h>
-
-class Q_DECL_HIDDEN KoOdfStylesReader::Private
-{
-public:
-
- Private()
- : globalFootnoteConfiguration(KoOdfNotesConfiguration::Footnote)
- , globalEndnoteConfiguration(KoOdfNotesConfiguration::Endnote)
- {
- }
-
- QHash < QString /*family*/, QHash < QString /*name*/, KoXmlElement* > > customStyles;
- // auto-styles in content.xml
- QHash < QString /*family*/, QHash < QString /*name*/, KoXmlElement* > > contentAutoStyles;
- // auto-styles in styles.xml
- QHash < QString /*family*/, QHash < QString /*name*/, KoXmlElement* > > stylesAutoStyles;
- QHash < QString /*family*/, KoXmlElement* > defaultStyles;
-
- QHash < QString /*name*/, KoXmlElement* > styles; // page-layout, font-face etc.
- QHash < QString /*name*/, KoXmlElement* > masterPages;
- QHash < QString /*name*/, KoXmlElement* > presentationPageLayouts;
- QHash < QString /*drawType*/, QHash< QString /*name*/, KoXmlElement* > > drawStyles;
-
- QList <KoXmlElement* > tableTemplates;
-
- KoXmlElement officeStyle;
- KoXmlElement layerSet;
-
- DataFormatsMap dataFormats;
-
- // XXX: there can also be notes configuration objects _per_ section.
- KoOdfNotesConfiguration globalFootnoteConfiguration;
- KoOdfNotesConfiguration globalEndnoteConfiguration;
-
- KoOdfBibliographyConfiguration globalBibliographyConfiguration;
-
- KoOdfLineNumberingConfiguration lineNumberingConfiguration;
-
-};
-
-KoOdfStylesReader::KoOdfStylesReader()
- : d(new Private)
-{
-}
-
-KoOdfStylesReader::~KoOdfStylesReader()
-{
- typedef QHash<QString, KoXmlElement*> AutoStylesMap;
- Q_FOREACH (const AutoStylesMap& map, d->customStyles)
- qDeleteAll(map);
- Q_FOREACH (const AutoStylesMap& map, d->contentAutoStyles)
- qDeleteAll(map);
- Q_FOREACH (const AutoStylesMap& map, d->stylesAutoStyles)
- qDeleteAll(map);
- Q_FOREACH (const DataFormatsMap::mapped_type& dataFormat, d->dataFormats)
- delete dataFormat.second;
- qDeleteAll(d->defaultStyles);
- qDeleteAll(d->styles);
- qDeleteAll(d->masterPages);
- qDeleteAll(d->presentationPageLayouts);
- qDeleteAll(d->tableTemplates);
- Q_FOREACH (const AutoStylesMap& map, d->drawStyles) {
- qDeleteAll(map);
- }
- delete d;
-}
-
-void KoOdfStylesReader::createStyleMap(const KoXmlDocument& doc, bool stylesDotXml)
-{
- const KoXmlElement docElement = doc.documentElement();
- // We used to have the office:version check here, but better let the apps do that
- KoXmlElement fontStyles = KoXml::namedItemNS(docElement, KoXmlNS::office, "font-face-decls");
-
- if (!fontStyles.isNull()) {
- //debugOdf <<"Starting reading in font-face-decls...";
- insertStyles(fontStyles, stylesDotXml ? AutomaticInStyles : AutomaticInContent);
- }// else
- // debugOdf <<"No items found";
-
- //debugOdf <<"Starting reading in office:automatic-styles. stylesDotXml=" << stylesDotXml;
-
- KoXmlElement autoStyles = KoXml::namedItemNS(docElement, KoXmlNS::office, "automatic-styles");
- if (!autoStyles.isNull()) {
- insertStyles(autoStyles, stylesDotXml ? AutomaticInStyles : AutomaticInContent);
- }// else
- // debugOdf <<"No items found";
-
-
- //debugOdf <<"Reading in master styles";
-
- KoXmlNode masterStyles = KoXml::namedItemNS(docElement, KoXmlNS::office, "master-styles");
- if (!masterStyles.isNull()) {
- KoXmlElement master;
- forEachElement(master, masterStyles) {
- if (master.localName() == "master-page" &&
- master.namespaceURI() == KoXmlNS::style) {
- const QString name = master.attributeNS(KoXmlNS::style, "name", QString());
- debugOdf << "Master style: '" << name << "' loaded";
- d->masterPages.insert(name, new KoXmlElement(master));
- } else if (master.localName() == "layer-set" && master.namespaceURI() == KoXmlNS::draw) {
- debugOdf << "Master style: layer-set loaded";
- d->layerSet = master;
- } else
- // OASIS docu mentions style:handout-master and draw:layer-set here
- warnOdf << "Unknown tag " << master.tagName() << " in office:master-styles";
- }
- }
-
-
- debugOdf << "Starting reading in office:styles";
-
- const KoXmlElement officeStyle = KoXml::namedItemNS(docElement, KoXmlNS::office, "styles");
-
- if (!officeStyle.isNull()) {
- d->officeStyle = officeStyle;
- insertOfficeStyles(officeStyle);
- }
-
- //debugOdf <<"Styles read in.";
-}
-
-QHash<QString, KoXmlElement*> KoOdfStylesReader::customStyles(const QString& family) const
-{
- if (family.isNull())
- return QHash<QString, KoXmlElement*>();
- return d->customStyles.value(family);
-}
-
-QHash<QString, KoXmlElement*> KoOdfStylesReader::autoStyles(const QString& family, bool stylesDotXml) const
-{
- if (family.isNull())
- return QHash<QString, KoXmlElement*>();
- return stylesDotXml ? d->stylesAutoStyles.value(family) : d->contentAutoStyles.value(family);
-}
-
-KoOdfStylesReader::DataFormatsMap KoOdfStylesReader::dataFormats() const
-{
- return d->dataFormats;
-}
-
-KoOdfNotesConfiguration KoOdfStylesReader::globalNotesConfiguration(KoOdfNotesConfiguration::NoteClass noteClass) const
-{
- switch (noteClass) {
- case (KoOdfNotesConfiguration::Endnote):
- return d->globalEndnoteConfiguration;
- case (KoOdfNotesConfiguration::Footnote):
- default:
- return d->globalFootnoteConfiguration;
- }
-}
-
-KoOdfBibliographyConfiguration KoOdfStylesReader::globalBibliographyConfiguration() const
-{
- return d->globalBibliographyConfiguration;
-}
-
-KoOdfLineNumberingConfiguration KoOdfStylesReader::lineNumberingConfiguration() const
-{
- return d->lineNumberingConfiguration;
-}
-
-
-void KoOdfStylesReader::insertOfficeStyles(const KoXmlElement& styles)
-{
- KoXmlElement e;
- forEachElement(e, styles) {
- const QString localName = e.localName();
- const QString ns = e.namespaceURI();
- if ((ns == KoXmlNS::svg && (
- localName == "linearGradient"
- || localName == "radialGradient"))
- || (ns == KoXmlNS::draw && (
- localName == "gradient"
- || localName == "hatch"
- || localName == "fill-image"
- || localName == "marker"
- || localName == "stroke-dash"
- || localName == "opacity"))
- || (ns == KoXmlNS::calligra && (
- localName == "conicalGradient"))
- ) {
- QString drawType = localName;
- if (drawType.endsWith("Gradient")) {
- drawType = "gradient";
- }
- const QString name = e.attributeNS(KoXmlNS::draw, "name", QString());
- Q_ASSERT(!name.isEmpty());
- KoXmlElement* ep = new KoXmlElement(e);
- d->drawStyles[drawType].insert(name, ep);
- }else if(ns == KoXmlNS::table && localName == "table-template") {
- d->tableTemplates.append(new KoXmlElement(e));
- } else {
- insertStyle(e, CustomInStyles);
- }
- }
-}
-
-void KoOdfStylesReader::insertStyles(const KoXmlElement& styles, TypeAndLocation typeAndLocation)
-{
- //debugOdf <<"Inserting styles from" << styles.tagName();
- KoXmlElement e;
- forEachElement(e, styles)
- insertStyle(e, typeAndLocation);
-}
-
-void KoOdfStylesReader::insertStyle(const KoXmlElement& e, TypeAndLocation typeAndLocation)
-{
- const QString localName = e.localName();
- const QString ns = e.namespaceURI();
- const QString name = e.attributeNS(KoXmlNS::style, "name", QString());
-
- if ((ns == KoXmlNS::style && localName == "style")
- || (ns == KoXmlNS::text && localName == "list-style")) {
- const QString family = localName == "list-style" ? "list" : e.attributeNS(KoXmlNS::style, "family", QString());
-
- if (typeAndLocation == AutomaticInContent) {
- QHash<QString, KoXmlElement*>& dict = d->contentAutoStyles[ family ];
- if (dict.contains(name)) {
- debugOdf << "Auto-style: '" << name << "' already exists";
- delete dict.take(name);
- }
- dict.insert(name, new KoXmlElement(e));
- //debugOdf <<"Style: '" << name <<"' loaded as a style auto style";
- } else if (typeAndLocation == AutomaticInStyles) {
- QHash<QString, KoXmlElement*>& dict = d->stylesAutoStyles[ family ];
- if (dict.contains(name)) {
- debugOdf << "Auto-style: '" << name << "' already exists";
- delete dict.take(name);
- }
- dict.insert(name, new KoXmlElement(e));
- //debugOdf <<"Style: '" << name <<"' loaded as a style auto style";
- } else {
- QHash<QString, KoXmlElement*>& dict = d->customStyles[ family ];
- if (dict.contains(name)) {
- debugOdf << "Style: '" << name << "' already exists";
- delete dict.take(name);
- }
- dict.insert(name, new KoXmlElement(e));
- //debugOdf <<"Style: '" << name <<"' loaded";
- }
- } else if (ns == KoXmlNS::style && (
- localName == "page-layout"
- || localName == "font-face")) {
- if (d->styles.contains(name)) {
- debugOdf << "Style: '" << name << "' already exists";
- delete d->styles.take(name);
- }
- d->styles.insert(name, new KoXmlElement(e));
- } else if (localName == "presentation-page-layout" && ns == KoXmlNS::style) {
- if (d->presentationPageLayouts.contains(name)) {
- debugOdf << "Presentation page layout: '" << name << "' already exists";
- delete d->presentationPageLayouts.take(name);
- }
- d->presentationPageLayouts.insert(name, new KoXmlElement(e));
- } else if (localName == "default-style" && ns == KoXmlNS::style) {
- const QString family = e.attributeNS(KoXmlNS::style, "family", QString());
- if (!family.isEmpty())
- d->defaultStyles.insert(family, new KoXmlElement(e));
- } else if (ns == KoXmlNS::number && (
- localName == "number-style"
- || localName == "currency-style"
- || localName == "percentage-style"
- || localName == "boolean-style"
- || localName == "text-style"
- || localName == "date-style"
- || localName == "time-style")) {
- QPair<QString, KoOdfNumberStyles::NumericStyleFormat> numberStyle = KoOdfNumberStyles::loadOdfNumberStyle(e);
- d->dataFormats.insert(numberStyle.first, qMakePair(numberStyle.second, new KoXmlElement(e)));
- } else if (ns == KoXmlNS::text && localName == "notes-configuration") {
- if (e.attributeNS(KoXmlNS::text, "note-class", "footnote") == "footnote") {
- d->globalFootnoteConfiguration.loadOdf(e);
- } else {
- d->globalEndnoteConfiguration.loadOdf(e);
- }
- } else if (ns == KoXmlNS::text && localName == "linenumbering-configuration") {
- d->lineNumberingConfiguration.loadOdf(e);
- } else if (ns == KoXmlNS::text && localName == "bibliography-configuration") {
- KoOdfBibliographyConfiguration bibConfiguration;
- bibConfiguration.loadOdf(e);
- d->globalBibliographyConfiguration = bibConfiguration;
- }
-}
-
-KoXmlElement *KoOdfStylesReader::defaultStyle(const QString &family) const
-{
- return d->defaultStyles[family];
-}
-
-KoXmlElement KoOdfStylesReader::officeStyle() const
-{
- return d->officeStyle;
-}
-
-KoXmlElement KoOdfStylesReader::layerSet() const
-{
- return d->layerSet;
-}
-
-QHash<QString, KoXmlElement*> KoOdfStylesReader::masterPages() const
-{
- return d->masterPages;
-}
-
-QHash<QString, KoXmlElement*> KoOdfStylesReader::presentationPageLayouts() const
-{
- return d->presentationPageLayouts;
-}
-
-QHash<QString, KoXmlElement*> KoOdfStylesReader::drawStyles(const QString &drawType) const
-{
- return d->drawStyles.value(drawType);
-}
-
-const KoXmlElement* KoOdfStylesReader::findStyle(const QString& name) const
-{
- return d->styles[ name ];
-}
-
-const KoXmlElement* KoOdfStylesReader::findStyle(const QString& styleName, const QString& family) const
-{
- const KoXmlElement* style = findStyleCustomStyle(styleName, family);
- if (!style)
- style = findAutoStyleStyle(styleName, family);
- if (!style)
- style = findContentAutoStyle(styleName, family);
- return style;
-}
-
-const KoXmlElement* KoOdfStylesReader::findStyle(const QString& styleName, const QString& family, bool stylesDotXml) const
-{
- const KoXmlElement* style = findStyleCustomStyle(styleName, family);
- if (!style && !stylesDotXml) {
- style = findContentAutoStyle(styleName, family);
- }
- if (!style && stylesDotXml) {
- style = findAutoStyleStyle(styleName, family);
- }
- return style;
-
-}
-
-const KoXmlElement* KoOdfStylesReader::findStyleCustomStyle(const QString& styleName, const QString& family) const
-{
- const KoXmlElement* style = d->customStyles.value(family).value(styleName);
- if (style && !family.isEmpty()) {
- const QString styleFamily = style->attributeNS(KoXmlNS::style, "family", QString());
- if (styleFamily != family) {
- warnOdf << "KoOdfStylesReader: was looking for style " << styleName
- << " in family " << family << " but got " << styleFamily << endl;
- }
- }
- return style;
-}
-
-const KoXmlElement* KoOdfStylesReader::findAutoStyleStyle(const QString& styleName, const QString& family) const
-{
- const KoXmlElement* style = d->stylesAutoStyles.value(family).value(styleName);
- if (style) {
- const QString styleFamily = style->attributeNS(KoXmlNS::style, "family", QString());
- if (styleFamily != family) {
- warnOdf << "KoOdfStylesReader: was looking for style " << styleName
- << " in family " << family << " but got " << styleFamily << endl;
- }
- }
- return style;
-}
-
-const KoXmlElement* KoOdfStylesReader::findContentAutoStyle(const QString& styleName, const QString& family) const
-{
- const KoXmlElement* style = d->contentAutoStyles.value(family).value(styleName);
- if (style) {
- const QString styleFamily = style->attributeNS(KoXmlNS::style, "family", QString());
- if (styleFamily != family) {
- warnOdf << "KoOdfStylesReader: was looking for style " << styleName
- << " in family " << family << " but got " << styleFamily << endl;
- }
- }
- return style;
-}
-
-QList<KoXmlElement*> KoOdfStylesReader::tableTemplates() const
-{
- return d->tableTemplates;
-}
diff --git a/libs/odf/KoOdfStylesReader.h b/libs/odf/KoOdfStylesReader.h
deleted file mode 100644
index df453bd8e2..0000000000
--- a/libs/odf/KoOdfStylesReader.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2004-2006 David Faure <faure@kde.org>
- Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
-
- 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.
-*/
-
-#ifndef KOODFSTYLESREADER_H
-#define KOODFSTYLESREADER_H
-
-#include <QHash>
-#include <QList>
-
-#include <KoXmlReaderForward.h>
-
-#include "kritaodf_export.h"
-#include "KoOdfNumberStyles.h"
-#include "KoOdfNotesConfiguration.h"
-
-class KoOdfLineNumberingConfiguration;
-class KoOdfBibliographyConfiguration;
-
-/**
- * Repository of styles used during loading of OASIS/OOo file
- */
-class KRITAODF_EXPORT KoOdfStylesReader
-{
-public:
- /// constructor
- KoOdfStylesReader();
- /// destructor
- ~KoOdfStylesReader();
-
- /// Look into @p doc for styles and remember them
- /// @param doc document to look into
- /// @param stylesDotXml true when loading styles.xml, false otherwise
- void createStyleMap(const KoXmlDocument &doc, bool stylesDotXml);
-
- /**
- * Look up a style by name.
- * This method can find styles defined by the tags "style:page-layout",
- * "style:presentation-page-layout", or "style:font-face".
- * Do NOT use this method for style:style styles.
- *
- * @param name the style name
- * @return the dom element representing the style, or an empty QString if it wasn't found.
- */
- const KoXmlElement* findStyle(const QString &name) const;
-
- /**
- * Looks up a style:style by name.
- * Searches in the list of custom styles first and then in the lists of automatic styles.
- * @param name the style name
- * @param family the style family (for a style:style, use 0 otherwise)
- * @return the dom element representing the style, or an empty QString if it wasn't found.
- */
- const KoXmlElement* findStyle(const QString &name, const QString &family) const;
-
- /**
- * Looks up a style:style by name.
- *
- * Searches in the list of custom styles first and then in the lists of automatic styles.
- *
- * @param name the style name
- * @param family the style family (for a style:style, use 0 otherwise)
- * @param stylesDotXml if true search the styles.xml auto-styles otherwise the content.xml ones
- *
- * @return the dom element representing the style, or an empty QString if it wasn't found.
- */
- const KoXmlElement* findStyle(const QString &name, const QString &family, bool stylesDotXml) const;
-
- /// Similar to findStyle but for custom styles only.
- const KoXmlElement *findStyleCustomStyle(const QString &name, const QString &family) const;
-
- /**
- * Similar to findStyle but for auto-styles only.
- * \note Searches in styles.xml only!
- * \see findStyle()
- */
- const KoXmlElement *findAutoStyleStyle(const QString &name, const QString &family) const;
-
- /**
- * Similar to findStyle but for auto-styles only.
- * \note Searches in content.xml only!
- * \see findStyle()
- */
- const KoXmlElement *findContentAutoStyle(const QString &name, const QString &family) const;
-
- /// @return the default style for a given family ("graphic","paragraph","table" etc.)
- /// Returns 0 if no default style for this family is available
- KoXmlElement *defaultStyle(const QString &family) const;
-
- /// @return the office:style element
- KoXmlElement officeStyle() const;
-
- /// @return the draw:layer-set element
- KoXmlElement layerSet() const;
-
- /// @return master pages ("style:master-page" elements), hashed by name
- QHash<QString, KoXmlElement*> masterPages() const;
-
- /// @return all presentation page layouts ("presentation-page-layout" elements), hashed by name
- QHash<QString, KoXmlElement*> presentationPageLayouts() const;
-
- /// @return all table templates("table-template" elements), template names may be duplicated
- QList<KoXmlElement *> tableTemplates() const;
-
- /**
- * Get the draw styles for a specified type.
- *
- * @param drawType The type of the wanted drawStyles
- * Available types: gradient(returns gradient, linearGradient, radialGradient and conicalGradient styles),
- * hatch, fill-image, marker, stroke-dash, opacity
- * @return draw styles of the specified type, hashed by name
- */
- QHash<QString, KoXmlElement*> drawStyles(const QString &drawType) const;
-
- /// @return all custom styles ("style:style" elements) for a given family, hashed by name
- QHash<QString, KoXmlElement*> customStyles(const QString& family) const;
-
- /**
- * Returns all auto-styles defined in styles.xml, if \p stylesDotXml is \c true ,
- * or all in content.xml, if \p stylesDotXml is \c false .
- * \return all auto-styles ("style:style" elements) for a given family, hashed by name
- */
- QHash<QString, KoXmlElement*> autoStyles(const QString& family, bool stylesDotXml = false) const;
-
- typedef QHash<QString, QPair<KoOdfNumberStyles::NumericStyleFormat, KoXmlElement*> > DataFormatsMap;
- /// Value (date/time/number...) formats found while parsing styles. Used e.g. for fields.
- /// Key: format name. Value:
- DataFormatsMap dataFormats() const;
-
- /**
- * Return the notes configuration for the given note class (footnote or endnote).
- *
- * Note that ODF supports different notes configurations for sections, but we don't
- * support that yet.
- */
- KoOdfNotesConfiguration globalNotesConfiguration(KoOdfNotesConfiguration::NoteClass noteClass) const;
-
- /**
- * return the line numbering configuration for this document.
- */
- KoOdfLineNumberingConfiguration lineNumberingConfiguration() const;
-
- /**
- * return the bibliography configuration for this document.
- */
- KoOdfBibliographyConfiguration globalBibliographyConfiguration() const;
-
-private:
- enum TypeAndLocation {
- CustomInStyles, ///< custom style located in styles.xml
- AutomaticInContent, ///< auto-style located in content.xml
- AutomaticInStyles ///< auto-style located in styles.xml
- };
- /// Add styles to styles map
- void insertStyles(const KoXmlElement &styles, TypeAndLocation typeAndLocation = CustomInStyles);
-
- void insertOfficeStyles(const KoXmlElement &styles);
- void insertStyle(const KoXmlElement &style, TypeAndLocation typeAndLocation);
-
- KoOdfStylesReader(const KoOdfStylesReader &); // forbidden
- KoOdfStylesReader& operator=(const KoOdfStylesReader &); // forbidden
-
- class Private;
- Private * const d;
-};
-
-#endif /* KOODFSTYLESREADER_H */
diff --git a/libs/odf/KoOdfWriteStore.cpp b/libs/odf/KoOdfWriteStore.cpp
deleted file mode 100644
index 09d0cf4b53..0000000000
--- a/libs/odf/KoOdfWriteStore.cpp
+++ /dev/null
@@ -1,229 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2005 David Faure <faure@kde.org>
- Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
-
- 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 "KoOdfWriteStore.h"
-
-#include <QBuffer>
-
-#include <QTemporaryFile>
-#include <OdfDebug.h>
-#include <klocalizedstring.h>
-
-#include <KoStore.h>
-#include <KoStoreDevice.h>
-#include <KoXmlWriter.h>
-
-#include "KoXmlNS.h"
-
-struct Q_DECL_HIDDEN KoOdfWriteStore::Private {
- Private(KoStore * store)
- : store(store)
- , storeDevice(0)
- , contentWriter(0)
- , bodyWriter(0)
- , manifestWriter(0)
- , contentTmpFile(0) {}
-
-
- ~Private() {
- // If all the right close methods were called, nothing should remain,
- // so those deletes are really just in case.
- Q_ASSERT(!contentWriter);
- delete contentWriter;
- Q_ASSERT(!bodyWriter);
- delete bodyWriter;
- Q_ASSERT(!storeDevice);
- delete storeDevice;
- Q_ASSERT(!manifestWriter);
- delete manifestWriter;
- }
-
- KoStore * store;
- KoStoreDevice * storeDevice;
- KoXmlWriter * contentWriter;
-
- KoXmlWriter * bodyWriter;
- KoXmlWriter * manifestWriter;
- QTemporaryFile * contentTmpFile;
-};
-
-KoOdfWriteStore::KoOdfWriteStore(KoStore* store)
- : d(new Private(store))
-{
-}
-
-KoOdfWriteStore::~KoOdfWriteStore()
-{
- delete d;
-}
-
-KoXmlWriter* KoOdfWriteStore::createOasisXmlWriter(QIODevice* dev, const char* rootElementName)
-{
- KoXmlWriter* writer = new KoXmlWriter(dev);
- writer->startDocument(rootElementName);
- writer->startElement(rootElementName);
-
- if (qstrcmp(rootElementName, "VL:version-list") == 0) {
- writer->addAttribute("xmlns:VL", KoXmlNS::VL);
- writer->addAttribute("xmlns:dc", KoXmlNS::dc);
- return writer;
- }
-
- writer->addAttribute("xmlns:office", KoXmlNS::office);
- writer->addAttribute("xmlns:meta", KoXmlNS::meta);
-
- if (qstrcmp(rootElementName, "office:document-meta") != 0) {
- writer->addAttribute("xmlns:config", KoXmlNS::config);
- writer->addAttribute("xmlns:text", KoXmlNS::text);
- writer->addAttribute("xmlns:table", KoXmlNS::table);
- writer->addAttribute("xmlns:draw", KoXmlNS::draw);
- writer->addAttribute("xmlns:presentation", KoXmlNS::presentation);
- writer->addAttribute("xmlns:dr3d", KoXmlNS::dr3d);
- writer->addAttribute("xmlns:chart", KoXmlNS::chart);
- writer->addAttribute("xmlns:form", KoXmlNS::form);
- writer->addAttribute("xmlns:script", KoXmlNS::script);
- writer->addAttribute("xmlns:style", KoXmlNS::style);
- writer->addAttribute("xmlns:number", KoXmlNS::number);
- writer->addAttribute("xmlns:math", KoXmlNS::math);
- writer->addAttribute("xmlns:svg", KoXmlNS::svg);
- writer->addAttribute("xmlns:fo", KoXmlNS::fo);
- writer->addAttribute("xmlns:anim", KoXmlNS::anim);
- writer->addAttribute("xmlns:smil", KoXmlNS::smil);
- writer->addAttribute("xmlns:calligra", KoXmlNS::calligra);
- writer->addAttribute("xmlns:officeooo", KoXmlNS::officeooo);
- writer->addAttribute("xmlns:delta", KoXmlNS::delta);
- writer->addAttribute("xmlns:split", KoXmlNS::split);
- writer->addAttribute("xmlns:ac", KoXmlNS::ac);
- }
-
- if (qstrcmp(rootElementName, "office:document-settings") == 0) {
- writer->addAttribute("xmlns:ooo", KoXmlNS::ooo);
- }
-
- writer->addAttribute("office:version", "1.2");
-
- writer->addAttribute("xmlns:dc", KoXmlNS::dc);
- writer->addAttribute("xmlns:xlink", KoXmlNS::xlink);
- return writer;
-}
-
-KoStore* KoOdfWriteStore::store() const
-{
- return d->store;
-}
-
-KoXmlWriter* KoOdfWriteStore::contentWriter()
-{
- if (!d->contentWriter) {
- if (!d->store->open("content.xml")) {
- return 0;
- }
- d->storeDevice = new KoStoreDevice(d->store);
- d->contentWriter = createOasisXmlWriter(d->storeDevice, "office:document-content");
- }
- return d->contentWriter;
-}
-
-KoXmlWriter* KoOdfWriteStore::bodyWriter()
-{
- if (!d->bodyWriter) {
- Q_ASSERT(!d->contentTmpFile);
- d->contentTmpFile = new QTemporaryFile;
- if (!d->contentTmpFile->open()) {
- warnOdf << "Failed to open the temporary content file";
- delete d->contentTmpFile;
- d->contentTmpFile = 0;
- return 0;
- }
- d->bodyWriter = new KoXmlWriter(d->contentTmpFile, 1);
- }
- return d->bodyWriter;
-}
-
-bool KoOdfWriteStore::closeContentWriter()
-{
- Q_ASSERT(d->bodyWriter);
- Q_ASSERT(d->contentTmpFile);
-
- delete d->bodyWriter; d->bodyWriter = 0;
-
- // copy over the contents from the tempfile to the real one
- d->contentTmpFile->close(); // does not really close but seeks to the beginning of the file
- if (d->contentWriter) {
- d->contentWriter->addCompleteElement(d->contentTmpFile);
- }
- d->contentTmpFile->close(); // seek again to the beginning
- delete d->contentTmpFile; d->contentTmpFile = 0; // and finally close and remove the QTemporaryFile
-
- if (d->contentWriter) {
- d->contentWriter->endElement(); // document-content
- d->contentWriter->endDocument();
- delete d->contentWriter;
- d->contentWriter = 0;
- }
-
- delete d->storeDevice; d->storeDevice = 0;
- if (!d->store->close()) { // done with content.xml
- return false;
- }
- return true;
-}
-
-KoXmlWriter* KoOdfWriteStore::manifestWriter(const char* mimeType)
-{
- if (!d->manifestWriter) {
- // the pointer to the buffer is already stored in the KoXmlWriter, no need to store it here as well
- QBuffer *manifestBuffer = new QBuffer;
- manifestBuffer->open(QIODevice::WriteOnly);
- d->manifestWriter = new KoXmlWriter(manifestBuffer);
- d->manifestWriter->startDocument("manifest:manifest");
- d->manifestWriter->startElement("manifest:manifest");
- d->manifestWriter->addAttribute("xmlns:manifest", KoXmlNS::manifest);
- d->manifestWriter->addAttribute("manifest:version", "1.2");
- d->manifestWriter->addManifestEntry("/", mimeType);
- }
- return d->manifestWriter;
-}
-
-KoXmlWriter* KoOdfWriteStore::manifestWriter()
-{
- Q_ASSERT(d->manifestWriter);
- return d->manifestWriter;
-}
-
-bool KoOdfWriteStore::closeManifestWriter(bool writeMainfest)
-{
- Q_ASSERT(d->manifestWriter);
- bool ok = true;
- if (writeMainfest) {
- d->manifestWriter->endElement();
- d->manifestWriter->endDocument();
- QBuffer* buffer = static_cast<QBuffer *>(d->manifestWriter->device());
- if (d->store->open("META-INF/manifest.xml")) {
- qint64 written = d->store->write(buffer->buffer());
- ok = (written == (qint64) buffer->buffer().size() && d->store->close());
- } else {
- ok = false;
- }
- delete buffer;
- }
- delete d->manifestWriter; d->manifestWriter = 0;
- return ok;
-}
diff --git a/libs/odf/KoOdfWriteStore.h b/libs/odf/KoOdfWriteStore.h
deleted file mode 100644
index fc2638ec5b..0000000000
--- a/libs/odf/KoOdfWriteStore.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2005 David Faure <faure@kde.org>
- Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
-
- 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 KOODFWRITESTORE_H
-#define KOODFWRITESTORE_H
-
-class QIODevice;
-class KoXmlWriter;
-class KoStore;
-
-/**
- * Helper class around KoStore for writing out ODF files.
- * This class helps solving the problem that automatic styles must be before
- * the body, but it's easier to iterate over the application's objects only
- * once. So we open a KoXmlWriter into a memory buffer, write the body into it,
- * collect automatic styles while doing that, write out automatic styles,
- * and then copy the body XML from the buffer into the real KoXmlWriter.
- *
- * The typical use of this class is therefore:
- * - write body into bodyWriter() and collect auto styles
- * - write auto styles into contentWriter()
- * - call closeContentWriter()
- * - write other files into the store (styles.xml, settings.xml etc.)
- *
- *
- * TODO: maybe we could encapsulate a bit more things, to e.g. handle
- * adding manifest entries automatically.
- *
- * @author: David Faure <faure@kde.org>
- */
-#include "kritaodf_export.h"
-
-class KRITAODF_EXPORT KoOdfWriteStore
-{
-public:
- /// @param store recontents the property of the caller
- explicit KoOdfWriteStore(KoStore *store);
-
- ~KoOdfWriteStore();
-
- /**
- * Return an XML writer for saving Oasis XML into the device @p dev,
- * including the XML processing instruction,
- * and the root element with all its namespaces.
- * You can add more namespaces afterwards with addAttribute.
- *
- * @param dev the device into which the XML will be written.
- * @param rootElementName the tag name of the root element.
- * This is either office:document, office:document-content,
- * office:document-styles, office:document-meta or office:document-settings
- * @return the KoXmlWriter instance. It becomes owned by the caller, which
- * must delete it at some point.
- *
- * Once done with writing the contents of the root element, you
- * will need to call endElement(); endDocument(); before destroying the KoXmlWriter.
- */
- static KoXmlWriter *createOasisXmlWriter(QIODevice *dev, const char *rootElementName);
-
- KoStore *store() const;
-
- /**
- * Open contents.xml for writing and return the KoXmlWriter
- */
- KoXmlWriter *contentWriter();
-
- /**
- * Open another KoXmlWriter for writing out the contents
- * into a temporary file, to collect automatic styles while doing that.
- */
- KoXmlWriter *bodyWriter();
-
- /**
- * This will copy the body into the content writer,
- * delete the bodyWriter and the contentWriter, and then
- * close contents.xml.
- */
- bool closeContentWriter();
-
- // For other files in the store, use open/addManifestEntry/KoStoreDevice/createOasisXmlWriter/close
-
- /**
- * Create and return a manifest writer. It will write to a memory buffer.
- */
- KoXmlWriter *manifestWriter(const char *mimeType);
-
- /**
- * Return the manifest writer. It has to be created by manifestWriter( mimeType ) before you can use
- * this function.
- */
- KoXmlWriter *manifestWriter();
-
- /**
- * Close the manifest writer.
- * @param writeMainfest If true then on closing we also write the contents to the manifest.xml else
- * we only close the writer and don't write the content to the manifest.xml
- */
- bool closeManifestWriter(bool writeMainfest = true);
-
-private:
- struct Private;
- Private * const d;
-};
-
-#endif /* KOODFWRITESTORE_H */
diff --git a/libs/odf/KoPageFormat.cpp b/libs/odf/KoPageFormat.cpp
deleted file mode 100644
index 686e79c34f..0000000000
--- a/libs/odf/KoPageFormat.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
- Copyright 2002, 2003 David Faure <faure@kde.org>
- Copyright 2003 Nicolas GOUTTE <goutte@kde.org>
- Copyright 2007 Thomas Zander <zander@kde.org>
-
- 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 "KoPageFormat.h"
-
-#include <klocalizedstring.h>
-#include <OdfDebug.h>
-
-// paper formats ( mm )
-#define PG_A3_WIDTH 297.0
-#define PG_A3_HEIGHT 420.0
-#define PG_A4_WIDTH 210.0
-#define PG_A4_HEIGHT 297.0
-#define PG_A5_WIDTH 148.0
-#define PG_A5_HEIGHT 210.0
-#define PG_B5_WIDTH 182.0
-#define PG_B5_HEIGHT 257.0
-#define PG_US_LETTER_WIDTH 216.0
-#define PG_US_LETTER_HEIGHT 279.0
-#define PG_US_LEGAL_WIDTH 216.0
-#define PG_US_LEGAL_HEIGHT 356.0
-#define PG_US_EXECUTIVE_WIDTH 191.0
-#define PG_US_EXECUTIVE_HEIGHT 254.0
-
-struct PageFormatInfo {
- KoPageFormat::Format format;
- QPrinter::PageSize qprinter;
- const char* shortName; // Short name
- const char* descriptiveName; // Full name, which will be translated
- qreal width; // in mm
- qreal height; // in mm
-};
-
-// NOTES:
-// - the width and height of non-ISO formats are rounded
-// https://en.wikipedia.org/wiki/Paper_size can help
-// - the comments "should be..." indicates the exact values if the inch sizes would be multiplied by 25.4 mm/inch
-
-const PageFormatInfo pageFormatInfo[] = {
- { KoPageFormat::IsoA3Size, QPrinter::A3, "A3", I18N_NOOP2("Page size", "ISO A3"), 297.0, 420.0 },
- { KoPageFormat::IsoA4Size, QPrinter::A4, "A4", I18N_NOOP2("Page size", "ISO A4"), 210.0, 297.0 },
- { KoPageFormat::IsoA5Size, QPrinter::A5, "A5", I18N_NOOP2("Page size", "ISO A5"), 148.0, 210.0 },
- { KoPageFormat::UsLetterSize, QPrinter::Letter, "Letter", I18N_NOOP2("Page size", "US Letter"), 215.9, 279.4 },
- { KoPageFormat::UsLegalSize, QPrinter::Legal, "Legal", I18N_NOOP2("Page size", "US Legal"), 215.9, 355.6 },
- { KoPageFormat::ScreenSize, QPrinter::A4, "Screen", I18N_NOOP2("Page size", "Screen"), PG_A4_HEIGHT, PG_A4_WIDTH }, // Custom, so fall back to A4
- { KoPageFormat::CustomSize, QPrinter::A4, "Custom", I18N_NOOP2("Page size", "Custom"), PG_A4_WIDTH, PG_A4_HEIGHT }, // Custom, so fall back to A4
- { KoPageFormat::IsoB5Size, QPrinter::B5, "B5", I18N_NOOP2("Page size", "ISO B5"), 182.0, 257.0 },
- { KoPageFormat::UsExecutiveSize, QPrinter::Executive, "Executive", I18N_NOOP2("Page size", "US Executive"), 191.0, 254.0 }, // should be 190.5 mm x 254.0 mm
- { KoPageFormat::IsoA0Size, QPrinter::A0, "A0", I18N_NOOP2("Page size", "ISO A0"), 841.0, 1189.0 },
- { KoPageFormat::IsoA1Size, QPrinter::A1, "A1", I18N_NOOP2("Page size", "ISO A1"), 594.0, 841.0 },
- { KoPageFormat::IsoA2Size, QPrinter::A2, "A2", I18N_NOOP2("Page size", "ISO A2"), 420.0, 594.0 },
- { KoPageFormat::IsoA6Size, QPrinter::A6, "A6", I18N_NOOP2("Page size", "ISO A6"), 105.0, 148.0 },
- { KoPageFormat::IsoA7Size, QPrinter::A7, "A7", I18N_NOOP2("Page size", "ISO A7"), 74.0, 105.0 },
- { KoPageFormat::IsoA8Size, QPrinter::A8, "A8", I18N_NOOP2("Page size", "ISO A8"), 52.0, 74.0 },
- { KoPageFormat::IsoA9Size, QPrinter::A9, "A9", I18N_NOOP2("Page size", "ISO A9"), 37.0, 52.0 },
- { KoPageFormat::IsoB0Size, QPrinter::B0, "B0", I18N_NOOP2("Page size", "ISO B0"), 1030.0, 1456.0 },
- { KoPageFormat::IsoB1Size, QPrinter::B1, "B1", I18N_NOOP2("Page size", "ISO B1"), 728.0, 1030.0 },
- { KoPageFormat::IsoB10Size, QPrinter::B10, "B10", I18N_NOOP2("Page size", "ISO B10"), 32.0, 45.0 },
- { KoPageFormat::IsoB2Size, QPrinter::B2, "B2", I18N_NOOP2("Page size", "ISO B2"), 515.0, 728.0 },
- { KoPageFormat::IsoB3Size, QPrinter::B3, "B3", I18N_NOOP2("Page size", "ISO B3"), 364.0, 515.0 },
- { KoPageFormat::IsoB4Size, QPrinter::B4, "B4", I18N_NOOP2("Page size", "ISO B4"), 257.0, 364.0 },
- { KoPageFormat::IsoB6Size, QPrinter::B6, "B6", I18N_NOOP2("Page size", "ISO B6"), 128.0, 182.0 },
- { KoPageFormat::IsoC5Size, QPrinter::C5E, "C5", I18N_NOOP2("Page size", "ISO C5"), 163.0, 229.0 }, // Some sources tells: 162 mm x 228 mm
- { KoPageFormat::UsComm10Size, QPrinter::Comm10E, "Comm10", I18N_NOOP2("Page size", "US Common 10"), 105.0, 241.0 }, // should be 104.775 mm x 241.3 mm
- { KoPageFormat::IsoDLSize, QPrinter::DLE, "DL", I18N_NOOP2("Page size", "ISO DL"), 110.0, 220.0 },
- { KoPageFormat::UsFolioSize, QPrinter::Folio, "Folio", I18N_NOOP2("Page size", "US Folio"), 210.0, 330.0 }, // should be 209.54 mm x 330.2 mm
- { KoPageFormat::UsLedgerSize, QPrinter::Ledger, "Ledger", I18N_NOOP2("Page size", "US Ledger"), 432.0, 279.0 }, // should be 431.8 mm x 297.4 mm
- { KoPageFormat::UsTabloidSize, QPrinter::Tabloid, "Tabloid", I18N_NOOP2("Page size", "US Tabloid"), 279.0, 432.0 }, // should be 297.4 mm x 431.8 mm
- { KoPageFormat::Invalid, QPrinter::Custom, "", "", -1, -1 }
-};
-
-QPrinter::PageSize KoPageFormat::printerPageSize(KoPageFormat::Format format)
-{
- if (format == ScreenSize) {
- warnOdf << "You use the page layout SCREEN. Printing in ISO A4 Landscape.";
- return QPrinter::A4;
- }
- if (format == CustomSize) {
- warnOdf << "The used page layout (Custom) is not supported by KQPrinter. Printing in A4.";
- return QPrinter::A4;
- }
- return pageFormatInfo[format].qprinter;
-}
-
-qreal KoPageFormat::width(Format format, Orientation orientation)
-{
- if (orientation == Landscape)
- return height(format, Portrait);
- return pageFormatInfo[format].width;
-}
-
-qreal KoPageFormat::height(Format format, Orientation orientation)
-{
- if (orientation == Landscape)
- return width(format, Portrait);
- return pageFormatInfo[format].height;
-}
-
-KoPageFormat::Format KoPageFormat::guessFormat(qreal width, qreal height)
-{
- for (int i = 0; pageFormatInfo[i].format != KoPageFormat::Invalid ;i++) {
- // We have some tolerance. 1pt is a third of a mm, this is
- // barely noticeable for a page size.
- if (qAbs(width - pageFormatInfo[i].width) < 1.0 && qAbs(height - pageFormatInfo[i].height) < 1.0)
- return pageFormatInfo[i].format;
- }
- return CustomSize;
-}
-
-QString KoPageFormat::formatString(Format format)
-{
- return QString::fromLatin1(pageFormatInfo[format].shortName);
-}
-
-KoPageFormat::Format KoPageFormat::formatFromString(const QString & string)
-{
- for (int i = 0; pageFormatInfo[i].format != KoPageFormat::Invalid ;i++) {
- if (string == QString::fromLatin1(pageFormatInfo[i].shortName))
- return pageFormatInfo[i].format;
- }
- // We do not know the format name, so we have a custom format
- return CustomSize;
-}
-
-KoPageFormat::Format KoPageFormat::defaultFormat()
-{
- int qprinter;
- if (QLocale().measurementSystem() == QLocale::ImperialSystem) {
- qprinter = static_cast<int>(QPageSize::Letter);
- }
- else {
- qprinter = static_cast<int>(QPageSize::A4);
- }
- for (int i = 0; pageFormatInfo[i].format != KoPageFormat::Invalid ;i++) {
- if (pageFormatInfo[i].qprinter == qprinter)
- return static_cast<Format>(i);
- }
- return IsoA4Size;
-}
-
-QString KoPageFormat::name(Format format)
-{
- return i18nc("Page size", pageFormatInfo[format].descriptiveName);
-}
-
-QStringList KoPageFormat::localizedPageFormatNames()
-{
- QStringList lst;
- for (int i = 0; pageFormatInfo[i].format != KoPageFormat::Invalid ;i++) {
- lst << i18nc("Page size", pageFormatInfo[i].descriptiveName);
- }
- return lst;
-}
-
-QStringList KoPageFormat::pageFormatNames()
-{
- QStringList lst;
- for (int i = 0; pageFormatInfo[i].format != KoPageFormat::Invalid ;i++) {
- lst << pageFormatInfo[i].shortName;
- }
- return lst;
-}
diff --git a/libs/odf/KoPageFormat.h b/libs/odf/KoPageFormat.h
deleted file mode 100644
index ffe0afe3ee..0000000000
--- a/libs/odf/KoPageFormat.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
- Copyright 2002, 2003 David Faure <faure@kde.org>
- Copyright 2003 Nicolas GOUTTE <goutte@kde.org>
- Copyright 2007 Thomas Zander <zander@kde.org>
-
- 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 KOPAGEFORMAT_H
-#define KOPAGEFORMAT_H
-
-#include "kritaodf_export.h"
-
-#include <QPrinter>
-
-/// The page formats calligra supports
-namespace KoPageFormat
-{
-/**
- * @brief Represents the paper format a document shall be printed on.
- *
- * For compatibility reasons, and because of screen and custom,
- * this enum doesn't map to QPrinter::PageSize but KoPageFormat::printerPageSize
- * does the conversion.
- */
-enum Format {
- IsoA3Size,
- IsoA4Size,
- IsoA5Size,
- UsLetterSize,
- UsLegalSize,
- ScreenSize,
- CustomSize,
- IsoB5Size,
- UsExecutiveSize,
- IsoA0Size,
- IsoA1Size,
- IsoA2Size,
- IsoA6Size,
- IsoA7Size,
- IsoA8Size,
- IsoA9Size,
- IsoB0Size,
- IsoB1Size,
- IsoB10Size,
- IsoB2Size,
- IsoB3Size,
- IsoB4Size,
- IsoB6Size,
- IsoC5Size,
- UsComm10Size,
- IsoDLSize,
- UsFolioSize,
- UsLedgerSize,
- UsTabloidSize,
- Invalid
-};
-
-/**
- * Represents the orientation of a printed document.
- */
-enum Orientation {
- Portrait,
- Landscape
-};
-
-/**
- * @brief Convert a Format into a KPrinter::PageSize.
- *
- * If format is 'screen' it will use A4 landscape.
- * If format is 'custom' it will use A4 portrait.
- * (you may want to take care of those cases separately).
- * Usually passed to KPrinter::setPageSize().
- */
-KRITAODF_EXPORT QPrinter::PageSize printerPageSize(Format format);
-
-/**
- * Returns the width (in mm) for a given page format and orientation
- * 'Custom' isn't supported by this function, obviously.
- */
-KRITAODF_EXPORT qreal width(Format format, Orientation orientation = Landscape);
-
-/**
- * Returns the height (in mm) for a given page format and orientation
- * 'Custom' isn't supported by this function, obviously.
- */
-KRITAODF_EXPORT qreal height(Format format, Orientation orientation = Landscape);
-
-/**
- * Returns the internal name of the given page format.
- * Use for saving.
- */
-KRITAODF_EXPORT QString formatString(Format format);
-
-/**
- * Convert a format string (internal name) to a page format value.
- * Use for loading.
- */
-KRITAODF_EXPORT Format formatFromString(const QString &string);
-
-/**
- * Returns the default format (based on the KControl settings)
- */
-KRITAODF_EXPORT Format defaultFormat();
-
-/**
- * Returns the translated name of the given page format.
- * Use for showing the user.
- */
-KRITAODF_EXPORT QString name(Format format);
-
-/**
- * Lists the translated names of all the available formats
- */
-KRITAODF_EXPORT QStringList localizedPageFormatNames();
-
-/**
- * Lists the non-translated names of all the available formats
- */
-KRITAODF_EXPORT QStringList pageFormatNames();
-
-/**
- * Try to find the paper format for the given width and height (in mm).
- * Useful to some import filters.
- */
-KRITAODF_EXPORT Format guessFormat(qreal width, qreal height);
-}
-
-#endif
-
diff --git a/libs/odf/KoPageLayout.cpp b/libs/odf/KoPageLayout.cpp
deleted file mode 100644
index 0fa313d75c..0000000000
--- a/libs/odf/KoPageLayout.cpp
+++ /dev/null
@@ -1,176 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
- Copyright 2002, 2003 David Faure <faure@kde.org>
- Copyright 2003 Nicolas GOUTTE <goutte@kde.org>
- Copyright 2007, 2010 Thomas Zander <zander@kde.org>
- Copyright 2009 Inge Wallin <inge@lysator.liu.se>
-
- 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 "KoPageLayout.h"
-
-#include <OdfDebug.h>
-
-#include "KoXmlNS.h"
-#include "KoUnit.h"
-#include "KoXmlReader.h"
-
-KoGenStyle KoPageLayout::saveOdf() const
-{
- KoGenStyle style(KoGenStyle::PageLayoutStyle);
-
- // Save page dimension.
- style.addPropertyPt("fo:page-width", width);
- style.addPropertyPt("fo:page-height", height);
-
- // Save margins. If all margins are the same, only one value needs to be saved.
- if (leftMargin == topMargin && leftMargin == rightMargin && leftMargin == bottomMargin) {
- style.addPropertyPt("fo:margin", leftMargin);
- }
- else {
- style.addPropertyPt("fo:margin-left", leftMargin);
- style.addPropertyPt("fo:margin-right", rightMargin);
- style.addPropertyPt("fo:margin-top", topMargin);
- style.addPropertyPt("fo:margin-bottom", bottomMargin);
- }
-
- // Save padding. If all paddings are the same, only one value needs to be saved.
- if (leftPadding == topPadding && leftPadding == rightPadding && leftPadding == bottomPadding) {
- style.addPropertyPt("fo:padding", leftPadding);
- }
- else {
- style.addPropertyPt("fo:padding-left", leftPadding);
- style.addPropertyPt("fo:padding-right", rightPadding);
- style.addPropertyPt("fo:padding-top", topPadding);
- style.addPropertyPt("fo:padding-bottom", bottomPadding);
- }
-
- // If there are any page borders, add them to the style.
- border.saveOdf(style);
-
- style.addProperty("style:print-orientation",
- (orientation == KoPageFormat::Landscape
- ? "landscape" : "portrait"));
- return style;
-}
-
-void KoPageLayout::loadOdf(const KoXmlElement &style)
-{
- KoXmlElement properties(KoXml::namedItemNS(style, KoXmlNS::style,
- "page-layout-properties"));
-
- if (!properties.isNull()) {
- KoPageLayout standard;
-
- // Page dimension -- width / height
- width = KoUnit::parseValue(properties.attributeNS(KoXmlNS::fo, "page-width"),
- standard.width);
- height = KoUnit::parseValue(properties.attributeNS(KoXmlNS::fo, "page-height"),
- standard.height);
-
- // Page orientation
- if (properties.attributeNS(KoXmlNS::style, "print-orientation", QString()) == "portrait")
- orientation = KoPageFormat::Portrait;
- else
- orientation = KoPageFormat::Landscape;
-
- // Margins. Check if there is one "margin" attribute and use it for all
- // margins if there is. Otherwise load the individual margins.
- if (properties.hasAttributeNS(KoXmlNS::fo, "margin")) {
- leftMargin = KoUnit::parseValue(properties.attributeNS(KoXmlNS::fo, "margin"));
- topMargin = leftMargin;
- rightMargin = leftMargin;
- bottomMargin = leftMargin;
- } else {
- /*
- If one of the individual margins is specified then the default for the others is zero.
- Otherwise all of them are set to 20mm.
- */
- qreal defaultValue = 0;
- if (!(properties.hasAttributeNS(KoXmlNS::fo, "margin-left")
- || properties.hasAttributeNS(KoXmlNS::fo, "margin-top")
- || properties.hasAttributeNS(KoXmlNS::fo, "margin-right")
- || properties.hasAttributeNS(KoXmlNS::fo, "margin-bottom")))
- defaultValue = MM_TO_POINT(20.0); // no margin specified at all, lets make it 20mm
-
- leftMargin = KoUnit::parseValue(properties.attributeNS(KoXmlNS::fo, "margin-left"), defaultValue);
- topMargin = KoUnit::parseValue(properties.attributeNS(KoXmlNS::fo, "margin-top"), defaultValue);
- rightMargin = KoUnit::parseValue(properties.attributeNS(KoXmlNS::fo, "margin-right"), defaultValue);
- bottomMargin = KoUnit::parseValue(properties.attributeNS(KoXmlNS::fo, "margin-bottom"), defaultValue);
- }
-
- // Padding. Same reasoning as for margins
- if (properties.hasAttributeNS(KoXmlNS::fo, "padding")) {
- leftPadding = KoUnit::parseValue(properties.attributeNS(KoXmlNS::fo, "padding"));
- topPadding = leftPadding;
- rightPadding = leftPadding;
- bottomPadding = leftPadding;
- }
- else {
- leftPadding = KoUnit::parseValue(properties.attributeNS(KoXmlNS::fo, "padding-left"));
- topPadding = KoUnit::parseValue(properties.attributeNS(KoXmlNS::fo, "padding-top"));
- rightPadding = KoUnit::parseValue(properties.attributeNS(KoXmlNS::fo, "padding-right"));
- bottomPadding = KoUnit::parseValue(properties.attributeNS(KoXmlNS::fo, "padding-bottom"));
- }
-
- // Parse border properties if there are any.
- border.loadOdf(properties);
-
- // guessFormat takes millimeters
- if (orientation == KoPageFormat::Landscape)
- format = KoPageFormat::guessFormat(POINT_TO_MM(height), POINT_TO_MM(width));
- else
- format = KoPageFormat::guessFormat(POINT_TO_MM(width), POINT_TO_MM(height));
- }
-}
-
-bool KoPageLayout::operator==(const KoPageLayout &l) const
-{
- return qFuzzyCompare(width,l.width)
- && qFuzzyCompare(height,l.height)
- && qFuzzyCompare(leftMargin,l.leftMargin)
- && qFuzzyCompare(rightMargin,l.rightMargin)
- && qFuzzyCompare(topMargin,l.topMargin)
- && qFuzzyCompare(bottomMargin,l.bottomMargin)
- && qFuzzyCompare(pageEdge,l.pageEdge)
- && qFuzzyCompare(bindingSide,l.bindingSide)
- && border == l.border;
-}
-
-bool KoPageLayout::operator!=(const KoPageLayout& l) const
-{
- return !((*this) == l);
-}
-
-KoPageLayout::KoPageLayout()
- : format(KoPageFormat::defaultFormat())
- , orientation(KoPageFormat::Portrait)
- , width(MM_TO_POINT(KoPageFormat::width(format, orientation)))
- , height(MM_TO_POINT(KoPageFormat::height(format, orientation)))
- , leftMargin(MM_TO_POINT(20.0))
- , rightMargin(MM_TO_POINT(20.0))
- , topMargin(MM_TO_POINT(20.0))
- , bottomMargin(MM_TO_POINT(20.0))
- , pageEdge(-1)
- , bindingSide(-1)
- , leftPadding(0)
- , rightPadding(0)
- , topPadding(0)
- , bottomPadding(0)
- , border()
-{
-}
diff --git a/libs/odf/KoPageLayout.h b/libs/odf/KoPageLayout.h
deleted file mode 100644
index 9497e673ba..0000000000
--- a/libs/odf/KoPageLayout.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
- Copyright 2002, 2003 David Faure <faure@kde.org>
- Copyright 2003 Nicolas GOUTTE <goutte@kde.org>
- Copyright 2007 Thomas Zander <zander@kde.org>
-
- 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 KOPAGELAYOUT_H
-#define KOPAGELAYOUT_H
-
-#include "KoPageFormat.h"
-#include "KoXmlReaderForward.h"
-#include "KoBorder.h"
-
-#include "kritaodf_export.h"
-
-class KoGenStyle;
-
-/**
- * This structure defines the page layout, including
- * its size in points, its format (e.g. A4), orientation, unit, margins etc.
- */
-struct KoPageLayout {
- /** Page format */
- KoPageFormat::Format format;
- /** Page orientation */
- KoPageFormat::Orientation orientation;
-
- /** Page width in points */
- qreal width;
- /** Page height in points */
- qreal height;
-
- /**
- * margin on left edge
- * Using a margin >= 0 here indicates this is a single page system and the
- * bindingSide + pageEdge variables should be -1 at the same time.
- */
- qreal leftMargin;
- /**
- * margin on right edge
- * Using a margin >= 0 here indicates this is a single page system and the
- * bindingSide + pageEdge variables should be -1 at the same time.
- */
- qreal rightMargin;
- /** Top margin in points */
- qreal topMargin;
- /** Bottom margin in points */
- qreal bottomMargin;
-
- /**
- * margin on page edge
- * Using a margin >= 0 here indicates this is a pageSpread (facing pages) and the
- * left + right variables should be -1 at the same time.
- */
- qreal pageEdge;
- /**
- * margin on page-binding edge
- * Using a margin >= 0 here indicates this is a pageSpread (facing pages) and the
- * left + right variables should be -1 at the same time.
- */
- qreal bindingSide;
-
- /** Left padding in points */
- qreal leftPadding;
- /** Right padding in points */
- qreal rightPadding;
- /** Top padding in points */
- qreal topPadding;
- /** Bottom padding in points */
- qreal bottomPadding;
-
- /// page border definition
- KoBorder border;
-
- KRITAODF_EXPORT bool operator==(const KoPageLayout &l) const;
- KRITAODF_EXPORT bool operator!=(const KoPageLayout& l) const;
-
- /**
- * Save this page layout to ODF.
- */
- KRITAODF_EXPORT KoGenStyle saveOdf() const;
-
- /**
- * Load this page layout from ODF
- */
- KRITAODF_EXPORT void loadOdf(const KoXmlElement &style);
-
- /**
- * Construct a page layout with the default page size depending on the locale settings,
- * default margins (2 cm), and portrait orientation.
- */
- KRITAODF_EXPORT KoPageLayout();
-};
-
-#endif /* KOPAGELAYOUT_H */
-
diff --git a/libs/odf/KoShadowStyle.cpp b/libs/odf/KoShadowStyle.cpp
deleted file mode 100644
index 1ee7b81e7c..0000000000
--- a/libs/odf/KoShadowStyle.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
- *
- * 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 "KoShadowStyle.h"
-
-#include <KoUnit.h>
-
-
-// KoShadowStyle private class
-class KoShadowStylePrivate: public QSharedData
-{
-public:
- KoShadowStylePrivate();
- ~KoShadowStylePrivate();
-
- QVector<KoShadowStyle::ShadowData> shadows;
-};
-
-KoShadowStylePrivate::KoShadowStylePrivate()
-{
-}
-
-KoShadowStylePrivate::~KoShadowStylePrivate()
-{
-}
-
-// KoShadowStyle::ShadowData structure
-KoShadowStyle::ShadowData::ShadowData()
- : color(), offset(0, 0), radius(0.0)
-{
-}
-
-bool KoShadowStyle::ShadowData::operator==(const KoShadowStyle::ShadowData &other) const
-{
- return (color == other.color) && (offset == other.offset) && (radius == other.radius);
-}
-
-// KoShadowStyle class
-KoShadowStyle::KoShadowStyle()
- : d(new KoShadowStylePrivate)
-{
-}
-
-KoShadowStyle::KoShadowStyle(const KoShadowStyle &other)
- : d(other.d)
-{
-}
-
-KoShadowStyle::~KoShadowStyle()
-{
-}
-
-bool KoShadowStyle::operator==(const KoShadowStyle &other) const
-{
- if (d.data() == other.d.data())
- return true;
-
- if (shadowCount() != other.shadowCount())
- return false;
-
- foreach (const ShadowData &data, d->shadows)
- {
- if (!other.d->shadows.contains(data))
- return false;
- }
- return true;
-}
-
-bool KoShadowStyle::operator!=(const KoShadowStyle &other) const
-{
- return !operator==(other);
-}
-
-// load value string as specified by CSS2 §7.16.5 "text-shadow"
-bool KoShadowStyle::loadOdf (const QString &data)
-{
- if (data == QLatin1String("none"))
- return true;
-
- const QStringList sub_shadows = data.split(QLatin1Char(','));
- foreach (const QString &shadow, sub_shadows) {
- QStringList words = shadow.split(QLatin1Char(' '), QString::SkipEmptyParts);
- if (words.isEmpty())
- return false;
-
- KoShadowStyle::ShadowData currentData;
-
- // look for color at begin
- QColor shadowColor(words.first());
- if (shadowColor.isValid()) {
- currentData.color = shadowColor;
- words.removeFirst();
- } else if (words.length() > 2) {
- // look for color at end, if there could be one
- shadowColor = QColor(words.last());
- if (shadowColor.isValid()) {
- currentData.color = shadowColor;
- words.removeLast();
- }
- }
- // We keep an invalid color.if none was found
-
- // "Each shadow effect must specify a shadow offset and may optionally
- // specify a blur radius and a shadow color.", from CSS2 §7.16.5 "text-shadow"
- // But for some reason also no offset has been accepted before. TODO: which?
- if (! words.isEmpty()) {
- if ((words.length() < 2) || (words.length() > 3))
- return false;
-
- // Parse offset
- currentData.offset.setX(KoUnit::parseValue(words.at(0), 0.0));
- currentData.offset.setY(KoUnit::parseValue(words.at(1), 0.0));
- // Parse blur radius if present
- if (words.length() == 3)
- currentData.radius = KoUnit::parseValue(words.at(2), 0.0);
- }
- d->shadows << currentData;
- }
- return true;
-}
-
-int KoShadowStyle::shadowCount() const
-{
- return d->shadows.size();
-}
-
-QString KoShadowStyle::saveOdf() const
-{
- if (d->shadows.isEmpty())
- return QLatin1String("none");
-
- QStringList parts;
- const QString pt = QLatin1String("%1pt");
- foreach (const ShadowData &data, d->shadows) {
- QStringList elements;
- if (data.color.isValid()) {
- elements << data.color.name();
- }
- elements << pt.arg(data.offset.x()) << pt.arg(data.offset.y());
- if (data.radius != 0)
- elements << pt.arg(data.radius);
-
- parts << elements.join(QLatin1String(" "));
- }
- return parts.join(QLatin1String(","));
-}
-
diff --git a/libs/odf/KoShadowStyle.h b/libs/odf/KoShadowStyle.h
deleted file mode 100644
index 8f3b2e5b08..0000000000
--- a/libs/odf/KoShadowStyle.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
- *
- * 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 KOSHADOWSTYLE_H
-#define KOSHADOWSTYLE_H
-
-#include "kritaodf_export.h"
-
-#include <QColor>
-#include <QMetaType>
-#include <QPointF>
-#include <QSharedDataPointer>
-
-class KoShadowStylePrivate;
-
-/**
- * A container and parser for shadows as defined in the
- * OpenDocument specification.
- * Applies to at least :
- * - graphic elements,
- * - headers-footers,
- * - pages,
- * - paragraphs,
- * - tables and table cells.
- */
-class KRITAODF_EXPORT KoShadowStyle
-{
-public:
- /// Default constructor, constructs an empty shadow
- KoShadowStyle();
- /// Copy constructor
- KoShadowStyle(const KoShadowStyle &other);
- ~KoShadowStyle();
-
-
- // Holds data about one of the shadow this shadow contains
- struct KRITAODF_EXPORT ShadowData {
- ShadowData();
- bool operator==(const ShadowData &other) const;
- QColor color;
- QPointF offset;
- qreal radius;
- };
-
-
- bool operator==(const KoShadowStyle &other) const;
- bool operator!=(const KoShadowStyle &other) const;
-
- /**
- * Loads the given OpenDocument-defined shadow
- * in this KoShadow object.
- * @param shadow the shadow to parse
- * @return true when the parsing was successful
- */
- bool loadOdf(const QString &shadow);
-
- /**
- * Returns this shadow as a string formatted like an
- * OpenDocument-defined shadow.
- */
- QString saveOdf() const;
-
- /**
- * Returns the number of shadows that are contained in this shadow
- */
- int shadowCount() const;
-
-
-private:
- QSharedDataPointer<KoShadowStylePrivate> d;
-};
-
-Q_DECLARE_TYPEINFO(KoShadowStyle::ShadowData, Q_MOVABLE_TYPE);
-
-Q_DECLARE_METATYPE(KoShadowStyle)
-
-#endif
-
diff --git a/libs/odf/KoStyleStack.cpp b/libs/odf/KoStyleStack.cpp
deleted file mode 100644
index 7b09f5e5b1..0000000000
--- a/libs/odf/KoStyleStack.cpp
+++ /dev/null
@@ -1,279 +0,0 @@
-/* This file is part of the KDE project
- Copyright (c) 2003 Lukas Tinkl <lukas@kde.org>
- Copyright (c) 2003 David Faure <faure@kde.org>
-
- 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 "KoStyleStack.h"
-#include "KoUnit.h"
-#include "KoXmlNS.h"
-#include "KoXmlReader.h"
-
-#include <OdfDebug.h>
-
-//#define DEBUG_STYLESTACK
-
-class KoStyleStack::KoStyleStackPrivate
-{
-};
-
-KoStyleStack::KoStyleStack()
- : m_styleNSURI(KoXmlNS::style), m_foNSURI(KoXmlNS::fo), d(0)
-{
- clear();
-}
-
-KoStyleStack::KoStyleStack(const char* styleNSURI, const char* foNSURI)
- : m_styleNSURI(styleNSURI), m_foNSURI(foNSURI), d(0)
-{
- m_propertiesTagNames.append("properties");
- clear();
-}
-
-KoStyleStack::~KoStyleStack()
-{
- delete d;
-}
-
-void KoStyleStack::clear()
-{
- m_stack.clear();
-#ifdef DEBUG_STYLESTACK
- debugOdf << "clear!";
-#endif
-}
-
-void KoStyleStack::save()
-{
- m_marks.push(m_stack.count());
-#ifdef DEBUG_STYLESTACK
- debugOdf << "save (level" << m_marks.count() << ") -> index" << m_stack.count();
-#endif
-}
-
-void KoStyleStack::restore()
-{
- Q_ASSERT(!m_marks.isEmpty());
- int toIndex = m_marks.pop();
-#ifdef DEBUG_STYLESTACK
- debugOdf << "restore (level" << m_marks.count() + 1 << ") -> to index" << toIndex;
-#endif
- Q_ASSERT(toIndex > -1);
- Q_ASSERT(toIndex <= (int)m_stack.count()); // If equal, nothing to remove. If greater, bug.
- for (int index = (int)m_stack.count() - 1; index >= toIndex; --index)
- m_stack.pop_back();
-}
-
-void KoStyleStack::pop()
-{
- Q_ASSERT(!m_stack.isEmpty());
- m_stack.pop_back();
-#ifdef DEBUG_STYLESTACK
- debugOdf << "pop -> count=" << m_stack.count();
-#endif
-}
-
-void KoStyleStack::push(const KoXmlElement& style)
-{
- m_stack.append(style);
-#ifdef DEBUG_STYLESTACK
- debugOdf << "pushed" << style.attributeNS(m_styleNSURI, "name", QString()) << " -> count=" << m_stack.count();
-#endif
-}
-
-QString KoStyleStack::property(const QString &nsURI, const QString &name) const
-{
- return property(nsURI, name, 0);
-}
-QString KoStyleStack::property(const QString &nsURI, const QString &name, const QString &detail) const
-{
- return property(nsURI, name, &detail);
-}
-
-inline QString KoStyleStack::property(const QString &nsURI, const QString &name, const QString *detail) const
-{
- QString fullName(name);
- if (detail) {
- fullName += '-' + *detail;
- }
- QList<KoXmlElement>::ConstIterator it = m_stack.end();
- while (it != m_stack.begin()) {
- --it;
- foreach (const QString &propertyTagName, m_propertiesTagNames) {
- KoXmlElement properties = KoXml::namedItemNS(*it, m_styleNSURI, propertyTagName);
- if (detail) {
- QString attribute(properties.attributeNS(nsURI, fullName));
- if (!attribute.isEmpty()) {
- return attribute;
- }
- }
- QString attribute(properties.attributeNS(nsURI, name));
- if (!attribute.isEmpty()) {
- return attribute;
- }
- }
- }
- return QString();
-}
-
-bool KoStyleStack::hasProperty(const QString &nsURI, const QString &name) const
-{
- return hasProperty(nsURI, name, 0);
-}
-
-bool KoStyleStack::hasProperty(const QString &nsURI, const QString &name, const QString &detail) const
-{
- return hasProperty(nsURI, name, &detail);
-}
-
-inline bool KoStyleStack::hasProperty(const QString &nsURI, const QString &name, const QString *detail) const
-{
- QString fullName(name);
- if (detail) {
- fullName += '-' + *detail;
- }
- QList<KoXmlElement>::ConstIterator it = m_stack.end();
- while (it != m_stack.begin()) {
- --it;
- foreach (const QString &propertiesTagName, m_propertiesTagNames) {
- const KoXmlElement properties = KoXml::namedItemNS(*it, m_styleNSURI, propertiesTagName);
- if (properties.hasAttributeNS(nsURI, name) ||
- (detail && properties.hasAttributeNS(nsURI, fullName)))
- return true;
- }
- }
- return false;
-}
-
-// Font size is a bit special. "115%" applies to "the fontsize of the parent style".
-// This can be generalized though (hasPropertyThatCanBePercentOfParent() ? :)
-QPair<qreal,qreal> KoStyleStack::fontSize(const qreal defaultFontPointSize) const
-{
- const QString name = "font-size";
- qreal percent = 100;
- QList<KoXmlElement>::ConstIterator it = m_stack.end(); // reverse iterator
-
- while (it != m_stack.begin()) {
- --it;
- foreach (const QString &propertiesTagName, m_propertiesTagNames) {
- KoXmlElement properties = KoXml::namedItemNS(*it, m_styleNSURI, propertiesTagName).toElement();
- if (properties.hasAttributeNS(m_foNSURI, name)) {
- const QString value = properties.attributeNS(m_foNSURI, name, QString());
- if (value.endsWith('%')) {
- //sebsauer, 20070609, the specs don't say that we have to calc them together but
- //just that we are looking for a valid parent fontsize. So, let's only take the
- //first percent definition into account and keep on to seek for a valid parent,
- //percent *= value.left( value.length() - 1 ).toDouble() / 100.0;
- if (percent == 100)
- percent = value.left(value.length() - 1).toDouble();
- } else {
- // e.g. 12pt and indicate that there was not percentage there
- return QPair<qreal,qreal> ((percent * KoUnit::parseValue(value))/100.0, 0.0);
- }
- break;
- }
- }
- }
-
- //if there was no valid parent, we return the default fontsize together with an optional calculated percent-value.
- return QPair<qreal,qreal> ((percent * defaultFontPointSize)/100.0, percent);
-}
-
-bool KoStyleStack::hasChildNode(const QString &nsURI, const QString &localName) const
-{
- QList<KoXmlElement>::ConstIterator it = m_stack.end();
- while (it != m_stack.begin()) {
- --it;
- foreach (const QString &propertiesTagName, m_propertiesTagNames) {
- KoXmlElement properties = KoXml::namedItemNS(*it, m_styleNSURI, propertiesTagName);
- if (!KoXml::namedItemNS(properties, nsURI, localName).isNull())
- return true;
- }
- }
-
- return false;
-}
-
-KoXmlElement KoStyleStack::childNode(const QString &nsURI, const QString &localName) const
-{
- QList<KoXmlElement>::ConstIterator it = m_stack.end();
-
- while (it != m_stack.begin()) {
- --it;
- foreach (const QString &propertiesTagName, m_propertiesTagNames) {
- KoXmlElement properties = KoXml::namedItemNS(*it, m_styleNSURI, propertiesTagName);
- KoXmlElement e = KoXml::namedItemNS(properties, nsURI, localName);
- if (!e.isNull())
- return e;
- }
- }
-
- return KoXmlElement(); // a null element
-}
-
-bool KoStyleStack::isUserStyle(const KoXmlElement& e, const QString& family) const
-{
- if (e.attributeNS(m_styleNSURI, "family", QString()) != family)
- return false;
- const KoXmlElement parent = e.parentNode().toElement();
- //debugOdf <<"tagName=" << e.tagName() <<" parent-tagName=" << parent.tagName();
- return parent.localName() == "styles" /*&& parent.namespaceURI() == KoXmlNS::office*/;
-}
-
-QString KoStyleStack::userStyleName(const QString& family) const
-{
- QList<KoXmlElement>::ConstIterator it = m_stack.end();
- while (it != m_stack.begin()) {
- --it;
- //debugOdf << (*it).attributeNS( m_styleNSURI,"name", QString());
- if (isUserStyle(*it, family))
- return (*it).attributeNS(m_styleNSURI, "name", QString());
- }
- // Can this ever happen?
- return "Standard";
-}
-
-QString KoStyleStack::userStyleDisplayName(const QString& family) const
-{
- QList<KoXmlElement>::ConstIterator it = m_stack.end();
- while (it != m_stack.begin()) {
- --it;
- //debugOdf << (*it).attributeNS( m_styleNSURI,"display-name");
- if (isUserStyle(*it, family))
- return (*it).attributeNS(m_styleNSURI, "display-name", QString());
- }
- return QString(); // no display name, this can happen since it's optional
-}
-
-void KoStyleStack::setTypeProperties(const char* typeProperties)
-{
- m_propertiesTagNames.clear();
- m_propertiesTagNames.append(typeProperties == 0 || qstrlen(typeProperties) == 0 ? QString("properties") : (QString(typeProperties) + "-properties"));
-}
-
-void KoStyleStack::setTypeProperties(const QList<QString> &typeProperties)
-{
- m_propertiesTagNames.clear();
- foreach (const QString &typeProperty, typeProperties) {
- if (!typeProperty.isEmpty()) {
- m_propertiesTagNames.append(typeProperty + "-properties");
- }
- }
- if (m_propertiesTagNames.empty()) {
- m_propertiesTagNames.append("properties");
- }
-}
diff --git a/libs/odf/KoStyleStack.h b/libs/odf/KoStyleStack.h
deleted file mode 100644
index d7f47b4bc4..0000000000
--- a/libs/odf/KoStyleStack.h
+++ /dev/null
@@ -1,199 +0,0 @@
-/* This file is part of the KDE project
- Copyright (c) 2003 Lukas Tinkl <lukas@kde.org>
- Copyright (c) 2003 David Faure <faure@kde.org>
-
- 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 KOSTYLESTACK_H
-#define KOSTYLESTACK_H
-
-
-#include <QList>
-#include <QStack>
-#include <QPair>
-
-#include "kritaodf_export.h"
-#include <KoXmlReaderForward.h>
-
-/**
- * @brief This class implements a stack for the different styles of an object.
- *
- * There can be several styles that are valid for one object. For example
- * a textobject on a page has styles 'pr3' and 'P7' and a paragraph in
- * that textobject has styles 'P1' and 'T3'. And some styles even have
- * parent-styles...
- *
- * If you want to know if there is, for example, the attribute 'fo:font-family'
- * for this paragraph, you have to look into style 'T3', 'P1', 'P7' and 'pr3'.
- * When you find this attribute in one style you have to stop processing the list
- * and take the found attribute for this object.
- *
- * This is what this class does. You can push styles on the stack while walking
- * through the xml-tree to your object and then ask the stack if any of the styles
- * provides a certain attribute. The stack will search from top to bottom, i.e.
- * in our example from 'T3' to 'pr3' and return the first occurrence of the wanted
- * attribute.
- *
- * So this is some sort of inheritance where the styles on top of the stack overwrite
- * the same attribute of a lower style on the stack.
- *
- * In general though, you wouldn't use push/pop directly, but KoOdfLoadingContext::fillStyleStack
- * or KoOdfLoadingContext::addStyles to automatically push a style and all its
- * parent styles onto the stack.
- */
-class KRITAODF_EXPORT KoStyleStack
-{
-public:
- /**
- * Create a OASIS style stack
- */
- KoStyleStack();
- /**
- * Create a style stack based on other namespaces than OASIS - used for OOo-1.1 import.
- */
- explicit KoStyleStack(const char* styleNSURI, const char* foNSURI);
- virtual ~KoStyleStack();
-
- /**
- * Clears the complete stack.
- */
- void clear();
-
- /**
- * Save the current state of the stack. Any items added between
- * this call and its corresponding restore() will be removed when calling restore().
- */
- void save();
-
- /**
- * Restore the stack to the state it was at the corresponding save() call.
- */
- void restore();
-
- /**
- * Removes the style on top of the stack.
- */
- void pop();
-
- /**
- * Pushes the new style onto the stack.
- */
- void push(const KoXmlElement& style);
-
- /**
- * Check if any of the styles on the stack has an attribute called 'localName'
- */
- bool hasProperty(const QString &nsURI, const QString &localName) const;
-
- /**
- * Check if any of the styles on the stack has an attribute called 'localname'-'detail'
- * where detail is e.g. left, right, top or bottom.
- * This allows to also find 'name' alone (e.g. padding implies padding-left, padding-right etc.)
- */
- bool hasProperty(const QString &nsURI, const QString &localName, const QString &detail) const;
-
- /**
- * Search for the attribute called 'localName', starting on top of the stack,
- * and return it.
- */
- QString property(const QString &nsURI, const QString &localName) const;
-
- /**
- * Search for the attribute called 'localName'-'detail', starting on top of the stack,
- * and return it, where detail is e.g. left, right, top or bottom.
- * This allows to also find 'name' alone (e.g. padding implies padding-left, padding-right etc.)
- */
- QString property(const QString &nsURI, const QString &localName, const QString &detail) const;
-
- /**
- * Check if any of the styles on the stack has a child element called 'localName' in the namespace 'nsURI'.
- */
- bool hasChildNode(const QString &nsURI, const QString &localName) const;
-
- /**
- * Search for a child element which has a child element called 'localName'
- * in the namespace 'nsURI' starting on top of the stack,
- * and return it.
- */
- KoXmlElement childNode(const QString &nsURI, const QString &localName) const;
-
- /**
- * Special case for the current font size, due to special handling of fo:font-size="115%".
- * First item in the returned value contains the font point size and the second the got percent.
- */
- QPair<qreal,qreal> fontSize(const qreal defaultFontPointSize = 12.0) const;
-
- /**
- * Return the name of the style specified by the user,
- * i.e. not an auto style.
- * This is used to know e.g. which user-style is associated with the current paragraph.
- * There could be none though.
- */
- QString userStyleName(const QString& family) const;
-
- /**
- * Return the display name of the style specified by the user,
- * i.e. not an auto style
- */
- QString userStyleDisplayName(const QString& family) const;
-
- /**
- * Set the type of properties that will be looked for.
- * For instance setTypeProperties("paragraph") will make hasAttribute() and attribute()
- * look into "paragraph-properties".
- * If @p typeProperties is 0, the stylestack is reset to look for "properties"
- * as it does by default.
- */
- void setTypeProperties(const char* typeProperties);
-
- /**
- * Overloaded method to also set backup properties to search in
- *
- * If the list is graphic, paragraph it will search first in graphic-properties and then in paragraph-properties
- */
- void setTypeProperties(const QList<QString> &typeProperties);
-
-private:
- bool isUserStyle(const KoXmlElement& e, const QString& family) const;
-
- inline bool hasProperty(const QString &nsURI, const QString &localName, const QString *detail) const;
-
- inline QString property(const QString &nsURI, const QString &localName, const QString *detail) const;
-
- /// For save/restore: stack of "marks". Each mark is an index in m_stack.
- QStack<int> m_marks;
-
- /**
- * We use QValueList instead of QValueStack because we need access to all styles
- * not only the top one.
- */
- QList<KoXmlElement> m_stack;
-
- QList<QString> m_propertiesTagNames;
-
- QString m_styleNSURI;
- QString m_foNSURI;
-
- class KoStyleStackPrivate;
- KoStyleStackPrivate * const d;
-
- // forbidden
- void operator=(const KoStyleStack&);
- KoStyleStack(const KoStyleStack&);
-};
-
-#endif /* KOSTYLESTACK_H */
diff --git a/libs/odf/KoTableProperties.h b/libs/odf/KoTableProperties.h
deleted file mode 100644
index e97e2d5c94..0000000000
--- a/libs/odf/KoTableProperties.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2010 Carlos Licea <carlos@kdab.com>
- *
- * 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 KOTABLEPROPERTIES_H
-#define KOTABLEPROPERTIES_H
-
-#include "KoTblStyle.h"
-
-class KoTableTemplate;
-
-class TableProperties
-{
-public:
- TableStyle* tableStyle();
- void setTableStyle(TableStyle* style);
-
- TableTemplate* tableTemplate();
- void setTableTemplate(KoTableTemplate* tableTemplate);
- TableTemplateFlags templateFlags();
- void setTemplateFlags(TableTemplateFlags templateFlags);
-
- bool printable() const;
- void setPrintable(bool printable);
-
- void setPrintRange(CellRange cellRange);
- CellRange printRange() const;
-
- void setName(QString name);
- QString name() const;
-
- void setProtected(bool isProtected);
- bool isPprotected() const;
- void setPlainPassword(QString password, QString uri = "http://www.w3.org/2000/09/xmldsig#sha1");
-
-private:
- void saveOdf(KoXmlWriter* writer, KoGenStyles* styles);
-
- TableStyle* m_style;
- TableTemplate* m_template;
- TableTemplateFlags m_templateFlags;
-
- bool m_printable;
- CellRange m_printRange;
- QString m_name;
-
- bool m_protected;
- QString m_password;
-};
-
-#endif
diff --git a/libs/odf/KoTableTemplate.h b/libs/odf/KoTableTemplate.h
deleted file mode 100644
index e2db8ca6d3..0000000000
--- a/libs/odf/KoTableTemplate.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2010 Carlos Licea <carlos@kdab.com>
- *
- * 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 KOTABLETEMPLATE_H
-#define KOTABLETEMPLATE_H
-
-#include "KoStyle.h"
-
-#include <QMap>
-
-class KoTableTemplate : public KoStyle
-{
-public:
- enum Type {
- BandingColumns,
- BandingRows,
- FirstColumn,
- FirstRow,
- LastColumn,
- LastRow
- };
- Q_DECLARE_FLAGS(Types, Type);
-
-private:
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(TableTemplate::Type)
-
-#endif
diff --git a/libs/odf/Mainpage.dox b/libs/odf/Mainpage.dox
deleted file mode 100644
index a98d7ac326..0000000000
--- a/libs/odf/Mainpage.dox
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * \mainpage
- *
- * KritaOdf is a library which contains all kind of classes for ODF
- * (OpenDocument Format) in Krita.
- */
-
-// DOXYGEN_SET_PROJECT_NAME = KritaOdf
-// DOXYGEN_SET_IGNORE_PREFIX = Ko K
diff --git a/libs/odf/OdfDebug.cpp b/libs/odf/OdfDebug.cpp
deleted file mode 100644
index d8a6d69fe4..0000000000
--- a/libs/odf/OdfDebug.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2015 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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 "OdfDebug.h"
-
-const QLoggingCategory &ODF_LOG() \
-{
- static const QLoggingCategory category("krita.lib.odf", QtInfoMsg);
- return category;
-}
-
-
diff --git a/libs/odf/OdfDebug.h b/libs/odf/OdfDebug.h
deleted file mode 100644
index 72f6789263..0000000000
--- a/libs/odf/OdfDebug.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2015 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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 ODF_DEBUG_H_
-#define ODF_DEBUG_H_
-
-#include <QDebug>
-#include <QLoggingCategory>
-#include <kritaodf_export.h>
-
-extern const KRITAODF_EXPORT QLoggingCategory &ODF_LOG();
-
-#define debugOdf qCDebug(ODF_LOG)
-#define warnOdf qCWarning(ODF_LOG)
-#define errorOdf qCCritical(ODF_LOG)
-
-#endif
diff --git a/libs/odf/tests/CMakeLists.txt b/libs/odf/tests/CMakeLists.txt
deleted file mode 100644
index dc5ec1500d..0000000000
--- a/libs/odf/tests/CMakeLists.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
-
-include(ECMAddTests)
-include(KritaAddBrokenUnitTest)
-
-ecm_add_tests(
- TestKoGenStyles.cpp
- TestOdfSettings.cpp
- TestKoOdfLoadingContext.cpp
- TestStorage.cpp
- NAME_PREFIX "libs-odf-"
- LINK_LIBRARIES kritaodf KF5::I18n Qt5::Test)
-
-ecm_add_tests(
- TestXmlWriter.cpp
- kodomtest.cpp
- TestKoUnit.cpp
- TestKoElementReference.cpp
- NAME_PREFIX "libs-odf-"
- LINK_LIBRARIES kritaodf Qt5::Test)
-
-
-include(KritaAddBrokenUnitTest)
-
-krita_add_broken_unit_test(
- TestNumberStyle.cpp
- TEST_NAME TestNumberStyle
- LINK_LIBRARIES kritaodf Qt5::Test
- NAME_PREFIX "libs-odf-")
-
diff --git a/libs/odf/tests/TestKoElementReference.cpp b/libs/odf/tests/TestKoElementReference.cpp
deleted file mode 100644
index 211ecf3ddd..0000000000
--- a/libs/odf/tests/TestKoElementReference.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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 "TestKoElementReference.h"
-
-#include <KoElementReference.h>
-
-#include <QTest>
-
-void TestKoElementReference::testElementReference()
-{
- KoElementReference ref1;
- KoElementReference ref2;
-
- QVERIFY(ref1 != ref2);
-
- KoElementReference ref3(ref1);
- QVERIFY(ref1 == ref3);
-
- {
- KoElementReference ref4;
- ref3 = ref4;
-
- QVERIFY(ref3 == ref4);
- }
-
- QVERIFY(ref3 != ref1);
-}
-
-QTEST_MAIN(TestKoElementReference)
diff --git a/libs/odf/tests/TestKoElementReference.h b/libs/odf/tests/TestKoElementReference.h
deleted file mode 100644
index ac7f0c3084..0000000000
--- a/libs/odf/tests/TestKoElementReference.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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 TESTKOELEMENTREFERENCE_H
-#define TESTKOELEMENTREFERENCE_H
-
-#include <QObject>
-
-class TestKoElementReference : public QObject
-{
- Q_OBJECT
-
-private Q_SLOTS:
-
- void testElementReference();
-};
-
-#endif
diff --git a/libs/odf/tests/TestKoGenStyles.cpp b/libs/odf/tests/TestKoGenStyles.cpp
deleted file mode 100644
index f855d8dc92..0000000000
--- a/libs/odf/tests/TestKoGenStyles.cpp
+++ /dev/null
@@ -1,378 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2004-2006 David Faure <faure@kde.org>
- Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
- Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- Copyright (C) 2009 Thomas Zander <zander@kde.org>
-
- 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 "TestKoGenStyles.h"
-
-#include <KoGenStyles.h>
-#include <KoXmlWriter.h>
-#include <OdfDebug.h>
-#include <QBuffer>
-#include <QRegExp>
-
-#include <QTest>
-
-#define TEST_BEGIN(publicId,systemId) \
- { \
- QByteArray cstr; \
- QBuffer buffer( &cstr ); \
- buffer.open( QIODevice::WriteOnly ); \
- { \
- KoXmlWriter writer( &buffer ); \
- writer.startDocument( "r", publicId, systemId ); \
- writer.startElement( "r" )
-
-#define TEST_END_QTTEST(expected) \
- writer.endElement(); \
- writer.endDocument(); \
- } \
- buffer.putChar( '\0' ); /*null-terminate*/ \
- QString expectedFull = QString::fromLatin1( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ); \
- expectedFull += expected; \
- QString s1 = QString::fromLatin1( cstr ); \
- QCOMPARE( expectedFull, s1 ); \
- }
-
-
-void TestKoGenStyles::testLookup()
-{
- debugOdf ;
- KoGenStyles coll;
-
- QMap<QString, QString> map1;
- map1.insert("map1key", "map1value");
- QMap<QString, QString> map2;
- map2.insert("map2key1", "map2value1");
- map2.insert("map2key2", "map2value2");
-
- QBuffer buffer;
- buffer.open(QIODevice::WriteOnly);
- KoXmlWriter childWriter(&buffer);
- childWriter.startElement("child");
- childWriter.addAttribute("test:foo", "bar");
- childWriter.endElement();
- QString childContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
-
- QBuffer buffer2;
- buffer2.open(QIODevice::WriteOnly);
- KoXmlWriter childWriter2(&buffer2);
- childWriter2.startElement("child2");
- childWriter2.addAttribute("test:foo", "bar");
- childWriter2.endElement();
- QString childContents2 = QString::fromUtf8(buffer2.buffer(), buffer2.buffer().size());
-
- KoGenStyle first(KoGenStyle::ParagraphAutoStyle, "paragraph");
- first.addAttribute("style:master-page-name", "Standard");
- first.addProperty("style:page-number", "0");
- first.addProperty("style:foobar", "2", KoGenStyle::TextType);
- first.addStyleMap(map1);
- first.addStyleMap(map2);
- first.addChildElement("test", childContents);
- first.addChildElement("test", childContents2, KoGenStyle::TextType);
-
- QString firstName = coll.insert(first);
- debugOdf << "The first style got assigned the name" << firstName;
- QVERIFY(!firstName.isEmpty());
- QCOMPARE(first.type(), KoGenStyle::ParagraphAutoStyle);
-
- KoGenStyle second(KoGenStyle::ParagraphAutoStyle, "paragraph");
- second.addAttribute("style:master-page-name", "Standard");
- second.addProperty("style:page-number", "0");
- second.addProperty("style:foobar", "2", KoGenStyle::TextType);
- second.addStyleMap(map1);
- second.addStyleMap(map2);
- second.addChildElement("test", childContents);
- second.addChildElement("test", childContents2, KoGenStyle::TextType);
-
- QString secondName = coll.insert(second);
- debugOdf << "The second style got assigned the name" << secondName;
-
- QCOMPARE(firstName, secondName); // check that sharing works
- QCOMPARE(first, second); // check that operator== works :)
-
- const KoGenStyle* s = coll.style(firstName, "paragraph"); // check insert of existing style
- QVERIFY(s != 0);
- QCOMPARE(*s, first);
- s = coll.style("foobarblah", "paragraph"); // check insert of non-existing style
- QVERIFY(s == 0);
-
- KoGenStyle third(KoGenStyle::ParagraphAutoStyle, "paragraph", secondName); // inherited style
- third.addProperty("style:margin-left", "1.249cm");
- third.addProperty("style:page-number", "0"); // same as parent
- third.addProperty("style:foobar", "3", KoGenStyle::TextType); // different from parent
- QCOMPARE(third.parentName(), secondName);
-
- QString thirdName = coll.insert(third, "P");
- debugOdf << "The third style got assigned the name" << thirdName;
- QVERIFY(thirdName != firstName);
- QVERIFY(!thirdName.isEmpty());
-
- KoGenStyle user(KoGenStyle::ParagraphStyle, "paragraph"); // differs from third since it doesn't inherit second, and has a different type
- user.addProperty("style:margin-left", "1.249cm");
-
- QString userStyleName = coll.insert(user, "User", KoGenStyles::DontAddNumberToName);
- debugOdf << "The user style got assigned the name" << userStyleName;
- QCOMPARE(userStyleName, QString("User"));
-
- KoGenStyle sameAsParent(KoGenStyle::ParagraphAutoStyle, "paragraph", secondName); // inherited style
- sameAsParent.addAttribute("style:master-page-name", "Standard");
- sameAsParent.addProperty("style:page-number", "0");
- sameAsParent.addProperty("style:foobar", "2", KoGenStyle::TextType);
- sameAsParent.addStyleMap(map1);
- sameAsParent.addStyleMap(map2);
- sameAsParent.addChildElement("test", childContents);
- sameAsParent.addChildElement("test", childContents2, KoGenStyle::TextType);
- QString sapName = coll.insert(sameAsParent, "foobar");
- debugOdf << "The 'same as parent' style got assigned the name" << sapName;
-
- QCOMPARE(sapName, secondName);
- QCOMPARE(coll.styles().count(), 3);
-
- // OK, now add a style marked as for styles.xml; it looks like the above style, but
- // since it's marked for styles.xml it shouldn't be shared with it.
- KoGenStyle headerStyle(KoGenStyle::ParagraphAutoStyle, "paragraph");
- headerStyle.addAttribute("style:master-page-name", "Standard");
- headerStyle.addProperty("style:page-number", "0");
- headerStyle.addProperty("style:foobar", "2", KoGenStyle::TextType);
- headerStyle.addStyleMap(map1);
- headerStyle.addStyleMap(map2);
- headerStyle.setAutoStyleInStylesDotXml(true);
- QString headerStyleName = coll.insert(headerStyle, "foobar");
-
- QCOMPARE(coll.styles().count(), 4);
- //QCOMPARE(coll.styles(KoGenStyle::ParagraphAutoStyle).count(), 2);
- //QCOMPARE(coll.styles(KoGenStyle::ParagraphStyle).count(), 1);
-
- // XML for first/second style
- TEST_BEGIN(0, 0);
- first.writeStyle(&writer, coll, "style:style", firstName, "style:paragraph-properties");
-
-
- TEST_END_QTTEST("<r>\n <style:style style:name=\"" + firstName + "\" style:family=\"paragraph\" "
- "style:master-page-name=\"Standard\">\n <style:paragraph-properties style:page-number=\"0\">\n"
- " <child test:foo=\"bar\"/>\n </style:paragraph-properties>\n <style:text-properties style:foobar=\"2\">\n"
- " <child2 test:foo=\"bar\"/>\n </style:text-properties>\n"
- " <style:map map1key=\"map1value\"/>\n <style:map map2key1=\"map2value1\" map2key2=\"map2value2\"/>\n"
- " </style:style>\n</r>\n");
-
- // XML for third style
- TEST_BEGIN(0, 0);
- third.writeStyle(&writer, coll, "style:style", thirdName, "style:paragraph-properties");
- TEST_END_QTTEST("<r>\n <style:style style:name=\"" + thirdName + "\""
- " style:parent-style-name=\"" + firstName + "\" style:family=\"paragraph\">\n"
- " <style:paragraph-properties style:margin-left=\"1.249cm\"/>\n"
- " <style:text-properties style:foobar=\"3\"/>\n </style:style>\n</r>\n");
-}
-
-void TestKoGenStyles::testLookupFlags()
-{
- KoGenStyles coll;
-
- KoGenStyle first(KoGenStyle::ParagraphAutoStyle, "paragraph");
- first.addAttribute("style:master-page-name", "Standard");
- first.addProperty("style:page-number", "0");
-
- QString styleName = coll.insert(first, "P", KoGenStyles::DontAddNumberToName);
- QCOMPARE(styleName, QString("P"));
-
- styleName = coll.insert(first, "P");
- QCOMPARE(styleName, QString("P"));
-
- KoGenStyle second(KoGenStyle::ParagraphAutoStyle, "paragraph");
- second.addProperty("fo:text-align", "left");
-
- styleName = coll.insert(second, "P");
- QCOMPARE(styleName, QString("P1"));
-
- styleName = coll.insert(second, "P", KoGenStyles::AllowDuplicates);
- QCOMPARE(styleName, QString("P2"));
-
- styleName = coll.insert(second, "P", KoGenStyles::AllowDuplicates);
- QCOMPARE(styleName, QString("P3"));
-
- styleName = coll.insert(second, "P", KoGenStyles::AllowDuplicates | KoGenStyles::DontAddNumberToName);
- QCOMPARE(styleName, QString("P4"));
-}
-
-void TestKoGenStyles::testWriteStyle()
-{
- debugOdf;
- KoGenStyles coll;
-
- QBuffer buffer;
- buffer.open(QIODevice::WriteOnly);
- KoXmlWriter styleChildWriter(&buffer);
- styleChildWriter.startElement("styleChild");
- styleChildWriter.addAttribute("foo", "bar");
- styleChildWriter.endElement();
- QString styleChildContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
-
- KoGenStyle style(KoGenStyle::ParagraphStyle, "paragraph");
- style.addProperty("style:foo", "bar");
- style.addProperty("style:paragraph", "property", KoGenStyle::ParagraphType);
- style.addProperty("style:graphic", "property", KoGenStyle::GraphicType);
- style.addProperty("styleChild", styleChildContents, KoGenStyle::StyleChildElement);
- QString styleName = coll.insert(style, "P");
-
- // XML for style
- TEST_BEGIN(0, 0);
- style.writeStyle(&writer, coll, "style:style", styleName, "style:paragraph-properties");
- TEST_END_QTTEST("<r>\n <style:style style:name=\"P1\" style:family=\"paragraph\">\n <style:paragraph-properties style:foo=\"bar\" style:paragraph=\"property\"/>\n <style:graphic-properties style:graphic=\"property\"/>\n <styleChild foo=\"bar\"/>\n </style:style>\n</r>\n");
-
- KoGenStyle pageLayoutStyle(KoGenStyle::PageLayoutStyle);
- pageLayoutStyle.addProperty("style:print-orientation", "portrait");
- QString pageLayoutStyleName = coll.insert(pageLayoutStyle, "pm");
-
- // XML for page layout style
- TEST_BEGIN(0, 0);
- pageLayoutStyle.writeStyle(&writer, coll, "style:page-layout", pageLayoutStyleName, "style:page-layout-properties");
- TEST_END_QTTEST("<r>\n <style:page-layout style:name=\"pm1\">\n <style:page-layout-properties style:print-orientation=\"portrait\"/>\n </style:page-layout>\n</r>\n");
-
- KoGenStyle listStyle(KoGenStyle::ListStyle);
- QString listStyleName = coll.insert(listStyle, "L");
- // XML for list layout style
- TEST_BEGIN(0, 0);
- listStyle.writeStyle(&writer, coll, "text:list-style", listStyleName, 0);
- TEST_END_QTTEST("<r>\n <text:list-style style:name=\"L1\"/>\n</r>\n");
-}
-
-void TestKoGenStyles::testDefaultStyle()
-{
- debugOdf ;
- /* Create a default style,
- * and then an auto style with exactly the same attributes
- * -> the insert gives the default style.
- *
- * Also checks how the default style gets written out to XML.
- */
- KoGenStyles coll;
-
- KoGenStyle defaultStyle(KoGenStyle::ParagraphStyle, "paragraph");
- defaultStyle.addAttribute("style:master-page-name", "Standard");
- defaultStyle.addProperty("myfont", "isBold");
- defaultStyle.setDefaultStyle(true);
- QString defaultStyleName = coll.insert(defaultStyle);
- // default styles don't get a name
- QVERIFY(defaultStyleName.isEmpty());
- QCOMPARE(defaultStyle.type(), KoGenStyle::ParagraphStyle);
- QVERIFY(defaultStyle.isDefaultStyle());
-
- KoGenStyle anotherStyle(KoGenStyle::ParagraphStyle, "paragraph");
- anotherStyle.addAttribute("style:master-page-name", "Standard");
- anotherStyle.addProperty("myfont", "isBold");
- QString anotherStyleName = coll.insert(anotherStyle);
- QVERIFY(anotherStyleName != defaultStyleName);
-
- QCOMPARE(coll.styles().count(), 1);
-
- // XML for default style
- TEST_BEGIN(0, 0);
- defaultStyle.writeStyle(&writer, coll, "style:default-style", defaultStyleName, "style:paragraph-properties");
- TEST_END_QTTEST("<r>\n <style:default-style style:family=\"paragraph\" style:master-page-name=\"Standard\">\n <style:paragraph-properties myfont=\"isBold\"/>\n </style:default-style>\n</r>\n");
-
- // The kspread case: not writing out all properties, only if they differ
- // from the default style.
- // KoGenStyles doesn't fetch info from the parent style when testing
- // for equality, so KSpread uses isEmpty() to check for equality-to-parent.
- KoGenStyle dataStyle(KoGenStyle::ParagraphStyle, "paragraph", defaultStyleName);
- QVERIFY(dataStyle.isEmpty());
- // and then it doesn't look up the auto style, but rather uses the parent style directly.
-}
-
-void TestKoGenStyles:: testUserStyles()
-{
- debugOdf ;
- /* Two user styles with exactly the same attributes+properties will not get merged, since
- * they don't have exactly the same attributes after all: the display-name obviously differs :)
- */
- KoGenStyles coll;
-
- KoGenStyle user1(KoGenStyle::ParagraphStyle, "paragraph");
- user1.addAttribute("style:display-name", "User 1");
- user1.addProperty("myfont", "isBold");
-
- QString user1StyleName = coll.insert(user1, "User1", KoGenStyles::DontAddNumberToName);
- debugOdf << "The user style got assigned the name" << user1StyleName;
- QCOMPARE(user1StyleName, QString("User1"));
-
- KoGenStyle user2(KoGenStyle::ParagraphStyle, "paragraph");
- user2.addAttribute("style:display-name", "User 2");
- user2.addProperty("myfont", "isBold");
-
- QString user2StyleName = coll.insert(user2, "User2", KoGenStyles::DontAddNumberToName);
- debugOdf << "The user style got assigned the name" << user2StyleName;
- QCOMPARE(user2StyleName, QString("User2"));
-
- // And now, what if the data uses that style?
- // This is like sameAsParent in the other test, but this time the
- // parent is a STYLE_USER...
- KoGenStyle dataStyle(KoGenStyle::ParagraphAutoStyle, "paragraph", user2StyleName);
- dataStyle.addProperty("myfont", "isBold");
-
- QString dataStyleName = coll.insert(dataStyle, "DataStyle");
- debugOdf << "The auto style got assigned the name" << dataStyleName;
- QCOMPARE(dataStyleName, QString("User2")); // it found the parent as equal
-
- // Let's do the opposite test, just to make sure
- KoGenStyle dataStyle2(KoGenStyle::ParagraphAutoStyle, "paragraph", user2StyleName);
- dataStyle2.addProperty("myfont", "isNotBold");
-
- QString dataStyle2Name = coll.insert(dataStyle2, "DataStyle");
- debugOdf << "The different auto style got assigned the name" << dataStyle2Name;
- QCOMPARE(dataStyle2Name, QString("DataStyle1"));
-
- QCOMPARE(coll.styles().count(), 3);
-
- // XML for user style 1
- TEST_BEGIN(0, 0);
- user1.writeStyle(&writer, coll, "style:style", user1StyleName, "style:paragraph-properties");
- TEST_END_QTTEST("<r>\n <style:style style:name=\"User1\" style:display-name=\"User 1\" style:family=\"paragraph\">\n <style:paragraph-properties myfont=\"isBold\"/>\n </style:style>\n</r>\n");
-
- // XML for user style 2
- TEST_BEGIN(0, 0);
- user2.writeStyle(&writer, coll, "style:style", user2StyleName, "style:paragraph-properties");
- TEST_END_QTTEST("<r>\n <style:style style:name=\"User2\" style:display-name=\"User 2\" style:family=\"paragraph\">\n <style:paragraph-properties myfont=\"isBold\"/>\n </style:style>\n</r>\n");
-}
-
-void TestKoGenStyles::testStylesDotXml()
-{
- debugOdf ;
- KoGenStyles coll;
-
- // Check that an autostyle-in-style.xml and an autostyle-in-content.xml
- // don't get the same name. It confuses KoGenStyle's named-based maps.
- KoGenStyle headerStyle(KoGenStyle::ParagraphAutoStyle, "paragraph");
- headerStyle.addAttribute("style:master-page-name", "Standard");
- headerStyle.addProperty("style:page-number", "0");
- headerStyle.setAutoStyleInStylesDotXml(true);
- QString headerStyleName = coll.insert(headerStyle, "P");
- QCOMPARE(headerStyleName, QString("P1"));
-
- //debugOdf << coll;
-
- KoGenStyle first(KoGenStyle::ParagraphAutoStyle, "paragraph");
- first.addAttribute("style:master-page-name", "Standard");
- QString firstName = coll.insert(first, "P");
- debugOdf << "The auto style got assigned the name" << firstName;
- QCOMPARE(firstName, QString("P2")); // anything but not P1.
-}
-
-QTEST_MAIN(TestKoGenStyles)
diff --git a/libs/odf/tests/TestKoGenStyles.h b/libs/odf/tests/TestKoGenStyles.h
deleted file mode 100644
index dacb166f61..0000000000
--- a/libs/odf/tests/TestKoGenStyles.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef TESTKOGENSTYLES_H
-#define TESTKOGENSTYLES_H
-/* This file is part of the KDE project
- Copyright (C) 2004-2006 David Faure <faure@kde.org>
- Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
-
- 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 <QObject>
-
-class TestKoGenStyles : public QObject
-{
- Q_OBJECT
-private Q_SLOTS:
- void testLookup();
- void testLookupFlags();
- void testDefaultStyle();
- void testUserStyles();
- void testWriteStyle();
- void testStylesDotXml();
-};
-
-#endif // TESTKOGENSTYLES_H
diff --git a/libs/odf/tests/TestKoOdfLoadingContext.cpp b/libs/odf/tests/TestKoOdfLoadingContext.cpp
deleted file mode 100644
index 40a4c6a62a..0000000000
--- a/libs/odf/tests/TestKoOdfLoadingContext.cpp
+++ /dev/null
@@ -1,146 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
-
- 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 "TestKoOdfLoadingContext.h"
-
-#include <QByteArray>
-#include <QBuffer>
-#include <KoStore.h>
-#include <KoStoreDevice.h>
-#include <KoXmlReader.h>
-#include <KoXmlNS.h>
-#include <KoOdfLoadingContext.h>
-#include <KoStyleStack.h>
-#include <KoOdfReadStore.h>
-#include <KoOdfWriteStore.h>
-#include <KoXmlWriter.h>
-
-#include <QTest>
-
-void TestKoOdfLoadingContext::testFillStyleStack()
-{
-#if 0
- QByteArray byteArray;
- QBuffer buffer(&byteArray);
-#endif
- const char * mimeType = "application/vnd.oasis.opendocument.text";
- KoStore * store(KoStore::createStore("test.odt", KoStore::Write, mimeType));
- KoOdfWriteStore odfStore(store);
- KoXmlWriter* manifestWriter = odfStore.manifestWriter(mimeType);
-
- KoXmlWriter* contentWriter = odfStore.contentWriter();
- QVERIFY(contentWriter != 0);
-
- KoXmlWriter * bodyWriter = odfStore.bodyWriter();
-
- bodyWriter->startElement("office:body");
- bodyWriter->startElement("office:text");
- bodyWriter->startElement("draw:rect");
- bodyWriter->addAttribute("draw:style-name", "gr1");
- bodyWriter->endElement();
- bodyWriter->endElement();
- bodyWriter->endElement();
-
- contentWriter->startElement("office:automatic-styles");
- contentWriter->startElement("style:style");
- contentWriter->addAttribute("style:name", "gr1");
- contentWriter->addAttribute("style:family", "graphic");
- contentWriter->addAttribute("style:parent-style-name", "standard");
- contentWriter->startElement("style:graphic-properties");
- contentWriter->addAttribute("draw:fill", "solid");
- contentWriter->endElement();
- contentWriter->endElement();
- contentWriter->endElement(); // office:automatic-styles
-
- odfStore.closeContentWriter();
-
- //add manifest line for content.xml
- manifestWriter->addManifestEntry("content.xml", "text/xml");
-
- QVERIFY(store->open("styles.xml") == true);
-
- KoStoreDevice stylesDev(store);
- KoXmlWriter* stylesWriter = KoOdfWriteStore::createOasisXmlWriter(&stylesDev, "office:document-styles");
-
- stylesWriter->startElement("office:styles");
- stylesWriter->startElement("style:style");
- stylesWriter->addAttribute("style:name", "standard");
- stylesWriter->addAttribute("style:family", "graphic");
- stylesWriter->startElement("style:graphic-properties");
- stylesWriter->addAttribute("draw:fill", "hatch");
- stylesWriter->addAttribute("draw:stroke", "solid");
- stylesWriter->endElement();
- stylesWriter->endElement();
- stylesWriter->endElement();
-
- stylesWriter->startElement("office:automatic-styles");
- stylesWriter->startElement("style:style");
- stylesWriter->addAttribute("style:name", "gr1");
- stylesWriter->addAttribute("style:family", "graphic");
- stylesWriter->addAttribute("style:parent-style-name", "standard");
- stylesWriter->startElement("style:graphic-properties");
- stylesWriter->addAttribute("draw:fill", "none");
- stylesWriter->addAttribute("draw:stroke", "none");
- stylesWriter->endElement();
- stylesWriter->endElement();
- stylesWriter->endElement(); // office:automatic-styles
-
- stylesWriter->endElement(); // root element (office:document-styles)
- stylesWriter->endDocument();
- delete stylesWriter;
-
- manifestWriter->addManifestEntry("styles.xml", "text/xml");
-
- QVERIFY(store->close() == true); // done with styles.xml
-
- QVERIFY(odfStore.closeManifestWriter() == true);
-
- delete store;
-
- store = KoStore::createStore("test.odt", KoStore::Read, mimeType);
- KoOdfReadStore readStore(store);
- QString errorMessage;
- QVERIFY(readStore.loadAndParse(errorMessage) == true);
- KoOdfLoadingContext context(readStore.styles(), readStore.store());
-
- KoXmlElement content = readStore.contentDoc().documentElement();
- KoXmlElement realBody(KoXml::namedItemNS(content, KoXmlNS::office, "body"));
-
- QVERIFY(realBody.isNull() == false);
-
- KoXmlElement body = KoXml::namedItemNS(realBody, KoXmlNS::office, "text");
- QVERIFY(body.isNull() == false);
-
- KoXmlElement tag;
- forEachElement(tag, body) {
- //tz: So now that I have a test the fails I can go on implementing the solution
- QCOMPARE(tag.localName(), QString("rect"));
- KoStyleStack & styleStack = context.styleStack();
- styleStack.save();
- context.fillStyleStack(tag, KoXmlNS::draw, "style-name", "graphic");
- styleStack.setTypeProperties("graphic");
- QVERIFY(styleStack.hasProperty(KoXmlNS::draw, "fill"));
- QCOMPARE(styleStack.property(KoXmlNS::draw, "fill"), QString("solid"));
- QVERIFY(styleStack.hasProperty(KoXmlNS::draw, "stroke"));
- QCOMPARE(styleStack.property(KoXmlNS::draw, "stroke"), QString("solid"));
- styleStack.restore();
- }
- delete store;
-}
-
-QTEST_GUILESS_MAIN(TestKoOdfLoadingContext)
diff --git a/libs/odf/tests/TestKoOdfLoadingContext.h b/libs/odf/tests/TestKoOdfLoadingContext.h
deleted file mode 100644
index c6f83fbd2d..0000000000
--- a/libs/odf/tests/TestKoOdfLoadingContext.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
-
- 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.
-*/
-
-#ifndef TESTKOODFLOADINGCONTEXT_H
-#define TESTKOODFLOADINGCONTEXT_H
-
-#include <QObject>
-
-class TestKoOdfLoadingContext : public QObject
-{
- Q_OBJECT
-private Q_SLOTS:
- void testFillStyleStack();
-};
-
-#endif /* TESTKOODFLOADINGCONTEXT_H */
diff --git a/libs/odf/tests/TestKoXmlVector.cpp b/libs/odf/tests/TestKoXmlVector.cpp
deleted file mode 100644
index 2ac91bcf4a..0000000000
--- a/libs/odf/tests/TestKoXmlVector.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/* This file is part of the KDE project
- * Copyright 2015 Friedrich W. H. Kossebau <kossebau@kde.org>
- *
- * 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 "TestKoXmlVector.h"
-
-#include <KoXmlVector.h>
-
-#include <QTest>
-#include <QDebug>
-
-
-enum TestEnum
-{
- FirstType = 0,
- SecondType = 1,
- ThirdType = 2,
- FourthType = 3,
- FifthType = 4
-};
-
-class TestStruct
-{
-public:
- bool attr: 1;
- TestEnum type: 3;
- unsigned int number: 28;
- QString string;
-};
-
-Q_DECLARE_TYPEINFO(TestStruct, Q_MOVABLE_TYPE);
-
-static QDataStream& operator<<(QDataStream& s, const TestStruct& item)
-{
- quint8 flag = item.attr ? 1 : 0;
-
- s << flag;
- s << (quint8) item.type;
- s << item.number;
- s << item.string;
-
- return s;
-}
-
-static QDataStream& operator>>(QDataStream& s, TestStruct& item)
-{
- quint8 flag;
- quint8 type;
- int number;
- QString string;
-
- s >> flag;
- s >> type;
- s >> number;
- s >> string;
-
- item.attr = (flag != 0);
- item.type = (TestEnum) type;
- item.number = number;
- item.string = string;
-
- return s;
-}
-
-void TestKoXmlVector::simpleConstructor()
-{
- KoXmlVector<TestStruct> vector;
-
- QCOMPARE(vector.count(), 0);
- QCOMPARE(vector.size(), 0);
- QCOMPARE(vector.isEmpty(), true);
-}
-
-
-static const int writeAndReadUncompressedCount = 5;
-
-void TestKoXmlVector::writeAndRead_data()
-{
- QTest::addColumn<unsigned int>("itemCount");
- for(unsigned int i = 0; i < writeAndReadUncompressedCount*3+1; ++i) {
- QTest::newRow(QByteArray::number(i)) << i;
- }
-}
-
-
-void TestKoXmlVector::writeAndRead()
-{
- QFETCH(unsigned int, itemCount);
-
- KoXmlVector<TestStruct, writeAndReadUncompressedCount+1> vector;
-
- // add 3x items than what would not be compressed
- for (unsigned int i = 0; i < itemCount; ++i) {
- // test adding
- TestStruct &item = vector.newItem();
-
- const bool attr = (i % 2) == 0;
- const TestEnum type = (TestEnum)(i % 5);
- const unsigned int number = i;
- const QString string = QString::number(i);
-
- item.attr = attr;
- item.type = type;
- item.number = number;
- item.string = string;
-
- QCOMPARE(vector.count(), (signed)i+1);
- QCOMPARE(vector.size(), (signed)i+1);
- QCOMPARE(vector.isEmpty(), false);
- }
-
- vector.squeeze();
-
- // now check all in a row again, so including all the uncompressed
- for (unsigned int i = 0; i < itemCount; ++i) {
- const bool attr = (i % 2) == 0;
- const TestEnum type = (TestEnum)(i % 5);
- const unsigned int number = i;
- const QString string = QString::number(i);
-
- const TestStruct &readItem = vector[i];
-
- QCOMPARE(readItem.attr, attr);
- QCOMPARE(readItem.type, type);
- QCOMPARE(readItem.number, number);
- QCOMPARE(readItem.string, string);
- }
- // and backwards
- for (unsigned int ri = itemCount; ri > 0; --ri) {
- const unsigned int i = ri-1;
- const bool attr = (i % 2) == 0;
- const TestEnum type = (TestEnum)(i % 5);
- const unsigned int number = i;
- const QString string = QString::number(i);
-
- const TestStruct &readItem = vector[i];
-
- QCOMPARE(readItem.attr, attr);
- QCOMPARE(readItem.type, type);
- QCOMPARE(readItem.number, number);
- QCOMPARE(readItem.string, string);
- }
-}
-
-
-
-QTEST_GUILESS_MAIN(TestKoXmlVector)
diff --git a/libs/odf/tests/TestKoXmlVector.h b/libs/odf/tests/TestKoXmlVector.h
deleted file mode 100644
index f57f8cadf7..0000000000
--- a/libs/odf/tests/TestKoXmlVector.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* This file is part of the KDE project
- * Copyright 2015 Friedrich W. H. Kossebau <kossebau@kde.org>
- *
- * 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 TESTKOXMLVECTOR_H
-#define TESTKOXMLVECTOR_H
-
-// Qt
-#include <QObject>
-
-class TestKoXmlVector : public QObject
-{
- Q_OBJECT
-
-private Q_SLOTS:
- void simpleConstructor();
- void writeAndRead_data();
- void writeAndRead();
-};
-
-#endif
diff --git a/libs/odf/tests/TestNumberStyle.cpp b/libs/odf/tests/TestNumberStyle.cpp
deleted file mode 100644
index 5a39cc30e7..0000000000
--- a/libs/odf/tests/TestNumberStyle.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Sebastian Sauer <sebsauer@kdab.com>
- *
- * 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 "TestNumberStyle.h"
-
-#include <KoOdfNumberStyles.h>
-#include <QTest>
-
-QString escapeLocals(const QString &text)
-{
- QString t(text);
- t.replace(',','.');
- return t;
-}
-
-void TestNumberStyle::testEmpty()
-{
- KoOdfNumberStyles::NumericStyleFormat f;
- QCOMPARE(f.formatStr, QString());
- QCOMPARE(f.prefix, QString());
- QCOMPARE(f.suffix, QString());
- QCOMPARE(f.type, KoOdfNumberStyles::Text);
- QCOMPARE(f.precision, -1);
- QCOMPARE(f.currencySymbol, QString());
- QCOMPARE(f.thousandsSep, false);
- QCOMPARE(f.styleMaps.count(), 0);
-}
-
-void TestNumberStyle::testText()
-{
- KoOdfNumberStyles::NumericStyleFormat f;
- f.type = KoOdfNumberStyles::Text;
- QCOMPARE(KoOdfNumberStyles::format("Some text", f), QString("Some text"));
-}
-
-void TestNumberStyle::testNumber()
-{
- QCOMPARE(KoOdfNumberStyles::formatNumber(23, "0."), QString("23"));
- QCOMPARE(KoOdfNumberStyles::formatNumber(0, "0."), QString("0"));
-
- KoOdfNumberStyles::NumericStyleFormat f;
- f.type = KoOdfNumberStyles::Number;
- f.precision = 3;
- f.thousandsSep = true;
- f.formatStr = "00.00 test";
- QCOMPARE(KoOdfNumberStyles::format("12345.6789", f), QString("12345.679 test"));
- f.precision = 1;
- f.formatStr = "test1 00.00 test2";
- QCOMPARE(KoOdfNumberStyles::format("12345.6789", f), QString("test1 12345.70 test2"));
-}
-
-void TestNumberStyle::testDate()
-{
- QCOMPARE(KoOdfNumberStyles::formatDate(4567, "MM/dd/yyyy"), QString("07/02/1912"));
- QCOMPARE(KoOdfNumberStyles::formatDate(0, "MM/dd/yy"), QString("12/30/99"));
-}
-
-void TestNumberStyle::testTime()
-{
- QCOMPARE(KoOdfNumberStyles::formatTime(0.524259259259, "hh:mm:ss"), QString("12:34:56"));
- QCOMPARE(KoOdfNumberStyles::formatTime(0.524259259259, "hh:mm"), QString("12:34"));
- QCOMPARE(KoOdfNumberStyles::formatTime(0, "hh:mm:ss"), QString("00:00:00"));
-
- KoOdfNumberStyles::NumericStyleFormat f;
- f.type = KoOdfNumberStyles::Time;
- f.formatStr = "hh:mm:ss";
- QCOMPARE(KoOdfNumberStyles::format("0.524259259259", f), QString("12:34:56"));
- QCOMPARE(KoOdfNumberStyles::format("test", f), QString("test"));
- QCOMPARE(KoOdfNumberStyles::format("123", f), QString("00:00:00"));
- QCOMPARE(KoOdfNumberStyles::format("1.23", f), QString("05:31:12"));
-}
-
-void TestNumberStyle::testBoolean()
-{
- QCOMPARE(KoOdfNumberStyles::formatBoolean("0", ""), QString("FALSE"));
- QCOMPARE(KoOdfNumberStyles::formatBoolean("234", ""), QString("TRUE"));
- QCOMPARE(KoOdfNumberStyles::formatBoolean("0", ""), QString("FALSE"));
-
- KoOdfNumberStyles::NumericStyleFormat f;
- f.type = KoOdfNumberStyles::Boolean;
- QCOMPARE(KoOdfNumberStyles::format("0", f), QString("FALSE"));
- QCOMPARE(KoOdfNumberStyles::format("1", f), QString("TRUE"));
- QCOMPARE(KoOdfNumberStyles::format("123", f), QString("TRUE"));
- QCOMPARE(KoOdfNumberStyles::format("test", f), QString("FALSE"));
-}
-
-void TestNumberStyle::testPercent()
-{
- QCOMPARE(KoOdfNumberStyles::formatPercent("23", ""), QString("23"));
- QCOMPARE(KoOdfNumberStyles::formatPercent("23.4567", "0.00%", 2), QString("2345.67%"));
- QCOMPARE(KoOdfNumberStyles::formatPercent("23.456789", "0.0000%", 4), QString("2345.6789%"));
- QCOMPARE(KoOdfNumberStyles::formatPercent("0", ""), QString("0"));
-
- KoOdfNumberStyles::NumericStyleFormat f;
- f.type = KoOdfNumberStyles::Percentage;
- f.precision = 2;
- f.formatStr = "0%";
- QCOMPARE(KoOdfNumberStyles::format("0.2", f), QString("20.00%"));
- QCOMPARE(KoOdfNumberStyles::format("0.02", f), QString("2.00%"));
- QCOMPARE(KoOdfNumberStyles::format("0.02228", f), QString("2.23%"));
- QCOMPARE(KoOdfNumberStyles::format("test", f), QString("test"));
- QCOMPARE(KoOdfNumberStyles::format("123", f), QString("123"));
- QCOMPARE(KoOdfNumberStyles::format("1.23", f), QString("123.00%"));
-}
-
-void TestNumberStyle::testScientific()
-{
- //QEXPECT_FAIL("", "min-exponent-digits not handled", Continue);
- QCOMPARE(escapeLocals(KoOdfNumberStyles::formatScientific(345678, "0.00E+000")), QString("3.456780E+05"));
-
- KoOdfNumberStyles::NumericStyleFormat f;
- f.type = KoOdfNumberStyles::Scientific;
- f.precision = 3;
- //QEXPECT_FAIL("", "min-exponent-digits not handled", Continue);
- QCOMPARE(escapeLocals(KoOdfNumberStyles::format("0.2", f)), QString("2.000E-01"));
- //QEXPECT_FAIL("", "min-exponent-digits not handled", Continue);
- QCOMPARE(escapeLocals(KoOdfNumberStyles::format("1.23", f)), QString("1.230E+00"));
- QCOMPARE(escapeLocals(KoOdfNumberStyles::format("test", f)), QString("test"));
-}
-
-void TestNumberStyle::testFraction()
-{
- QCOMPARE(KoOdfNumberStyles::formatFraction(34.5678, " ?/?"), QString("34 4/7"));
-}
-
-void TestNumberStyle::testCurrency()
-{
- QCOMPARE(KoOdfNumberStyles::formatCurrency(34.56, "-$#,###0.00", QString(), 2), QString("$34.56"));
- QCOMPARE(KoOdfNumberStyles::formatCurrency(34.56, "-#,###0.00 EUR", QString(), 2), QString("34.56 EUR"));
- QCOMPARE(KoOdfNumberStyles::formatCurrency(34.56, "-$#,###0.", QString(), 0), QString("$35"));
- QString localDependentDollar = escapeLocals(KoOdfNumberStyles::formatCurrency(34.5, "#,###0 CCC", "CCC"));
- QVERIFY(localDependentDollar.startsWith("34.50") || localDependentDollar.endsWith("34.50"));
- QVERIFY(localDependentDollar.startsWith("USD") || localDependentDollar.endsWith("USD"));
- QCOMPARE(KoOdfNumberStyles::formatCurrency(34.56789, "-#,###0.00 EUR", QString(), 2), QString("34.57 EUR"));
- QCOMPARE(KoOdfNumberStyles::formatCurrency(34.5, "-#,###0.00 EUR", QString(), 2), QString("34.50 EUR"));
-
- KoOdfNumberStyles::NumericStyleFormat f;
- f.type = KoOdfNumberStyles::Currency;
- f.currencySymbol = "";
- f.precision = 2;
- f.formatStr = "-#,###0.00 EUR";
- QCOMPARE(escapeLocals(KoOdfNumberStyles::format("0.2", f)), QString("0.20 EUR"));
- QCOMPARE(escapeLocals(KoOdfNumberStyles::format("$ 1.23", f)), QString("$ 1.23"));
- QCOMPARE(escapeLocals(KoOdfNumberStyles::format("test", f)), QString("test"));
- f.currencySymbol = "$";
- QCOMPARE(escapeLocals(KoOdfNumberStyles::format("0.2", f)), QString("0.20 EUR"));
- f.formatStr = "-#,###0.00";
- QCOMPARE(escapeLocals(KoOdfNumberStyles::format("0.2", f)), QString("0.20"));
- f.formatStr = "";
- localDependentDollar = escapeLocals(KoOdfNumberStyles::format("0.2", f));
- QVERIFY(localDependentDollar.startsWith("0.20") || localDependentDollar.endsWith("0.20"));
- QVERIFY(localDependentDollar.startsWith("$") || localDependentDollar.endsWith("$"));
-}
-
-QTEST_MAIN(TestNumberStyle)
diff --git a/libs/odf/tests/TestNumberStyle.h b/libs/odf/tests/TestNumberStyle.h
deleted file mode 100644
index 41754da993..0000000000
--- a/libs/odf/tests/TestNumberStyle.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Sebastian Sauer <sebsauer@kdab.com>
- *
- * 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 TESTNUMBERSTYLE_H
-#define TESTNUMBERSTYLE_H
-
-#include <QObject>
-
-class TestNumberStyle : public QObject
-{
- Q_OBJECT
-private Q_SLOTS:
- void testEmpty();
- void testText();
- void testNumber();
- void testDate();
- void testTime();
- void testBoolean();
- void testPercent();
- void testScientific();
- void testFraction();
- void testCurrency();
-};
-
-#endif
diff --git a/libs/odf/tests/TestOdfSettings.cpp b/libs/odf/tests/TestOdfSettings.cpp
deleted file mode 100644
index 6b92593d73..0000000000
--- a/libs/odf/tests/TestOdfSettings.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-#include <QTest>
-
-#include <QObject>
-
-#include <KoXmlReader.h>
-#include <KoOasisSettings.h>
-
-class TestOdfSettings : public QObject
-{
- Q_OBJECT
-public:
- TestOdfSettings() { }
-
-private Q_SLOTS:
- void initTestCase();
- void testParseConfigItemString();
- void testSelectItemSet();
- void testIndexedMap();
- void testNamedMap();
-
-private:
- KoXmlDocument doc;
- KoOasisSettings *settings;
-};
-
-void TestOdfSettings::initTestCase()
-{
- const QString xml =
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
- "<office:document-settings xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\""
- " xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\">"
- "<office:settings>"
- "<config:config-item-set config:name=\"view-settings\">"
- "<config:config-item config:name=\"unit\" config:type=\"string\">mm</config:config-item>"
- "<config:config-item-map-indexed config:name=\"Views\">"
- "<config:config-item-map-entry>"
- "<config:config-item config:name=\"ZoomFactor\" config:type=\"short\">100</config:config-item>"
- "</config:config-item-map-entry>"
- "</config:config-item-map-indexed>"
- "<config:config-item-map-named config:name=\"NamedMap\">"
- "<config:config-item-map-entry config:name=\"foo\">"
- "<config:config-item config:name=\"ZoomFactor\" config:type=\"int\">100</config:config-item>"
- "</config:config-item-map-entry>"
- "</config:config-item-map-named>"
- "</config:config-item-set>"
- "</office:settings>"
- "</office:document-settings>";
-
- bool ok = doc.setContent( xml, true /* namespace processing */ );
- QVERIFY(ok);
- settings = new KoOasisSettings(doc);
-}
-
-void TestOdfSettings::testSelectItemSet()
-{
- KoOasisSettings::Items items = settings->itemSet("notexist");
- QVERIFY(items.isNull());
- items = settings->itemSet("view-settings");
- QVERIFY(!items.isNull());
-}
-
-void TestOdfSettings::testParseConfigItemString()
-{
- KoOasisSettings::Items viewSettings = settings->itemSet("view-settings");
- const QString unit = viewSettings.parseConfigItemString("unit");
- QCOMPARE(unit, QString("mm"));
-}
-
-void TestOdfSettings::testIndexedMap()
-{
- KoOasisSettings::Items viewSettings = settings->itemSet("view-settings");
- QVERIFY(!viewSettings.isNull());
- KoOasisSettings::IndexedMap viewMap = viewSettings.indexedMap("Views");
- QVERIFY(!viewMap.isNull());
- KoOasisSettings::Items firstView = viewMap.entry(0);
- QVERIFY(!firstView.isNull());
- const short zoomFactor = firstView.parseConfigItemShort("ZoomFactor");
- QCOMPARE(zoomFactor, (short) 100);
- KoOasisSettings::Items secondView = viewMap.entry(1);
- QVERIFY(secondView.isNull());
-}
-
-void TestOdfSettings::testNamedMap()
-{
- KoOasisSettings::Items viewSettings = settings->itemSet("view-settings");
- QVERIFY(!viewSettings.isNull());
- KoOasisSettings::NamedMap viewMap = viewSettings.namedMap("NamedMap");
- QVERIFY(!viewMap.isNull());
- KoOasisSettings::Items foo = viewMap.entry("foo");
- QVERIFY(!foo.isNull());
- const int zoomFactor = foo.parseConfigItemShort("ZoomFactor");
- QCOMPARE(zoomFactor, 100);
- KoOasisSettings::Items secondView = viewMap.entry("foobar");
- QVERIFY(secondView.isNull());
-}
-
-QTEST_GUILESS_MAIN(TestOdfSettings)
-
-#include <TestOdfSettings.moc>
diff --git a/libs/store/KoStore.cpp b/libs/store/KoStore.cpp
index ecde07531e..7561da0315 100644
--- a/libs/store/KoStore.cpp
+++ b/libs/store/KoStore.cpp
@@ -1,457 +1,442 @@
/* This file is part of the KDE project
Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
Copyright (C) 2000-2002 David Faure <faure@kde.org>, Werner Trobin <trobin@kde.org>
Copyright (C) 2010 C. Boemann <cbo@boemann.dk>
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 "KoStore.h"
#include "KoStore_p.h"
#include "KoQuaZipStore.h"
#include "KoDirectoryStore.h"
#include <QBuffer>
#include <QFileInfo>
#include <QFile>
#include <QUrl>
#include <StoreDebug.h>
#include <KConfig>
#include <KSharedConfig>
#include <KConfigGroup>
#define DefaultFormat KoStore::Zip
static KoStore::Backend determineBackend(QIODevice *dev)
{
unsigned char buf[5];
if (dev->read((char *)buf, 4) < 4)
return DefaultFormat; // will create a "bad" store (bad()==true)
if (buf[0] == 'P' && buf[1] == 'K' && buf[2] == 3 && buf[3] == 4)
return KoStore::Zip;
return DefaultFormat; // fallback
}
KoStore* KoStore::createStore(const QString& fileName, Mode mode, const QByteArray & appIdentification, Backend backend, bool writeMimetype)
{
if (backend == Auto) {
if (mode == KoStore::Write)
backend = DefaultFormat;
else {
QFileInfo inf(fileName);
if (inf.isDir())
backend = Directory;
else {
QFile file(fileName);
if (file.open(QIODevice::ReadOnly))
backend = determineBackend(&file);
else
backend = DefaultFormat; // will create a "bad" store (bad()==true)
}
}
}
switch (backend) {
case Zip:
return new KoQuaZipStore(fileName, mode, appIdentification, writeMimetype);
case Directory:
return new KoDirectoryStore(fileName /* should be a dir name.... */, mode, writeMimetype);
default:
warnStore << "Unsupported backend requested for KoStore : " << backend;
return 0;
}
}
KoStore* KoStore::createStore(QIODevice *device, Mode mode, const QByteArray & appIdentification, Backend backend, bool writeMimetype)
{
if (backend == Auto) {
if (mode == KoStore::Write)
backend = DefaultFormat;
else {
if (device->open(QIODevice::ReadOnly)) {
backend = determineBackend(device);
device->close();
}
}
}
switch (backend) {
case Directory:
errorStore << "Can't create a Directory store for a memory buffer!" << endl;
return 0;
case Zip:
return new KoQuaZipStore(device, mode, appIdentification, writeMimetype);
default:
warnStore << "Unsupported backend requested for KoStore : " << backend;
return 0;
}
}
namespace
{
const char ROOTPART[] = "root";
const char MAINNAME[] = "maindoc.xml";
}
KoStore::KoStore(Mode mode, bool writeMimetype)
: d_ptr(new KoStorePrivate(this, mode, writeMimetype))
{}
KoStore::~KoStore()
{
Q_D(KoStore);
delete d->stream;
delete d_ptr;
}
bool KoStore::open(const QString & _name)
{
Q_D(KoStore);
// This also converts from relative to absolute, i.e. merges the currentPath()
d->fileName = d->toExternalNaming(_name);
debugStore << "KOStore" << _name << d->fileName;
if (d->isOpen) {
warnStore << "Store is already opened, missing close";
return false;
}
if (d->fileName.length() > 512) {
errorStore << "KoStore: Filename " << d->fileName << " is too long" << endl;
return false;
}
if (d->mode == Write) {
debugStore << "opening for writing" << d->fileName;
if (d->filesList.contains(d->fileName)) {
warnStore << "KoStore: Duplicate filename" << d->fileName;
return false;
}
d->filesList.append(d->fileName);
d->size = 0;
if (!openWrite(d->fileName))
return false;
} else if (d->mode == Read) {
debugStore << "Opening for reading" << d->fileName;
if (!openRead(d->fileName))
return false;
} else
return false;
d->isOpen = true;
return true;
}
bool KoStore::isOpen() const
{
Q_D(const KoStore);
return d->isOpen;
}
bool KoStore::close()
{
Q_D(KoStore);
if (!d->isOpen) {
warnStore << "You must open before closing";
return false;
}
bool ret = d->mode == Write ? closeWrite() : closeRead();
delete d->stream;
d->stream = 0;
d->isOpen = false;
return ret;
}
QIODevice* KoStore::device() const
{
Q_D(const KoStore);
if (!d->isOpen)
warnStore << "You must open before asking for a device";
if (d->mode != Read)
warnStore << "Can not get device from store that is opened for writing";
return d->stream;
}
QByteArray KoStore::read(qint64 max)
{
Q_D(KoStore);
QByteArray data;
if (!d->isOpen) {
warnStore << "You must open before reading";
return data;
}
if (d->mode != Read) {
errorStore << "KoStore: Can not read from store that is opened for writing" << endl;
return data;
}
return d->stream->read(max);
}
qint64 KoStore::write(const QByteArray& data)
{
return write(data.constData(), data.size()); // see below
}
qint64 KoStore::read(char *_buffer, qint64 _len)
{
Q_D(KoStore);
if (!d->isOpen) {
errorStore << "KoStore: You must open before reading" << endl;
return -1;
}
if (d->mode != Read) {
errorStore << "KoStore: Can not read from store that is opened for writing" << endl;
return -1;
}
return d->stream->read(_buffer, _len);
}
qint64 KoStore::write(const char* _data, qint64 _len)
{
Q_D(KoStore);
if (_len == 0) return 0;
if (!d->isOpen) {
errorStore << "KoStore: You must open before writing" << endl;
return 0;
}
if (d->mode != Write) {
errorStore << "KoStore: Can not write to store that is opened for reading" << endl;
return 0;
}
int nwritten = d->stream->write(_data, _len);
Q_ASSERT(nwritten == (int)_len);
d->size += nwritten;
return nwritten;
}
qint64 KoStore::size() const
{
Q_D(const KoStore);
if (!d->isOpen) {
warnStore << "You must open before asking for a size";
return static_cast<qint64>(-1);
}
if (d->mode != Read) {
warnStore << "Can not get size from store that is opened for writing";
return static_cast<qint64>(-1);
}
return d->size;
}
bool KoStore::enterDirectory(const QString &directory)
{
Q_D(KoStore);
//debugStore <<"enterDirectory" << directory;
int pos;
bool success = true;
QString tmp(directory);
while ((pos = tmp.indexOf('/')) != -1 &&
(success = d->enterDirectoryInternal(tmp.left(pos))))
tmp.remove(0, pos + 1);
if (success && !tmp.isEmpty())
return d->enterDirectoryInternal(tmp);
return success;
}
bool KoStore::leaveDirectory()
{
Q_D(KoStore);
if (d->currentPath.isEmpty())
return false;
d->currentPath.pop_back();
return enterAbsoluteDirectory(currentPath());
}
QString KoStore::currentPath() const
{
Q_D(const KoStore);
QString path;
QStringList::ConstIterator it = d->currentPath.begin();
QStringList::ConstIterator end = d->currentPath.end();
for (; it != end; ++it) {
path += *it;
path += '/';
}
return path;
}
void KoStore::pushDirectory()
{
Q_D(KoStore);
d->directoryStack.push(currentPath());
}
void KoStore::popDirectory()
{
Q_D(KoStore);
d->currentPath.clear();
enterAbsoluteDirectory(QString());
enterDirectory(d->directoryStack.pop());
}
bool KoStore::extractFile(const QString &srcName, QByteArray &data)
{
Q_D(KoStore);
QBuffer buffer(&data);
return d->extractFile(srcName, buffer);
}
bool KoStorePrivate::extractFile(const QString &srcName, QIODevice &buffer)
{
if (!q->open(srcName))
return false;
if (!buffer.open(QIODevice::WriteOnly)) {
q->close();
return false;
}
QByteArray data;
data.resize(8 * 1024);
uint total = 0;
for (int block = 0; (block = q->read(data.data(), data.size())) > 0; total += block) {
buffer.write(data.data(), block);
}
if (q->size() != static_cast<qint64>(-1))
Q_ASSERT(total == q->size());
buffer.close();
q->close();
return true;
}
bool KoStore::seek(qint64 pos)
{
Q_D(KoStore);
return d->stream->seek(pos);
}
qint64 KoStore::pos() const
{
Q_D(const KoStore);
return d->stream->pos();
}
bool KoStore::atEnd() const
{
Q_D(const KoStore);
return d->stream->atEnd();
}
// See the specification for details of what this function does.
QString KoStorePrivate::toExternalNaming(const QString & _internalNaming) const
{
if (_internalNaming == ROOTPART)
return q->currentPath() + MAINNAME;
QString intern;
if (_internalNaming.startsWith("tar:/")) // absolute reference
intern = _internalNaming.mid(5); // remove protocol
else
intern = q->currentPath() + _internalNaming;
return intern;
}
bool KoStorePrivate::enterDirectoryInternal(const QString &directory)
{
if (q->enterRelativeDirectory(directory)) {
currentPath.append(directory);
return true;
}
return false;
}
bool KoStore::hasFile(const QString& fileName) const
{
Q_D(const KoStore);
return fileExists(d->toExternalNaming(fileName));
}
bool KoStore::hasDirectory(const QString &directoryName)
{
return enterAbsoluteDirectory(directoryName);
}
bool KoStore::finalize()
{
Q_D(KoStore);
Q_ASSERT(!d->finalized); // call this only once!
d->finalized = true;
return doFinalize();
}
void KoStore::setCompressionEnabled(bool /*e*/)
{
}
void KoStore::setSubstitution(const QString &name, const QString &substitution)
{
Q_D(KoStore);
d->substituteThis = name;
d->substituteWith = substitution;
}
-bool KoStore::isEncrypted()
-{
- return false;
-}
-
-bool KoStore::setPassword(const QString& /*password*/)
-{
- return false;
-}
-
-QString KoStore::password()
-{
- return QString();
-}
-
bool KoStore::bad() const
{
Q_D(const KoStore);
return !d->good;
}
KoStore::Mode KoStore::mode() const
{
Q_D(const KoStore);
return d->mode;
}
QStringList KoStore::directoryList() const
{
return QStringList();
}
diff --git a/libs/store/KoStore.h b/libs/store/KoStore.h
index d847edd9b6..7c8c20f7a8 100644
--- a/libs/store/KoStore.h
+++ b/libs/store/KoStore.h
@@ -1,335 +1,301 @@
/* This file is part of the KDE project
Copyright (C) 1998, 1999 David Faure <faure@kde.org>
Copyright (C) 2010 C. Boemann <cbo@boemann.dk>
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 __koStore_h_
#define __koStore_h_
#include <QByteArray>
#include <QIODevice>
#include "kritastore_export.h"
class QWidget;
class QUrl;
class KoStorePrivate;
/**
* Saves and loads Krita documents using various backends. Currently supported
* backends are zip and directory.
* We call a "store" the file on the hard disk (the one the users sees)
* and call a "file" a file inside the store.
*/
class KRITASTORE_EXPORT KoStore
{
public:
enum Mode { Read, Write };
enum Backend { Auto, Zip, Directory };
/**
* Open a store (i.e. the representation on disk of a Krita document).
*
* @param fileName the name of the file to open
* @param mode if KoStore::Read, open an existing store to read it.
* if KoStore::Write, create or replace a store.
* @param backend the backend to use for the data storage.
* Auto means automatically-determined for reading,
* and the current format (now Zip) for writing.
*
* @param appIdentification the application's mimetype,
* to be written in the file for "mime-magic" identification.
* Only meaningful if mode is Write, and if backend!=Directory.
*
* @param writeMimetype If true, some backends (notably the Zip
* store) will write a file called 'mimetype' automatically and
* fill it with data from the appIdentification. This is only
* applicable if Mode is set to Write.
*/
static KoStore *createStore(const QString &fileName, Mode mode,
const QByteArray &appIdentification = QByteArray(),
Backend backend = Auto, bool writeMimetype = true);
/**
* Create a store for any kind of QIODevice: file, memory buffer...
* KoStore will take care of opening the QIODevice.
* This method doesn't support the Directory store!
*/
static KoStore *createStore(QIODevice *device, Mode mode,
const QByteArray &appIdentification = QByteArray(),
Backend backend = Auto, bool writeMimetype = true);
/**
* Destroys the store (i.e. closes the file on the hard disk)
*/
virtual ~KoStore();
/**
* Open a new file inside the store
* @param name The filename, internal representation ("root", "tar:/0"... ).
* If the tar:/ prefix is missing it's assumed to be a relative URI.
* @return true on success.
*/
bool open(const QString &name);
/**
* Check whether a file inside the store is currently opened with open(),
* ready to be read or written.
* @return true if a file is currently opened.
*/
bool isOpen() const;
/**
* Close the file inside the store
* @return true on success.
*/
bool close();
/**
* Get a device for reading a file from the store directly
* (slightly faster than read() calls)
* You need to call @ref open first, and @ref close afterwards.
*/
QIODevice *device() const;
/**
* Read data from the currently opened file. You can also use the streams
* for this.
*/
QByteArray read(qint64 max);
/**
* Write data into the currently opened file. You can also use the streams
* for this.
*/
qint64 write(const QByteArray &data);
/**
* Read data from the currently opened file. You can also use the streams
* for this.
* @return size of data read, -1 on error
*/
qint64 read(char *buffer, qint64 length);
/**
* Write data into the currently opened file. You can also use the streams
* for this.
*/
virtual qint64 write(const char* data, qint64 length);
/**
* @return the size of the currently opened file, -1 on error.
* Can be used as an argument for the read methods, for instance
*/
qint64 size() const;
/**
* @return true if an error occurred
*/
bool bad() const;
/**
* @return the mode used when opening, read or write
*/
Mode mode() const;
/**
* If an store is opened for reading, then the directories
* of the store can be accessed via this function.
*
* @return a stringlist with all directories found
*/
virtual QStringList directoryList() const;
/**
* Enters one or multiple directories. In Read mode this actually
* checks whether the specified directories exist and returns false
* if they don't. In Write mode we don't create the directory, we
* just use the "current directory" to generate the absolute path
* if you pass a relative path (one not starting with tar:/) when
* opening a stream.
* Note: Operates on internal names
*/
virtual bool enterDirectory(const QString &directory);
/**
* Leaves a directory. Equivalent to "cd .."
* @return true on success, false if we were at the root already to
* make it possible to "loop to the root"
*/
bool leaveDirectory();
/**
* Returns the current path including a trailing slash.
* Note: Returns a path in "internal name" style
*/
QString currentPath() const;
/**
* Stacks the current directory. Restore the current path using
* @ref popDirectory .
*/
void pushDirectory();
/**
* Restores the previously pushed directory. No-op if the stack is
* empty.
*/
void popDirectory();
/**
* @return true if the given file exists in the current directory,
* i.e. if open(fileName) will work.
*/
bool hasFile(const QString &fileName) const;
/**
*@return true if the given directory exists in the archive
*/
bool hasDirectory(const QString &directoryName);
/**
* Extracts a file out of the store to a buffer
* @param sourceName file in the store
* @param data memory buffer
*/
bool extractFile(const QString &sourceName, QByteArray &data);
//@{
/// See QIODevice
bool seek(qint64 pos);
qint64 pos() const;
bool atEnd() const;
//@}
/**
* Call this before destroying the store, to be able to catch errors
* (e.g. from ksavefile)
*/
bool finalize();
- /**
- * Sets the password to be used for decryption or encryption of the store.
- * Use of this function is optional: an encryptable store should make
- * a best effort in obtaining a password if it wasn't supplied.
- *
- * This method only works before opening a file. It might fail when a file
- * has already been opened before calling this method.
- *
- * This method will not function for any store that is not encrypted or
- * can't be encrypted when saving.
- *
- * @param password A non-empty password.
- *
- * @return True if the password was set.
- */
- virtual bool setPassword(const QString &password);
-
- /**
- * Retrieves the password used to encrypt or decrypt the store. Note that
- * QString() will returned if no password has been given or the store is
- * not encrypted.
- *
- * @return The password this store is encrypted with.
- */
- virtual QString password();
-
- /**
- * Returns whether a store opened for reading is encrypted or a store opened
- * for saving will be encrypted.
- *
- * @return True if the store is encrypted.
- */
- virtual bool isEncrypted();
-
/**
* Allow to enable or disable compression of the files. Only supported by the
* ZIP backend.
*/
virtual void setCompressionEnabled(bool e);
/// When reading, in the paths in the store where name occurs, substitution is used.
void setSubstitution(const QString &name, const QString &substitution);
protected:
KoStore(Mode mode, bool writeMimetype = true);
/**
* Finalize store - called by finalize.
* @return true on success
*/
virtual bool doFinalize() {
return true;
}
/**
* Open the file @p name in the store, for writing
* On success, this method must set m_stream to a stream in which we can write.
* @param name "absolute path" (in the archive) to the file to open
* @return true on success
*/
virtual bool openWrite(const QString &name) = 0;
/**
* Open the file @p name in the store, for reading.
* On success, this method must set m_stream to a stream from which we can read,
* as well as setting m_iSize to the size of the file.
* @param name "absolute path" (in the archive) to the file to open
* @return true on success
*/
virtual bool openRead(const QString &name) = 0;
/**
* @return true on success
*/
virtual bool closeRead() = 0;
/**
* @return true on success
*/
virtual bool closeWrite() = 0;
/**
* Enter a subdirectory of the current directory.
* The directory might not exist yet in Write mode.
*/
virtual bool enterRelativeDirectory(const QString &dirName) = 0;
/**
* Enter a directory where we've been before.
* It is guaranteed to always exist.
*/
virtual bool enterAbsoluteDirectory(const QString &path) = 0;
/**
* Check if a file exists inside the store.
* @param absPath the absolute path inside the store, i.e. not relative to the current directory
*/
virtual bool fileExists(const QString &absPath) const = 0;
protected:
KoStorePrivate *d_ptr;
private:
Q_DECLARE_PRIVATE(KoStore)
private:
KoStore(const KoStore& store); ///< don't copy
KoStore& operator=(const KoStore& store); ///< don't assign
};
#endif
diff --git a/libs/odf/tests/TestStorage.cpp b/libs/store/tests/TestStorage.cpp
similarity index 97%
rename from libs/odf/tests/TestStorage.cpp
rename to libs/store/tests/TestStorage.cpp
index 5ea955e1f4..13d6faf6cb 100644
--- a/libs/odf/tests/TestStorage.cpp
+++ b/libs/store/tests/TestStorage.cpp
@@ -1,257 +1,250 @@
/* This file is part of the KDE project
Copyright (C) 2002 Werner Trobin <trobin@kde.org>
Copyright (C) 2008 Thomas Zander <zander@kde.org>
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 <QFile>
#include <QDir>
#include <KoStore.h>
-#include <KoEncryptionChecker.h>
#include <OdfDebug.h>
#include <stdlib.h>
#include <string.h>
#include <QTest>
class TestStorage : public QObject
{
Q_OBJECT
private Q_SLOTS:
void storage_data();
void storage();
void storage2_data();
void storage2();
private:
char getch(QIODevice * dev);
};
char TestStorage::getch(QIODevice * dev)
{
char c = 0;
dev->getChar(&c);
return c;
}
void TestStorage::storage_data()
{
QTest::addColumn<int>("type");
QTest::addColumn<QString>("testFile");
QTest::newRow("directory") << (int) KoStore::Directory << "testdir";
QTest::newRow("zip") << (int) KoStore::Zip <<"test.zip";
}
void TestStorage::storage()
{
const char test1[] = "This test checks whether we're able to write to some arbitrary directory.\n";
const char testDir[] = "0";
const char testDirResult[] = "0/";
const char test2[] = "This time we try to append the given relative path to the current dir.\n";
const char test3[] = "<xml>Hello World</xml>";
const char testDir2[] = "test2/with/a";
const char testDir2Result[] = "0/test2/with/a/";
const char test4[] = "<xml>Heureka, it works</xml>";
QFETCH(int, type);
QFETCH(QString, testFile);
KoStore::Backend backend = static_cast<KoStore::Backend>(type);
if (QFile::exists(testFile))
QFile::remove(testFile);
QDir dirTest(testFile);
if (dirTest.exists()) {
#ifdef Q_OS_UNIX
QByteArray ba = QByteArray("rm -rf ") + QFile::encodeName(testFile);
Q_UNUSED(system(ba.constData())); // QDir::rmdir isn't recursive!
#else
QFAIL("build dir not empty");
#endif
}
KoStore* store = KoStore::createStore(testFile, KoStore::Write, "", backend);
QVERIFY(store);
QVERIFY(store->bad() == false);
- if (store->isEncrypted())
- store->setPassword("password");
-
QVERIFY(store->open("test1/with/a/relative/dir.txt"));
for (int i = 0; i < 100; ++i)
store->write(test1, strlen(test1));
store->close();
store->enterDirectory(testDir);
QCOMPARE(store->currentPath(), QString(testDirResult));
QVERIFY(store->open("test2/with/a/relative/dir.txt"));
for (int i = 0; i < 100; ++i)
store->write(test2, strlen(test2));
store->close();
QVERIFY(store->open("root"));
store->write(test3, strlen(test3));
store->close();
store->enterDirectory(testDir2);
QCOMPARE(store->currentPath(), QString(testDir2Result));
QVERIFY(store->open("root"));
store->write(test4, strlen(test4));
store->close();
if (store->isOpen())
store->close();
delete store;
store = KoStore::createStore(testFile, KoStore::Read, "", backend);
QVERIFY(store->bad() == false);
- if (store->isEncrypted())
- store->setPassword("password");
-
QVERIFY (store->open("test1/with/a/relative/dir.txt"));
QIODevice* dev = store->device();
int i = 0, lim = strlen(test1), count = 0;
while (static_cast<char>(getch(dev)) == test1[i++]) {
if (i == lim) {
i = 0;
++count;
}
}
store->close();
QCOMPARE(count, 100);
store->enterDirectory(testDir);
QCOMPARE (store->currentPath(), QString(testDirResult));
QVERIFY (store->open("test2/with/a/relative/dir.txt"));
dev = store->device();
i = 0;
lim = strlen(test2);
count = 0;
while (static_cast<char>(getch(dev)) == test2[i++]) {
if (i == lim) {
i = 0;
++count;
}
}
store->close();
QCOMPARE(count, 100);
store->enterDirectory(testDir2);
store->pushDirectory();
while (store->leaveDirectory()) {
;
}
store->enterDirectory(testDir);
QCOMPARE (store->currentPath(), QString(testDirResult));
QVERIFY (store->open("root"));
QCOMPARE (store->size(), (qint64) 22);
dev = store->device();
QByteArray dataReadBack = dev->read(strlen(test3));
store->close();
QCOMPARE (dataReadBack, QByteArray(test3));
store->popDirectory();
QCOMPARE(store->currentPath(), QString(testDir2Result));
QVERIFY (store->hasFile("relative/dir.txt"));
QVERIFY (store->open("root"));
char buf[29];
store->read(buf, 28);
buf[28] = '\0';
store->close();
QVERIFY(strncmp(buf, test4, 28) == 0);
if (store->isOpen())
store->close();
delete store;
QFile::remove(testFile);
}
#define DATALEN 64
void TestStorage::storage2_data()
{
QTest::addColumn<int>("type");
QTest::addColumn<QString>("testFile");
QTest::newRow("directory") << (int) KoStore::Directory << "testdir";
QTest::newRow("zip") << (int) KoStore::Zip <<"test.zip";
}
void TestStorage::storage2()
{
QFETCH(int, type);
QFETCH(QString, testFile);
KoStore::Backend backend = static_cast<KoStore::Backend>(type);
if (QFile::exists(testFile))
QFile::remove(testFile);
QDir dirTest(testFile);
if (dirTest.exists()) {
#ifdef Q_OS_UNIX
QByteArray ba = QByteArray("rm -rf ") + QFile::encodeName(testFile);
Q_UNUSED(system(ba.constData())); // QDir::rmdir isn't recursive!
#else
QFAIL("build dir not empty");
#endif
}
KoStore* store = KoStore::createStore(testFile, KoStore::Write, "", backend);
QVERIFY(store->bad() == false);
// Write
QVERIFY (store->open("layer"));
char str[DATALEN];
sprintf(str, "1,2,3,4\n");
store->write(str, strlen(str));
memset(str, '\0', DATALEN);
store->write(str, DATALEN);
store->close();
delete store;
store = KoStore::createStore(testFile, KoStore::Read, "", backend);
QVERIFY(store->bad() == false);
// Read back
QVERIFY (store->open("layer"));
char str2[DATALEN];
QIODevice *stream = store->device(); // << Possible suspect!
stream->readLine(str2, DATALEN); // << as is this
qint64 len = store->read(str2, DATALEN);
QCOMPARE(len, (qint64) DATALEN);
store->close();
delete store;
QFile::remove(testFile);
}
QTEST_GUILESS_MAIN(TestStorage)
#include <TestStorage.moc>
diff --git a/libs/odf/tests/TestXmlWriter.cpp b/libs/store/tests/TestXmlWriter.cpp
similarity index 100%
rename from libs/odf/tests/TestXmlWriter.cpp
rename to libs/store/tests/TestXmlWriter.cpp
diff --git a/libs/odf/tests/kodomtest.cpp b/libs/store/tests/kodomtest.cpp
similarity index 100%
rename from libs/odf/tests/kodomtest.cpp
rename to libs/store/tests/kodomtest.cpp
diff --git a/libs/odf/tests/kodomtest.h b/libs/store/tests/kodomtest.h
similarity index 100%
rename from libs/odf/tests/kodomtest.h
rename to libs/store/tests/kodomtest.h
diff --git a/libs/ui/CMakeLists.txt b/libs/ui/CMakeLists.txt
index 01abdd16b3..c78ee941d6 100644
--- a/libs/ui/CMakeLists.txt
+++ b/libs/ui/CMakeLists.txt
@@ -1,650 +1,656 @@
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/qtlockedfile
)
include_directories(SYSTEM
${EIGEN3_INCLUDE_DIR}
${OCIO_INCLUDE_DIR}
)
if (ANDROID)
add_definitions(-DQT_OPENGL_ES_3)
add_definitions(-DHAS_ONLY_OPENGL_ES)
include_directories (${Qt5AndroidExtras_INCLUDE_DIRS})
endif()
add_subdirectory( tests )
if (APPLE)
find_library(FOUNDATION_LIBRARY Foundation)
find_library(APPKIT_LIBRARY AppKit)
endif ()
set(kritaui_LIB_SRCS
canvas/kis_canvas_widget_base.cpp
canvas/kis_canvas2.cpp
canvas/kis_canvas_updates_compressor.cpp
canvas/kis_canvas_controller.cpp
canvas/kis_display_color_converter.cpp
canvas/kis_display_filter.cpp
canvas/kis_exposure_gamma_correction_interface.cpp
canvas/kis_tool_proxy.cpp
canvas/kis_canvas_decoration.cc
canvas/kis_coordinates_converter.cpp
canvas/kis_grid_manager.cpp
canvas/kis_grid_decoration.cpp
canvas/kis_grid_config.cpp
canvas/kis_prescaled_projection.cpp
canvas/kis_qpainter_canvas.cpp
canvas/kis_projection_backend.cpp
canvas/kis_update_info.cpp
canvas/kis_image_patch.cpp
canvas/kis_image_pyramid.cpp
canvas/kis_infinity_manager.cpp
canvas/kis_change_guides_command.cpp
canvas/kis_guides_decoration.cpp
canvas/kis_guides_manager.cpp
canvas/kis_guides_config.cpp
canvas/kis_snap_config.cpp
canvas/kis_snap_line_strategy.cpp
canvas/KisSnapPointStrategy.cpp
canvas/KisSnapPixelStrategy.cpp
canvas/KisMirrorAxisConfig.cpp
dialogs/kis_about_application.cpp
dialogs/kis_dlg_adj_layer_props.cc
dialogs/kis_dlg_adjustment_layer.cc
dialogs/kis_dlg_filter.cpp
dialogs/kis_dlg_generator_layer.cpp
dialogs/kis_dlg_file_layer.cpp
dialogs/kis_dlg_filter.cpp
dialogs/kis_dlg_stroke_selection_properties.cpp
dialogs/kis_dlg_image_properties.cc
dialogs/kis_dlg_layer_properties.cc
dialogs/kis_dlg_preferences.cc
dialogs/slider_and_spin_box_sync.cpp
dialogs/kis_dlg_layer_style.cpp
dialogs/kis_dlg_png_import.cpp
dialogs/kis_dlg_import_image_sequence.cpp
dialogs/kis_delayed_save_dialog.cpp
dialogs/KisSessionManagerDialog.cpp
dialogs/KisNewWindowLayoutDialog.cpp
dialogs/KisDlgChangeCloneSource.cpp
dialogs/KisRecoverNamedAutosaveDialog.cpp
flake/kis_node_dummies_graph.cpp
flake/kis_dummies_facade_base.cpp
flake/kis_dummies_facade.cpp
flake/kis_node_shapes_graph.cpp
flake/kis_node_shape.cpp
flake/kis_shape_controller.cpp
flake/kis_shape_layer.cc
flake/kis_shape_layer_canvas.cpp
flake/kis_shape_selection.cpp
flake/kis_shape_selection_canvas.cpp
flake/kis_shape_selection_model.cpp
flake/kis_take_all_shapes_command.cpp
brushhud/kis_uniform_paintop_property_widget.cpp
brushhud/kis_brush_hud.cpp
brushhud/kis_round_hud_button.cpp
brushhud/kis_dlg_brush_hud_config.cpp
brushhud/kis_brush_hud_properties_list.cpp
brushhud/kis_brush_hud_properties_config.cpp
kis_aspect_ratio_locker.cpp
kis_autogradient.cc
kis_bookmarked_configurations_editor.cc
kis_bookmarked_configurations_model.cc
kis_bookmarked_filter_configurations_model.cc
KisPaintopPropertiesBase.cpp
kis_canvas_resource_provider.cpp
kis_derived_resources.cpp
kis_categories_mapper.cpp
kis_categorized_list_model.cpp
kis_categorized_item_delegate.cpp
kis_clipboard.cc
kis_config.cc
KisOcioConfiguration.cpp
kis_control_frame.cpp
kis_composite_ops_model.cc
kis_paint_ops_model.cpp
kis_custom_pattern.cc
kis_file_layer.cpp
kis_change_file_layer_command.h
kis_safe_document_loader.cpp
kis_splash_screen.cpp
kis_filter_manager.cc
kis_filters_model.cc
KisImageBarrierLockerWithFeedback.cpp
kis_image_manager.cc
kis_image_view_converter.cpp
kis_import_catcher.cc
kis_layer_manager.cc
kis_mask_manager.cc
kis_mimedata.cpp
kis_node_commands_adapter.cpp
kis_node_manager.cpp
kis_node_juggler_compressed.cpp
kis_node_selection_adapter.cpp
kis_node_insertion_adapter.cpp
KisNodeDisplayModeAdapter.cpp
kis_node_model.cpp
kis_node_filter_proxy_model.cpp
kis_model_index_converter_base.cpp
kis_model_index_converter.cpp
kis_model_index_converter_show_all.cpp
kis_painting_assistant.cc
kis_painting_assistants_decoration.cpp
KisDecorationsManager.cpp
kis_paintop_box.cc
kis_paintop_option.cpp
kis_paintop_options_model.cpp
kis_paintop_settings_widget.cpp
kis_popup_palette.cpp
kis_png_converter.cpp
kis_preference_set_registry.cpp
KisResourceServerProvider.cpp
KisSelectedShapesProxy.cpp
kis_selection_decoration.cc
kis_selection_manager.cc
KisSelectionActionsAdapter.cpp
kis_statusbar.cc
kis_zoom_manager.cc
kis_favorite_resource_manager.cpp
kis_workspace_resource.cpp
kis_action.cpp
kis_action_manager.cpp
KisActionPlugin.cpp
kis_canvas_controls_manager.cpp
kis_tooltip_manager.cpp
kis_multinode_property.cpp
kis_stopgradient_editor.cpp
KisWelcomePageWidget.cpp
KisChangeCloneLayersCommand.cpp
kisexiv2/kis_exif_io.cpp
kisexiv2/kis_exiv2.cpp
kisexiv2/kis_iptc_io.cpp
kisexiv2/kis_xmp_io.cpp
opengl/kis_opengl.cpp
opengl/kis_opengl_canvas2.cpp
opengl/kis_opengl_canvas_debugger.cpp
opengl/kis_opengl_image_textures.cpp
opengl/kis_texture_tile.cpp
opengl/kis_opengl_shader_loader.cpp
opengl/kis_texture_tile_info_pool.cpp
opengl/KisOpenGLUpdateInfoBuilder.cpp
opengl/KisOpenGLModeProber.cpp
opengl/KisScreenInformationAdapter.cpp
kis_fps_decoration.cpp
tool/KisToolChangesTracker.cpp
tool/KisToolChangesTrackerData.cpp
tool/kis_selection_tool_helper.cpp
tool/kis_selection_tool_config_widget_helper.cpp
tool/kis_rectangle_constraint_widget.cpp
tool/kis_shape_tool_helper.cpp
tool/kis_tool.cc
tool/kis_delegated_tool_policies.cpp
tool/kis_tool_freehand.cc
tool/kis_speed_smoother.cpp
tool/kis_painting_information_builder.cpp
tool/kis_stabilized_events_sampler.cpp
tool/kis_tool_freehand_helper.cpp
tool/kis_tool_multihand_helper.cpp
tool/kis_figure_painting_tool_helper.cpp
tool/KisAsyncronousStrokeUpdateHelper.cpp
tool/kis_tool_paint.cc
tool/kis_tool_shape.cc
tool/kis_tool_ellipse_base.cpp
tool/kis_tool_rectangle_base.cpp
tool/kis_tool_polyline_base.cpp
tool/kis_tool_utils.cpp
tool/kis_resources_snapshot.cpp
tool/kis_smoothing_options.cpp
tool/KisStabilizerDelayedPaintHelper.cpp
tool/KisStrokeSpeedMonitor.cpp
tool/strokes/freehand_stroke.cpp
tool/strokes/KisStrokeEfficiencyMeasurer.cpp
tool/strokes/kis_painter_based_stroke_strategy.cpp
tool/strokes/kis_filter_stroke_strategy.cpp
tool/strokes/kis_color_picker_stroke_strategy.cpp
tool/strokes/KisFreehandStrokeInfo.cpp
tool/strokes/KisMaskedFreehandStrokePainter.cpp
tool/strokes/KisMaskingBrushRenderer.cpp
tool/strokes/KisMaskingBrushCompositeOpFactory.cpp
tool/strokes/move_stroke_strategy.cpp
+ tool/strokes/KisNodeSelectionRecipe.cpp
tool/KisSelectionToolFactoryBase.cpp
tool/KisToolPaintFactoryBase.cpp
widgets/kis_cmb_composite.cc
widgets/kis_cmb_contour.cpp
widgets/kis_cmb_gradient.cpp
widgets/kis_paintop_list_widget.cpp
widgets/kis_cmb_idlist.cc
widgets/kis_color_space_selector.cc
widgets/kis_advanced_color_space_selector.cc
widgets/kis_cie_tongue_widget.cpp
widgets/kis_tone_curve_widget.cpp
widgets/kis_curve_widget.cpp
widgets/kis_custom_image_widget.cc
widgets/kis_image_from_clipboard_widget.cpp
widgets/kis_double_widget.cc
widgets/kis_filter_selector_widget.cc
widgets/kis_gradient_chooser.cc
widgets/kis_iconwidget.cc
widgets/kis_mask_widgets.cpp
widgets/kis_meta_data_merge_strategy_chooser_widget.cc
widgets/kis_multi_bool_filter_widget.cc
widgets/kis_multi_double_filter_widget.cc
widgets/kis_multi_integer_filter_widget.cc
widgets/kis_multipliers_double_slider_spinbox.cpp
widgets/kis_paintop_presets_popup.cpp
widgets/kis_tool_options_popup.cpp
widgets/kis_paintop_presets_chooser_popup.cpp
widgets/kis_paintop_presets_save.cpp
widgets/kis_paintop_preset_icon_library.cpp
widgets/kis_pattern_chooser.cc
widgets/kis_preset_chooser.cpp
widgets/kis_progress_widget.cpp
widgets/kis_selection_options.cc
widgets/kis_scratch_pad.cpp
widgets/kis_scratch_pad_event_filter.cpp
widgets/kis_preset_selector_strip.cpp
widgets/KisSelectionPropertySlider.cpp
widgets/kis_size_group.cpp
widgets/kis_size_group_p.cpp
widgets/kis_wdg_generator.cpp
widgets/kis_workspace_chooser.cpp
widgets/kis_categorized_list_view.cpp
widgets/kis_widget_chooser.cpp
widgets/kis_tool_button.cpp
widgets/kis_floating_message.cpp
widgets/kis_lod_availability_widget.cpp
widgets/kis_color_label_selector_widget.cpp
widgets/kis_color_filter_combo.cpp
widgets/kis_elided_label.cpp
widgets/kis_stopgradient_slider_widget.cpp
widgets/kis_preset_live_preview_view.cpp
widgets/KisScreenColorPicker.cpp
widgets/KoDualColorButton.cpp
widgets/KoStrokeConfigWidget.cpp
widgets/KoFillConfigWidget.cpp
widgets/KisLayerStyleAngleSelector.cpp
widgets/KisMemoryReportButton.cpp
widgets/KisDitherWidget.cpp
KisPaletteEditor.cpp
dialogs/KisDlgPaletteEditor.cpp
widgets/KisNewsWidget.cpp
widgets/KisGamutMaskToolbar.cpp
utils/kis_document_aware_spin_box_unit_manager.cpp
utils/KisSpinBoxSplineUnitConverter.cpp
utils/KisClipboardUtil.cpp
utils/KisDitherUtil.cpp
utils/KisFileIconCreator.cpp
input/kis_input_manager.cpp
input/kis_input_manager_p.cpp
input/kis_extended_modifiers_mapper.cpp
input/kis_abstract_input_action.cpp
input/kis_tool_invocation_action.cpp
input/kis_pan_action.cpp
input/kis_alternate_invocation_action.cpp
input/kis_rotate_canvas_action.cpp
input/kis_zoom_action.cpp
input/kis_change_frame_action.cpp
input/kis_gamma_exposure_action.cpp
input/kis_show_palette_action.cpp
input/kis_change_primary_setting_action.cpp
input/kis_abstract_shortcut.cpp
input/kis_native_gesture_shortcut.cpp
input/kis_single_action_shortcut.cpp
input/kis_stroke_shortcut.cpp
input/kis_shortcut_matcher.cpp
input/kis_select_layer_action.cpp
input/KisQtWidgetsTweaker.cpp
input/KisInputActionGroup.cpp
input/kis_zoom_and_rotate_action.cpp
operations/kis_operation.cpp
operations/kis_operation_configuration.cpp
operations/kis_operation_registry.cpp
operations/kis_operation_ui_factory.cpp
operations/kis_operation_ui_widget.cpp
operations/kis_filter_selection_operation.cpp
actions/kis_selection_action_factories.cpp
actions/KisPasteActionFactories.cpp
actions/KisTransformToolActivationCommand.cpp
input/kis_touch_shortcut.cpp
kis_document_undo_store.cpp
kis_gui_context_command.cpp
kis_gui_context_command_p.cpp
input/kis_tablet_debugger.cpp
input/kis_input_profile_manager.cpp
input/kis_input_profile.cpp
input/kis_shortcut_configuration.cpp
input/config/kis_input_configuration_page.cpp
input/config/kis_edit_profiles_dialog.cpp
input/config/kis_input_profile_model.cpp
input/config/kis_input_configuration_page_item.cpp
input/config/kis_action_shortcuts_model.cpp
input/config/kis_input_type_delegate.cpp
input/config/kis_input_mode_delegate.cpp
input/config/kis_input_button.cpp
input/config/kis_input_editor_delegate.cpp
input/config/kis_mouse_input_editor.cpp
input/config/kis_wheel_input_editor.cpp
input/config/kis_key_input_editor.cpp
processing/fill_processing_visitor.cpp
canvas/kis_mirror_axis.cpp
kis_abstract_perspective_grid.cpp
KisApplication.cpp
KisAutoSaveRecoveryDialog.cpp
KisDetailsPane.cpp
KisDocument.cpp
KisCloneDocumentStroke.cpp
kis_node_view_color_scheme.cpp
KisImportExportFilter.cpp
KisImportExportManager.cpp
KisImportExportUtils.cpp
kis_async_action_feedback.cpp
KisMainWindow.cpp
KisOpenPane.cpp
KisPart.cpp
- KisPrintJob.cpp
KisTemplate.cpp
KisTemplateCreateDia.cpp
KisTemplateGroup.cpp
KisTemplates.cpp
KisTemplatesPane.cpp
KisTemplateTree.cpp
KisUndoActionsUpdateManager.cpp
KisView.cpp
KisCanvasWindow.cpp
KisImportExportErrorCode.cpp
KisImportExportAdditionalChecks.cpp
thememanager.cpp
kis_mainwindow_observer.cpp
KisViewManager.cpp
kis_mirror_manager.cpp
qtlockedfile/qtlockedfile.cpp
qtsingleapplication/qtlocalpeer.cpp
qtsingleapplication/qtsingleapplication.cpp
KisApplicationArguments.cpp
KisNetworkAccessManager.cpp
KisRssReader.cpp
KisMultiFeedRSSModel.cpp
KisRemoteFileFetcher.cpp
KisSaveGroupVisitor.cpp
KisWindowLayoutResource.cpp
KisWindowLayoutManager.cpp
KisSessionResource.cpp
KisReferenceImagesDecoration.cpp
KisReferenceImage.cpp
flake/KisReferenceImagesLayer.cpp
flake/KisReferenceImagesLayer.h
KisMouseClickEater.cpp
KisDecorationsWrapperLayer.cpp
+
+ KoDocumentInfoDlg.cpp
+ KoDocumentInfo.cpp
)
if(WIN32)
# Private headers are needed for:
# * KisDlgCustomTabletResolution
# * KisScreenInformationAdapter
include_directories(SYSTEM ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
set(kritaui_LIB_SRCS
${kritaui_LIB_SRCS}
qtlockedfile/qtlockedfile_win.cpp
)
if (NOT USE_QT_TABLET_WINDOWS)
set(kritaui_LIB_SRCS
${kritaui_LIB_SRCS}
input/wintab/kis_tablet_support_win.cpp
input/wintab/kis_screen_size_choice_dialog.cpp
input/wintab/kis_tablet_support_win8.cpp
)
else()
set(kritaui_LIB_SRCS
${kritaui_LIB_SRCS}
dialogs/KisDlgCustomTabletResolution.cpp
)
endif()
endif()
set(kritaui_LIB_SRCS
${kritaui_LIB_SRCS}
kis_animation_frame_cache.cpp
kis_animation_cache_populator.cpp
KisAsyncAnimationRendererBase.cpp
KisAsyncAnimationCacheRenderer.cpp
KisAsyncAnimationFramesSavingRenderer.cpp
dialogs/KisAsyncAnimationRenderDialogBase.cpp
dialogs/KisAsyncAnimationCacheRenderDialog.cpp
dialogs/KisAsyncAnimationFramesSaveDialog.cpp
canvas/kis_animation_player.cpp
kis_animation_importer.cpp
KisSyncedAudioPlayback.cpp
KisFrameDataSerializer.cpp
KisFrameCacheStore.cpp
KisFrameCacheSwapper.cpp
KisAbstractFrameCacheSwapper.cpp
KisInMemoryFrameCacheSwapper.cpp
input/wintab/drawpile_tablettester/tablettester.cpp
input/wintab/drawpile_tablettester/tablettest.cpp
)
if (UNIX)
set(kritaui_LIB_SRCS
${kritaui_LIB_SRCS}
qtlockedfile/qtlockedfile_unix.cpp
)
endif()
if (ENABLE_UPDATERS)
if (UNIX)
set(kritaui_LIB_SRCS
${kritaui_LIB_SRCS}
utils/KisAppimageUpdater.cpp
)
endif()
set(kritaui_LIB_SRCS
${kritaui_LIB_SRCS}
utils/KisUpdaterBase.cpp
utils/KisManualUpdater.cpp
utils/KisUpdaterStatus.cpp
)
endif()
if(APPLE)
set(kritaui_LIB_SRCS
${kritaui_LIB_SRCS}
input/kis_extended_modifiers_mapper_osx.mm
osx.mm
)
endif()
if (ANDROID)
set (kritaui_LIB_SRCS ${kritaui_LIB_SRCS} KisAndroidFileManager.cpp)
endif()
ki18n_wrap_ui(kritaui_LIB_SRCS
widgets/KoFillConfigWidget.ui
widgets/KoStrokeConfigWidget.ui
widgets/KisDitherWidget.ui
forms/wdgdlgpngimport.ui
forms/wdgfullscreensettings.ui
forms/wdgautogradient.ui
forms/wdggeneralsettings.ui
forms/wdgperformancesettings.ui
forms/wdggenerators.ui
forms/wdgbookmarkedconfigurationseditor.ui
forms/wdgapplyprofile.ui
forms/wdgcustompattern.ui
forms/wdglayerproperties.ui
forms/wdgcolorsettings.ui
forms/wdgtabletsettings.ui
forms/wdgcolorspaceselector.ui
forms/wdgcolorspaceselectoradvanced.ui
forms/wdgdisplaysettings.ui
forms/kis_previewwidgetbase.ui
forms/kis_matrix_widget.ui
forms/wdgselectionoptions.ui
forms/wdggeometryoptions.ui
forms/wdgnewimage.ui
forms/wdgimageproperties.ui
forms/wdgmaskfromselection.ui
forms/wdgmasksource.ui
forms/wdgfilterdialog.ui
forms/wdgmetadatamergestrategychooser.ui
forms/wdgpaintoppresets.ui
forms/wdgpaintopsettings.ui
forms/wdgdlggeneratorlayer.ui
forms/wdgdlgfilelayer.ui
forms/wdgfilterselector.ui
forms/wdgfilternodecreation.ui
forms/wdgmultipliersdoublesliderspinbox.ui
forms/wdgnodequerypatheditor.ui
forms/wdgpresetselectorstrip.ui
forms/wdgsavebrushpreset.ui
forms/wdgpreseticonlibrary.ui
forms/wdgrectangleconstraints.ui
forms/wdgimportimagesequence.ui
forms/wdgstrokeselectionproperties.ui
forms/KisDetailsPaneBase.ui
forms/KisOpenPaneBase.ui
forms/wdgstopgradienteditor.ui
forms/wdgsessionmanager.ui
forms/wdgnewwindowlayout.ui
forms/KisWelcomePage.ui
forms/WdgDlgPaletteEditor.ui
forms/KisNewsPage.ui
forms/wdgGamutMaskToolbar.ui
forms/wdgchangeclonesource.ui
+ forms/koDocumentInfoAboutWidget.ui
+ forms/koDocumentInfoAuthorWidget.ui
+
brushhud/kis_dlg_brush_hud_config.ui
dialogs/kis_delayed_save_dialog.ui
dialogs/KisRecoverNamedAutosaveDialog.ui
input/config/kis_input_configuration_page.ui
input/config/kis_edit_profiles_dialog.ui
input/config/kis_input_configuration_page_item.ui
input/config/kis_mouse_input_editor.ui
input/config/kis_wheel_input_editor.ui
input/config/kis_key_input_editor.ui
layerstyles/wdgBevelAndEmboss.ui
layerstyles/wdgblendingoptions.ui
layerstyles/WdgColorOverlay.ui
layerstyles/wdgContour.ui
layerstyles/wdgdropshadow.ui
layerstyles/WdgGradientOverlay.ui
layerstyles/wdgInnerGlow.ui
layerstyles/wdglayerstyles.ui
layerstyles/WdgPatternOverlay.ui
layerstyles/WdgSatin.ui
layerstyles/WdgStroke.ui
layerstyles/wdgstylesselector.ui
layerstyles/wdgTexture.ui
layerstyles/wdgKisLayerStyleAngleSelector.ui
wdgsplash.ui
input/wintab/kis_screen_size_choice_dialog.ui
input/wintab/drawpile_tablettester/tablettest.ui
)
if(WIN32)
if(USE_QT_TABLET_WINDOWS)
ki18n_wrap_ui(kritaui_LIB_SRCS
dialogs/KisDlgCustomTabletResolution.ui
)
else()
ki18n_wrap_ui(kritaui_LIB_SRCS
input/wintab/kis_screen_size_choice_dialog.ui
)
endif()
endif()
add_library(kritaui SHARED ${kritaui_HEADERS_MOC} ${kritaui_LIB_SRCS} )
generate_export_header(kritaui BASE_NAME kritaui)
target_link_libraries(kritaui KF5::CoreAddons KF5::Completion KF5::I18n KF5::ItemViews Qt5::Network
kritaversion kritaimpex kritacolor kritaimage kritalibbrush kritawidgets kritawidgetutils kritaresources ${PNG_LIBRARIES} LibExiv2::LibExiv2
)
if (ANDROID)
target_link_libraries(kritaui GLESv3)
target_link_libraries(kritaui Qt5::Gui)
target_link_libraries(kritaui Qt5::AndroidExtras)
endif()
if (HAVE_QT_MULTIMEDIA)
target_link_libraries(kritaui Qt5::Multimedia)
endif()
if (NOT WIN32 AND NOT APPLE AND NOT ANDROID)
target_link_libraries(kritaui ${X11_X11_LIB}
${X11_Xinput_LIB})
endif()
if(APPLE)
target_link_libraries(kritaui ${FOUNDATION_LIBRARY})
target_link_libraries(kritaui ${APPKIT_LIBRARY})
endif ()
target_link_libraries(kritaui ${OPENEXR_LIBRARIES})
# Add VSync disable workaround
if(NOT WIN32 AND NOT APPLE AND NOT ANDROID)
target_link_libraries(kritaui ${CMAKE_DL_LIBS} Qt5::X11Extras)
endif()
if(X11_FOUND)
target_link_libraries(kritaui Qt5::X11Extras ${X11_LIBRARIES})
endif()
target_include_directories(kritaui
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/canvas>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/flake>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/ora>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/tool>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/utils>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/widgets>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/input/wintab>
)
set_target_properties(kritaui
PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION}
)
install(TARGETS kritaui ${INSTALL_TARGETS_DEFAULT_ARGS})
if (APPLE)
install(FILES osx.stylesheet DESTINATION ${DATA_INSTALL_DIR}/krita)
endif ()
if (UNIX AND BUILD_TESTING AND ENABLE_UPDATERS)
install(FILES tests/data/AppImageUpdateDummy
PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
endif ()
diff --git a/libs/ui/KisActionPlugin.h b/libs/ui/KisActionPlugin.h
index 43e551bc6d..a9124357f8 100644
--- a/libs/ui/KisActionPlugin.h
+++ b/libs/ui/KisActionPlugin.h
@@ -1,63 +1,63 @@
/*
* Copyright (c) 2013 Sven Langkamp <sven.langkamp@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KIS_VIEW_PLUGIN_H
#define KIS_VIEW_PLUGIN_H
#include <kritaui_export.h>
#include <QObject>
#include <QPointer>
class KisOperation;
class KisOperationUIFactory;
class KisAction;
class KisViewManager;
/**
* KisActionPlugin is the base for plugins which add actions to the main window
*/
class KRITAUI_EXPORT KisActionPlugin : public QObject
{
Q_OBJECT
public:
KisActionPlugin(QObject *parent = 0);
~KisActionPlugin() override;
protected:
/**
* Registers a KisAction to the UI and action manager.
- * @param name - title of the action in the krita4.xmlgui file
+ * @param name - title of the action in the krita5.xmlgui file
* @param action the action that should be added
*/
void addAction(const QString& name, KisAction *action);
KisAction *createAction(const QString &name);
void addUIFactory(KisOperationUIFactory *factory);
void addOperation(KisOperation *operation);
QPointer<KisViewManager> viewManager() const;
private:
QPointer<KisViewManager> m_viewManager;
};
#endif // KIS_VIEW_PLUGIN_H
diff --git a/libs/ui/KisApplication.cpp b/libs/ui/KisApplication.cpp
index 26e91a7238..73f6c8f6e3 100644
--- a/libs/ui/KisApplication.cpp
+++ b/libs/ui/KisApplication.cpp
@@ -1,1017 +1,1028 @@
/*
* Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
* Copyright (C) 2012 Boudewijn Rempt <boud@valdyas.org>
*
* 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 "KisApplication.h"
#include <stdlib.h>
#ifdef Q_OS_WIN
#include <windows.h>
#include <tchar.h>
#endif
#ifdef Q_OS_MACOS
#include "osx.h"
#endif
#include <QStandardPaths>
#include <QDesktopWidget>
#include <QDir>
#include <QFile>
#include <QLocale>
#include <QMessageBox>
#include <QProcessEnvironment>
#include <QStringList>
#include <QStyle>
#include <QStyleFactory>
#include <QSysInfo>
#include <QTimer>
#include <QWidget>
#include <QImageReader>
#include <QImageWriter>
#include <QThread>
#include <klocalizedstring.h>
#include <kdesktopfile.h>
#include <kconfig.h>
#include <kconfiggroup.h>
#include <KoDockRegistry.h>
#include <KoToolRegistry.h>
#include <KoColorSpaceRegistry.h>
#include <KoPluginLoader.h>
#include <KoShapeRegistry.h>
#include <KoDpi.h>
#include "KoConfig.h"
#include <KoResourcePaths.h>
#include <KisMimeDatabase.h>
#include "thememanager.h"
-#include "KisPrintJob.h"
#include "KisDocument.h"
#include "KisMainWindow.h"
#include "KisAutoSaveRecoveryDialog.h"
#include "KisPart.h"
#include <kis_icon.h>
#include "kis_splash_screen.h"
#include "kis_config.h"
#include "flake/kis_shape_selection.h"
#include <filter/kis_filter.h>
#include <filter/kis_filter_registry.h>
#include <filter/kis_filter_configuration.h>
#include <generator/kis_generator_registry.h>
#include <generator/kis_generator.h>
#include <brushengine/kis_paintop_registry.h>
#include <kis_meta_data_io_backend.h>
#include "kisexiv2/kis_exiv2.h"
#include "KisApplicationArguments.h"
#include <kis_debug.h>
#include "kis_action_registry.h"
#include <KoResourceServer.h>
#include <KisResourceServerProvider.h>
#include <KoResourceServerProvider.h>
#include "kis_image_barrier_locker.h"
#include "opengl/kis_opengl.h"
#include "kis_spin_box_unit_manager.h"
#include "kis_document_aware_spin_box_unit_manager.h"
#include "KisViewManager.h"
#include <KisUsageLogger.h>
#include <KritaVersionWrapper.h>
#include <dialogs/KisSessionManagerDialog.h>
#include <KisResourceCacheDb.h>
#include <KisResourceLocator.h>
#include <KisResourceLoader.h>
#include <KisResourceLoaderRegistry.h>
#include <kis_gbr_brush.h>
#include <kis_png_brush.h>
#include <kis_svg_brush.h>
#include <kis_imagepipe_brush.h>
#include <KoColorSet.h>
#include <KoSegmentGradient.h>
#include <KoStopGradient.h>
#include <KoPattern.h>
#include <kis_workspace_resource.h>
#include <KisSessionResource.h>
#include <resources/KoSvgSymbolCollectionResource.h>
#include "widgets/KisScreenColorPicker.h"
#include "KisDlgInternalColorSelector.h"
#include <dialogs/KisAsyncAnimationFramesSaveDialog.h>
#include <kis_image_animation_interface.h>
#include "kis_file_layer.h"
#include "kis_group_layer.h"
#include "kis_node_commands_adapter.h"
#include <kis_psd_layer_style.h>
namespace {
const QTime appStartTime(QTime::currentTime());
}
class KisApplication::Private
{
public:
Private() {}
QPointer<KisSplashScreen> splashScreen;
KisAutoSaveRecoveryDialog *autosaveDialog {0};
QPointer<KisMainWindow> mainWindow; // The first mainwindow we create on startup
bool batchRun {false};
QVector<QByteArray> earlyRemoteArguments;
};
class KisApplication::ResetStarting
{
public:
ResetStarting(KisSplashScreen *splash, int fileCount)
: m_splash(splash)
, m_fileCount(fileCount)
{
}
~ResetStarting() {
if (m_splash) {
m_splash->hide();
}
}
QPointer<KisSplashScreen> m_splash;
int m_fileCount;
};
KisApplication::KisApplication(const QString &key, int &argc, char **argv)
: QtSingleApplication(key, argc, argv)
, d(new Private)
{
#ifdef Q_OS_MACOS
setMouseCoalescingEnabled(false);
#endif
QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath());
setApplicationDisplayName("Krita");
setApplicationName("krita");
// Note: Qt docs suggest we set this, but if we do, we get resource paths of the form of krita/krita, which is weird.
// setOrganizationName("krita");
setOrganizationDomain("krita.org");
QString version = KritaVersionWrapper::versionString(true);
setApplicationVersion(version);
setWindowIcon(KisIconUtils::loadIcon("krita"));
+
+
if (qgetenv("KRITA_NO_STYLE_OVERRIDE").isEmpty()) {
QStringList styles = QStringList() << "breeze" << "fusion" << "plastique";
if (!styles.contains(style()->objectName().toLower())) {
Q_FOREACH (const QString & style, styles) {
if (!setStyle(style)) {
qDebug() << "No" << style << "available.";
}
else {
qDebug() << "Set style" << style;
break;
}
}
}
+
+ // if style is set from config, try to load that
+ KisConfig cfg(true);
+ QString widgetStyleFromConfig = cfg.widgetStyle();
+ if(widgetStyleFromConfig != "") {
+ qApp->setStyle(widgetStyleFromConfig);
+ }
+
}
else {
qDebug() << "Style override disabled, using" << style()->objectName();
}
+
+
}
#if defined(Q_OS_WIN) && defined(ENV32BIT)
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
LPFN_ISWOW64PROCESS fnIsWow64Process;
BOOL isWow64()
{
BOOL bIsWow64 = FALSE;
//IsWow64Process is not available on all supported versions of Windows.
//Use GetModuleHandle to get a handle to the DLL that contains the function
//and GetProcAddress to get a pointer to the function if available.
fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
if(0 != fnIsWow64Process)
{
if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
{
//handle error
}
}
return bIsWow64;
}
#endif
void KisApplication::initializeGlobals(const KisApplicationArguments &args)
{
int dpiX = args.dpiX();
int dpiY = args.dpiY();
if (dpiX > 0 && dpiY > 0) {
KoDpi::setDPI(dpiX, dpiY);
}
}
void KisApplication::addResourceTypes()
{
// qDebug() << "addResourceTypes();";
// All Krita's resource types
KoResourcePaths::addResourceType("markers", "data", "/styles/");
KoResourcePaths::addResourceType("kis_pics", "data", "/pics/");
KoResourcePaths::addResourceType("kis_images", "data", "/images/");
KoResourcePaths::addResourceType("metadata_schema", "data", "/metadata/schemas/");
KoResourcePaths::addResourceType(ResourceType::Brushes, "data", "/brushes/");
KoResourcePaths::addResourceType("kis_taskset", "data", "/taskset/");
KoResourcePaths::addResourceType("kis_taskset", "data", "/taskset/");
KoResourcePaths::addResourceType("gmic_definitions", "data", "/gmic/");
KoResourcePaths::addResourceType("kis_resourcebundles", "data", "/bundles/");
KoResourcePaths::addResourceType("kis_defaultpresets", "data", "/defaultpresets/");
KoResourcePaths::addResourceType(ResourceType::PaintOpPresets, "data", "/paintoppresets/");
KoResourcePaths::addResourceType(ResourceType::Workspaces, "data", "/workspaces/");
KoResourcePaths::addResourceType(ResourceType::WindowLayouts, "data", "/windowlayouts/");
KoResourcePaths::addResourceType(ResourceType::Sessions, "data", "/sessions/");
KoResourcePaths::addResourceType("psd_layer_style_collections", "data", "/asl");
KoResourcePaths::addResourceType(ResourceType::Patterns, "data", "/patterns/", true);
KoResourcePaths::addResourceType(ResourceType::Gradients, "data", "/gradients/");
KoResourcePaths::addResourceType(ResourceType::Gradients, "data", "/gradients/", true);
KoResourcePaths::addResourceType(ResourceType::Palettes, "data", "/palettes/", true);
KoResourcePaths::addResourceType("kis_shortcuts", "data", "/shortcuts/");
KoResourcePaths::addResourceType("kis_actions", "data", "/actions");
KoResourcePaths::addResourceType("kis_actions", "data", "/pykrita");
KoResourcePaths::addResourceType("icc_profiles", "data", "/color/icc");
KoResourcePaths::addResourceType("icc_profiles", "data", "/profiles/");
KoResourcePaths::addResourceType(ResourceType::FilterEffects, "data", "/effects/");
KoResourcePaths::addResourceType("tags", "data", "/tags/");
KoResourcePaths::addResourceType("templates", "data", "/templates");
KoResourcePaths::addResourceType("pythonscripts", "data", "/pykrita");
KoResourcePaths::addResourceType(ResourceType::Symbols, "data", "/symbols");
KoResourcePaths::addResourceType("preset_icons", "data", "/preset_icons");
KoResourcePaths::addResourceType(ResourceType::GamutMasks, "data", "/gamutmasks/", true);
// // Extra directories to look for create resources. (Does anyone actually use that anymore?)
// KoResourcePaths::addResourceDir(ResourceType::Gradients, "/usr/share/create/gradients/gimp");
// KoResourcePaths::addResourceDir(ResourceType::Gradients, QDir::homePath() + QString("/.create/gradients/gimp"));
// KoResourcePaths::addResourceDir(ResourceType::Patterns, "/usr/share/create/patterns/gimp");
// KoResourcePaths::addResourceDir(ResourceType::Patterns, QDir::homePath() + QString("/.create/patterns/gimp"));
// KoResourcePaths::addResourceDir(ResourceType::Brushes, "/usr/share/create/brushes/gimp");
// KoResourcePaths::addResourceDir(ResourceType::Brushes, QDir::homePath() + QString("/.create/brushes/gimp"));
// KoResourcePaths::addResourceDir(ResourceType::Palettes, "/usr/share/create/swatches");
// KoResourcePaths::addResourceDir(ResourceType::Palettes, QDir::homePath() + QString("/.create/swatches"));
// Make directories for all resources we can save, and tags
QDir d;
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/tags/");
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/asl/");
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/bundles/");
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/brushes/");
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/gradients/");
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/paintoppresets/");
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/palettes/");
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/patterns/");
// between 4.2.x and 4.3.0 there was a change from 'taskset' to 'tasksets'
// so to make older resource folders compatible with the new version, let's rename the folder
// so no tasksets are lost.
if (d.exists(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/taskset/")) {
d.rename(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/taskset/",
QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/tasksets/");
}
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/tasksets/");
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/workspaces/");
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/input/");
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/pykrita/");
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/symbols/");
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/color-schemes/");
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/preset_icons/");
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/preset_icons/tool_icons/");
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/preset_icons/emblem_icons/");
d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/gamutmasks/");
}
bool KisApplication::registerResources()
{
KisResourceLoaderRegistry *reg = KisResourceLoaderRegistry::instance();
reg->add(new KisResourceLoader<KisPaintOpPreset>(ResourceType::PaintOpPresets, ResourceType::PaintOpPresets, i18n("Brush presets"), QStringList() << "application/x-krita-paintoppreset"));
reg->add(new KisResourceLoader<KisGbrBrush>(ResourceSubType::GbrBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/x-gimp-brush"));
reg->add(new KisResourceLoader<KisImagePipeBrush>(ResourceSubType::GihBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/x-gimp-brush-animated"));
reg->add(new KisResourceLoader<KisSvgBrush>(ResourceSubType::SvgBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/svg+xml"));
reg->add(new KisResourceLoader<KisPngBrush>(ResourceSubType::PngBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/png"));
reg->add(new KisResourceLoader<KoSegmentGradient>(ResourceSubType::SegmentedGradients, ResourceType::Gradients, i18n("Gradients"), QStringList() << "application/x-gimp-gradient"));
reg->add(new KisResourceLoader<KoStopGradient>(ResourceSubType::StopGradients, ResourceType::Gradients, i18n("Gradients"), QStringList() << "application/x-karbon-gradient" << "image/svg+xml"));
reg->add(new KisResourceLoader<KoColorSet>(ResourceType::Palettes, ResourceType::Palettes, i18n("Palettes"),
QStringList() << KisMimeDatabase::mimeTypeForSuffix("kpl")
<< KisMimeDatabase::mimeTypeForSuffix("gpl")
<< KisMimeDatabase::mimeTypeForSuffix("pal")
<< KisMimeDatabase::mimeTypeForSuffix("act")
<< KisMimeDatabase::mimeTypeForSuffix("aco")
<< KisMimeDatabase::mimeTypeForSuffix("css")
<< KisMimeDatabase::mimeTypeForSuffix("colors")
<< KisMimeDatabase::mimeTypeForSuffix("xml")
<< KisMimeDatabase::mimeTypeForSuffix("sbz")));
QList<QByteArray> src = QImageReader::supportedMimeTypes();
QStringList allImageMimes;
Q_FOREACH(const QByteArray ba, src) {
if (QImageWriter::supportedMimeTypes().contains(ba)) {
allImageMimes << QString::fromUtf8(ba);
}
}
allImageMimes << KisMimeDatabase::mimeTypeForSuffix("pat");
reg->add(new KisResourceLoader<KoPattern>(ResourceType::Patterns, ResourceType::Patterns, i18n("Patterns"), allImageMimes));
reg->add(new KisResourceLoader<KisWorkspaceResource>(ResourceType::Workspaces, ResourceType::Workspaces, i18n("Workspaces"), QStringList() << "application/x-krita-workspace"));
reg->add(new KisResourceLoader<KoSvgSymbolCollectionResource>(ResourceType::Symbols, ResourceType::Symbols, i18n("SVG symbol libraries"), QStringList() << "image/svg+xml"));
reg->add(new KisResourceLoader<KisWindowLayoutResource>(ResourceType::WindowLayouts, ResourceType::WindowLayouts, i18n("Window layouts"), QStringList() << "application/x-krita-windowlayout"));
reg->add(new KisResourceLoader<KisSessionResource>(ResourceType::Sessions, ResourceType::Sessions, i18n("Sessions"), QStringList() << "application/x-krita-session"));
reg->add(new KisResourceLoader<KoGamutMask>(ResourceType::GamutMasks, ResourceType::GamutMasks, i18n("Gamut masks"), QStringList() << "application/x-krita-gamutmasks"));
reg->add(new KisResourceLoader<KisPSDLayerStyle>(ResourceType::LayerStyles,
ResourceType::LayerStyles,
ResourceType::LayerStyles,
QStringList() << "application/x-photoshop-style"));
if (!KisResourceCacheDb::initialize(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation))) {
QMessageBox::critical(0, i18nc("@title:window", "Krita: Fatal error"), i18n("%1\n\nKrita will quit now.", KisResourceCacheDb::lastError()));
//return false;
}
KisResourceLocator::LocatorError r = KisResourceLocator::instance()->initialize(KoResourcePaths::getApplicationRoot() + "/share/krita");
connect(KisResourceLocator::instance(), SIGNAL(progressMessage(const QString&)), this, SLOT(setSplashScreenLoadingText(const QString&)));
if (r != KisResourceLocator::LocatorError::Ok ) {
QMessageBox::critical(0, i18nc("@title:window", "Krita: Fatal error"), KisResourceLocator::instance()->errorMessages().join('\n') + i18n("\n\nKrita will quit now."));
//return false;
}
return true;
}
void KisApplication::loadPlugins()
{
// qDebug() << "loadPlugins();";
KoShapeRegistry* r = KoShapeRegistry::instance();
r->add(new KisShapeSelectionFactory());
KoColorSpaceRegistry::instance();
KisActionRegistry::instance();
KisFilterRegistry::instance();
KisGeneratorRegistry::instance();
KisPaintOpRegistry::instance();
KoToolRegistry::instance();
KoDockRegistry::instance();
}
void KisApplication::loadGuiPlugins()
{
// XXX_EXIV: make the exiv io backends real plugins
setSplashScreenLoadingText(i18n("Loading Plugins Exiv/IO..."));
processEvents();
// qDebug() << "loading exiv2";
KisExiv2::initialize();
}
bool KisApplication::start(const KisApplicationArguments &args)
{
KisConfig cfg(false);
#if defined(Q_OS_WIN)
#ifdef ENV32BIT
if (isWow64() && !cfg.readEntry("WarnedAbout32Bits", false)) {
QMessageBox::information(0,
i18nc("@title:window", "Krita: Warning"),
i18n("You are running a 32 bits build on a 64 bits Windows.\n"
"This is not recommended.\n"
"Please download and install the x64 build instead."));
cfg.writeEntry("WarnedAbout32Bits", true);
}
#endif
#endif
QString opengl = cfg.canvasState();
if (opengl == "OPENGL_NOT_TRIED" ) {
cfg.setCanvasState("TRY_OPENGL");
}
else if (opengl != "OPENGL_SUCCESS" && opengl != "TRY_OPENGL") {
cfg.setCanvasState("OPENGL_FAILED");
}
setSplashScreenLoadingText(i18n("Initializing Globals"));
processEvents();
initializeGlobals(args);
const bool doNewImage = args.doNewImage();
const bool doTemplate = args.doTemplate();
const bool exportAs = args.exportAs();
const bool exportSequence = args.exportSequence();
const QString exportFileName = args.exportFileName();
d->batchRun = (exportAs || exportSequence || !exportFileName.isEmpty());
const bool needsMainWindow = (!exportAs && !exportSequence);
// only show the mainWindow when no command-line mode option is passed
bool showmainWindow = (!exportAs && !exportSequence); // would be !batchRun;
const bool showSplashScreen = !d->batchRun && qEnvironmentVariableIsEmpty("NOSPLASH");
if (showSplashScreen && d->splashScreen) {
d->splashScreen->show();
d->splashScreen->repaint();
processEvents();
}
KConfigGroup group(KSharedConfig::openConfig(), "theme");
Digikam::ThemeManager themeManager;
themeManager.setCurrentTheme(group.readEntry("Theme", "Krita dark"));
ResetStarting resetStarting(d->splashScreen, args.filenames().count()); // remove the splash when done
Q_UNUSED(resetStarting);
// Make sure we can save resources and tags
setSplashScreenLoadingText(i18n("Adding resource types"));
processEvents();
addResourceTypes();
// Load the plugins
loadPlugins();
// Load all resources
if (!registerResources()) {
return false;
}
// Load the gui plugins
loadGuiPlugins();
KisPart *kisPart = KisPart::instance();
if (needsMainWindow) {
// show a mainWindow asap, if we want that
setSplashScreenLoadingText(i18n("Loading Main Window..."));
processEvents();
bool sessionNeeded = true;
auto sessionMode = cfg.sessionOnStartup();
if (!args.session().isEmpty()) {
sessionNeeded = !kisPart->restoreSession(args.session());
} else if (sessionMode == KisConfig::SOS_ShowSessionManager) {
showmainWindow = false;
sessionNeeded = false;
kisPart->showSessionManager();
} else if (sessionMode == KisConfig::SOS_PreviousSession) {
KConfigGroup sessionCfg = KSharedConfig::openConfig()->group("session");
const QString &sessionName = sessionCfg.readEntry("previousSession");
sessionNeeded = !kisPart->restoreSession(sessionName);
}
if (sessionNeeded) {
kisPart->startBlankSession();
}
if (!args.windowLayout().isEmpty()) {
KoResourceServer<KisWindowLayoutResource> * rserver = KisResourceServerProvider::instance()->windowLayoutServer();
KisWindowLayoutResourceSP windowLayout = rserver->resourceByName(args.windowLayout());
if (windowLayout) {
windowLayout->applyLayout();
}
}
if (showmainWindow) {
d->mainWindow = kisPart->currentMainwindow();
if (!args.workspace().isEmpty()) {
KoResourceServer<KisWorkspaceResource> * rserver = KisResourceServerProvider::instance()->workspaceServer();
KisWorkspaceResourceSP workspace = rserver->resourceByName(args.workspace());
if (workspace) {
d->mainWindow->restoreWorkspace(workspace->resourceId());
}
}
if (args.canvasOnly()) {
d->mainWindow->viewManager()->switchCanvasOnly(true);
}
if (args.fullScreen()) {
d->mainWindow->showFullScreen();
}
} else {
d->mainWindow = kisPart->createMainWindow();
}
}
short int numberOfOpenDocuments = 0; // number of documents open
// Check for autosave files that can be restored, if we're not running a batchrun (test)
if (!d->batchRun) {
checkAutosaveFiles();
}
setSplashScreenLoadingText(QString()); // done loading, so clear out label
processEvents();
//configure the unit manager
KisSpinBoxUnitManagerFactory::setDefaultUnitManagerBuilder(new KisDocumentAwareSpinBoxUnitManagerBuilder());
connect(this, &KisApplication::aboutToQuit, &KisSpinBoxUnitManagerFactory::clearUnitManagerBuilder); //ensure the builder is destroyed when the application leave.
//the new syntax slot syntax allow to connect to a non q_object static method.
// Create a new image, if needed
if (doNewImage) {
KisDocument *doc = args.createDocumentFromArguments();
if (doc) {
kisPart->addDocument(doc);
d->mainWindow->addViewAndNotifyLoadingCompleted(doc);
}
}
// Get the command line arguments which we have to parse
int argsCount = args.filenames().count();
if (argsCount > 0) {
// Loop through arguments
for (int argNumber = 0; argNumber < argsCount; argNumber++) {
QString fileName = args.filenames().at(argNumber);
// are we just trying to open a template?
if (doTemplate) {
// called in mix with batch options? ignore and silently skip
if (d->batchRun) {
continue;
}
if (createNewDocFromTemplate(fileName, d->mainWindow)) {
++numberOfOpenDocuments;
}
// now try to load
}
else {
if (exportAs) {
QString outputMimetype = KisMimeDatabase::mimeTypeForFile(exportFileName, false);
if (outputMimetype == "application/octetstream") {
dbgKrita << i18n("Mimetype not found, try using the -mimetype option") << endl;
return false;
}
KisDocument *doc = kisPart->createDocument();
doc->setFileBatchMode(d->batchRun);
bool result = doc->openUrl(QUrl::fromLocalFile(fileName));
if (!result) {
errKrita << "Could not load " << fileName << ":" << doc->errorMessage();
QTimer::singleShot(0, this, SLOT(quit()));
return false;
}
if (exportFileName.isEmpty()) {
errKrita << "Export destination is not specified for" << fileName << "Please specify export destination with --export-filename option";
QTimer::singleShot(0, this, SLOT(quit()));
return false;
}
qApp->processEvents(); // For vector layers to be updated
doc->setFileBatchMode(true);
if (!doc->exportDocumentSync(QUrl::fromLocalFile(exportFileName), outputMimetype.toLatin1())) {
errKrita << "Could not export " << fileName << "to" << exportFileName << ":" << doc->errorMessage();
}
QTimer::singleShot(0, this, SLOT(quit()));
return true;
}
else if (exportSequence) {
KisDocument *doc = kisPart->createDocument();
doc->setFileBatchMode(d->batchRun);
doc->openUrl(QUrl::fromLocalFile(fileName));
qApp->processEvents(); // For vector layers to be updated
if (!doc->image()->animationInterface()->hasAnimation()) {
errKrita << "This file has no animation." << endl;
QTimer::singleShot(0, this, SLOT(quit()));
return false;
}
doc->setFileBatchMode(true);
int sequenceStart = 0;
KisAsyncAnimationFramesSaveDialog exporter(doc->image(),
doc->image()->animationInterface()->fullClipRange(),
exportFileName,
sequenceStart,
false,
0);
exporter.setBatchMode(d->batchRun);
KisAsyncAnimationFramesSaveDialog::Result result =
exporter.regenerateRange(0);
if (result == KisAsyncAnimationFramesSaveDialog::RenderFailed) {
errKrita << i18n("Failed to render animation frames!") << endl;
}
QTimer::singleShot(0, this, SLOT(quit()));
return true;
}
else if (d->mainWindow) {
if (fileName.endsWith(".bundle")) {
d->mainWindow->installBundle(fileName);
}
else {
KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
if (d->mainWindow->openDocument(QUrl::fromLocalFile(fileName), flags)) {
// Normal case, success
numberOfOpenDocuments++;
}
}
}
}
}
}
//add an image as file-layer
if (!args.fileLayer().isEmpty()){
if (d->mainWindow->viewManager()->image()){
KisFileLayer *fileLayer = new KisFileLayer(d->mainWindow->viewManager()->image(), "",
args.fileLayer(), KisFileLayer::None,
d->mainWindow->viewManager()->image()->nextLayerName(), OPACITY_OPAQUE_U8);
QFileInfo fi(fileLayer->path());
if (fi.exists()){
KisNodeCommandsAdapter adapter(d->mainWindow->viewManager());
adapter.addNode(fileLayer, d->mainWindow->viewManager()->activeNode()->parent(),
d->mainWindow->viewManager()->activeNode());
}
else{
QMessageBox::warning(nullptr, i18nc("@title:window", "Krita:Warning"),
i18n("Cannot add %1 as a file layer: the file does not exist.", fileLayer->path()));
}
}
else if (this->isRunning()){
QMessageBox::warning(nullptr, i18nc("@title:window", "Krita:Warning"),
i18n("Cannot add the file layer: no document is open.\n\n"
"You can create a new document using the --new-image option, or you can open an existing file.\n\n"
"If you instead want to add the file layer to a document in an already running instance of Krita, check the \"Allow only one instance of Krita\" checkbox in the settings (Settings -> General -> Window)."));
}
else {
QMessageBox::warning(nullptr, i18nc("@title:window", "Krita: Warning"),
i18n("Cannot add the file layer: no document is open.\n"
"You can either create a new file using the --new-image option, or you can open an existing file."));
}
}
// fixes BUG:369308 - Krita crashing on splash screen when loading.
// trying to open a file before Krita has loaded can cause it to hang and crash
if (d->splashScreen) {
d->splashScreen->displayLinks(true);
d->splashScreen->displayRecentFiles(true);
}
Q_FOREACH(const QByteArray &message, d->earlyRemoteArguments) {
executeRemoteArguments(message, d->mainWindow);
}
KisUsageLogger::writeSysInfo(KisUsageLogger::screenInformation());
// not calling this before since the program will quit there.
return true;
}
KisApplication::~KisApplication()
{
KisResourceCacheDb::deleteTemporaryResources();
}
void KisApplication::setSplashScreen(QWidget *splashScreen)
{
d->splashScreen = qobject_cast<KisSplashScreen*>(splashScreen);
}
void KisApplication::setSplashScreenLoadingText(const QString &textToLoad)
{
if (d->splashScreen) {
d->splashScreen->setLoadingText(textToLoad);
d->splashScreen->repaint();
}
}
void KisApplication::hideSplashScreen()
{
if (d->splashScreen) {
// hide the splashscreen to see the dialog
d->splashScreen->hide();
}
}
bool KisApplication::notify(QObject *receiver, QEvent *event)
{
try {
return QApplication::notify(receiver, event);
} catch (std::exception &e) {
qWarning("Error %s sending event %i to object %s",
e.what(), event->type(), qPrintable(receiver->objectName()));
} catch (...) {
qWarning("Error <unknown> sending event %i to object %s",
event->type(), qPrintable(receiver->objectName()));
}
return false;
}
void KisApplication::executeRemoteArguments(QByteArray message, KisMainWindow *mainWindow)
{
KisApplicationArguments args = KisApplicationArguments::deserialize(message);
const bool doTemplate = args.doTemplate();
const bool doNewImage = args.doNewImage();
const int argsCount = args.filenames().count();
bool documentCreated = false;
// Create a new image, if needed
if (doNewImage) {
KisDocument *doc = args.createDocumentFromArguments();
if (doc) {
KisPart::instance()->addDocument(doc);
d->mainWindow->addViewAndNotifyLoadingCompleted(doc);
}
}
if (argsCount > 0) {
// Loop through arguments
for (int argNumber = 0; argNumber < argsCount; ++argNumber) {
QString filename = args.filenames().at(argNumber);
// are we just trying to open a template?
if (doTemplate) {
documentCreated |= createNewDocFromTemplate(filename, mainWindow);
}
else if (QFile(filename).exists()) {
KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
documentCreated |= mainWindow->openDocument(QUrl::fromLocalFile(filename), flags);
}
}
}
//add an image as file-layer if called in another process and singleApplication is enabled
if (!args.fileLayer().isEmpty()){
if (argsCount > 0 && !documentCreated){
//arg was passed but document was not created so don't add the file layer.
QMessageBox::warning(mainWindow, i18nc("@title:window", "Krita:Warning"),
i18n("Couldn't open file %1",args.filenames().at(argsCount - 1)));
}
else if (mainWindow->viewManager()->image()){
KisFileLayer *fileLayer = new KisFileLayer(mainWindow->viewManager()->image(), "",
args.fileLayer(), KisFileLayer::None,
mainWindow->viewManager()->image()->nextLayerName(), OPACITY_OPAQUE_U8);
QFileInfo fi(fileLayer->path());
if (fi.exists()){
KisNodeCommandsAdapter adapter(d->mainWindow->viewManager());
adapter.addNode(fileLayer, d->mainWindow->viewManager()->activeNode()->parent(),
d->mainWindow->viewManager()->activeNode());
}
else{
QMessageBox::warning(mainWindow, i18nc("@title:window", "Krita:Warning"),
i18n("Cannot add %1 as a file layer: the file does not exist.", fileLayer->path()));
}
}
else {
QMessageBox::warning(mainWindow, i18nc("@title:window", "Krita:Warning"),
i18n("Cannot add the file layer: no document is open."));
}
}
}
void KisApplication::remoteArguments(QByteArray message, QObject *socket)
{
Q_UNUSED(socket);
// check if we have any mainwindow
KisMainWindow *mw = qobject_cast<KisMainWindow*>(qApp->activeWindow());
if (!mw && KisPart::instance()->mainWindows().size() > 0) {
mw = KisPart::instance()->mainWindows().first();
}
if (!mw) {
d->earlyRemoteArguments << message;
return;
}
executeRemoteArguments(message, mw);
}
void KisApplication::fileOpenRequested(const QString &url)
{
KisMainWindow *mainWindow = KisPart::instance()->mainWindows().first();
if (mainWindow) {
KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
mainWindow->openDocument(QUrl::fromLocalFile(url), flags);
}
}
void KisApplication::checkAutosaveFiles()
{
if (d->batchRun) return;
#ifdef Q_OS_WIN
QDir dir = QDir::temp();
#else
QDir dir = QDir::home();
#endif
// Check for autosave files from a previous run. There can be several, and
// we want to offer a restore for every one. Including a nice thumbnail!
// Hidden autosave files
QStringList filters = QStringList() << QString(".krita-*-*-autosave.kra");
// all autosave files for our application
QStringList autosaveFiles = dir.entryList(filters, QDir::Files | QDir::Hidden);
// Visible autosave files
filters = QStringList() << QString("krita-*-*-autosave.kra");
autosaveFiles += dir.entryList(filters, QDir::Files);
// Allow the user to make their selection
if (autosaveFiles.size() > 0) {
if (d->splashScreen) {
// hide the splashscreen to see the dialog
d->splashScreen->hide();
}
d->autosaveDialog = new KisAutoSaveRecoveryDialog(autosaveFiles, activeWindow());
QDialog::DialogCode result = (QDialog::DialogCode) d->autosaveDialog->exec();
if (result == QDialog::Accepted) {
QStringList filesToRecover = d->autosaveDialog->recoverableFiles();
Q_FOREACH (const QString &autosaveFile, autosaveFiles) {
if (!filesToRecover.contains(autosaveFile)) {
KisUsageLogger::log(QString("Removing autosave file %1").arg(dir.absolutePath() + "/" + autosaveFile));
QFile::remove(dir.absolutePath() + "/" + autosaveFile);
}
}
autosaveFiles = filesToRecover;
} else {
autosaveFiles.clear();
}
if (autosaveFiles.size() > 0) {
QList<QUrl> autosaveUrls;
Q_FOREACH (const QString &autoSaveFile, autosaveFiles) {
const QUrl url = QUrl::fromLocalFile(dir.absolutePath() + QLatin1Char('/') + autoSaveFile);
autosaveUrls << url;
}
if (d->mainWindow) {
Q_FOREACH (const QUrl &url, autosaveUrls) {
KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
d->mainWindow->openDocument(url, flags | KisMainWindow::RecoveryFile);
}
}
}
// cleanup
delete d->autosaveDialog;
d->autosaveDialog = nullptr;
}
}
bool KisApplication::createNewDocFromTemplate(const QString &fileName, KisMainWindow *mainWindow)
{
QString templatePath;
const QUrl templateUrl = QUrl::fromLocalFile(fileName);
if (QFile::exists(fileName)) {
templatePath = templateUrl.toLocalFile();
dbgUI << "using full path...";
}
else {
QString desktopName(fileName);
const QString templatesResourcePath = QStringLiteral("templates/");
QStringList paths = KoResourcePaths::findAllResources("data", templatesResourcePath + "*/" + desktopName);
if (paths.isEmpty()) {
paths = KoResourcePaths::findAllResources("data", templatesResourcePath + desktopName);
}
if (paths.isEmpty()) {
QMessageBox::critical(0, i18nc("@title:window", "Krita"),
i18n("No template found for: %1", desktopName));
} else if (paths.count() > 1) {
QMessageBox::critical(0, i18nc("@title:window", "Krita"),
i18n("Too many templates found for: %1", desktopName));
} else {
templatePath = paths.at(0);
}
}
if (!templatePath.isEmpty()) {
QUrl templateBase;
templateBase.setPath(templatePath);
KDesktopFile templateInfo(templatePath);
QString templateName = templateInfo.readUrl();
QUrl templateURL;
templateURL.setPath(templateBase.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path() + '/' + templateName);
if (templateURL.scheme().isEmpty()) {
templateURL.setScheme("file");
}
KisMainWindow::OpenFlags batchFlags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
if (mainWindow->openDocument(templateURL, KisMainWindow::Import | batchFlags)) {
dbgUI << "Template loaded...";
return true;
}
else {
QMessageBox::critical(0, i18nc("@title:window", "Krita"),
i18n("Template %1 failed to load.", templateURL.toDisplayString()));
}
}
return false;
}
void KisApplication::resetConfig()
{
KIS_ASSERT_RECOVER_RETURN(qApp->thread() == QThread::currentThread());
KSharedConfigPtr config = KSharedConfig::openConfig();
config->markAsClean();
// find user settings file
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QString kritarcPath = configPath + QStringLiteral("/kritarc");
QFile kritarcFile(kritarcPath);
if (kritarcFile.exists()) {
if (kritarcFile.open(QFile::ReadWrite)) {
QString backupKritarcPath = kritarcPath + QStringLiteral(".backup");
QFile backupKritarcFile(backupKritarcPath);
if (backupKritarcFile.exists()) {
backupKritarcFile.remove();
}
QMessageBox::information(0,
i18nc("@title:window", "Krita"),
i18n("Krita configurations reset!\n\n"
"Backup file was created at: %1\n\n"
"Restart Krita for changes to take effect.",
backupKritarcPath),
QMessageBox::Ok, QMessageBox::Ok);
// clear file
kritarcFile.rename(backupKritarcPath);
kritarcFile.close();
}
else {
QMessageBox::warning(0,
i18nc("@title:window", "Krita"),
i18n("Failed to clear %1\n\n"
"Please make sure no other program is using the file and try again.",
kritarcPath),
QMessageBox::Ok, QMessageBox::Ok);
}
}
// reload from disk; with the user file settings cleared,
// this should load any default configuration files shipping with the program
config->reparseConfiguration();
config->sync();
// Restore to default workspace
KConfigGroup cfg = KSharedConfig::openConfig()->group("MainWindow");
QString currentWorkspace = cfg.readEntry<QString>("CurrentWorkspace", "Default");
KoResourceServer<KisWorkspaceResource> * rserver = KisResourceServerProvider::instance()->workspaceServer();
KisWorkspaceResourceSP workspace = rserver->resourceByName(currentWorkspace);
if (workspace) {
d->mainWindow->restoreWorkspace(workspace->resourceId());
}
}
void KisApplication::askresetConfig()
{
bool ok = QMessageBox::question(0,
i18nc("@title:window", "Krita"),
i18n("Do you want to clear the settings file?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes;
if (ok) {
resetConfig();
}
}
diff --git a/libs/ui/KisDocument.cpp b/libs/ui/KisDocument.cpp
index 5cd1f5d14b..5b7708105b 100644
--- a/libs/ui/KisDocument.cpp
+++ b/libs/ui/KisDocument.cpp
@@ -1,2350 +1,2343 @@
/* This file is part of the Krita project
*
* Copyright (C) 2014 Boudewijn Rempt <boud@valdyas.org>
*
* 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 "KisMainWindow.h" // XXX: remove
#include <QMessageBox> // XXX: remove
#include <KisMimeDatabase.h>
#include <KoCanvasBase.h>
#include <KoColor.h>
#include <KoColorProfile.h>
#include <KoColorSpaceEngine.h>
#include <KoColorSpace.h>
#include <KoColorSpaceRegistry.h>
#include <KoDocumentInfoDlg.h>
#include <KoDocumentInfo.h>
#include <KoDpi.h>
#include <KoUnit.h>
#include <KoID.h>
-#include <KoOdfReadStore.h>
#include <KoProgressProxy.h>
#include <KoProgressUpdater.h>
#include <KoSelection.h>
#include <KoShape.h>
#include <KoShapeController.h>
#include <KoStore.h>
#include <KoUpdater.h>
#include <KoXmlWriter.h>
#include <KoXmlReader.h>
#include <KoStoreDevice.h>
#include <KoDialog.h>
#include <KisImportExportErrorCode.h>
#include <KoDocumentResourceManager.h>
#include <KoMD5Generator.h>
#include <KisResourceStorage.h>
#include <KisResourceLocator.h>
#include <KisResourceTypes.h>
#include <KisGlobalResourcesInterface.h>
#include <KisUsageLogger.h>
#include <klocalizedstring.h>
#include <kis_debug.h>
#include <kis_generator_layer.h>
#include <kis_generator_registry.h>
#include <kdesktopfile.h>
#include <kconfiggroup.h>
#include <kbackup.h>
#include <QTextBrowser>
#include <QApplication>
#include <QBuffer>
#include <QStandardPaths>
#include <QDir>
#include <QDomDocument>
#include <QDomElement>
#include <QFileInfo>
#include <QImage>
#include <QList>
#include <QPainter>
#include <QRect>
#include <QScopedPointer>
#include <QSize>
#include <QStringList>
#include <QtGlobal>
#include <QTimer>
#include <QWidget>
#include <QFuture>
#include <QFutureWatcher>
#include <QUuid>
// Krita Image
#include <kis_image_animation_interface.h>
#include <kis_config.h>
#include <flake/kis_shape_layer.h>
#include <kis_group_layer.h>
#include <kis_image.h>
#include <kis_layer.h>
#include <kis_name_server.h>
#include <kis_paint_layer.h>
#include <kis_painter.h>
#include <kis_selection.h>
#include <kis_fill_painter.h>
#include <kis_document_undo_store.h>
#include <kis_idle_watcher.h>
#include <kis_signal_auto_connection.h>
#include <kis_canvas_widget_base.h>
#include "kis_layer_utils.h"
#include "kis_selection_mask.h"
// Local
#include "KisViewManager.h"
#include "kis_clipboard.h"
#include "widgets/kis_custom_image_widget.h"
#include "canvas/kis_canvas2.h"
#include "flake/kis_shape_controller.h"
#include "kis_statusbar.h"
#include "widgets/kis_progress_widget.h"
#include "kis_canvas_resource_provider.h"
#include "KisResourceServerProvider.h"
#include "kis_node_manager.h"
#include "KisPart.h"
#include "KisApplication.h"
#include "KisDocument.h"
#include "KisImportExportManager.h"
#include "KisView.h"
#include "kis_grid_config.h"
#include "kis_guides_config.h"
#include "kis_image_barrier_lock_adapter.h"
#include "KisReferenceImagesLayer.h"
#include "dialogs/KisRecoverNamedAutosaveDialog.h"
#include <mutex>
#include "kis_config_notifier.h"
#include "kis_async_action_feedback.h"
#include "KisCloneDocumentStroke.h"
#include <KisMirrorAxisConfig.h>
#include <KisDecorationsWrapperLayer.h>
#include "kis_simple_stroke_strategy.h"
// Define the protocol used here for embedded documents' URL
// This used to "store" but QUrl didn't like it,
// so let's simply make it "tar" !
#define STORE_PROTOCOL "tar"
// The internal path is a hack to make QUrl happy and for document children
#define INTERNAL_PROTOCOL "intern"
#define INTERNAL_PREFIX "intern:/"
// Warning, keep it sync in koStore.cc
#include <unistd.h>
using namespace std;
namespace {
constexpr int errorMessageTimeout = 5000;
constexpr int successMessageTimeout = 1000;
}
/**********************************************************
*
* KisDocument
*
**********************************************************/
//static
QString KisDocument::newObjectName()
{
static int s_docIFNumber = 0;
QString name; name.setNum(s_docIFNumber++); name.prepend("document_");
return name;
}
class UndoStack : public KUndo2Stack
{
public:
UndoStack(KisDocument *doc)
: KUndo2Stack(doc),
m_doc(doc)
{
}
void setIndex(int idx) override {
KisImageWSP image = this->image();
image->requestStrokeCancellation();
if(image->tryBarrierLock()) {
KUndo2Stack::setIndex(idx);
image->unlock();
}
}
void notifySetIndexChangedOneCommand() override {
KisImageWSP image = this->image();
image->unlock();
/**
* Some very weird commands may emit blocking signals to
* the GUI (e.g. KisGuiContextCommand). Here is the best thing
* we can do to avoid the deadlock
*/
while(!image->tryBarrierLock()) {
QApplication::processEvents();
}
}
void undo() override {
KisImageWSP image = this->image();
image->requestUndoDuringStroke();
if (image->tryUndoUnfinishedLod0Stroke() == UNDO_OK) {
return;
}
if(image->tryBarrierLock()) {
KUndo2Stack::undo();
image->unlock();
}
}
void redo() override {
KisImageWSP image = this->image();
if(image->tryBarrierLock()) {
KUndo2Stack::redo();
image->unlock();
}
}
private:
KisImageWSP image() {
KisImageWSP currentImage = m_doc->image();
Q_ASSERT(currentImage);
return currentImage;
}
private:
KisDocument *m_doc;
};
class Q_DECL_HIDDEN KisDocument::Private
{
public:
Private(KisDocument *_q)
: q(_q)
, docInfo(new KoDocumentInfo(_q)) // deleted by QObject
, importExportManager(new KisImportExportManager(_q)) // deleted manually
, autoSaveTimer(new QTimer(_q))
, undoStack(new UndoStack(_q)) // deleted by QObject
, m_bAutoDetectedMime(false)
, modified(false)
, readwrite(true)
, firstMod(QDateTime::currentDateTime())
, lastMod(firstMod)
, nserver(new KisNameServer(1))
, imageIdleWatcher(2000 /*ms*/)
, globalAssistantsColor(KisConfig(true).defaultAssistantsColor())
, savingLock(&savingMutex)
, batchMode(false)
{
if (QLocale().measurementSystem() == QLocale::ImperialSystem) {
unit = KoUnit::Inch;
} else {
unit = KoUnit::Centimeter;
}
connect(&imageIdleWatcher, SIGNAL(startedIdleMode()), q, SLOT(slotPerformIdleRoutines()));
}
Private(const Private &rhs, KisDocument *_q)
: q(_q)
, docInfo(new KoDocumentInfo(*rhs.docInfo, _q))
, importExportManager(new KisImportExportManager(_q))
, autoSaveTimer(new QTimer(_q))
, undoStack(new UndoStack(_q))
, nserver(new KisNameServer(*rhs.nserver))
, preActivatedNode(0) // the node is from another hierarchy!
, imageIdleWatcher(2000 /*ms*/)
, savingLock(&savingMutex)
{
copyFromImpl(rhs, _q, CONSTRUCT);
connect(&imageIdleWatcher, SIGNAL(startedIdleMode()), q, SLOT(slotPerformIdleRoutines()));
}
~Private() {
// Don't delete m_d->shapeController because it's in a QObject hierarchy.
delete nserver;
}
KisDocument *q = 0;
KoDocumentInfo *docInfo = 0;
KoUnit unit;
KisImportExportManager *importExportManager = 0; // The filter-manager to use when loading/saving [for the options]
QByteArray mimeType; // The actual mimetype of the document
QByteArray outputMimeType; // The mimetype to use when saving
QTimer *autoSaveTimer;
QString lastErrorMessage; // see openFile()
QString lastWarningMessage;
int autoSaveDelay = 300; // in seconds, 0 to disable.
bool modifiedAfterAutosave = false;
bool isAutosaving = false;
bool disregardAutosaveFailure = false;
int autoSaveFailureCount = 0;
KUndo2Stack *undoStack = 0;
KisGuidesConfig guidesConfig;
KisMirrorAxisConfig mirrorAxisConfig;
bool m_bAutoDetectedMime = false; // whether the mimetype in the arguments was detected by the part itself
QUrl m_url; // local url - the one displayed to the user.
QString m_file; // Local file - the only one the part implementation should deal with.
QMutex savingMutex;
bool modified = false;
bool readwrite = false;
QDateTime firstMod;
QDateTime lastMod;
KisNameServer *nserver;
KisImageSP image;
KisImageSP savingImage;
KisNodeWSP preActivatedNode;
KisShapeController* shapeController = 0;
KoShapeController* koShapeController = 0;
KisIdleWatcher imageIdleWatcher;
QScopedPointer<KisSignalAutoConnection> imageIdleConnection;
QList<KisPaintingAssistantSP> assistants;
QColor globalAssistantsColor;
KisSharedPtr<KisReferenceImagesLayer> referenceImagesLayer;
KisGridConfig gridConfig;
StdLockableWrapper<QMutex> savingLock;
bool modifiedWhileSaving = false;
QScopedPointer<KisDocument> backgroundSaveDocument;
QPointer<KoUpdater> savingUpdater;
QFuture<KisImportExportErrorCode> childSavingFuture;
KritaUtils::ExportFileJob backgroundSaveJob;
bool isRecovered = false;
bool batchMode { false };
QString documentStorageID {QUuid::createUuid().toString()};
KisResourceStorageSP documentResourceStorage;
void syncDecorationsWrapperLayerState();
void setImageAndInitIdleWatcher(KisImageSP _image) {
image = _image;
imageIdleWatcher.setTrackedImage(image);
}
void copyFrom(const Private &rhs, KisDocument *q);
void copyFromImpl(const Private &rhs, KisDocument *q, KisDocument::CopyPolicy policy);
/// clones the palette list oldList
/// the ownership of the returned KoColorSet * belongs to the caller
class StrippedSafeSavingLocker;
};
void KisDocument::Private::syncDecorationsWrapperLayerState()
{
if (!this->image) return;
KisImageSP image = this->image;
KisDecorationsWrapperLayerSP decorationsLayer =
KisLayerUtils::findNodeByType<KisDecorationsWrapperLayer>(image->root());
const bool needsDecorationsWrapper =
gridConfig.showGrid() || (guidesConfig.showGuides() && guidesConfig.hasGuides()) || !assistants.isEmpty();
struct SyncDecorationsWrapperStroke : public KisSimpleStrokeStrategy {
SyncDecorationsWrapperStroke(KisDocument *document, bool needsDecorationsWrapper)
: KisSimpleStrokeStrategy(QLatin1String("sync-decorations-wrapper"),
kundo2_noi18n("start-isolated-mode")),
m_document(document),
m_needsDecorationsWrapper(needsDecorationsWrapper)
{
this->enableJob(JOB_INIT, true, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE);
setClearsRedoOnStart(false);
}
void initStrokeCallback() override {
KisDecorationsWrapperLayerSP decorationsLayer =
KisLayerUtils::findNodeByType<KisDecorationsWrapperLayer>(m_document->image()->root());
if (m_needsDecorationsWrapper && !decorationsLayer) {
m_document->image()->addNode(new KisDecorationsWrapperLayer(m_document));
} else if (!m_needsDecorationsWrapper && decorationsLayer) {
m_document->image()->removeNode(decorationsLayer);
}
}
private:
KisDocument *m_document = 0;
bool m_needsDecorationsWrapper = false;
};
KisStrokeId id = image->startStroke(new SyncDecorationsWrapperStroke(q, needsDecorationsWrapper));
image->endStroke(id);
}
void KisDocument::Private::copyFrom(const Private &rhs, KisDocument *q)
{
copyFromImpl(rhs, q, KisDocument::REPLACE);
}
void KisDocument::Private::copyFromImpl(const Private &rhs, KisDocument *q, KisDocument::CopyPolicy policy)
{
if (policy == REPLACE) {
delete docInfo;
}
docInfo = (new KoDocumentInfo(*rhs.docInfo, q));
unit = rhs.unit;
mimeType = rhs.mimeType;
outputMimeType = rhs.outputMimeType;
if (policy == REPLACE) {
q->setGuidesConfig(rhs.guidesConfig);
q->setMirrorAxisConfig(rhs.mirrorAxisConfig);
q->setModified(rhs.modified);
q->setAssistants(KisPaintingAssistant::cloneAssistantList(rhs.assistants));
q->setGridConfig(rhs.gridConfig);
} else {
// in CONSTRUCT mode, we cannot use the functions of KisDocument
// because KisDocument does not yet have a pointer to us.
guidesConfig = rhs.guidesConfig;
mirrorAxisConfig = rhs.mirrorAxisConfig;
modified = rhs.modified;
assistants = KisPaintingAssistant::cloneAssistantList(rhs.assistants);
gridConfig = rhs.gridConfig;
}
m_bAutoDetectedMime = rhs.m_bAutoDetectedMime;
m_url = rhs.m_url;
m_file = rhs.m_file;
readwrite = rhs.readwrite;
firstMod = rhs.firstMod;
lastMod = rhs.lastMod;
// XXX: the display properties will be shared between different snapshots
globalAssistantsColor = rhs.globalAssistantsColor;
batchMode = rhs.batchMode;
// CHECK THIS! This is what happened to the palette list -- but is it correct here as well? Ask Dmitry!!!
// if (policy == REPLACE) {
// QList<KoColorSetSP> newPaletteList = clonePaletteList(rhs.paletteList);
// q->setPaletteList(newPaletteList, /* emitSignal = */ true);
// // we still do not own palettes if we did not
// } else {
// paletteList = rhs.paletteList;
// }
if (rhs.documentResourceStorage) {
if (policy == REPLACE) {
// Clone the resources, but don't add them to the database, only the editable
// version of the document should have those resources in the database.
documentResourceStorage = rhs.documentResourceStorage->clone();
}
else {
documentResourceStorage = rhs.documentResourceStorage;
}
}
}
class KisDocument::Private::StrippedSafeSavingLocker {
public:
StrippedSafeSavingLocker(QMutex *savingMutex, KisImageSP image)
: m_locked(false)
, m_image(image)
, m_savingLock(savingMutex)
, m_imageLock(image, true)
{
/**
* Initial try to lock both objects. Locking the image guards
* us from any image composition threads running in the
* background, while savingMutex guards us from entering the
* saving code twice by autosave and main threads.
*
* Since we are trying to lock multiple objects, so we should
* do it in a safe manner.
*/
m_locked = std::try_lock(m_imageLock, m_savingLock) < 0;
if (!m_locked) {
m_image->requestStrokeEnd();
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
// one more try...
m_locked = std::try_lock(m_imageLock, m_savingLock) < 0;
}
}
~StrippedSafeSavingLocker() {
if (m_locked) {
m_imageLock.unlock();
m_savingLock.unlock();
}
}
bool successfullyLocked() const {
return m_locked;
}
private:
bool m_locked;
KisImageSP m_image;
StdLockableWrapper<QMutex> m_savingLock;
KisImageBarrierLockAdapter m_imageLock;
};
KisDocument::KisDocument(bool addStorage)
: d(new Private(this))
{
connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged()));
connect(d->undoStack, SIGNAL(cleanChanged(bool)), this, SLOT(slotUndoStackCleanChanged(bool)));
connect(d->autoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave()));
setObjectName(newObjectName());
if (addStorage) {
d->documentResourceStorage.reset(new KisResourceStorage(d->documentStorageID));
KisResourceLocator::instance()->addStorage(d->documentStorageID, d->documentResourceStorage);
}
// preload the krita resources
KisResourceServerProvider::instance();
d->shapeController = new KisShapeController(this, d->nserver);
d->koShapeController = new KoShapeController(0, d->shapeController);
d->shapeController->resourceManager()->setGlobalShapeController(d->koShapeController);
slotConfigChanged();
}
KisDocument::KisDocument(const KisDocument &rhs)
: QObject(),
d(new Private(*rhs.d, this))
{
copyFromDocumentImpl(rhs, CONSTRUCT);
}
KisDocument::~KisDocument()
{
// wait until all the pending operations are in progress
waitForSavingToComplete();
/**
* Push a timebomb, which will try to release the memory after
* the document has been deleted
*/
KisPaintDevice::createMemoryReleaseObject()->deleteLater();
d->autoSaveTimer->disconnect(this);
d->autoSaveTimer->stop();
delete d->importExportManager;
// Despite being QObject they needs to be deleted before the image
delete d->shapeController;
delete d->koShapeController;
if (d->image) {
d->image->notifyAboutToBeDeleted();
/**
* WARNING: We should wait for all the internal image jobs to
* finish before entering KisImage's destructor. The problem is,
* while execution of KisImage::~KisImage, all the weak shared
* pointers pointing to the image enter an inconsistent
* state(!). The shared counter is already zero and destruction
* has started, but the weak reference doesn't know about it,
* because KisShared::~KisShared hasn't been executed yet. So all
* the threads running in background and having weak pointers will
* enter the KisImage's destructor as well.
*/
d->image->requestStrokeCancellation();
d->image->waitForDone();
// clear undo commands that can still point to the image
d->undoStack->clear();
d->image->waitForDone();
KisImageWSP sanityCheckPointer = d->image;
Q_UNUSED(sanityCheckPointer);
// The following line trigger the deletion of the image
d->image.clear();
// check if the image has actually been deleted
KIS_SAFE_ASSERT_RECOVER_NOOP(!sanityCheckPointer.isValid());
}
if (KisResourceLocator::instance()->hasStorage(d->documentStorageID)) {
KisResourceLocator::instance()->removeStorage(d->documentStorageID);
}
delete d;
}
QString KisDocument::uniqueID() const
{
return d->documentStorageID;
}
-bool KisDocument::reload()
-{
- // XXX: reimplement!
- return false;
-}
-
KisDocument *KisDocument::clone()
{
return new KisDocument(*this);
}
bool KisDocument::exportDocumentImpl(const KritaUtils::ExportFileJob &job, KisPropertiesConfigurationSP exportConfiguration)
{
QFileInfo filePathInfo(job.filePath);
if (filePathInfo.exists() && !filePathInfo.isWritable()) {
slotCompleteSavingDocument(job, ImportExportCodes::NoAccessToWrite,
i18n("%1 cannot be written to. Please save under a different name.", job.filePath));
//return ImportExportCodes::NoAccessToWrite;
return false;
}
KisConfig cfg(true);
if (cfg.backupFile() && filePathInfo.exists()) {
QString backupDir;
switch(cfg.readEntry<int>("backupfilelocation", 0)) {
case 1:
backupDir = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
break;
case 2:
backupDir = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
break;
default:
// Do nothing: the empty string is user file location
break;
}
int numOfBackupsKept = cfg.readEntry<int>("numberofbackupfiles", 1);
QString suffix = cfg.readEntry<QString>("backupfilesuffix", "~");
if (numOfBackupsKept == 1) {
if (!KBackup::simpleBackupFile(job.filePath, backupDir, suffix)) {
qWarning() << "Failed to create simple backup file!" << job.filePath << backupDir << suffix;
KisUsageLogger::log(QString("Failed to create a simple backup for %1 in %2.").arg(job.filePath).arg(backupDir.isEmpty() ? "the same location as the file" : backupDir));
return false;
}
else {
KisUsageLogger::log(QString("Create a simple backup for %1 in %2.").arg(job.filePath).arg(backupDir.isEmpty() ? "the same location as the file" : backupDir));
}
}
else if (numOfBackupsKept > 1) {
if (!KBackup::numberedBackupFile(job.filePath, backupDir, suffix, numOfBackupsKept)) {
qWarning() << "Failed to create numbered backup file!" << job.filePath << backupDir << suffix;
KisUsageLogger::log(QString("Failed to create a numbered backup for %2.").arg(job.filePath).arg(backupDir.isEmpty() ? "the same location as the file" : backupDir));
return false;
}
else {
KisUsageLogger::log(QString("Create a simple backup for %1 in %2.").arg(job.filePath).arg(backupDir.isEmpty() ? "the same location as the file" : backupDir));
}
}
}
//KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!job.mimeType.isEmpty(), false);
if (job.mimeType.isEmpty()) {
KisImportExportErrorCode error = ImportExportCodes::FileFormatIncorrect;
slotCompleteSavingDocument(job, error, error.errorMessage());
return false;
}
const QString actionName =
job.flags & KritaUtils::SaveIsExporting ?
i18n("Exporting Document...") :
i18n("Saving Document...");
bool started =
initiateSavingInBackground(actionName,
this, SLOT(slotCompleteSavingDocument(KritaUtils::ExportFileJob, KisImportExportErrorCode ,QString)),
job, exportConfiguration);
if (!started) {
emit canceled(QString());
}
return started;
}
bool KisDocument::exportDocument(const QUrl &url, const QByteArray &mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration)
{
using namespace KritaUtils;
SaveFlags flags = SaveIsExporting;
if (showWarnings) {
flags |= SaveShowWarnings;
}
KisUsageLogger::log(QString("Exporting Document: %1 as %2. %3 * %4 pixels, %5 layers, %6 frames, %7 framerate. Export configuration: %8")
.arg(url.toLocalFile())
.arg(QString::fromLatin1(mimeType))
.arg(d->image->width())
.arg(d->image->height())
.arg(d->image->nlayers())
.arg(d->image->animationInterface()->totalLength())
.arg(d->image->animationInterface()->framerate())
.arg(exportConfiguration ? exportConfiguration->toXML() : "No configuration"));
return exportDocumentImpl(KritaUtils::ExportFileJob(url.toLocalFile(),
mimeType,
flags),
exportConfiguration);
}
bool KisDocument::saveAs(const QUrl &_url, const QByteArray &mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration)
{
using namespace KritaUtils;
KisUsageLogger::log(QString("Saving Document %9 as %1 (mime: %2). %3 * %4 pixels, %5 layers. %6 frames, %7 framerate. Export configuration: %8")
.arg(_url.toLocalFile())
.arg(QString::fromLatin1(mimeType))
.arg(d->image->width())
.arg(d->image->height())
.arg(d->image->nlayers())
.arg(d->image->animationInterface()->totalLength())
.arg(d->image->animationInterface()->framerate())
.arg(exportConfiguration ? exportConfiguration->toXML() : "No configuration")
.arg(url().toLocalFile()));
return exportDocumentImpl(ExportFileJob(_url.toLocalFile(),
mimeType,
showWarnings ? SaveShowWarnings : SaveNone),
exportConfiguration);
}
bool KisDocument::save(bool showWarnings, KisPropertiesConfigurationSP exportConfiguration)
{
return saveAs(url(), mimeType(), showWarnings, exportConfiguration);
}
QByteArray KisDocument::serializeToNativeByteArray()
{
QByteArray byteArray;
QBuffer buffer(&byteArray);
QScopedPointer<KisImportExportFilter> filter(KisImportExportManager::filterForMimeType(nativeFormatMimeType(), KisImportExportManager::Export));
filter->setBatchMode(true);
filter->setMimeType(nativeFormatMimeType());
Private::StrippedSafeSavingLocker locker(&d->savingMutex, d->image);
if (!locker.successfullyLocked()) {
return byteArray;
}
d->savingImage = d->image;
if (!filter->convert(this, &buffer).isOk()) {
qWarning() << "serializeToByteArray():: Could not export to our native format";
}
return byteArray;
}
void KisDocument::slotCompleteSavingDocument(const KritaUtils::ExportFileJob &job, KisImportExportErrorCode status, const QString &errorMessage)
{
if (status.isCancelled())
return;
const QString fileName = QFileInfo(job.filePath).fileName();
if (!status.isOk()) {
emit statusBarMessage(i18nc("%1 --- failing file name, %2 --- error message",
"Error during saving %1: %2",
fileName,
exportErrorToUserMessage(status, errorMessage)), errorMessageTimeout);
if (!fileBatchMode()) {
const QString filePath = job.filePath;
QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not save %1\nReason: %2", filePath, exportErrorToUserMessage(status, errorMessage)));
}
} else {
if (!(job.flags & KritaUtils::SaveIsExporting)) {
const QString existingAutoSaveBaseName = localFilePath();
const bool wasRecovered = isRecovered();
setUrl(QUrl::fromLocalFile(job.filePath));
setLocalFilePath(job.filePath);
setMimeType(job.mimeType);
updateEditingTime(true);
if (!d->modifiedWhileSaving) {
/**
* If undo stack is already clean/empty, it doesn't emit any
* signals, so we might forget update document modified state
* (which was set, e.g. while recovering an autosave file)
*/
if (d->undoStack->isClean()) {
setModified(false);
} else {
d->undoStack->setClean();
}
}
setRecovered(false);
removeAutoSaveFiles(existingAutoSaveBaseName, wasRecovered);
}
emit completed();
emit sigSavingFinished();
emit statusBarMessage(i18n("Finished saving %1", fileName), successMessageTimeout);
}
}
QByteArray KisDocument::mimeType() const
{
return d->mimeType;
}
void KisDocument::setMimeType(const QByteArray & mimeType)
{
d->mimeType = mimeType;
}
bool KisDocument::fileBatchMode() const
{
return d->batchMode;
}
void KisDocument::setFileBatchMode(const bool batchMode)
{
d->batchMode = batchMode;
}
KisDocument* KisDocument::lockAndCloneForSaving()
{
// force update of all the asynchronous nodes before cloning
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
KisLayerUtils::forceAllDelayedNodesUpdate(d->image->root());
KisMainWindow *window = KisPart::instance()->currentMainwindow();
if (window) {
if (window->viewManager()) {
if (!window->viewManager()->blockUntilOperationsFinished(d->image)) {
return 0;
}
}
}
Private::StrippedSafeSavingLocker locker(&d->savingMutex, d->image);
if (!locker.successfullyLocked()) {
return 0;
}
return new KisDocument(*this);
}
KisDocument *KisDocument::lockAndCreateSnapshot()
{
KisDocument *doc = lockAndCloneForSaving();
if (doc) {
// clone the local resource storage and its contents -- that is, the old palette list
if (doc->d->documentResourceStorage) {
doc->d->documentResourceStorage = doc->d->documentResourceStorage->clone();
}
}
return doc;
}
void KisDocument::copyFromDocument(const KisDocument &rhs)
{
copyFromDocumentImpl(rhs, REPLACE);
}
void KisDocument::copyFromDocumentImpl(const KisDocument &rhs, CopyPolicy policy)
{
if (policy == REPLACE) {
d->copyFrom(*(rhs.d), this);
d->undoStack->clear();
} else {
// in CONSTRUCT mode, d should be already initialized
connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged()));
connect(d->undoStack, SIGNAL(cleanChanged(bool)), this, SLOT(slotUndoStackCleanChanged(bool)));
connect(d->autoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave()));
d->shapeController = new KisShapeController(this, d->nserver);
d->koShapeController = new KoShapeController(0, d->shapeController);
d->shapeController->resourceManager()->setGlobalShapeController(d->koShapeController);
}
setObjectName(rhs.objectName());
slotConfigChanged();
if (rhs.d->image) {
if (policy == REPLACE) {
d->image->barrierLock(/* readOnly = */ false);
rhs.d->image->barrierLock(/* readOnly = */ true);
d->image->copyFromImage(*(rhs.d->image));
d->image->unlock();
rhs.d->image->unlock();
setCurrentImage(d->image, /* forceInitialUpdate = */ true);
} else {
// clone the image with keeping the GUIDs of the layers intact
// NOTE: we expect the image to be locked!
setCurrentImage(rhs.image()->clone(/* exactCopy = */ true), /* forceInitialUpdate = */ false);
}
}
if (rhs.d->preActivatedNode) {
QQueue<KisNodeSP> linearizedNodes;
KisLayerUtils::recursiveApplyNodes(rhs.d->image->root(),
[&linearizedNodes](KisNodeSP node) {
linearizedNodes.enqueue(node);
});
KisLayerUtils::recursiveApplyNodes(d->image->root(),
[&linearizedNodes, &rhs, this](KisNodeSP node) {
KisNodeSP refNode = linearizedNodes.dequeue();
if (rhs.d->preActivatedNode.data() == refNode.data()) {
d->preActivatedNode = node;
}
});
}
// reinitialize references' signal connection
KisReferenceImagesLayerSP referencesLayer = this->referenceImagesLayer();
setReferenceImagesLayer(referencesLayer, false);
KisDecorationsWrapperLayerSP decorationsLayer =
KisLayerUtils::findNodeByType<KisDecorationsWrapperLayer>(d->image->root());
if (decorationsLayer) {
decorationsLayer->setDocument(this);
}
if (policy == REPLACE) {
setModified(true);
}
}
bool KisDocument::exportDocumentSync(const QUrl &url, const QByteArray &mimeType, KisPropertiesConfigurationSP exportConfiguration)
{
{
/**
* The caller guarantees that no one else uses the document (usually,
* it is a temporary document created specifically for exporting), so
* we don't need to copy or lock the document. Instead we should just
* ensure the barrier lock is synced and then released.
*/
Private::StrippedSafeSavingLocker locker(&d->savingMutex, d->image);
if (!locker.successfullyLocked()) {
return false;
}
}
d->savingImage = d->image;
const QString fileName = url.toLocalFile();
KisImportExportErrorCode status =
d->importExportManager->
exportDocument(fileName, fileName, mimeType, false, exportConfiguration);
d->savingImage = 0;
return status.isOk();
}
bool KisDocument::initiateSavingInBackground(const QString actionName,
const QObject *receiverObject, const char *receiverMethod,
const KritaUtils::ExportFileJob &job,
KisPropertiesConfigurationSP exportConfiguration)
{
return initiateSavingInBackground(actionName, receiverObject, receiverMethod,
job, exportConfiguration, std::unique_ptr<KisDocument>());
}
bool KisDocument::initiateSavingInBackground(const QString actionName,
const QObject *receiverObject, const char *receiverMethod,
const KritaUtils::ExportFileJob &job,
KisPropertiesConfigurationSP exportConfiguration,
std::unique_ptr<KisDocument> &&optionalClonedDocument)
{
KIS_ASSERT_RECOVER_RETURN_VALUE(job.isValid(), false);
QScopedPointer<KisDocument> clonedDocument;
if (!optionalClonedDocument) {
clonedDocument.reset(lockAndCloneForSaving());
} else {
clonedDocument.reset(optionalClonedDocument.release());
}
// we block saving until the current saving is finished!
if (!clonedDocument || !d->savingMutex.tryLock()) {
return false;
}
auto waitForImage = [] (KisImageSP image) {
KisMainWindow *window = KisPart::instance()->currentMainwindow();
if (window) {
if (window->viewManager()) {
window->viewManager()->blockUntilOperationsFinishedForced(image);
}
}
};
{
KisNodeSP newRoot = clonedDocument->image()->root();
KIS_SAFE_ASSERT_RECOVER(!KisLayerUtils::hasDelayedNodeWithUpdates(newRoot)) {
KisLayerUtils::forceAllDelayedNodesUpdate(newRoot);
waitForImage(clonedDocument->image());
}
}
if (clonedDocument->image()->hasOverlaySelectionMask()) {
clonedDocument->image()->setOverlaySelectionMask(0);
waitForImage(clonedDocument->image());
}
KisConfig cfg(true);
if (cfg.trimKra()) {
clonedDocument->image()->cropImage(clonedDocument->image()->bounds());
clonedDocument->image()->purgeUnusedData(false);
waitForImage(clonedDocument->image());
}
KIS_SAFE_ASSERT_RECOVER(clonedDocument->image()->isIdle()) {
waitForImage(clonedDocument->image());
}
KIS_ASSERT_RECOVER_RETURN_VALUE(!d->backgroundSaveDocument, false);
KIS_ASSERT_RECOVER_RETURN_VALUE(!d->backgroundSaveJob.isValid(), false);
d->backgroundSaveDocument.reset(clonedDocument.take());
d->backgroundSaveJob = job;
d->modifiedWhileSaving = false;
if (d->backgroundSaveJob.flags & KritaUtils::SaveInAutosaveMode) {
d->backgroundSaveDocument->d->isAutosaving = true;
}
connect(d->backgroundSaveDocument.data(),
SIGNAL(sigBackgroundSavingFinished(KisImportExportErrorCode, QString)),
this,
SLOT(slotChildCompletedSavingInBackground(KisImportExportErrorCode, QString)));
connect(this, SIGNAL(sigCompleteBackgroundSaving(KritaUtils::ExportFileJob, KisImportExportErrorCode, QString)),
receiverObject, receiverMethod, Qt::UniqueConnection);
bool started =
d->backgroundSaveDocument->startExportInBackground(actionName,
job.filePath,
job.filePath,
job.mimeType,
job.flags & KritaUtils::SaveShowWarnings,
exportConfiguration);
if (!started) {
// the state should have been deinitialized in slotChildCompletedSavingInBackground()
KIS_SAFE_ASSERT_RECOVER (!d->backgroundSaveDocument && !d->backgroundSaveJob.isValid()) {
d->backgroundSaveDocument.take()->deleteLater();
d->savingMutex.unlock();
d->backgroundSaveJob = KritaUtils::ExportFileJob();
}
}
return started;
}
void KisDocument::slotChildCompletedSavingInBackground(KisImportExportErrorCode status, const QString &errorMessage)
{
KIS_ASSERT_RECOVER_RETURN(isSaving());
KIS_ASSERT_RECOVER(d->backgroundSaveDocument) {
d->savingMutex.unlock();
return;
}
if (d->backgroundSaveJob.flags & KritaUtils::SaveInAutosaveMode) {
d->backgroundSaveDocument->d->isAutosaving = false;
}
d->backgroundSaveDocument.take()->deleteLater();
KIS_ASSERT_RECOVER(d->backgroundSaveJob.isValid()) {
d->savingMutex.unlock();
return;
}
const KritaUtils::ExportFileJob job = d->backgroundSaveJob;
d->backgroundSaveJob = KritaUtils::ExportFileJob();
// unlock at the very end
d->savingMutex.unlock();
QFileInfo fi(job.filePath);
KisUsageLogger::log(QString("Completed saving %1 (mime: %2). Result: %3. Size: %4. MD5 Hash: %5")
.arg(job.filePath)
.arg(QString::fromLatin1(job.mimeType))
.arg(!status.isOk() ? exportErrorToUserMessage(status, errorMessage) : "OK")
.arg(fi.size())
.arg(fi.size() > 10000000 ? "FILE_BIGGER_10MB" : QString::fromLatin1(KoMD5Generator().generateHash(job.filePath).toHex())));
emit sigCompleteBackgroundSaving(job, status, errorMessage);
}
void KisDocument::slotAutoSaveImpl(std::unique_ptr<KisDocument> &&optionalClonedDocument)
{
if (!d->modified || !d->modifiedAfterAutosave) return;
const QString autoSaveFileName = generateAutoSaveFileName(localFilePath());
emit statusBarMessage(i18n("Autosaving... %1", autoSaveFileName), successMessageTimeout);
KisUsageLogger::log(QString("Autosaving: %1").arg(autoSaveFileName));
const bool hadClonedDocument = bool(optionalClonedDocument);
bool started = false;
if (d->image->isIdle() || hadClonedDocument) {
started = initiateSavingInBackground(i18n("Autosaving..."),
this, SLOT(slotCompleteAutoSaving(KritaUtils::ExportFileJob, KisImportExportErrorCode, QString)),
KritaUtils::ExportFileJob(autoSaveFileName, nativeFormatMimeType(), KritaUtils::SaveIsExporting | KritaUtils::SaveInAutosaveMode),
0,
std::move(optionalClonedDocument));
} else {
emit statusBarMessage(i18n("Autosaving postponed: document is busy..."), errorMessageTimeout);
}
if (!started && !hadClonedDocument && d->autoSaveFailureCount >= 3) {
KisCloneDocumentStroke *stroke = new KisCloneDocumentStroke(this);
connect(stroke, SIGNAL(sigDocumentCloned(KisDocument*)),
this, SLOT(slotInitiateAsyncAutosaving(KisDocument*)),
Qt::BlockingQueuedConnection);
KisStrokeId strokeId = d->image->startStroke(stroke);
d->image->endStroke(strokeId);
setInfiniteAutoSaveInterval();
} else if (!started) {
setEmergencyAutoSaveInterval();
} else {
d->modifiedAfterAutosave = false;
}
}
void KisDocument::slotAutoSave()
{
slotAutoSaveImpl(std::unique_ptr<KisDocument>());
}
void KisDocument::slotInitiateAsyncAutosaving(KisDocument *clonedDocument)
{
slotAutoSaveImpl(std::unique_ptr<KisDocument>(clonedDocument));
}
void KisDocument::slotPerformIdleRoutines()
{
d->image->explicitRegenerateLevelOfDetail();
/// TODO: automatical purging is disabled for now: it modifies
/// data managers without creating a transaction, which breaks
/// undo.
// d->image->purgeUnusedData(true);
}
void KisDocument::slotCompleteAutoSaving(const KritaUtils::ExportFileJob &job, KisImportExportErrorCode status, const QString &errorMessage)
{
Q_UNUSED(job);
const QString fileName = QFileInfo(job.filePath).fileName();
if (!status.isOk()) {
setEmergencyAutoSaveInterval();
emit statusBarMessage(i18nc("%1 --- failing file name, %2 --- error message",
"Error during autosaving %1: %2",
fileName,
exportErrorToUserMessage(status, errorMessage)), errorMessageTimeout);
} else {
KisConfig cfg(true);
d->autoSaveDelay = cfg.autoSaveInterval();
if (!d->modifiedWhileSaving) {
d->autoSaveTimer->stop(); // until the next change
d->autoSaveFailureCount = 0;
} else {
setNormalAutoSaveInterval();
}
emit statusBarMessage(i18n("Finished autosaving %1", fileName), successMessageTimeout);
}
}
bool KisDocument::startExportInBackground(const QString &actionName,
const QString &location,
const QString &realLocation,
const QByteArray &mimeType,
bool showWarnings,
KisPropertiesConfigurationSP exportConfiguration)
{
d->savingImage = d->image;
KisMainWindow *window = KisPart::instance()->currentMainwindow();
if (window) {
if (window->viewManager()) {
d->savingUpdater = window->viewManager()->createThreadedUpdater(actionName);
d->importExportManager->setUpdater(d->savingUpdater);
}
}
KisImportExportErrorCode initializationStatus(ImportExportCodes::OK);
d->childSavingFuture =
d->importExportManager->exportDocumentAsyc(location,
realLocation,
mimeType,
initializationStatus,
showWarnings,
exportConfiguration);
if (!initializationStatus.isOk()) {
if (d->savingUpdater) {
d->savingUpdater->cancel();
}
d->savingImage.clear();
emit sigBackgroundSavingFinished(initializationStatus, initializationStatus.errorMessage());
return false;
}
typedef QFutureWatcher<KisImportExportErrorCode> StatusWatcher;
StatusWatcher *watcher = new StatusWatcher();
watcher->setFuture(d->childSavingFuture);
connect(watcher, SIGNAL(finished()), SLOT(finishExportInBackground()));
connect(watcher, SIGNAL(finished()), watcher, SLOT(deleteLater()));
return true;
}
void KisDocument::finishExportInBackground()
{
KIS_SAFE_ASSERT_RECOVER(d->childSavingFuture.isFinished()) {
emit sigBackgroundSavingFinished(ImportExportCodes::InternalError, "");
return;
}
KisImportExportErrorCode status =
d->childSavingFuture.result();
const QString errorMessage = status.errorMessage();
d->savingImage.clear();
d->childSavingFuture = QFuture<KisImportExportErrorCode>();
d->lastErrorMessage.clear();
if (d->savingUpdater) {
d->savingUpdater->setProgress(100);
}
emit sigBackgroundSavingFinished(status, errorMessage);
}
void KisDocument::setReadWrite(bool readwrite)
{
d->readwrite = readwrite;
setNormalAutoSaveInterval();
Q_FOREACH (KisMainWindow *mainWindow, KisPart::instance()->mainWindows()) {
mainWindow->setReadWrite(readwrite);
}
}
void KisDocument::setAutoSaveDelay(int delay)
{
if (isReadWrite() && delay > 0) {
d->autoSaveTimer->start(delay * 1000);
} else {
d->autoSaveTimer->stop();
}
}
void KisDocument::setNormalAutoSaveInterval()
{
setAutoSaveDelay(d->autoSaveDelay);
d->autoSaveFailureCount = 0;
}
void KisDocument::setEmergencyAutoSaveInterval()
{
const int emergencyAutoSaveInterval = 10; /* sec */
setAutoSaveDelay(emergencyAutoSaveInterval);
d->autoSaveFailureCount++;
}
void KisDocument::setInfiniteAutoSaveInterval()
{
setAutoSaveDelay(-1);
}
KoDocumentInfo *KisDocument::documentInfo() const
{
return d->docInfo;
}
bool KisDocument::isModified() const
{
return d->modified;
}
QPixmap KisDocument::generatePreview(const QSize& size)
{
KisImageSP image = d->image;
if (d->savingImage) image = d->savingImage;
if (image) {
QRect bounds = image->bounds();
QSize newSize = bounds.size();
newSize.scale(size, Qt::KeepAspectRatio);
QPixmap px = QPixmap::fromImage(image->convertToQImage(newSize, 0));
if (px.size() == QSize(0,0)) {
px = QPixmap(newSize);
QPainter gc(&px);
QBrush checkBrush = QBrush(KisCanvasWidgetBase::createCheckersImage(newSize.width() / 5));
gc.fillRect(px.rect(), checkBrush);
gc.end();
}
return px;
}
return QPixmap(size);
}
QString KisDocument::generateAutoSaveFileName(const QString & path) const
{
QString retval;
// Using the extension allows to avoid relying on the mime magic when opening
const QString extension (".kra");
QString prefix = KisConfig(true).readEntry<bool>("autosavefileshidden") ? QString(".") : QString();
QRegularExpression autosavePattern1("^\\..+-autosave.kra$");
QRegularExpression autosavePattern2("^.+-autosave.kra$");
QFileInfo fi(path);
QString dir = fi.absolutePath();
QString filename = fi.fileName();
if (path.isEmpty() || autosavePattern1.match(filename).hasMatch() || autosavePattern2.match(filename).hasMatch() || !fi.isWritable()) {
// Never saved?
#ifdef Q_OS_WIN
// On Windows, use the temp location (https://bugs.kde.org/show_bug.cgi?id=314921)
retval = QString("%1%2%7%3-%4-%5-autosave%6").arg(QDir::tempPath()).arg('/').arg("krita").arg(qApp->applicationPid()).arg(objectName()).arg(extension).arg(prefix);
#else
// On Linux, use a temp file in $HOME then. Mark it with the pid so two instances don't overwrite each other's autosave file
retval = QString("%1%2%7%3-%4-%5-autosave%6").arg(QDir::homePath()).arg('/').arg("krita").arg(qApp->applicationPid()).arg(objectName()).arg(extension).arg(prefix);
#endif
} else {
retval = QString("%1%2%5%3-autosave%4").arg(dir).arg('/').arg(filename).arg(extension).arg(prefix);
}
//qDebug() << "generateAutoSaveFileName() for path" << path << ":" << retval;
return retval;
}
bool KisDocument::importDocument(const QUrl &_url)
{
bool ret;
dbgUI << "url=" << _url.url();
// open...
ret = openUrl(_url);
// reset url & m_file (kindly? set by KisParts::openUrl()) to simulate a
// File --> Import
if (ret) {
dbgUI << "success, resetting url";
resetURL();
setTitleModified();
}
return ret;
}
bool KisDocument::openUrl(const QUrl &_url, OpenFlags flags)
{
if (!_url.isLocalFile()) {
return false;
}
dbgUI << "url=" << _url.url();
d->lastErrorMessage.clear();
// Reimplemented, to add a check for autosave files and to improve error reporting
if (!_url.isValid()) {
d->lastErrorMessage = i18n("Malformed URL\n%1", _url.url()); // ## used anywhere ?
return false;
}
QUrl url(_url);
QString original = "";
bool autosaveOpened = false;
if (url.isLocalFile() && !fileBatchMode()) {
QString file = url.toLocalFile();
QString asf = generateAutoSaveFileName(file);
if (QFile::exists(asf)) {
KisApplication *kisApp = static_cast<KisApplication*>(qApp);
kisApp->hideSplashScreen();
//qDebug() <<"asf=" << asf;
// ## TODO compare timestamps ?
KisRecoverNamedAutosaveDialog dlg(0, file, asf);
dlg.exec();
int res = dlg.result();
switch (res) {
case KisRecoverNamedAutosaveDialog::OpenAutosave :
original = file;
url.setPath(asf);
autosaveOpened = true;
break;
case KisRecoverNamedAutosaveDialog::OpenMainFile :
KisUsageLogger::log(QString("Removing autosave file: %1").arg(asf));
QFile::remove(asf);
break;
default: // Cancel
return false;
}
}
}
bool ret = openUrlInternal(url);
if (autosaveOpened || flags & RecoveryFile) {
setReadWrite(true); // enable save button
setModified(true);
setRecovered(true);
setUrl(QUrl::fromLocalFile(original)); // since it was an autosave, it will be a local file
setLocalFilePath(original);
}
else {
if (ret) {
if (!(flags & DontAddToRecent)) {
KisPart::instance()->addRecentURLToAllMainWindows(_url);
}
// Detect readonly local-files; remote files are assumed to be writable
QFileInfo fi(url.toLocalFile());
setReadWrite(fi.isWritable());
}
setRecovered(false);
}
return ret;
}
class DlgLoadMessages : public KoDialog {
public:
DlgLoadMessages(const QString &title, const QString &message, const QStringList &warnings) {
setWindowTitle(title);
setWindowIcon(KisIconUtils::loadIcon("warning"));
QWidget *page = new QWidget(this);
QVBoxLayout *layout = new QVBoxLayout(page);
QHBoxLayout *hlayout = new QHBoxLayout();
QLabel *labelWarning= new QLabel();
labelWarning->setPixmap(KisIconUtils::loadIcon("warning").pixmap(32, 32));
hlayout->addWidget(labelWarning);
hlayout->addWidget(new QLabel(message));
layout->addLayout(hlayout);
QTextBrowser *browser = new QTextBrowser();
QString warning = "<html><body><p><b>";
if (warnings.size() == 1) {
warning += "</b> Reason:</p>";
}
else {
warning += "</b> Reasons:</p>";
}
warning += "<p/><ul>";
Q_FOREACH(const QString &w, warnings) {
warning += "\n<li>" + w + "</li>";
}
warning += "</ul>";
browser->setHtml(warning);
browser->setMinimumHeight(200);
browser->setMinimumWidth(400);
layout->addWidget(browser);
setMainWidget(page);
setButtons(KoDialog::Ok);
resize(minimumSize());
}
};
bool KisDocument::openFile()
{
//dbgUI <<"for" << localFilePath();
if (!QFile::exists(localFilePath()) && !fileBatchMode()) {
QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("File %1 does not exist.", localFilePath()));
return false;
}
QString filename = localFilePath();
QString typeName = mimeType();
if (typeName.isEmpty()) {
typeName = KisMimeDatabase::mimeTypeForFile(filename);
}
//qDebug() << "mimetypes 4:" << typeName;
// Allow to open backup files, don't keep the mimetype application/x-trash.
if (typeName == "application/x-trash") {
QString path = filename;
while (path.length() > 0) {
path.chop(1);
typeName = KisMimeDatabase::mimeTypeForFile(path);
//qDebug() << "\t" << path << typeName;
if (!typeName.isEmpty()) {
break;
}
}
//qDebug() << "chopped" << filename << "to" << path << "Was trash, is" << typeName;
}
dbgUI << localFilePath() << "type:" << typeName;
KisMainWindow *window = KisPart::instance()->currentMainwindow();
KoUpdaterPtr updater;
if (window && window->viewManager()) {
updater = window->viewManager()->createUnthreadedUpdater(i18n("Opening document"));
d->importExportManager->setUpdater(updater);
}
KisImportExportErrorCode status = d->importExportManager->importDocument(localFilePath(), typeName);
if (!status.isOk()) {
if (window && window->viewManager()) {
updater->cancel();
}
QString msg = status.errorMessage();
if (!msg.isEmpty() && !fileBatchMode()) {
DlgLoadMessages dlg(i18nc("@title:window", "Krita"),
i18n("Could not open %2.\nReason: %1.", msg, prettyPathOrUrl()),
errorMessage().split("\n") + warningMessage().split("\n"));
dlg.exec();
}
return false;
}
else if (!warningMessage().isEmpty() && !fileBatchMode()) {
DlgLoadMessages dlg(i18nc("@title:window", "Krita"),
i18n("There were problems opening %1.", prettyPathOrUrl()),
warningMessage().split("\n"));
dlg.exec();
setUrl(QUrl());
}
setMimeTypeAfterLoading(typeName);
d->syncDecorationsWrapperLayerState();
emit sigLoadingFinished();
undoStack()->clear();
return true;
}
void KisDocument::autoSaveOnPause()
{
if (!d->modified || !d->modifiedAfterAutosave)
return;
const QString autoSaveFileName = generateAutoSaveFileName(localFilePath());
QUrl url("file:/" + autoSaveFileName);
bool started = exportDocumentSync(url, nativeFormatMimeType());
if (started)
{
d->modifiedAfterAutosave = false;
dbgAndroid << "autoSaveOnPause successful";
}
else
{
qWarning() << "Could not auto-save when paused";
}
}
// shared between openFile and koMainWindow's "create new empty document" code
void KisDocument::setMimeTypeAfterLoading(const QString& mimeType)
{
d->mimeType = mimeType.toLatin1();
d->outputMimeType = d->mimeType;
}
bool KisDocument::loadNativeFormat(const QString & file_)
{
return openUrl(QUrl::fromLocalFile(file_));
}
void KisDocument::setModified(bool mod)
{
if (mod) {
updateEditingTime(false);
}
if (d->isAutosaving) // ignore setModified calls due to autosaving
return;
if ( !d->readwrite && d->modified ) {
errKrita << "Can't set a read-only document to 'modified' !" << endl;
return;
}
//dbgUI<<" url:" << url.path();
//dbgUI<<" mod="<<mod<<" MParts mod="<<KisParts::ReadWritePart::isModified()<<" isModified="<<isModified();
if (mod && !d->autoSaveTimer->isActive()) {
// First change since last autosave -> start the autosave timer
setNormalAutoSaveInterval();
}
d->modifiedAfterAutosave = mod;
d->modifiedWhileSaving = mod;
if (mod == isModified())
return;
d->modified = mod;
if (mod) {
documentInfo()->updateParameters();
}
// This influences the title
setTitleModified();
emit modified(mod);
}
void KisDocument::setRecovered(bool value)
{
d->isRecovered = value;
}
bool KisDocument::isRecovered() const
{
return d->isRecovered;
}
void KisDocument::updateEditingTime(bool forceStoreElapsed)
{
QDateTime now = QDateTime::currentDateTime();
int firstModDelta = d->firstMod.secsTo(now);
int lastModDelta = d->lastMod.secsTo(now);
if (lastModDelta > 30) {
d->docInfo->setAboutInfo("editing-time", QString::number(d->docInfo->aboutInfo("editing-time").toInt() + d->firstMod.secsTo(d->lastMod)));
d->firstMod = now;
} else if (firstModDelta > 60 || forceStoreElapsed) {
d->docInfo->setAboutInfo("editing-time", QString::number(d->docInfo->aboutInfo("editing-time").toInt() + firstModDelta));
d->firstMod = now;
}
d->lastMod = now;
}
QString KisDocument::prettyPathOrUrl() const
{
QString _url(url().toDisplayString());
#ifdef Q_OS_WIN
if (url().isLocalFile()) {
_url = QDir::toNativeSeparators(_url);
}
#endif
return _url;
}
// Get caption from document info (title(), in about page)
QString KisDocument::caption() const
{
QString c;
const QString _url(url().fileName());
// if URL is empty...it is probably an unsaved file
if (_url.isEmpty()) {
c = " [" + i18n("Not Saved") + "] ";
} else {
c = _url; // Fall back to document URL
}
return c;
}
void KisDocument::setTitleModified()
{
emit titleModified(caption(), isModified());
}
QDomDocument KisDocument::createDomDocument(const QString& tagName, const QString& version) const
{
return createDomDocument("krita", tagName, version);
}
//static
QDomDocument KisDocument::createDomDocument(const QString& appName, const QString& tagName, const QString& version)
{
QDomImplementation impl;
QString url = QString("http://www.calligra.org/DTD/%1-%2.dtd").arg(appName).arg(version);
QDomDocumentType dtype = impl.createDocumentType(tagName,
QString("-//KDE//DTD %1 %2//EN").arg(appName).arg(version),
url);
// The namespace URN doesn't need to include the version number.
QString namespaceURN = QString("http://www.calligra.org/DTD/%1").arg(appName);
QDomDocument doc = impl.createDocument(namespaceURN, tagName, dtype);
doc.insertBefore(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\""), doc.documentElement());
return doc;
}
bool KisDocument::isNativeFormat(const QByteArray& mimetype) const
{
if (mimetype == nativeFormatMimeType())
return true;
return extraNativeMimeTypes().contains(mimetype);
}
void KisDocument::setErrorMessage(const QString& errMsg)
{
d->lastErrorMessage = errMsg;
}
QString KisDocument::errorMessage() const
{
return d->lastErrorMessage;
}
void KisDocument::setWarningMessage(const QString& warningMsg)
{
d->lastWarningMessage = warningMsg;
}
QString KisDocument::warningMessage() const
{
return d->lastWarningMessage;
}
void KisDocument::removeAutoSaveFiles(const QString &autosaveBaseName, bool wasRecovered)
{
// Eliminate any auto-save file
QString asf = generateAutoSaveFileName(autosaveBaseName); // the one in the current dir
if (QFile::exists(asf)) {
KisUsageLogger::log(QString("Removing autosave file: %1").arg(asf));
QFile::remove(asf);
}
asf = generateAutoSaveFileName(QString()); // and the one in $HOME
if (QFile::exists(asf)) {
KisUsageLogger::log(QString("Removing autosave file: %1").arg(asf));
QFile::remove(asf);
}
QList<QRegularExpression> expressions;
expressions << QRegularExpression("^\\..+-autosave.kra$")
<< QRegularExpression("^.+-autosave.kra$");
Q_FOREACH(const QRegularExpression &rex, expressions) {
if (wasRecovered &&
!autosaveBaseName.isEmpty() &&
rex.match(QFileInfo(autosaveBaseName).fileName()).hasMatch() &&
QFile::exists(autosaveBaseName)) {
KisUsageLogger::log(QString("Removing autosave file: %1").arg(autosaveBaseName));
QFile::remove(autosaveBaseName);
}
}
}
KoUnit KisDocument::unit() const
{
return d->unit;
}
void KisDocument::setUnit(const KoUnit &unit)
{
if (d->unit != unit) {
d->unit = unit;
emit unitChanged(unit);
}
}
KUndo2Stack *KisDocument::undoStack()
{
return d->undoStack;
}
KisImportExportManager *KisDocument::importExportManager() const
{
return d->importExportManager;
}
void KisDocument::addCommand(KUndo2Command *command)
{
if (command)
d->undoStack->push(command);
}
void KisDocument::beginMacro(const KUndo2MagicString & text)
{
d->undoStack->beginMacro(text);
}
void KisDocument::endMacro()
{
d->undoStack->endMacro();
}
void KisDocument::slotUndoStackCleanChanged(bool value)
{
setModified(!value);
}
void KisDocument::slotConfigChanged()
{
KisConfig cfg(true);
if (d->undoStack->undoLimit() != cfg.undoStackLimit()) {
if (!d->undoStack->isClean()) {
d->undoStack->clear();
}
d->undoStack->setUndoLimit(cfg.undoStackLimit());
}
d->autoSaveDelay = cfg.autoSaveInterval();
setNormalAutoSaveInterval();
}
void KisDocument::slotImageRootChanged()
{
d->syncDecorationsWrapperLayerState();
}
void KisDocument::clearUndoHistory()
{
d->undoStack->clear();
}
KisGridConfig KisDocument::gridConfig() const
{
return d->gridConfig;
}
void KisDocument::setGridConfig(const KisGridConfig &config)
{
if (d->gridConfig != config) {
d->gridConfig = config;
d->syncDecorationsWrapperLayerState();
emit sigGridConfigChanged(config);
}
}
QList<KoColorSetSP > KisDocument::paletteList()
{
qDebug() << "PALETTELIST storage" << d->documentResourceStorage;
QList<KoColorSetSP> _paletteList;
if (d->documentResourceStorage.isNull()) {
qWarning() << "No documentstorage for palettes";
return _paletteList;
}
QSharedPointer<KisResourceStorage::ResourceIterator> iter = d->documentResourceStorage->resources(ResourceType::Palettes);
while (iter->hasNext()) {
iter->next();
KoResourceSP resource = iter->resource();
if (resource && resource->valid()) {
_paletteList << resource.dynamicCast<KoColorSet>();
}
}
return _paletteList;
}
void KisDocument::setPaletteList(const QList<KoColorSetSP > &paletteList, bool emitSignal)
{
qDebug() << "SET PALETTE LIST" << paletteList.size() << "storage" << d->documentResourceStorage;
QList<KoColorSetSP> oldPaletteList;
if (d->documentResourceStorage) {
QSharedPointer<KisResourceStorage::ResourceIterator> iter = d->documentResourceStorage->resources(ResourceType::Palettes);
while (iter->hasNext()) {
iter->next();
KoResourceSP resource = iter->resource();
if (resource && resource->valid()) {
oldPaletteList << resource.dynamicCast<KoColorSet>();
}
}
if (oldPaletteList != paletteList) {
KisResourceModel *resourceModel = KisResourceModelProvider::resourceModel(ResourceType::Palettes);
Q_FOREACH(KoColorSetSP palette, oldPaletteList) {
resourceModel->removeResource(palette);
}
Q_FOREACH(KoColorSetSP palette, paletteList) {
qDebug()<< "loading palette into document" << palette->filename();
resourceModel->addResource(palette, d->documentStorageID);
}
if (emitSignal) {
emit sigPaletteListChanged(oldPaletteList, paletteList);
}
}
}
}
const KisGuidesConfig& KisDocument::guidesConfig() const
{
return d->guidesConfig;
}
void KisDocument::setGuidesConfig(const KisGuidesConfig &data)
{
if (d->guidesConfig == data) return;
d->guidesConfig = data;
d->syncDecorationsWrapperLayerState();
emit sigGuidesConfigChanged(d->guidesConfig);
}
const KisMirrorAxisConfig& KisDocument::mirrorAxisConfig() const
{
return d->mirrorAxisConfig;
}
void KisDocument::setMirrorAxisConfig(const KisMirrorAxisConfig &config)
{
if (d->mirrorAxisConfig == config) {
return;
}
d->mirrorAxisConfig = config;
setModified(true);
emit sigMirrorAxisConfigChanged();
}
void KisDocument::resetURL() {
setUrl(QUrl());
setLocalFilePath(QString());
}
KoDocumentInfoDlg *KisDocument::createDocumentInfoDialog(QWidget *parent, KoDocumentInfo *docInfo) const
{
return new KoDocumentInfoDlg(parent, docInfo);
}
bool KisDocument::isReadWrite() const
{
return d->readwrite;
}
QUrl KisDocument::url() const
{
return d->m_url;
}
bool KisDocument::closeUrl(bool promptToSave)
{
if (promptToSave) {
if ( isReadWrite() && isModified()) {
Q_FOREACH (KisView *view, KisPart::instance()->views()) {
if (view && view->document() == this) {
if (!view->queryClose()) {
return false;
}
}
}
}
}
// Not modified => ok and delete temp file.
d->mimeType = QByteArray();
// It always succeeds for a read-only part,
// but the return value exists for reimplementations
// (e.g. pressing cancel for a modified read-write part)
return true;
}
void KisDocument::setUrl(const QUrl &url)
{
d->m_url = url;
}
QString KisDocument::localFilePath() const
{
return d->m_file;
}
void KisDocument::setLocalFilePath( const QString &localFilePath )
{
d->m_file = localFilePath;
}
bool KisDocument::openUrlInternal(const QUrl &url)
{
if ( !url.isValid() ) {
return false;
}
if (d->m_bAutoDetectedMime) {
d->mimeType = QByteArray();
d->m_bAutoDetectedMime = false;
}
QByteArray mimetype = d->mimeType;
if ( !closeUrl() ) {
return false;
}
d->mimeType = mimetype;
setUrl(url);
d->m_file.clear();
if (d->m_url.isLocalFile()) {
d->m_file = d->m_url.toLocalFile();
bool ret;
// set the mimetype only if it was not already set (for example, by the host application)
if (d->mimeType.isEmpty()) {
// get the mimetype of the file
// using findByUrl() to avoid another string -> url conversion
QString mime = KisMimeDatabase::mimeTypeForFile(d->m_url.toLocalFile());
d->mimeType = mime.toLocal8Bit();
d->m_bAutoDetectedMime = true;
}
setUrl(d->m_url);
ret = openFile();
if (ret) {
emit completed();
} else {
emit canceled(QString());
}
return ret;
}
return false;
}
bool KisDocument::newImage(const QString& name,
qint32 width, qint32 height,
const KoColorSpace* cs,
const KoColor &bgColor, KisConfig::BackgroundStyle bgStyle,
int numberOfLayers,
const QString &description, const double imageResolution)
{
Q_ASSERT(cs);
KisImageSP image;
if (!cs) return false;
QApplication::setOverrideCursor(Qt::BusyCursor);
image = new KisImage(createUndoStore(), width, height, cs, name);
Q_CHECK_PTR(image);
connect(image, SIGNAL(sigImageModified()), this, SLOT(setImageModified()), Qt::UniqueConnection);
image->setResolution(imageResolution, imageResolution);
image->assignImageProfile(cs->profile());
image->waitForDone();
documentInfo()->setAboutInfo("title", name);
documentInfo()->setAboutInfo("abstract", description);
KisConfig cfg(false);
cfg.defImageWidth(width);
cfg.defImageHeight(height);
cfg.defImageResolution(imageResolution);
cfg.defColorModel(image->colorSpace()->colorModelId().id());
cfg.setDefaultColorDepth(image->colorSpace()->colorDepthId().id());
cfg.defColorProfile(image->colorSpace()->profile()->name());
bool autopin = cfg.autoPinLayersToTimeline();
KisLayerSP bgLayer;
if (bgStyle == KisConfig::RASTER_LAYER || bgStyle == KisConfig::FILL_LAYER) {
KoColor strippedAlpha = bgColor;
strippedAlpha.setOpacity(OPACITY_OPAQUE_U8);
if (bgStyle == KisConfig::RASTER_LAYER) {
bgLayer = new KisPaintLayer(image.data(), "Background", OPACITY_OPAQUE_U8, cs);;
bgLayer->paintDevice()->setDefaultPixel(strippedAlpha);
bgLayer->setPinnedToTimeline(autopin);
} else if (bgStyle == KisConfig::FILL_LAYER) {
KisFilterConfigurationSP filter_config = KisGeneratorRegistry::instance()->get("color")->defaultConfiguration(KisGlobalResourcesInterface::instance());
filter_config->setProperty("color", strippedAlpha.toQColor());
filter_config->createLocalResourcesSnapshot();
bgLayer = new KisGeneratorLayer(image.data(), "Background Fill", filter_config, image->globalSelection());
}
bgLayer->setOpacity(bgColor.opacityU8());
if (numberOfLayers > 1) {
//Lock bg layer if others are present.
bgLayer->setUserLocked(true);
}
}
else { // KisConfig::CANVAS_COLOR (needs an unlocked starting layer).
image->setDefaultProjectionColor(bgColor);
bgLayer = new KisPaintLayer(image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8, cs);
}
Q_CHECK_PTR(bgLayer);
image->addNode(bgLayer.data(), image->rootLayer().data());
bgLayer->setDirty(QRect(0, 0, width, height));
setCurrentImage(image);
for(int i = 1; i < numberOfLayers; ++i) {
KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), OPACITY_OPAQUE_U8, cs);
layer->setPinnedToTimeline(autopin);
image->addNode(layer, image->root(), i);
layer->setDirty(QRect(0, 0, width, height));
}
KisUsageLogger::log(QString("Created image \"%1\", %2 * %3 pixels, %4 dpi. Color model: %6 %5 (%7). Layers: %8")
.arg(name)
.arg(width).arg(height)
.arg(imageResolution * 72.0)
.arg(image->colorSpace()->colorModelId().name())
.arg(image->colorSpace()->colorDepthId().name())
.arg(image->colorSpace()->profile()->name())
.arg(numberOfLayers));
QApplication::restoreOverrideCursor();
return true;
}
bool KisDocument::isSaving() const
{
const bool result = d->savingMutex.tryLock();
if (result) {
d->savingMutex.unlock();
}
return !result;
}
void KisDocument::waitForSavingToComplete()
{
if (isSaving()) {
KisAsyncActionFeedback f(i18nc("progress dialog message when the user closes the document that is being saved", "Waiting for saving to complete..."), 0);
f.waitForMutex(&d->savingMutex);
}
}
KoShapeControllerBase *KisDocument::shapeController() const
{
return d->shapeController;
}
KoShapeLayer* KisDocument::shapeForNode(KisNodeSP layer) const
{
return d->shapeController->shapeForNode(layer);
}
QList<KisPaintingAssistantSP> KisDocument::assistants() const
{
return d->assistants;
}
void KisDocument::setAssistants(const QList<KisPaintingAssistantSP> &value)
{
if (d->assistants != value) {
d->assistants = value;
d->syncDecorationsWrapperLayerState();
emit sigAssistantsChanged();
}
}
KisReferenceImagesLayerSP KisDocument::referenceImagesLayer() const
{
if (!d->image) return KisReferenceImagesLayerSP();
KisReferenceImagesLayerSP referencesLayer =
KisLayerUtils::findNodeByType<KisReferenceImagesLayer>(d->image->root());
return referencesLayer;
}
void KisDocument::setReferenceImagesLayer(KisSharedPtr<KisReferenceImagesLayer> layer, bool updateImage)
{
KisReferenceImagesLayerSP currentReferenceLayer = referenceImagesLayer();
if (currentReferenceLayer == layer) {
return;
}
if (currentReferenceLayer) {
currentReferenceLayer->disconnect(this);
}
if (updateImage) {
if (currentReferenceLayer) {
d->image->removeNode(currentReferenceLayer);
}
if (layer) {
d->image->addNode(layer);
}
}
currentReferenceLayer = layer;
if (currentReferenceLayer) {
connect(currentReferenceLayer, SIGNAL(sigUpdateCanvas(QRectF)),
this, SIGNAL(sigReferenceImagesChanged()));
}
emit sigReferenceImagesLayerChanged(layer);
}
void KisDocument::setPreActivatedNode(KisNodeSP activatedNode)
{
d->preActivatedNode = activatedNode;
}
KisNodeSP KisDocument::preActivatedNode() const
{
return d->preActivatedNode;
}
KisImageWSP KisDocument::image() const
{
return d->image;
}
KisImageSP KisDocument::savingImage() const
{
return d->savingImage;
}
void KisDocument::setCurrentImage(KisImageSP image, bool forceInitialUpdate)
{
if (d->image) {
// Disconnect existing sig/slot connections
d->image->setUndoStore(new KisDumbUndoStore());
d->image->disconnect(this);
d->shapeController->setImage(0);
d->image = 0;
}
if (!image) return;
if (d->documentResourceStorage){
d->documentResourceStorage->setMetaData(KisResourceStorage::s_meta_name, image->objectName());
}
d->setImageAndInitIdleWatcher(image);
d->image->setUndoStore(new KisDocumentUndoStore(this));
d->shapeController->setImage(image);
setModified(false);
connect(d->image, SIGNAL(sigImageModified()), this, SLOT(setImageModified()), Qt::UniqueConnection);
connect(d->image, SIGNAL(sigLayersChangedAsync()), this, SLOT(slotImageRootChanged()));
if (forceInitialUpdate) {
d->image->initialRefreshGraph();
}
}
void KisDocument::hackPreliminarySetImage(KisImageSP image)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(!d->image);
// we set image without connecting idle-watcher, because loading
// hasn't been finished yet
d->image = image;
d->shapeController->setImage(image);
}
void KisDocument::setImageModified()
{
// we only set as modified if undo stack is not at clean state
setModified(!d->undoStack->isClean());
}
KisUndoStore* KisDocument::createUndoStore()
{
return new KisDocumentUndoStore(this);
}
bool KisDocument::isAutosaving() const
{
return d->isAutosaving;
}
QString KisDocument::exportErrorToUserMessage(KisImportExportErrorCode status, const QString &errorMessage)
{
return errorMessage.isEmpty() ? status.errorMessage() : errorMessage;
}
void KisDocument::setAssistantsGlobalColor(QColor color)
{
d->globalAssistantsColor = color;
}
QColor KisDocument::assistantsGlobalColor()
{
return d->globalAssistantsColor;
}
QRectF KisDocument::documentBounds() const
{
QRectF bounds = d->image->bounds();
KisReferenceImagesLayerSP referenceImagesLayer = this->referenceImagesLayer();
if (referenceImagesLayer) {
bounds |= referenceImagesLayer->boundingImageRect();
}
return bounds;
}
diff --git a/libs/ui/KisDocument.h b/libs/ui/KisDocument.h
index 66536f93e5..37f6ddc7ae 100644
--- a/libs/ui/KisDocument.h
+++ b/libs/ui/KisDocument.h
@@ -1,717 +1,707 @@
/* This file is part of the Krita project
*
* Copyright (C) 2014 Boudewijn Rempt <boud@valdyas.org>
*
* 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 KISDOCUMENT_H
#define KISDOCUMENT_H
#include <QDateTime>
#include <QTransform>
#include <QList>
#include <klocalizedstring.h>
-#include <KoPageLayout.h>
-#include <KoDocumentBase.h>
#include <kundo2stack.h>
#include <KoColorSet.h>
#include <kis_image.h>
#include <KisImportExportFilter.h>
#include <kis_properties_configuration.h>
#include <kis_types.h>
#include <kis_painting_assistant.h>
#include <KisReferenceImage.h>
#include <kis_debug.h>
#include <KisImportExportUtils.h>
#include <kis_config.h>
#include "kritaui_export.h"
#include <memory>
class QString;
class KUndo2Command;
class KoUnit;
class KoColor;
class KoColorSpace;
class KoShapeControllerBase;
class KoShapeLayer;
class KoStore;
-class KoOdfReadStore;
class KoDocumentInfo;
class KoDocumentInfoDlg;
class KisImportExportManager;
class KisUndoStore;
class KisPart;
class KisGridConfig;
class KisGuidesConfig;
class KisMirrorAxisConfig;
class QDomDocument;
class KisReferenceImagesLayer;
#define KIS_MIME_TYPE "application/x-krita"
/**
* The %Calligra document class
*
* This class provides some functionality each %Calligra document should have.
*
* @short The %Calligra document class
*/
-class KRITAUI_EXPORT KisDocument : public QObject, public KoDocumentBase
+class KRITAUI_EXPORT KisDocument : public QObject
{
Q_OBJECT
protected:
explicit KisDocument(bool addStorage = true);
/**
* @brief KisDocument makes a deep copy of the document \p rhs.
* The caller *must* ensure that the image is properly
* locked and is in consistent state before asking for
* cloning.
* @param rhs the source document to copy from
*/
explicit KisDocument(const KisDocument &rhs);
public:
enum OpenFlag {
None = 0,
DontAddToRecent = 0x1,
RecoveryFile = 0x2
};
Q_DECLARE_FLAGS(OpenFlags, OpenFlag)
/**
* Destructor.
*
* The destructor does not delete any attached KisView objects and it does not
* delete the attached widget as returned by widget().
*/
- ~KisDocument() override;
+ ~KisDocument();
/**
* @brief uniqueID is a temporary unique ID that identifies the document. It is
* generated on creation and can be used to uniquely associated temporary objects
* with this document.
*
* @return the temporary unique id for this document.
*/
QString uniqueID() const;
- /**
- * @brief reload Reloads the document from the original url
- * @return the result of loading the document
- */
- bool reload();
-
-
/**
* @brief creates a clone of the document and returns it. Please make sure that you
* hold all the necessary locks on the image before asking for a clone!
*/
KisDocument* clone();
/**
* @brief openUrl Open an URL
* @param url The URL to open
* @param flags Control specific behavior
* @return success status
*/
bool openUrl(const QUrl &url, OpenFlags flags = None);
/**
* Opens the document given by @p url, without storing the URL
* in the KisDocument.
* Call this instead of openUrl() to implement KisMainWindow's
* File --> Import feature.
*
* @note This will call openUrl(). To differentiate this from an ordinary
* Open operation (in any reimplementation of openUrl() or openFile())
* call isImporting().
*/
bool importDocument(const QUrl &url);
/**
* Saves the document as @p url without changing the state of the
* KisDocument (URL, modified flag etc.). Call this instead of
* KisParts::ReadWritePart::saveAs() to implement KisMainWindow's
* File --> Export feature.
*/
bool exportDocument(const QUrl &url, const QByteArray &mimeType, bool showWarnings = false, KisPropertiesConfigurationSP exportConfiguration = 0);
/**
* Exports he document is a synchronous way. The caller must ensure that the
* image is not accessed by any other actors, because the exporting happens
* without holding the image lock.
*/
bool exportDocumentSync(const QUrl &url, const QByteArray &mimeType, KisPropertiesConfigurationSP exportConfiguration = 0);
private:
bool exportDocumentImpl(const KritaUtils::ExportFileJob &job, KisPropertiesConfigurationSP exportConfiguration);
public:
/**
* @brief Sets whether the document can be edited or is read only.
*
* This recursively applied to all child documents and
* KisView::updateReadWrite is called for every attached
* view.
*/
void setReadWrite(bool readwrite = true);
/**
* To be preferred when a document exists. It is fast when calling
* it multiple times since it caches the result that readNativeFormatMimeType()
* delivers.
* This comes from the X-KDE-NativeMimeType key in the .desktop file.
*/
static QByteArray nativeFormatMimeType() { return KIS_MIME_TYPE; }
/// Checks whether a given mimetype can be handled natively.
bool isNativeFormat(const QByteArray& mimetype) const;
/// Returns a list of the mimetypes considered "native", i.e. which can
/// be saved by KisDocument without a filter, in *addition* to the main one
static QStringList extraNativeMimeTypes() { return QStringList() << KIS_MIME_TYPE; }
/**
* Returns the actual mimetype of the document
*/
- QByteArray mimeType() const override;
+ QByteArray mimeType() const;
/**
* @brief Sets the mime type for the document.
*
* When choosing "save as" this is also the mime type
* selected by default.
*/
- void setMimeType(const QByteArray & mimeType) override;
+ void setMimeType(const QByteArray & mimeType);
/**
* @return true if file operations should inhibit the option dialog
*/
bool fileBatchMode() const;
/**
* @param batchMode if true, do not show the option dialog for file operations.
*/
void setFileBatchMode(const bool batchMode);
/**
* Sets the error message to be shown to the user (use i18n()!)
* when loading or saving fails.
* If you asked the user about something and they chose "Cancel",
*/
void setErrorMessage(const QString& errMsg);
/**
* Return the last error message. Usually KisDocument takes care of
* showing it; this method is mostly provided for non-interactive use.
*/
QString errorMessage() const;
/**
* Sets the warning message to be shown to the user (use i18n()!)
* when loading or saving fails.
*/
void setWarningMessage(const QString& warningMsg);
/**
* Return the last warning message set by loading or saving. Warnings
* mean that the document could not be completely loaded, but the errors
* were not absolutely fatal.
*/
QString warningMessage() const;
/**
* @brief Generates a preview picture of the document
* @note The preview is used in the File Dialog and also to create the Thumbnail
*/
QPixmap generatePreview(const QSize& size);
/**
* Tells the document that its title has been modified, either because
* the modified status changes (this is done by setModified() ) or
* because the URL or the document-info's title changed.
*/
void setTitleModified();
/**
* @brief Sets the document to empty.
*
* Used after loading a template
* (which is not empty, but not the user's input).
*
* @see isEmpty()
*/
void setEmpty(bool empty = true);
/**
* Return a correctly created QDomDocument for this KisDocument,
* including processing instruction, complete DOCTYPE tag (with systemId and publicId), and root element.
* @param tagName the name of the tag for the root element
* @param version the DTD version (usually the application's version).
*/
QDomDocument createDomDocument(const QString& tagName, const QString& version) const;
/**
* Return a correctly created QDomDocument for an old (1.3-style) %Calligra document,
* including processing instruction, complete DOCTYPE tag (with systemId and publicId), and root element.
* This static method can be used e.g. by filters.
* @param appName the app's instance name, e.g. words, kspread, kpresenter etc.
* @param tagName the name of the tag for the root element, e.g. DOC for words/kpresenter.
* @param version the DTD version (usually the application's version).
*/
static QDomDocument createDomDocument(const QString& appName, const QString& tagName, const QString& version);
/**
* Loads a document in the native format from a given URL.
* Reimplement if your native format isn't XML.
*
* @param file the file to load - usually KReadOnlyPart::m_file or the result of a filter
*/
bool loadNativeFormat(const QString & file);
/**
* Set standard autosave interval that is set by a config file
*/
void setNormalAutoSaveInterval();
/**
* Set emergency interval that autosave uses when the image is busy,
* by default it is 10 sec
*/
void setEmergencyAutoSaveInterval();
/**
* Disable autosave
*/
void setInfiniteAutoSaveInterval();
/**
* @return the information concerning this document.
* @see KoDocumentInfo
*/
KoDocumentInfo *documentInfo() const;
/**
* Performs a cleanup of unneeded backup files
*/
void removeAutoSaveFiles(const QString &autosaveBaseName, bool wasRecovered);
/**
* Returns true if this document or any of its internal child documents are modified.
*/
- bool isModified() const override;
+ bool isModified() const;
/**
* @return caption of the document
*
* Caption is of the form "[title] - [url]",
* built out of the document info (title) and pretty-printed
* document URL.
* If the title is not present, only the URL it returned.
*/
QString caption() const;
/**
* Sets the document URL to empty URL
* KParts doesn't allow this, but %Calligra apps have e.g. templates
* After using loadNativeFormat on a template, one wants
* to set the url to QUrl()
*/
void resetURL();
/**
* @internal (public for KisMainWindow)
*/
void setMimeTypeAfterLoading(const QString& mimeType);
/**
* Returns the unit used to display all measures/distances.
*/
KoUnit unit() const;
/**
* Sets the unit used to display all measures/distances.
*/
void setUnit(const KoUnit &unit);
KisGridConfig gridConfig() const;
void setGridConfig(const KisGridConfig &config);
/// returns the guides data for this document.
const KisGuidesConfig& guidesConfig() const;
void setGuidesConfig(const KisGuidesConfig &data);
/**
* @brief paletteList returns all the palettes found in the document's local resource storage
*/
QList<KoColorSetSP> paletteList();
/**
* @brief setPaletteList replaces the palettes in the document's local resource storage with the list
* of palettes passed to this function. It will then emitsigPaletteListChanged with both the old and
* the new list, if emitsignal is true.
*/
void setPaletteList(const QList<KoColorSetSP> &paletteList, bool emitSignal = false);
const KisMirrorAxisConfig& mirrorAxisConfig() const;
void setMirrorAxisConfig(const KisMirrorAxisConfig& config);
void clearUndoHistory();
/**
* Sets the modified flag on the document. This means that it has
* to be saved or not before deleting it.
*/
void setModified(bool _mod);
void setRecovered(bool value);
bool isRecovered() const;
void updateEditingTime(bool forceStoreElapsed);
/**
* Returns the global undo stack
*/
KUndo2Stack *undoStack();
/**
* @brief importExportManager gives access to the internal import/export manager
* @return the document's import/export manager
*/
KisImportExportManager *importExportManager() const;
/**
* @brief serializeToNativeByteArray daves the document into a .kra file wtitten
* to a memory-based byte-array
* @return a byte array containing the .kra file
*/
QByteArray serializeToNativeByteArray();
/**
* @brief isInSaving shown if the document has any (background) saving process or not
* @return true if there is some saving in action
*/
bool isInSaving() const;
public Q_SLOTS:
/**
* Adds a command to the undo stack and executes it by calling the redo() function.
* @param command command to add to the undo stack
*/
void addCommand(KUndo2Command *command);
/**
* Begins recording of a macro command. At the end endMacro needs to be called.
* @param text command description
*/
void beginMacro(const KUndo2MagicString &text);
/**
* Ends the recording of a macro command.
*/
void endMacro();
Q_SIGNALS:
/**
* This signal is emitted when the unit is changed by setUnit().
* It is common to connect views to it, in order to change the displayed units
* (e.g. in the rulers)
*/
void unitChanged(const KoUnit &unit);
/**
* Emitted e.g. at the beginning of a save operation
* This is emitted by KisDocument and used by KisView to display a statusbar message
*/
void statusBarMessage(const QString& text, int timeout = 0);
/**
* Emitted e.g. at the end of a save operation
* This is emitted by KisDocument and used by KisView to clear the statusbar message
*/
void clearStatusBarMessage();
/**
* Emitted when the document is modified
*/
void modified(bool);
void titleModified(const QString &caption, bool isModified);
void sigLoadingFinished();
void sigSavingFinished();
void sigGuidesConfigChanged(const KisGuidesConfig &config);
void sigBackgroundSavingFinished(KisImportExportErrorCode status, const QString &errorMessage);
void sigCompleteBackgroundSaving(const KritaUtils::ExportFileJob &job, KisImportExportErrorCode status, const QString &errorMessage);
void sigReferenceImagesChanged();
void sigMirrorAxisConfigChanged();
void sigGridConfigChanged(const KisGridConfig &config);
void sigReferenceImagesLayerChanged(KisSharedPtr<KisReferenceImagesLayer> layer);
/**
* Emitted when the palette list has changed.
* The pointers in oldPaletteList are to be deleted by the resource server.
**/
void sigPaletteListChanged(const QList<KoColorSetSP> &oldPaletteList, const QList<KoColorSetSP> &newPaletteList);
void sigAssistantsChanged();
private Q_SLOTS:
void finishExportInBackground();
void slotChildCompletedSavingInBackground(KisImportExportErrorCode status, const QString &errorMessage);
void slotCompleteAutoSaving(const KritaUtils::ExportFileJob &job, KisImportExportErrorCode status, const QString &errorMessage);
void slotCompleteSavingDocument(const KritaUtils::ExportFileJob &job, KisImportExportErrorCode status, const QString &errorMessage);
void slotInitiateAsyncAutosaving(KisDocument *clonedDocument);
void slotPerformIdleRoutines();
private:
friend class KisPart;
friend class SafeSavingLocker;
bool initiateSavingInBackground(const QString actionName,
const QObject *receiverObject, const char *receiverMethod,
const KritaUtils::ExportFileJob &job,
KisPropertiesConfigurationSP exportConfiguration,
std::unique_ptr<KisDocument> &&optionalClonedDocument);
bool initiateSavingInBackground(const QString actionName,
const QObject *receiverObject, const char *receiverMethod,
const KritaUtils::ExportFileJob &job,
KisPropertiesConfigurationSP exportConfiguration);
bool startExportInBackground(const QString &actionName, const QString &location,
const QString &realLocation,
const QByteArray &mimeType,
bool showWarnings,
KisPropertiesConfigurationSP exportConfiguration);
/**
* Activate/deactivate/configure the autosave feature.
* @param delay in seconds, 0 to disable
*/
void setAutoSaveDelay(int delay);
/**
* Generate a name for the document.
*/
QString newObjectName();
QString generateAutoSaveFileName(const QString & path) const;
/**
* Loads a document
*
* Applies a filter if necessary, and calls loadNativeFormat in any case
* You should not have to reimplement, except for very special cases.
*
* NOTE: this method also creates a new KisView instance!
*
* This method is called from the KReadOnlyPart::openUrl method.
*/
bool openFile();
public:
- bool isAutosaving() const override;
+ bool isAutosaving() const;
public:
- QString localFilePath() const override;
+ QString localFilePath() const;
void setLocalFilePath( const QString &localFilePath );
KoDocumentInfoDlg* createDocumentInfoDialog(QWidget *parent, KoDocumentInfo *docInfo) const;
bool isReadWrite() const;
- QUrl url() const override;
- void setUrl(const QUrl &url) override;
+ QUrl url() const;
+ void setUrl(const QUrl &url);
bool closeUrl(bool promptToSave = true);
bool saveAs(const QUrl &url, const QByteArray &mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfigration = 0);
/**
* Create a new image that has this document as a parent and
* replace the current image with this image.
*/
bool newImage(const QString& name, qint32 width, qint32 height, const KoColorSpace * cs, const KoColor &bgColor, KisConfig::BackgroundStyle bgStyle,
int numberOfLayers, const QString &imageDescription, const double imageResolution);
bool isSaving() const;
void waitForSavingToComplete();
KisImageWSP image() const;
/**
* @brief savingImage provides a detached, shallow copy of the original image that must be used when saving.
* Any strokes in progress will not be applied to this image, so the result might be missing some data. On
* the other hand, it won't block.
*
* @return a shallow copy of the original image, or 0 is saving is not in progress
*/
KisImageSP savingImage() const;
/**
* Set the current image to the specified image and turn undo on.
*/
void setCurrentImage(KisImageSP image, bool forceInitialUpdate = true);
/**
* Set the image of the document preliminary, before the document
* has completed loading. Some of the document items (shapes) may want
* to access image properties (bounds and resolution), so we should provide
* it to them even before the entire image is loaded.
*
* Right now, the only use by KoShapeRegistry::createShapeFromOdf(), remove
* after it is deprecated.
*/
void hackPreliminarySetImage(KisImageSP image);
KisUndoStore* createUndoStore();
/**
* The shape controller matches internal krita image layers with
* the flake shape hierarchy.
*/
KoShapeControllerBase * shapeController() const;
KoShapeLayer* shapeForNode(KisNodeSP layer) const;
/**
* Set the list of nodes that was marked as currently active. Used *only*
* for saving loading. Never use it for tools or processing.
*/
void setPreActivatedNode(KisNodeSP activatedNode);
/**
* @return the node that was set as active during loading. Used *only*
* for saving loading. Never use it for tools or processing.
*/
KisNodeSP preActivatedNode() const;
/// @return the list of assistants associated with this document
QList<KisPaintingAssistantSP> assistants() const;
/// @replace the current list of assistants with @param value
void setAssistants(const QList<KisPaintingAssistantSP> &value);
void setAssistantsGlobalColor(QColor color);
QColor assistantsGlobalColor();
/**
* Get existing reference images layer or null if none exists.
*/
KisSharedPtr<KisReferenceImagesLayer> referenceImagesLayer() const;
void setReferenceImagesLayer(KisSharedPtr<KisReferenceImagesLayer> layer, bool updateImage);
bool save(bool showWarnings, KisPropertiesConfigurationSP exportConfiguration);
/**
* Return the bounding box of the image and associated elements (e.g. reference images)
*/
QRectF documentBounds() const;
/**
* @brief Start saving when android activity is pushed to the background
*/
void autoSaveOnPause();
Q_SIGNALS:
void completed();
void canceled(const QString &);
private Q_SLOTS:
void setImageModified();
void slotAutoSave();
void slotUndoStackCleanChanged(bool value);
void slotConfigChanged();
void slotImageRootChanged();
/**
* @brief try to clone the image. This method handles all the locking for you. If locking
* has failed, no cloning happens
* @return cloned document on success, null otherwise
*/
KisDocument *lockAndCloneForSaving();
public:
KisDocument *lockAndCreateSnapshot();
void copyFromDocument(const KisDocument &rhs);
private:
enum CopyPolicy {
CONSTRUCT = 0, ///< we are copy-constructing a new KisDocument
REPLACE ///< we are replacing the current KisDocument with another
};
void copyFromDocumentImpl(const KisDocument &rhs, CopyPolicy policy);
QString exportErrorToUserMessage(KisImportExportErrorCode status, const QString &errorMessage);
QString prettyPathOrUrl() const;
bool openUrlInternal(const QUrl &url);
void slotAutoSaveImpl(std::unique_ptr<KisDocument> &&optionalClonedDocument);
class Private;
Private *const d;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(KisDocument::OpenFlags)
Q_DECLARE_METATYPE(KisDocument*)
#endif
diff --git a/libs/ui/KisImportExportErrorCode.cpp b/libs/ui/KisImportExportErrorCode.cpp
index b66d5edc78..b76d4f7493 100644
--- a/libs/ui/KisImportExportErrorCode.cpp
+++ b/libs/ui/KisImportExportErrorCode.cpp
@@ -1,223 +1,223 @@
/*
* Copyright (c) 2019 Agata Cacko <cacko.azh@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "KisImportExportErrorCode.h"
#include <KLocalizedString>
#include <kis_assert.h>
KisImportExportComplexError::KisImportExportComplexError(QFileDevice::FileError error) : m_error(error) { }
QString KisImportExportComplexError::qtErrorMessage() const
{
// Error descriptions in most cases taken from https://doc.qt.io/qt-5/qfiledevice.html
QString unspecifiedError = i18n("An unspecified error occurred.");
switch (m_error) {
case QFileDevice::FileError::NoError :
// Returning this file error may mean that something is wrong in our code.
// Successful operation should return ImportExportCodes::OK instead.
return i18n("The action has been completed successfully.");
case QFileDevice::FileError::ReadError :
return i18n("An error occurred when reading from the file.");
case QFileDevice::FileError::WriteError :
return i18n("An error occurred when writing to the file.");
case QFileDevice::FileError::FatalError :
return i18n("A fatal error occurred.");
case QFileDevice::FileError::ResourceError :
return i18n("Out of resources (e.g. out of memory).");
case QFileDevice::FileError::OpenError :
return i18n("The file could not be opened.");
case QFileDevice::FileError::AbortError :
return i18n("The operation was aborted.");
case QFileDevice::FileError::TimeOutError :
return i18n("A timeout occurred.");
case QFileDevice::FileError::UnspecifiedError :
return unspecifiedError;
case QFileDevice::FileError::RemoveError :
return i18n("The file could not be removed.");
case QFileDevice::FileError::RenameError :
return i18n("The file could not be renamed.");
case QFileDevice::FileError::PositionError :
return i18n("The position in the file could not be changed.");
case QFileDevice::FileError::ResizeError :
return i18n("The file could not be resized.");
case QFileDevice::FileError::PermissionsError :
return i18n("Permission denied. Krita is not allowed to read or write to the file.");
case QFileDevice::FileError::CopyError :
return i18n("The file could not be copied.");
}
return unspecifiedError;
}
KisImportExportErrorCannotRead::KisImportExportErrorCannotRead() : KisImportExportComplexError(QFileDevice::FileError()) { }
KisImportExportErrorCannotRead::KisImportExportErrorCannotRead(QFileDevice::FileError error) : KisImportExportComplexError(error) {
KIS_ASSERT_RECOVER_NOOP(error != QFileDevice::NoError);
}
QString KisImportExportErrorCannotRead::errorMessage() const
{
return i18n("Cannot open file for reading. Reason: %1", qtErrorMessage());
}
bool KisImportExportErrorCannotRead::operator==(KisImportExportErrorCannotRead other)
{
return other.m_error == m_error;
}
KisImportExportErrorCannotWrite::KisImportExportErrorCannotWrite() : KisImportExportComplexError(QFileDevice::FileError()) { }
KisImportExportErrorCannotWrite::KisImportExportErrorCannotWrite(QFileDevice::FileError error) : KisImportExportComplexError(error) {
KIS_ASSERT_RECOVER_NOOP(error != QFileDevice::NoError);
}
QString KisImportExportErrorCannotWrite::errorMessage() const
{
return i18n("Cannot open file for writing. Reason: %1", qtErrorMessage());
}
bool KisImportExportErrorCannotWrite::operator==(KisImportExportErrorCannotWrite other)
{
return other.m_error == m_error;
}
KisImportExportErrorCode::KisImportExportErrorCode() : errorFieldUsed(None), cannotRead(), cannotWrite() { }
KisImportExportErrorCode::KisImportExportErrorCode(ImportExportCodes::ErrorCodeID id) : errorFieldUsed(CodeId), codeId(id), cannotRead(), cannotWrite() { }
KisImportExportErrorCode::KisImportExportErrorCode(KisImportExportErrorCannotRead error) : errorFieldUsed(CannotRead), cannotRead(error), cannotWrite() { }
KisImportExportErrorCode::KisImportExportErrorCode(KisImportExportErrorCannotWrite error) : errorFieldUsed(CannotWrite), cannotRead(), cannotWrite(error) { }
bool KisImportExportErrorCode::isOk() const
{
// if cannotRead or cannotWrite is "NoError", it means that something is wrong in our code
return errorFieldUsed == CodeId && codeId == ImportExportCodes::OK;
}
bool KisImportExportErrorCode::isCancelled() const
{
return errorFieldUsed == CodeId && codeId == ImportExportCodes::Cancelled;
}
bool KisImportExportErrorCode::isInternalError() const
{
return errorFieldUsed == CodeId && codeId == ImportExportCodes::InternalError;
}
QString KisImportExportErrorCode::errorMessage() const
{
QString internal = i18n("Unexpected error. Please contact developers.");
if (errorFieldUsed == CannotRead) {
return cannotRead.errorMessage();
} else if (errorFieldUsed == CannotWrite) {
return cannotWrite.errorMessage();
} else if (errorFieldUsed == CodeId) {
switch (codeId) {
// Reading
case ImportExportCodes::FileNotExist:
- return i18n("The file doesn't exists.");
+ return i18n("The file doesn't exist.");
case ImportExportCodes::NoAccessToRead:
return i18n("Permission denied: Krita is not allowed to read the file.");
case ImportExportCodes::FileFormatIncorrect:
return i18n("The file format cannot be parsed.");
case ImportExportCodes::FormatFeaturesUnsupported:
return i18n("The file format contains unsupported features.");
case ImportExportCodes::FormatColorSpaceUnsupported:
return i18n("The file format contains unsupported color space.");
case ImportExportCodes::ErrorWhileReading:
return i18n("Error occurred while reading from the file.");
// Writing
case ImportExportCodes::CannotCreateFile:
return i18n("The file cannot be created.");
case ImportExportCodes::NoAccessToWrite:
return i18n("Permission denied: Krita is not allowed to write to the file.");
case ImportExportCodes::InsufficientMemory:
return i18n("There is not enough disk space left to save the file.");
case ImportExportCodes::ErrorWhileWriting:
return i18n("Error occurred while writing to the file.");
// Both
case ImportExportCodes::Cancelled:
return i18n("The action was cancelled by the user.");
// Other
case ImportExportCodes::Failure:
return i18n("Unknown error.");
case ImportExportCodes::InternalError:
return internal;
// OK
case ImportExportCodes::OK:
return i18n("The action has been completed successfully.");
default:
return internal;
}
}
return internal; // errorFieldUsed = None
}
bool KisImportExportErrorCode::operator==(KisImportExportErrorCode errorCode)
{
if (errorFieldUsed != errorCode.errorFieldUsed) {
return false;
}
if (errorFieldUsed == CodeId) {
return codeId == errorCode.codeId;
}
if (errorFieldUsed == CannotRead) {
return cannotRead == errorCode.cannotRead;
}
return cannotWrite == errorCode.cannotWrite;
}
QDebug operator<<(QDebug d, const KisImportExportErrorCode& errorCode)
{
switch(errorCode.errorFieldUsed) {
case KisImportExportErrorCode::None:
d << "None of the error fields is in use.";
break;
case KisImportExportErrorCode::CannotRead:
d << "Cannot read: " << errorCode.cannotRead.m_error;
break;
case KisImportExportErrorCode::CannotWrite:
d << "Cannot write: " << errorCode.cannotRead.m_error;
break;
case KisImportExportErrorCode::CodeId:
d << "Error code = " << errorCode.codeId;
}
d << " " << errorCode.errorMessage();
return d;
}
diff --git a/libs/ui/KisMainWindow.cpp b/libs/ui/KisMainWindow.cpp
index 98fc3806ba..5f610cf094 100644
--- a/libs/ui/KisMainWindow.cpp
+++ b/libs/ui/KisMainWindow.cpp
@@ -1,2872 +1,2722 @@
/* This file is part of the KDE project
Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
Copyright (C) 2000-2006 David Faure <faure@kde.org>
Copyright (C) 2007, 2009 Thomas zander <zander@kde.org>
Copyright (C) 2010 Benjamin Port <port.benjamin@gmail.com>
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 "KisMainWindow.h"
#include <KoConfig.h>
// qt includes
#include <QApplication>
#include <QByteArray>
#include <QCloseEvent>
#include <QStandardPaths>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QDialog>
#include <QDockWidget>
#include <QIcon>
#include <QInputDialog>
#include <QLabel>
#include <QLayout>
#include <QMdiArea>
#include <QMdiSubWindow>
#include <QMutex>
#include <QMutexLocker>
#include <QPointer>
#include <QPrintDialog>
#include <QPrinter>
#include <QPrintPreviewDialog>
#include <QToolButton>
#include <KisSignalMapper.h>
#include <QTabBar>
#include <QMoveEvent>
#include <QUrl>
#include <QMessageBox>
#include <QStatusBar>
+#include <QStyleFactory>
#include <QMenu>
#include <QMenuBar>
#include <KisMimeDatabase.h>
#include <QMimeData>
#include <QStackedWidget>
#include <QProxyStyle>
#include <QScreen>
#include <QAction>
#include <QWindow>
#include <QScrollArea>
#include <kactioncollection.h>
#include <kactionmenu.h>
#include <kis_debug.h>
#include <kedittoolbar.h>
#include <khelpmenu.h>
#include <klocalizedstring.h>
#include <kaboutdata.h>
#include <kis_workspace_resource.h>
#include <input/kis_input_manager.h>
#include "kis_selection_manager.h"
#include "kis_icon_utils.h"
#include <krecentfilesaction.h>
#include <ktoggleaction.h>
#include <ktoolbar.h>
#include <kmainwindow.h>
#include <kxmlguiwindow.h>
#include <kxmlguifactory.h>
#include <kxmlguiclient.h>
#include <kguiitem.h>
#include <kwindowconfig.h>
#include <kformat.h>
#include <KoResourcePaths.h>
#include <KoToolFactoryBase.h>
#include <KoToolRegistry.h>
#include "KoDockFactoryBase.h"
#include "KoDocumentInfoDlg.h"
#include "KoDocumentInfo.h"
#include "KoFileDialog.h"
#include <kis_icon.h>
-#include <KoPageLayoutDialog.h>
-#include <KoPageLayoutWidget.h>
#include <KoToolManager.h>
#include <KoZoomController.h>
#include "KoToolDocker.h"
#include "KoToolBoxDocker_p.h"
#include <KoToolBoxFactory.h>
#include <KoDockRegistry.h>
#include <KoPluginLoader.h>
#include <KoColorSpaceEngine.h>
#include <KoUpdater.h>
#include <KisResourceModel.h>
#include <KisResourceModelProvider.h>
#include <KisResourceLoaderRegistry.h>
#include <KisResourceIterator.h>
#include <KisResourceTypes.h>
#include <KisResourceCacheDb.h>
#ifdef Q_OS_ANDROID
#include <KisAndroidFileManager.h>
#endif
#include <KisUsageLogger.h>
#include <brushengine/kis_paintop_settings.h>
#include "dialogs/kis_about_application.h"
#include "dialogs/kis_delayed_save_dialog.h"
#include "dialogs/kis_dlg_preferences.h"
#include "kis_action_manager.h"
#include "KisApplication.h"
#include "kis_canvas2.h"
#include "kis_canvas_controller.h"
#include "kis_canvas_resource_provider.h"
#include "kis_clipboard.h"
#include "kis_config.h"
#include "kis_config_notifier.h"
#include "kis_custom_image_widget.h"
#include <KisDocument.h>
#include "kis_group_layer.h"
#include "kis_image_from_clipboard_widget.h"
#include "kis_image.h"
#include <KisImportExportFilter.h>
#include "KisImportExportManager.h"
#include "kis_mainwindow_observer.h"
#include "kis_memory_statistics_server.h"
#include "kis_node.h"
#include "KisOpenPane.h"
#include "kis_paintop_box.h"
#include "KisPart.h"
-#include "KisPrintJob.h"
#include "KisResourceServerProvider.h"
#include "kis_signal_compressor_with_param.h"
#include "kis_statusbar.h"
#include "KisView.h"
#include "KisViewManager.h"
#include "thememanager.h"
#include "kis_animation_importer.h"
#include "dialogs/kis_dlg_import_image_sequence.h"
#include <KisImageConfigNotifier.h>
#include "KisWindowLayoutManager.h"
#include <KisUndoActionsUpdateManager.h>
#include "KisWelcomePageWidget.h"
#include <KritaVersionWrapper.h>
#include <kritaversion.h>
#include "KisCanvasWindow.h"
#include "kis_action.h"
#include <mutex>
class ToolDockerFactory : public KoDockFactoryBase
{
public:
ToolDockerFactory() : KoDockFactoryBase() { }
QString id() const override {
return "sharedtooldocker";
}
QDockWidget* createDockWidget() override {
KoToolDocker* dockWidget = new KoToolDocker();
return dockWidget;
}
DockPosition defaultDockPosition() const override {
return DockRight;
}
};
class Q_DECL_HIDDEN KisMainWindow::Private
{
public:
Private(KisMainWindow *parent, QUuid id)
: q(parent)
, id(id)
+ , styleMenu(new KActionMenu(i18nc("@action:inmenu", "Styles"), parent))
, dockWidgetMenu(new KActionMenu(i18nc("@action:inmenu", "&Dockers"), parent))
, windowMenu(new KActionMenu(i18nc("@action:inmenu", "&Window"), parent))
, documentMenu(new KActionMenu(i18nc("@action:inmenu", "New &View"), parent))
, workspaceMenu(new KActionMenu(i18nc("@action:inmenu", "Wor&kspace"), parent))
, welcomePage(new KisWelcomePageWidget(parent))
, widgetStack(new QStackedWidget(parent))
, mdiArea(new QMdiArea(parent))
, windowMapper(new KisSignalMapper(parent))
, documentMapper(new KisSignalMapper(parent))
#ifdef Q_OS_ANDROID
, fileManager(new KisAndroidFileManager(parent))
#endif
{
if (id.isNull()) this->id = QUuid::createUuid();
welcomeScroller = new QScrollArea();
welcomeScroller->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
welcomeScroller->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
welcomeScroller->setWidget(welcomePage);
welcomeScroller->setWidgetResizable(true);
widgetStack->addWidget(welcomeScroller);
widgetStack->addWidget(mdiArea);
mdiArea->setTabsMovable(true);
mdiArea->setActivationOrder(QMdiArea::ActivationHistoryOrder);
}
~Private() {
qDeleteAll(toolbarList);
}
KisMainWindow *q {0};
QUuid id;
KisViewManager *viewManager {0};
QPointer<KisView> activeView;
QList<QAction *> toolbarList;
bool firstTime {true};
bool windowSizeDirty {false};
bool readOnly {false};
KisAction *showDocumentInfo {0};
KisAction *saveAction {0};
KisAction *saveActionAs {0};
- // KisAction *printAction;
- // KisAction *printActionPreview;
- // KisAction *exportPdf {0};
KisAction *importAnimation {0};
KisAction *closeAll {0};
- // KisAction *reloadFile;
KisAction *importFile {0};
KisAction *exportFile {0};
KisAction *undo {0};
KisAction *redo {0};
KisAction *newWindow {0};
KisAction *close {0};
KisAction *mdiCascade {0};
KisAction *mdiTile {0};
KisAction *mdiNextWindow {0};
KisAction *mdiPreviousWindow {0};
KisAction *toggleDockers {0};
KisAction *resetConfigurations {0};
KisAction *toggleDockerTitleBars {0};
KisAction *toggleDetachCanvas {0};
KisAction *fullScreenMode {0};
KisAction *showSessionManager {0};
KisAction *expandingSpacers[2];
+ KActionMenu *styleMenu;
+ QActionGroup* styleActions;
+ QMap<QString, QAction*> actionMap;
+
KActionMenu *dockWidgetMenu;
KActionMenu *windowMenu;
KActionMenu *documentMenu;
KActionMenu *workspaceMenu;
KHelpMenu *helpMenu {0};
KRecentFilesAction *recentFiles {0};
KisResourceModel *workspacemodel {0};
QScopedPointer<KisUndoActionsUpdateManager> undoActionsUpdateManager;
QString lastExportLocation;
QMap<QString, QDockWidget *> dockWidgetsMap;
QByteArray dockerStateBeforeHiding;
KoToolDocker *toolOptionsDocker {0};
QCloseEvent *deferredClosingEvent {0};
Digikam::ThemeManager *themeManager {0};
QScrollArea *welcomeScroller {0};
KisWelcomePageWidget *welcomePage {0};
QStackedWidget *widgetStack {0};
QMdiArea *mdiArea;
QMdiSubWindow *activeSubWindow {0};
KisSignalMapper *windowMapper;
KisSignalMapper *documentMapper;
KisCanvasWindow *canvasWindow {0};
QByteArray lastExportedFormat;
QScopedPointer<KisSignalCompressorWithParam<int> > tabSwitchCompressor;
QMutex savingEntryMutex;
KConfigGroup windowStateConfig;
QUuid workspaceBorrowedBy;
KisSignalAutoConnectionsStore screenConnectionsStore;
#ifdef Q_OS_ANDROID
KisAndroidFileManager *fileManager;
#endif
KisActionManager * actionManager() {
return viewManager->actionManager();
}
QTabBar* findTabBarHACK() {
QObjectList objects = mdiArea->children();
Q_FOREACH (QObject *object, objects) {
QTabBar *bar = qobject_cast<QTabBar*>(object);
if (bar) {
return bar;
}
}
return 0;
}
};
KisMainWindow::KisMainWindow(QUuid uuid)
: KXmlGuiWindow()
, d(new Private(this, uuid))
{
d->workspacemodel = KisResourceModelProvider::resourceModel(ResourceType::Workspaces);
connect(d->workspacemodel, SIGNAL(afterResourcesLayoutReset()), this, SLOT(updateWindowMenu()));
d->viewManager = new KisViewManager(this, actionCollection());
KConfigGroup group( KSharedConfig::openConfig(), "theme");
d->themeManager = new Digikam::ThemeManager(group.readEntry("Theme", "Krita dark"), this);
d->windowStateConfig = KSharedConfig::openConfig()->group("MainWindow");
setStandardToolBarMenuEnabled(true);
setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
setDockNestingEnabled(true);
qApp->setStartDragDistance(25); // 25 px is a distance that works well for Tablet and Mouse events
#ifdef Q_OS_MACOS
setUnifiedTitleAndToolBarOnMac(true);
#endif
connect(this, SIGNAL(restoringDone()), this, SLOT(forceDockTabFonts()));
connect(this, SIGNAL(themeChanged()), d->viewManager, SLOT(updateIcons()));
connect(KisPart::instance(), SIGNAL(documentClosed(QString)), SLOT(updateWindowMenu()));
connect(KisPart::instance(), SIGNAL(documentOpened(QString)), SLOT(updateWindowMenu()));
connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), this, SLOT(configChanged()));
actionCollection()->addAssociatedWidget(this);
KoPluginLoader::instance()->load("Krita/ViewPlugin", "Type == 'Service' and ([X-Krita-Version] == 28)", KoPluginLoader::PluginsConfig(), d->viewManager, false);
// Load the per-application plugins (Right now, only Python) We do this only once, when the first mainwindow is being created.
KoPluginLoader::instance()->load("Krita/ApplicationPlugin", "Type == 'Service' and ([X-Krita-Version] == 28)", KoPluginLoader::PluginsConfig(), qApp, true);
KoToolBoxFactory toolBoxFactory;
QDockWidget *toolbox = createDockWidget(&toolBoxFactory);
toolbox->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetClosable);
KisConfig cfg(true);
if (cfg.toolOptionsInDocker()) {
ToolDockerFactory toolDockerFactory;
d->toolOptionsDocker = qobject_cast<KoToolDocker*>(createDockWidget(&toolDockerFactory));
d->toolOptionsDocker->toggleViewAction()->setEnabled(true);
}
QMap<QString, QAction*> dockwidgetActions;
dockwidgetActions[toolbox->toggleViewAction()->text()] = toolbox->toggleViewAction();
Q_FOREACH (const QString & docker, KoDockRegistry::instance()->keys()) {
KoDockFactoryBase *factory = KoDockRegistry::instance()->value(docker);
QDockWidget *dw = createDockWidget(factory);
dockwidgetActions[dw->toggleViewAction()->text()] = dw->toggleViewAction();
}
if (d->toolOptionsDocker) {
dockwidgetActions[d->toolOptionsDocker->toggleViewAction()->text()] = d->toolOptionsDocker->toggleViewAction();
}
connect(KoToolManager::instance(), SIGNAL(toolOptionWidgetsChanged(KoCanvasController*,QList<QPointer<QWidget> >)), this, SLOT(newOptionWidgets(KoCanvasController*,QList<QPointer<QWidget> >)));
Q_FOREACH (QString title, dockwidgetActions.keys()) {
d->dockWidgetMenu->addAction(dockwidgetActions[title]);
}
+
+ // Style menu actions
+ d->styleActions = new QActionGroup(this);
+ QAction * action;
+ Q_FOREACH (QString styleName, QStyleFactory::keys()) {
+ action = new QAction(styleName, d->styleActions);
+ action->setCheckable(true);
+ d->actionMap.insert(styleName, action);
+ d->styleMenu->addAction(d->actionMap.value(styleName));
+ }
+
+
+ // select the config value, or the current style if that does not exist
+ QString styleFromConfig = cfg.widgetStyle().toLower();
+ QString styleToSelect = styleFromConfig == "" ? style()->objectName().toLower() : styleFromConfig;
+
+ Q_FOREACH (auto key, d->actionMap.keys()) {
+ if(key.toLower() == styleToSelect) { // does the key match selection
+ d->actionMap.value(key)->setChecked(true);
+ }
+ }
+
+ connect(d->styleActions, SIGNAL(triggered(QAction*)),
+ this, SLOT(slotUpdateWidgetStyle()));
+
+
+
+
Q_FOREACH (QDockWidget *wdg, dockWidgets()) {
if ((wdg->features() & QDockWidget::DockWidgetClosable) == 0) {
wdg->setVisible(true);
}
}
Q_FOREACH (KoCanvasObserverBase* observer, canvasObservers()) {
observer->setObservedCanvas(0);
KisMainwindowObserver* mainwindowObserver = dynamic_cast<KisMainwindowObserver*>(observer);
if (mainwindowObserver) {
mainwindowObserver->setViewManager(d->viewManager);
}
}
// Load all the actions from the tool plugins
Q_FOREACH(KoToolFactoryBase *toolFactory, KoToolRegistry::instance()->values()) {
toolFactory->createActions(actionCollection());
}
d->mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
d->mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
d->mdiArea->setTabPosition(QTabWidget::North);
d->mdiArea->setTabsClosable(true);
// Tab close button override
// Windows just has a black X, and Ubuntu has a dark x that is hard to read
// just switch this icon out for all OSs so it is easier to see
d->mdiArea->setStyleSheet("QTabBar::close-button { image: url(:/pics/broken-preset.png) }");
setCentralWidget(d->widgetStack);
d->widgetStack->setCurrentIndex(0);
connect(d->mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(subWindowActivated()));
connect(d->windowMapper, SIGNAL(mapped(QWidget*)), this, SLOT(setActiveSubWindow(QWidget*)));
connect(d->documentMapper, SIGNAL(mapped(QObject*)), this, SLOT(newView(QObject*)));
d->canvasWindow = new KisCanvasWindow(this);
actionCollection()->addAssociatedWidget(d->canvasWindow);
createActions();
// the welcome screen needs to grab actions...so make sure this line goes after the createAction() so they exist
d->welcomePage->setMainWindow(this);
setAutoSaveSettings(d->windowStateConfig, false);
subWindowActivated();
updateWindowMenu();
if (isHelpMenuEnabled() && !d->helpMenu) {
// workaround for KHelpMenu (or rather KAboutData::applicationData()) internally
// not using the Q*Application metadata ATM, which results e.g. in the bugreport wizard
// not having the app version preset
// fixed hopefully in KF5 5.22.0, patch pending
QGuiApplication *app = qApp;
KAboutData aboutData(app->applicationName(), app->applicationDisplayName(), app->applicationVersion());
aboutData.setOrganizationDomain(app->organizationDomain().toUtf8());
d->helpMenu = new KHelpMenu(this, aboutData, false);
// workaround-less version:
// d->helpMenu = new KHelpMenu(this, QString()/*unused*/, false);
// The difference between using KActionCollection->addAction() is that
// these actions do not get tied to the MainWindow. What does this all do?
KActionCollection *actions = d->viewManager->actionCollection();
QAction *helpContentsAction = d->helpMenu->action(KHelpMenu::menuHelpContents);
QAction *whatsThisAction = d->helpMenu->action(KHelpMenu::menuWhatsThis);
QAction *reportBugAction = d->helpMenu->action(KHelpMenu::menuReportBug);
QAction *switchLanguageAction = d->helpMenu->action(KHelpMenu::menuSwitchLanguage);
QAction *aboutAppAction = d->helpMenu->action(KHelpMenu::menuAboutApp);
QAction *aboutKdeAction = d->helpMenu->action(KHelpMenu::menuAboutKDE);
if (helpContentsAction) {
actions->addAction(helpContentsAction->objectName(), helpContentsAction);
}
if (whatsThisAction) {
actions->addAction(whatsThisAction->objectName(), whatsThisAction);
}
if (reportBugAction) {
actions->addAction(reportBugAction->objectName(), reportBugAction);
}
if (switchLanguageAction) {
actions->addAction(switchLanguageAction->objectName(), switchLanguageAction);
}
if (aboutAppAction) {
actions->addAction(aboutAppAction->objectName(), aboutAppAction);
}
if (aboutKdeAction) {
actions->addAction(aboutKdeAction->objectName(), aboutKdeAction);
}
connect(d->helpMenu, SIGNAL(showAboutApplication()), SLOT(showAboutApplication()));
}
// KDE' libs 4''s help contents action is broken outside kde, for some reason... We can handle it just as easily ourselves
QAction *helpAction = actionCollection()->action("help_contents");
helpAction->disconnect();
connect(helpAction, SIGNAL(triggered()), this, SLOT(showManual()));
#if 0
//check for colliding shortcuts
QSet<QKeySequence> existingShortcuts;
Q_FOREACH (QAction* action, actionCollection()->actions()) {
if(action->shortcut() == QKeySequence(0)) {
continue;
}
dbgKrita << "shortcut " << action->text() << " " << action->shortcut();
Q_ASSERT(!existingShortcuts.contains(action->shortcut()));
existingShortcuts.insert(action->shortcut());
}
#endif
configChanged();
// Make sure the python plugins create their actions in time
KisPart::instance()->notifyMainWindowIsBeingCreated(this);
// If we have customized the toolbars, load that first
- setLocalXMLFile(KoResourcePaths::locateLocal("data", "krita4.xmlgui"));
- setXMLFile(":/kxmlgui5/krita4.xmlgui");
+ setLocalXMLFile(KoResourcePaths::locateLocal("data", "krita5.xmlgui"));
+ setXMLFile(":/kxmlgui5/krita5.xmlgui");
guiFactory()->addClient(this);
connect(guiFactory(), SIGNAL(makingChanges(bool)), SLOT(slotXmlGuiMakingChanges(bool)));
// Create and plug toolbar list for Settings menu
QList<QAction *> toolbarList;
Q_FOREACH (QWidget* it, guiFactory()->containers("ToolBar")) {
KToolBar * toolBar = ::qobject_cast<KToolBar *>(it);
if (toolBar) {
toolBar->setMovable(KisConfig(true).readEntry<bool>("LockAllDockerPanels", false));
if (toolBar->objectName() == "BrushesAndStuff") {
toolBar->setEnabled(false);
}
KToggleAction* act = new KToggleAction(i18n("Show %1 Toolbar", toolBar->windowTitle()), this);
actionCollection()->addAction(toolBar->objectName().toUtf8(), act);
act->setCheckedState(KGuiItem(i18n("Hide %1 Toolbar", toolBar->windowTitle())));
connect(act, SIGNAL(toggled(bool)), this, SLOT(slotToolbarToggled(bool)));
act->setChecked(!toolBar->isHidden());
toolbarList.append(act);
} else {
warnUI << "Toolbar list contains a " << it->metaObject()->className() << " which is not a toolbar!";
}
}
KToolBar::setToolBarsLocked(KisConfig(true).readEntry<bool>("LockAllDockerPanels", false));
plugActionList("toolbarlist", toolbarList);
d->toolbarList = toolbarList;
applyToolBarLayout();
d->viewManager->updateGUI();
d->viewManager->updateIcons();
QTimer::singleShot(1000, this, SLOT(checkSanity()));
{
using namespace std::placeholders; // For _1 placeholder
std::function<void (int)> callback(
std::bind(&KisMainWindow::switchTab, this, _1));
d->tabSwitchCompressor.reset(
new KisSignalCompressorWithParam<int>(500, callback, KisSignalCompressor::FIRST_INACTIVE));
}
if (cfg.readEntry("CanvasOnlyActive", false)) {
QString currentWorkspace = cfg.readEntry<QString>("CurrentWorkspace", "Default");
KoResourceServer<KisWorkspaceResource> * rserver = KisResourceServerProvider::instance()->workspaceServer();
KisWorkspaceResourceSP workspace = rserver->resourceByName(currentWorkspace);
if (workspace) {
restoreWorkspace(workspace->resourceId());
}
cfg.writeEntry("CanvasOnlyActive", false);
menuBar()->setVisible(true);
}
this->winId(); // Ensures the native window has been created.
QWindow *window = this->windowHandle();
connect(window, SIGNAL(screenChanged(QScreen *)), this, SLOT(windowScreenChanged(QScreen *)));
}
KisMainWindow::~KisMainWindow()
{
// Q_FOREACH (QAction *ac, actionCollection()->actions()) {
// QAction *action = qobject_cast<QAction*>(ac);
// if (action) {
// qDebug() << "<Action"
// << "\n\tname=" << action->objectName()
// << "\n\ticon=" << action->icon().name()
// << "\n\ttext=" << action->text().replace("&", "&amp;")
// << "\n\twhatsThis=" << action->whatsThis()
// << "\n\ttoolTip=" << action->toolTip().replace("<html>", "").replace("</html>", "")
// << "\n\ticonText=" << action->iconText().replace("&", "&amp;")
// << "\n\tshortcut=" << action->shortcut().toString()
// << "\n\tisCheckable=" << QString((action->isChecked() ? "true" : "false"))
// << "\n\tstatusTip=" << action->statusTip()
// << "\n/>\n" ;
// }
// else {
// dbgKrita << "Got a non-qaction:" << ac->objectName();
// }
// }
// The doc and view might still exist (this is the case when closing the window)
KisPart::instance()->removeMainWindow(this);
delete d->viewManager;
delete d;
}
QUuid KisMainWindow::id() const {
return d->id;
}
void KisMainWindow::addView(KisView *view, QMdiSubWindow *subWindow)
{
if (d->activeView == view && !subWindow) return;
if (d->activeView) {
d->activeView->disconnect(this);
}
// register the newly created view in the input manager
viewManager()->inputManager()->addTrackedCanvas(view->canvasBase());
showView(view, subWindow);
updateCaption();
emit restoringDone();
if (d->activeView) {
connect(d->activeView, SIGNAL(titleModified(QString,bool)), SLOT(slotDocumentTitleModified()));
connect(d->viewManager->statusBar(), SIGNAL(memoryStatusUpdated()), this, SLOT(updateCaption()));
}
}
void KisMainWindow::notifyChildViewDestroyed(KisView *view)
{
/**
* If we are the last view of the window, Qt will not activate another tab
* before destroying tab/window. In this case we should clear all the dangling
* pointers manually by setting the current view to null
*/
viewManager()->inputManager()->removeTrackedCanvas(view->canvasBase());
if (view->canvasBase() == viewManager()->canvasBase()) {
viewManager()->setCurrentView(0);
}
}
void KisMainWindow::showView(KisView *imageView, QMdiSubWindow *subwin)
{
if (imageView && activeView() != imageView) {
// XXX: find a better way to initialize this!
imageView->setViewManager(d->viewManager);
imageView->canvasBase()->setFavoriteResourceManager(d->viewManager->paintOpBox()->favoriteResourcesManager());
imageView->slotLoadingFinished();
if (!subwin) {
subwin = d->mdiArea->addSubWindow(imageView);
} else {
subwin->setWidget(imageView);
}
imageView->setSubWindow(subwin);
subwin->setAttribute(Qt::WA_DeleteOnClose, true);
connect(subwin, SIGNAL(destroyed()), SLOT(updateWindowMenu()));
KisConfig cfg(true);
subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.readEntry<int>("mdi_rubberband", cfg.useOpenGL()));
subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.readEntry<int>("mdi_rubberband", cfg.useOpenGL()));
subwin->setWindowIcon(qApp->windowIcon());
#ifdef Q_OS_MACOS
connect(subwin, SIGNAL(destroyed()), SLOT(updateSubwindowFlags()));
updateSubwindowFlags();
#endif
if (d->mdiArea->subWindowList().size() == 1) {
imageView->showMaximized();
}
else {
imageView->show();
}
/**
* Hack alert!
*
* Here we explicitly request KoToolManager to emit all the tool
* activation signals, to reinitialize the tool options docker.
*
* That is needed due to a design flaw we have in the
* initialization procedure. The tool in the KoToolManager is
* initialized in KisView::setViewManager() calls, which
* happens early enough. During this call the tool manager
* requests KoCanvasControllerWidget to emit the signal to
* update the widgets in the tool docker. *But* at that moment
* of time the view is not yet connected to the main window,
* because it happens in KisViewManager::setCurrentView a bit
* later. This fact makes the widgets updating signals be lost
* and never reach the tool docker.
*
* So here we just explicitly call the tool activation stub.
*/
KoToolManager::instance()->initializeCurrentToolForCanvas();
// No, no, no: do not try to call this _before_ the show() has
// been called on the view; only when that has happened is the
// opengl context active, and very bad things happen if we tell
// the dockers to update themselves with a view if the opengl
// context is not active.
setActiveView(imageView);
updateWindowMenu();
updateCaption();
}
}
void KisMainWindow::slotPreferences()
{
QScopedPointer<KisDlgPreferences> dlgPreferences(new KisDlgPreferences(this));
if (dlgPreferences->editPreferences()) {
KisConfigNotifier::instance()->notifyConfigChanged();
KisConfigNotifier::instance()->notifyPixelGridModeChanged();
KisImageConfigNotifier::instance()->notifyConfigChanged();
// XXX: should this be changed for the views in other windows as well?
Q_FOREACH (QPointer<KisView> koview, KisPart::instance()->views()) {
KisViewManager *view = qobject_cast<KisViewManager*>(koview);
if (view) {
// Update the settings for all nodes -- they don't query
// KisConfig directly because they need the settings during
// compositing, and they don't connect to the config notifier
// because nodes are not QObjects (because only one base class
// can be a QObject).
KisNode* node = dynamic_cast<KisNode*>(view->image()->rootLayer().data());
node->updateSettings();
}
}
updateWindowMenu();
d->viewManager->showHideScrollbars();
}
}
void KisMainWindow::slotThemeChanged()
{
// save theme changes instantly
KConfigGroup group( KSharedConfig::openConfig(), "theme");
group.writeEntry("Theme", d->themeManager->currentThemeName());
// reload action icons!
Q_FOREACH (QAction *action, actionCollection()->actions()) {
KisIconUtils::updateIcon(action);
}
if (d->mdiArea) {
d->mdiArea->setPalette(qApp->palette());
for (int i=0; i<d->mdiArea->subWindowList().size(); i++) {
QMdiSubWindow *window = d->mdiArea->subWindowList().at(i);
if (window) {
window->setPalette(qApp->palette());
KisView *view = qobject_cast<KisView*>(window->widget());
if (view) {
view->slotThemeChanged(qApp->palette());
}
}
}
}
emit themeChanged();
}
bool KisMainWindow::canvasDetached() const
{
return centralWidget() != d->widgetStack;
}
void KisMainWindow::setCanvasDetached(bool detach)
{
if (detach == canvasDetached()) return;
QWidget *outgoingWidget = centralWidget() ? takeCentralWidget() : nullptr;
QWidget *incomingWidget = d->canvasWindow->swapMainWidget(outgoingWidget);
if (incomingWidget) {
setCentralWidget(incomingWidget);
}
if (detach) {
d->canvasWindow->show();
} else {
d->canvasWindow->hide();
}
}
void KisMainWindow::slotFileSelected(QString path)
{
QString url = path;
if (!url.isEmpty()) {
bool res = openDocument(QUrl::fromLocalFile(url), Import);
if (!res) {
warnKrita << "Loading" << url << "failed";
}
}
}
void KisMainWindow::slotEmptyFilePath()
{
QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("The chosen file's location could not be found. Does it exist?"));
}
QWidget * KisMainWindow::canvasWindow() const
{
return d->canvasWindow;
}
-void KisMainWindow::updateReloadFileAction(KisDocument *doc)
-{
- Q_UNUSED(doc);
- // d->reloadFile->setEnabled(doc && !doc->url().isEmpty());
-}
-
void KisMainWindow::setReadWrite(bool readwrite)
{
d->saveAction->setEnabled(readwrite);
d->importFile->setEnabled(readwrite);
d->readOnly = !readwrite;
updateCaption();
}
void KisMainWindow::addRecentURL(const QUrl &url, const QUrl &oldUrl)
{
// Add entry to recent documents list
// (call coming from KisDocument because it must work with cmd line, template dlg, file/open, etc.)
if (!url.isEmpty()) {
bool ok = true;
if (url.isLocalFile()) {
QString path = url.adjusted(QUrl::StripTrailingSlash).toLocalFile();
const QStringList tmpDirs = KoResourcePaths::resourceDirs("tmp");
for (QStringList::ConstIterator it = tmpDirs.begin() ; ok && it != tmpDirs.end() ; ++it) {
if (path.contains(*it)) {
ok = false; // it's in the tmp resource
}
}
const QStringList templateDirs = KoResourcePaths::findDirs("templates");
for (QStringList::ConstIterator it = templateDirs.begin() ; ok && it != templateDirs.end() ; ++it) {
if (path.contains(*it)) {
ok = false; // it's in the templates directory.
break;
}
}
}
if (ok) {
if (!oldUrl.isEmpty()) {
d->recentFiles->removeUrl(oldUrl);
}
d->recentFiles->addUrl(url);
}
saveRecentFiles();
}
}
void KisMainWindow::saveRecentFiles()
{
// Save list of recent files
KSharedConfigPtr config = KSharedConfig::openConfig();
d->recentFiles->saveEntries(config->group("RecentFiles"));
config->sync();
// Tell all windows to reload their list, after saving
// Doesn't work multi-process, but it's a start
Q_FOREACH (KisMainWindow *mw, KisPart::instance()->mainWindows()) {
if (mw != this) {
mw->reloadRecentFileList();
}
}
}
QList<QUrl> KisMainWindow::recentFilesUrls()
{
return d->recentFiles->urls();
}
void KisMainWindow::clearRecentFiles()
{
d->recentFiles->clear();
d->welcomePage->populateRecentDocuments();
}
void KisMainWindow::removeRecentUrl(const QUrl &url)
{
d->recentFiles->removeUrl(url);
KSharedConfigPtr config = KSharedConfig::openConfig();
d->recentFiles->saveEntries(config->group("RecentFiles"));
config->sync();
}
void KisMainWindow::reloadRecentFileList()
{
d->recentFiles->loadEntries(KSharedConfig::openConfig()->group("RecentFiles"));
}
void KisMainWindow::updateCaption()
{
if (!d->mdiArea->activeSubWindow()) {
updateCaption(QString(), false);
}
else if (d->activeView && d->activeView->document() && d->activeView->image()){
KisDocument *doc = d->activeView->document();
QString caption(doc->caption());
caption = "RESOURCES REWRITE GOING ON " + caption;
if (d->readOnly) {
caption += " [" + i18n("Write Protected") + "] ";
}
if (doc->isRecovered()) {
caption += " [" + i18n("Recovered") + "] ";
}
// show the file size for the document
KisMemoryStatisticsServer::Statistics m_fileSizeStats = KisMemoryStatisticsServer::instance()->fetchMemoryStatistics(d->activeView ? d->activeView->image() : 0);
if (m_fileSizeStats.imageSize) {
caption += QString(" (").append( KFormat().formatByteSize(m_fileSizeStats.imageSize)).append( ")");
}
updateCaption(caption, doc->isModified());
if (!doc->url().fileName().isEmpty()) {
d->saveAction->setToolTip(i18n("Save as %1", doc->url().fileName()));
}
else {
d->saveAction->setToolTip(i18n("Save"));
}
}
}
void KisMainWindow::updateCaption(const QString &caption, bool modified)
{
QString versionString = KritaVersionWrapper::versionString(true);
QString title = caption;
if (!title.contains(QStringLiteral("[*]"))) { // append the placeholder so that the modified mechanism works
title.append(QStringLiteral(" [*]"));
}
if (d->mdiArea->activeSubWindow()) {
#if defined(KRITA_ALPHA) || defined (KRITA_BETA) || defined (KRITA_RC)
d->mdiArea->activeSubWindow()->setWindowTitle(QString("%1: %2").arg(versionString).arg(title));
#else
d->mdiArea->activeSubWindow()->setWindowTitle(title);
#endif
d->mdiArea->activeSubWindow()->setWindowModified(modified);
}
else {
#if defined(KRITA_ALPHA) || defined (KRITA_BETA) || defined (KRITA_RC)
setWindowTitle(QString("%1: %2").arg(versionString).arg(title));
#else
setWindowTitle(title);
#endif
}
setWindowModified(modified);
}
KisView *KisMainWindow::activeView() const
{
if (d->activeView) {
return d->activeView;
}
return 0;
}
bool KisMainWindow::openDocument(const QUrl &url, OpenFlags flags)
{
if (!QFile(url.toLocalFile()).exists()) {
if (!(flags & BatchMode)) {
QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("The file %1 does not exist.", url.url()));
}
d->recentFiles->removeUrl(url); //remove the file from the recent-opened-file-list
saveRecentFiles();
return false;
}
return openDocumentInternal(url, flags);
}
bool KisMainWindow::openDocumentInternal(const QUrl &url, OpenFlags flags)
{
if (!url.isLocalFile()) {
qWarning() << "KisMainWindow::openDocumentInternal. Not a local file:" << url;
return false;
}
KisDocument *newdoc = KisPart::instance()->createDocument();
if (flags & BatchMode) {
newdoc->setFileBatchMode(true);
}
d->firstTime = true;
connect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted()));
connect(newdoc, SIGNAL(canceled(QString)), this, SLOT(slotLoadCanceled(QString)));
KisDocument::OpenFlags openFlags = KisDocument::None;
// XXX: Why this duplication of of OpenFlags...
if (flags & RecoveryFile) {
openFlags |= KisDocument::RecoveryFile;
}
bool openRet = !(flags & Import) ? newdoc->openUrl(url, openFlags) : newdoc->importDocument(url);
if (!openRet) {
delete newdoc;
return false;
}
KisPart::instance()->addDocument(newdoc);
- updateReloadFileAction(newdoc);
if (!QFileInfo(url.toLocalFile()).isWritable()) {
setReadWrite(false);
}
+ // Try to determine whether this was an unnamed autosave
if (flags & RecoveryFile &&
( url.toLocalFile().startsWith(QDir::tempPath())
- || url.toLocalFile().startsWith(QDir::homePath()))
- ) {
- newdoc->setUrl(QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation) + "/" + QFileInfo(url.toLocalFile()).fileName()));
- newdoc->save(false, 0);
+ || url.toLocalFile().startsWith(QDir::homePath())
+ ) &&
+ ( QFileInfo(url.toLocalFile()).fileName().startsWith(".krita")
+ || QFileInfo(url.toLocalFile()).fileName().startsWith("krita")
+ )
+ )
+ {
+ QString path = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
+ if (!QFileInfo(path).exists()) {
+ path = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
+ }
+ newdoc->setUrl(QUrl::fromLocalFile( path + "/" + newdoc->objectName() + ".kra"));
}
return true;
}
void KisMainWindow::showDocument(KisDocument *document) {
Q_FOREACH(QMdiSubWindow *subwindow, d->mdiArea->subWindowList()) {
KisView *view = qobject_cast<KisView*>(subwindow->widget());
KIS_SAFE_ASSERT_RECOVER_NOOP(view);
if (view) {
if (view->document() == document) {
setActiveSubWindow(subwindow);
return;
}
}
}
addViewAndNotifyLoadingCompleted(document);
}
KisView* KisMainWindow::addViewAndNotifyLoadingCompleted(KisDocument *document,
QMdiSubWindow *subWindow)
{
showWelcomeScreen(false); // see workaround in function header
KisView *view = KisPart::instance()->createView(document, d->viewManager, this);
addView(view, subWindow);
emit guiLoadingFinished();
return view;
}
QStringList KisMainWindow::showOpenFileDialog(bool isImporting)
{
KoFileDialog dialog(this, KoFileDialog::ImportFiles, "OpenDocument");
dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
dialog.setMimeTypeFilters(KisImportExportManager::supportedMimeTypes(KisImportExportManager::Import));
dialog.setCaption(isImporting ? i18n("Import Images") : i18n("Open Images"));
return dialog.filenames();
}
// Separate from openDocument to handle async loading (remote URLs)
void KisMainWindow::slotLoadCompleted()
{
KisDocument *newdoc = qobject_cast<KisDocument*>(sender());
if (newdoc && newdoc->image()) {
addViewAndNotifyLoadingCompleted(newdoc);
disconnect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted()));
disconnect(newdoc, SIGNAL(canceled(QString)), this, SLOT(slotLoadCanceled(QString)));
emit loadCompleted();
}
}
void KisMainWindow::slotLoadCanceled(const QString & errMsg)
{
KisUsageLogger::log(QString("Loading canceled. Error:").arg(errMsg));
if (!errMsg.isEmpty()) // empty when canceled by user
QMessageBox::critical(this, i18nc("@title:window", "Krita"), errMsg);
// ... can't delete the document, it's the one who emitted the signal...
KisDocument* doc = qobject_cast<KisDocument*>(sender());
Q_ASSERT(doc);
disconnect(doc, SIGNAL(completed()), this, SLOT(slotLoadCompleted()));
disconnect(doc, SIGNAL(canceled(QString)), this, SLOT(slotLoadCanceled(QString)));
}
void KisMainWindow::slotSaveCanceled(const QString &errMsg)
{
KisUsageLogger::log(QString("Saving canceled. Error:").arg(errMsg));
if (!errMsg.isEmpty()) { // empty when canceled by user
QMessageBox::critical(this, i18nc("@title:window", "Krita"), errMsg);
}
slotSaveCompleted();
}
void KisMainWindow::slotSaveCompleted()
{
KisUsageLogger::log(QString("Saving Completed"));
KisDocument* doc = qobject_cast<KisDocument*>(sender());
Q_ASSERT(doc);
disconnect(doc, SIGNAL(completed()), this, SLOT(slotSaveCompleted()));
disconnect(doc, SIGNAL(canceled(QString)), this, SLOT(slotSaveCanceled(QString)));
if (d->deferredClosingEvent) {
KXmlGuiWindow::closeEvent(d->deferredClosingEvent);
}
}
bool KisMainWindow::hackIsSaving() const
{
StdLockableWrapper<QMutex> wrapper(&d->savingEntryMutex);
std::unique_lock<StdLockableWrapper<QMutex>> l(wrapper, std::try_to_lock);
return !l.owns_lock();
}
bool KisMainWindow::installBundle(const QString &fileName) const
{
QFileInfo from(fileName);
QFileInfo to(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/bundles/" + from.fileName());
if (to.exists()) {
QFile::remove(to.canonicalFilePath());
}
return QFile::copy(fileName, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/bundles/" + from.fileName());
}
QImage KisMainWindow::layoutThumbnail()
{
int size = 256;
qreal scale = qreal(size)/qreal(qMax(geometry().width(), geometry().height()));
QImage layoutThumbnail = QImage(qRound(geometry().width()*scale), qRound(geometry().height()*scale), QImage::Format_ARGB32);
QPainter gc(&layoutThumbnail);
gc.fillRect(0, 0, layoutThumbnail.width(), layoutThumbnail.height(), this->palette().dark());
for (int childW = 0; childW< children().size(); childW++) {
if (children().at(childW)->isWidgetType()) {
QWidget *w = dynamic_cast<QWidget*>(children().at(childW));
if (w->isVisible()) {
QRect wRect = QRectF(w->geometry().x()*scale
, w->geometry().y()*scale
, w->geometry().width()*scale
, w->geometry().height()*scale
).toRect();
wRect = wRect.intersected(layoutThumbnail.rect().adjusted(-1, -1, -1, -1));
gc.setBrush(this->palette().window());
if (w == d->widgetStack) {
gc.setBrush(d->mdiArea->background());
}
gc.setPen(this->palette().windowText().color());
gc.drawRect(wRect);
}
}
}
gc.end();
return layoutThumbnail;
}
bool KisMainWindow::saveDocument(KisDocument *document, bool saveas, bool isExporting)
{
if (!document) {
return true;
}
/**
* Make sure that we cannot enter this method twice!
*
* The lower level functions may call processEvents() so
* double-entry is quite possible to achieve. Here we try to lock
* the mutex, and if it is failed, just cancel saving.
*/
StdLockableWrapper<QMutex> wrapper(&d->savingEntryMutex);
std::unique_lock<StdLockableWrapper<QMutex>> l(wrapper, std::try_to_lock);
if (!l.owns_lock()) return false;
// no busy wait for saving because it is dangerous!
KisDelayedSaveDialog dlg(document->image(), KisDelayedSaveDialog::SaveDialog, 0, this);
dlg.blockIfImageIsBusy();
if (dlg.result() == KisDelayedSaveDialog::Rejected) {
return false;
}
else if (dlg.result() == KisDelayedSaveDialog::Ignored) {
QMessageBox::critical(0,
i18nc("@title:window", "Krita"),
i18n("You are saving a file while the image is "
"still rendering. The saved file may be "
"incomplete or corrupted.\n\n"
"Please select a location where the original "
"file will not be overridden!"));
saveas = true;
}
if (document->isRecovered()) {
saveas = true;
}
if (document->url().isEmpty()) {
saveas = true;
}
connect(document, SIGNAL(completed()), this, SLOT(slotSaveCompleted()));
connect(document, SIGNAL(canceled(QString)), this, SLOT(slotSaveCanceled(QString)));
QByteArray nativeFormat = document->nativeFormatMimeType();
QByteArray oldMimeFormat = document->mimeType();
QUrl suggestedURL = document->url();
QStringList mimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export);
mimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export);
if (!mimeFilter.contains(oldMimeFormat)) {
dbgUI << "KisMainWindow::saveDocument no export filter for" << oldMimeFormat;
// --- don't setOutputMimeType in case the user cancels the Save As
// dialog and then tries to just plain Save ---
// suggest a different filename extension (yes, we fortunately don't all live in a world of magic :))
QString suggestedFilename = QFileInfo(suggestedURL.toLocalFile()).completeBaseName();
if (!suggestedFilename.isEmpty()) { // ".kra" looks strange for a name
suggestedFilename = suggestedFilename + "." + KisMimeDatabase::suffixesForMimeType(KIS_MIME_TYPE).first();
suggestedURL = suggestedURL.adjusted(QUrl::RemoveFilename);
suggestedURL.setPath(suggestedURL.path() + suggestedFilename);
}
// force the user to choose outputMimeType
saveas = true;
}
bool ret = false;
if (document->url().isEmpty() || isExporting || saveas) {
// if you're just File/Save As'ing to change filter options you
// don't want to be reminded about overwriting files etc.
bool justChangingFilterOptions = false;
KoFileDialog dialog(this, KoFileDialog::SaveFile, "SaveAs");
dialog.setCaption(isExporting ? i18n("Exporting") : i18n("Saving As"));
//qDebug() << ">>>>>" << isExporting << d->lastExportLocation << d->lastExportedFormat << QString::fromLatin1(document->mimeType());
if (isExporting && !d->lastExportLocation.isEmpty() && !d->lastExportLocation.contains(QDir::tempPath())) {
// Use the location where we last exported to, if it's set, as the opening location for the file dialog
QString proposedPath = QFileInfo(d->lastExportLocation).absolutePath();
// If the document doesn't have a filename yet, use the title
QString proposedFileName = suggestedURL.isEmpty() ? document->documentInfo()->aboutInfo("title") : QFileInfo(suggestedURL.toLocalFile()).completeBaseName();
// Use the last mimetype we exported to by default
QString proposedMimeType = d->lastExportedFormat.isEmpty() ? "" : d->lastExportedFormat;
QString proposedExtension = KisMimeDatabase::suffixesForMimeType(proposedMimeType).first().remove("*,");
// Set the default dir: this overrides the one loaded from the config file, since we're exporting and the lastExportLocation is not empty
dialog.setDefaultDir(proposedPath + "/" + proposedFileName + "." + proposedExtension, true);
dialog.setMimeTypeFilters(mimeFilter, proposedMimeType);
}
else {
// Get the last used location for saving
KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs");
QString proposedPath = group.readEntry("SaveAs", "");
// if that is empty, get the last used location for loading
if (proposedPath.isEmpty()) {
proposedPath = group.readEntry("OpenDocument", "");
}
// If that is empty, too, use the Pictures location.
if (proposedPath.isEmpty()) {
proposedPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
}
// But only use that if the suggestedUrl, that is, the document's own url is empty, otherwise
// open the location where the document currently is.
dialog.setDefaultDir(suggestedURL.isEmpty() ? proposedPath : suggestedURL.toLocalFile(), true);
// If exporting, default to all supported file types if user is exporting
QByteArray default_mime_type = "";
if (!isExporting) {
// otherwise use the document's mimetype, or if that is empty, kra, which is the savest.
default_mime_type = document->mimeType().isEmpty() ? nativeFormat : document->mimeType();
}
dialog.setMimeTypeFilters(mimeFilter, QString::fromLatin1(default_mime_type));
}
QUrl newURL = QUrl::fromUserInput(dialog.filename());
if (newURL.isLocalFile()) {
QString fn = newURL.toLocalFile();
if (QFileInfo(fn).completeSuffix().isEmpty()) {
fn.append(KisMimeDatabase::suffixesForMimeType(nativeFormat).first());
newURL = QUrl::fromLocalFile(fn);
}
}
if (document->documentInfo()->aboutInfo("title") == i18n("Unnamed")) {
QString fn = newURL.toLocalFile();
QFileInfo info(fn);
document->documentInfo()->setAboutInfo("title", info.completeBaseName());
}
QByteArray outputFormat = nativeFormat;
QString outputFormatString = KisMimeDatabase::mimeTypeForFile(newURL.toLocalFile(), false);
outputFormat = outputFormatString.toLatin1();
if (!isExporting) {
justChangingFilterOptions = (newURL == document->url()) && (outputFormat == document->mimeType());
}
else {
QString path = QFileInfo(d->lastExportLocation).absolutePath();
QString filename = QFileInfo(document->url().toLocalFile()).completeBaseName();
justChangingFilterOptions = (QFileInfo(newURL.toLocalFile()).absolutePath() == path)
&& (QFileInfo(newURL.toLocalFile()).completeBaseName() == filename)
&& (outputFormat == d->lastExportedFormat);
}
bool bOk = true;
if (newURL.isEmpty()) {
bOk = false;
}
if (bOk) {
bool wantToSave = true;
// don't change this line unless you know what you're doing :)
if (!justChangingFilterOptions) {
if (!document->isNativeFormat(outputFormat))
wantToSave = true;
}
if (wantToSave) {
if (!isExporting) { // Save As
ret = document->saveAs(newURL, outputFormat, true);
if (ret) {
dbgUI << "Successful Save As!";
KisPart::instance()->addRecentURLToAllMainWindows(newURL);
setReadWrite(true);
} else {
dbgUI << "Failed Save As!";
}
}
else { // Export
ret = document->exportDocument(newURL, outputFormat);
if (ret) {
d->lastExportLocation = newURL.toLocalFile();
d->lastExportedFormat = outputFormat;
}
}
} // if (wantToSave) {
else
ret = false;
} // if (bOk) {
else
ret = false;
} else { // saving
// We cannot "export" into the currently
// opened document. We are not Gimp.
KIS_ASSERT_RECOVER_NOOP(!isExporting);
// be sure document has the correct outputMimeType!
if (document->isModified()) {
ret = document->save(true, 0);
}
if (!ret) {
dbgUI << "Failed Save!";
}
}
- updateReloadFileAction(document);
updateCaption();
return ret;
}
void KisMainWindow::undo()
{
if (activeView()) {
activeView()->document()->undoStack()->undo();
}
}
void KisMainWindow::redo()
{
if (activeView()) {
activeView()->document()->undoStack()->redo();
}
}
void KisMainWindow::closeEvent(QCloseEvent *e)
{
if (hackIsSaving()) {
e->setAccepted(false);
return;
}
if (!KisPart::instance()->closingSession()) {
QAction *action= d->viewManager->actionCollection()->action("view_show_canvas_only");
if ((action) && (action->isChecked())) {
action->setChecked(false);
}
// Save session when last window is closed
if (KisPart::instance()->mainwindowCount() == 1) {
bool closeAllowed = KisPart::instance()->closeSession();
if (!closeAllowed) {
e->setAccepted(false);
return;
}
}
}
d->mdiArea->closeAllSubWindows();
QList<QMdiSubWindow*> childrenList = d->mdiArea->subWindowList();
if (childrenList.isEmpty()) {
d->deferredClosingEvent = e;
saveWindowState(true);
d->canvasWindow->close();
} else {
e->setAccepted(false);
}
}
void KisMainWindow::saveWindowSettings()
{
KSharedConfigPtr config = KSharedConfig::openConfig();
if (d->windowSizeDirty ) {
dbgUI << "KisMainWindow::saveWindowSettings";
KConfigGroup group = d->windowStateConfig;
KWindowConfig::saveWindowSize(windowHandle(), group);
config->sync();
d->windowSizeDirty = false;
}
if (!d->activeView || d->activeView->document()) {
// Save toolbar position into the config file of the app, under the doc's component name
KConfigGroup group = d->windowStateConfig;
saveMainWindowSettings(group);
// Save collapsible state of dock widgets
for (QMap<QString, QDockWidget*>::const_iterator i = d->dockWidgetsMap.constBegin();
i != d->dockWidgetsMap.constEnd(); ++i) {
if (i.value()->widget()) {
KConfigGroup dockGroup = group.group(QString("DockWidget ") + i.key());
dockGroup.writeEntry("Collapsed", i.value()->widget()->isHidden());
dockGroup.writeEntry("Locked", i.value()->property("Locked").toBool());
dockGroup.writeEntry("DockArea", (int) dockWidgetArea(i.value()));
dockGroup.writeEntry("xPosition", (int) i.value()->widget()->x());
dockGroup.writeEntry("yPosition", (int) i.value()->widget()->y());
dockGroup.writeEntry("width", (int) i.value()->widget()->width());
dockGroup.writeEntry("height", (int) i.value()->widget()->height());
}
}
}
KSharedConfig::openConfig()->sync();
resetAutoSaveSettings(); // Don't let KMainWindow override the good stuff we wrote down
}
void KisMainWindow::resizeEvent(QResizeEvent * e)
{
d->windowSizeDirty = true;
KXmlGuiWindow::resizeEvent(e);
}
void KisMainWindow::setActiveView(KisView* view)
{
d->activeView = view;
updateCaption();
if (d->undoActionsUpdateManager) {
d->undoActionsUpdateManager->setCurrentDocument(view ? view->document() : 0);
}
d->viewManager->setCurrentView(view);
KisWindowLayoutManager::instance()->activeDocumentChanged(view->document());
}
void KisMainWindow::dragMove(QDragMoveEvent * event)
{
QTabBar *tabBar = d->findTabBarHACK();
if (!tabBar && d->mdiArea->viewMode() == QMdiArea::TabbedView) {
qWarning() << "WARNING!!! Cannot find QTabBar in the main window! Looks like Qt has changed behavior. Drag & Drop between multiple tabs might not work properly (tabs will not switch automatically)!";
}
if (tabBar && tabBar->isVisible()) {
QPoint pos = tabBar->mapFromGlobal(mapToGlobal(event->pos()));
if (tabBar->rect().contains(pos)) {
const int tabIndex = tabBar->tabAt(pos);
if (tabIndex >= 0 && tabBar->currentIndex() != tabIndex) {
d->tabSwitchCompressor->start(tabIndex);
}
} else if (d->tabSwitchCompressor->isActive()) {
d->tabSwitchCompressor->stop();
}
}
}
void KisMainWindow::dragLeave()
{
if (d->tabSwitchCompressor->isActive()) {
d->tabSwitchCompressor->stop();
}
}
void KisMainWindow::switchTab(int index)
{
QTabBar *tabBar = d->findTabBarHACK();
if (!tabBar) return;
tabBar->setCurrentIndex(index);
}
void KisMainWindow::showWelcomeScreen(bool show)
{
d->widgetStack->setCurrentIndex(!show);
}
void KisMainWindow::slotFileNew()
{
const QStringList mimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Import);
KisOpenPane *startupWidget = new KisOpenPane(this, mimeFilter, QStringLiteral("templates/"));
startupWidget->setWindowModality(Qt::WindowModal);
startupWidget->setWindowTitle(i18n("Create new document"));
KisConfig cfg(true);
int w = cfg.defImageWidth();
int h = cfg.defImageHeight();
const double resolution = cfg.defImageResolution();
const QString colorModel = cfg.defColorModel();
const QString colorDepth = cfg.defaultColorDepth();
const QString colorProfile = cfg.defColorProfile();
CustomDocumentWidgetItem item;
item.widget = new KisCustomImageWidget(startupWidget,
w,
h,
resolution,
colorModel,
colorDepth,
colorProfile,
i18n("Unnamed"));
item.icon = "document-new";
item.title = i18n("Custom Document");
startupWidget->addCustomDocumentWidget(item.widget, item.title, "Custom Document", item.icon);
QSize sz = KisClipboard::instance()->clipSize();
if (sz.isValid() && sz.width() != 0 && sz.height() != 0) {
w = sz.width();
h = sz.height();
}
item.widget = new KisImageFromClipboard(startupWidget,
w,
h,
resolution,
colorModel,
colorDepth,
colorProfile,
i18n("Unnamed"));
item.title = i18n("Create from Clipboard");
item.icon = "tab-new";
startupWidget->addCustomDocumentWidget(item.widget, item.title, "Create from ClipBoard", item.icon);
// calls deleteLater
connect(startupWidget, SIGNAL(documentSelected(KisDocument*)), KisPart::instance(), SLOT(startCustomDocument(KisDocument*)));
// calls deleteLater
connect(startupWidget, SIGNAL(openTemplate(QUrl)), KisPart::instance(), SLOT(openTemplate(QUrl)));
startupWidget->exec();
// Cancel calls deleteLater...
}
void KisMainWindow::slotImportFile()
{
dbgUI << "slotImportFile()";
slotFileOpen(true);
}
void KisMainWindow::slotFileOpen(bool isImporting)
{
#ifndef Q_OS_ANDROID
QStringList urls = showOpenFileDialog(isImporting);
if (urls.isEmpty())
return;
Q_FOREACH (const QString& url, urls) {
if (!url.isEmpty()) {
OpenFlags flags = isImporting ? Import : None;
bool res = openDocument(QUrl::fromLocalFile(url), flags);
if (!res) {
warnKrita << "Loading" << url << "failed";
}
}
}
#else
Q_UNUSED(isImporting)
d->fileManager->openImportFile();
connect(d->fileManager, SIGNAL(sigFileSelected(QString)), this, SLOT(slotFileSelected(QString)));
connect(d->fileManager, SIGNAL(sigEmptyFilePath()), this, SLOT(slotEmptyFilePath()));
#endif
}
void KisMainWindow::slotFileOpenRecent(const QUrl &url)
{
(void) openDocument(QUrl::fromLocalFile(url.toLocalFile()), None);
}
void KisMainWindow::slotFileSave()
{
if (saveDocument(d->activeView->document(), false, false)) {
emit documentSaved();
}
}
void KisMainWindow::slotFileSaveAs()
{
if (saveDocument(d->activeView->document(), true, false)) {
emit documentSaved();
}
}
void KisMainWindow::slotExportFile()
{
if (saveDocument(d->activeView->document(), true, true)) {
emit documentSaved();
}
}
void KisMainWindow::slotShowSessionManager() {
KisPart::instance()->showSessionManager();
}
KoCanvasResourceProvider *KisMainWindow::resourceManager() const
{
return d->viewManager->canvasResourceProvider()->resourceManager();
}
int KisMainWindow::viewCount() const
{
return d->mdiArea->subWindowList().size();
}
const KConfigGroup &KisMainWindow::windowStateConfig() const
{
return d->windowStateConfig;
}
void KisMainWindow::saveWindowState(bool restoreNormalState)
{
if (restoreNormalState) {
QAction *showCanvasOnly = d->viewManager->actionCollection()->action("view_show_canvas_only");
if (showCanvasOnly && showCanvasOnly->isChecked()) {
showCanvasOnly->setChecked(false);
}
d->windowStateConfig.writeEntry("ko_geometry", saveGeometry().toBase64());
d->windowStateConfig.writeEntry("State", saveState().toBase64());
if (!d->dockerStateBeforeHiding.isEmpty()) {
restoreState(d->dockerStateBeforeHiding);
}
statusBar()->setVisible(true);
menuBar()->setVisible(true);
saveWindowSettings();
} else {
saveMainWindowSettings(d->windowStateConfig);
}
}
bool KisMainWindow::restoreWorkspaceState(const QByteArray &state)
{
QByteArray oldState = saveState();
// needed because otherwise the layout isn't correctly restored in some situations
Q_FOREACH (QDockWidget *dock, dockWidgets()) {
dock->toggleViewAction()->setEnabled(true);
dock->hide();
}
bool success = KXmlGuiWindow::restoreState(state);
if (!success) {
KXmlGuiWindow::restoreState(oldState);
return false;
}
return success;
}
bool KisMainWindow::restoreWorkspace(int workspaceId)
{
KisWorkspaceResourceSP workspace =
KisResourceModelProvider::resourceModel(ResourceType::Workspaces)
->resourceForId(workspaceId).dynamicCast<KisWorkspaceResource>();
bool success = restoreWorkspaceState(workspace->dockerState());
if (activeKisView()) {
activeKisView()->resourceProvider()->notifyLoadingWorkspace(workspace);
}
return success;
}
QByteArray KisMainWindow::borrowWorkspace(KisMainWindow *other)
{
QByteArray currentWorkspace = saveState();
if (!d->workspaceBorrowedBy.isNull()) {
if (other->id() == d->workspaceBorrowedBy) {
// We're swapping our original workspace back
d->workspaceBorrowedBy = QUuid();
return currentWorkspace;
} else {
// Get our original workspace back before swapping with a third window
KisMainWindow *borrower = KisPart::instance()->windowById(d->workspaceBorrowedBy);
if (borrower) {
QByteArray originalLayout = borrower->borrowWorkspace(this);
borrower->restoreWorkspaceState(currentWorkspace);
d->workspaceBorrowedBy = other->id();
return originalLayout;
}
}
}
d->workspaceBorrowedBy = other->id();
return currentWorkspace;
}
void KisMainWindow::swapWorkspaces(KisMainWindow *a, KisMainWindow *b)
{
QByteArray workspaceA = a->borrowWorkspace(b);
QByteArray workspaceB = b->borrowWorkspace(a);
a->restoreWorkspaceState(workspaceB);
b->restoreWorkspaceState(workspaceA);
}
KisViewManager *KisMainWindow::viewManager() const
{
return d->viewManager;
}
void KisMainWindow::slotDocumentInfo()
{
if (!d->activeView->document())
return;
KoDocumentInfo *docInfo = d->activeView->document()->documentInfo();
if (!docInfo)
return;
KoDocumentInfoDlg *dlg = d->activeView->document()->createDocumentInfoDialog(this, docInfo);
if (dlg->exec()) {
if (dlg->isDocumentSaved()) {
d->activeView->document()->setModified(false);
} else {
d->activeView->document()->setModified(true);
}
d->activeView->document()->setTitleModified();
}
delete dlg;
}
bool KisMainWindow::slotFileCloseAll()
{
Q_FOREACH (QMdiSubWindow *subwin, d->mdiArea->subWindowList()) {
if (subwin) {
if(!subwin->close())
return false;
}
}
updateCaption();
return true;
}
void KisMainWindow::slotFileQuit()
{
// Do not close while KisMainWindow has the savingEntryMutex locked, bug409395.
// After the background saving job is initiated, KisDocument blocks closing
// while it saves itself.
if (hackIsSaving()) {
return;
}
KisPart::instance()->closeSession();
}
-void KisMainWindow::slotFilePrint()
-{
- if (!activeView())
- return;
- KisPrintJob *printJob = activeView()->createPrintJob();
- if (printJob == 0)
- return;
- applyDefaultSettings(printJob->printer());
- QPrintDialog *printDialog = activeView()->createPrintDialog( printJob, this );
- if (printDialog && printDialog->exec() == QDialog::Accepted) {
- printJob->printer().setPageMargins(0.0, 0.0, 0.0, 0.0, QPrinter::Point);
- printJob->printer().setPaperSize(QSizeF(activeView()->image()->width() / (72.0 * activeView()->image()->xRes()),
- activeView()->image()->height()/ (72.0 * activeView()->image()->yRes())),
- QPrinter::Inch);
- printJob->startPrinting(KisPrintJob::DeleteWhenDone);
- }
- else {
- delete printJob;
- }
- delete printDialog;
-}
-
-void KisMainWindow::slotFilePrintPreview()
-{
- if (!activeView())
- return;
- KisPrintJob *printJob = activeView()->createPrintJob();
- if (printJob == 0)
- return;
-
- /* Sets the startPrinting() slot to be blocking.
- The Qt print-preview dialog requires the printing to be completely blocking
- and only return when the full document has been printed.
- By default the KisPrintingDialog is non-blocking and
- multithreading, setting blocking to true will allow it to be used in the preview dialog */
- printJob->setProperty("blocking", true);
- QPrintPreviewDialog *preview = new QPrintPreviewDialog(&printJob->printer(), this);
- printJob->setParent(preview); // will take care of deleting the job
- connect(preview, SIGNAL(paintRequested(QPrinter*)), printJob, SLOT(startPrinting()));
- preview->exec();
- delete preview;
-}
-
-KisPrintJob* KisMainWindow::exportToPdf(QString pdfFileName)
-{
- if (!activeView())
- return 0;
-
- if (!activeView()->document())
- return 0;
-
- KoPageLayout pageLayout;
- pageLayout.width = 0;
- pageLayout.height = 0;
- pageLayout.topMargin = 0;
- pageLayout.bottomMargin = 0;
- pageLayout.leftMargin = 0;
- pageLayout.rightMargin = 0;
-
- if (pdfFileName.isEmpty()) {
- KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs");
- QString defaultDir = group.readEntry("SavePdfDialog");
- if (defaultDir.isEmpty())
- defaultDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
- QUrl startUrl = QUrl::fromLocalFile(defaultDir);
- KisDocument* pDoc = d->activeView->document();
- /** if document has a file name, take file name and replace extension with .pdf */
- if (pDoc && pDoc->url().isValid()) {
- startUrl = pDoc->url();
- QString fileName = startUrl.toLocalFile();
- fileName = fileName.replace( QRegExp( "\\.\\w{2,5}$", Qt::CaseInsensitive ), ".pdf" );
- startUrl = startUrl.adjusted(QUrl::RemoveFilename);
- startUrl.setPath(startUrl.path() + fileName );
- }
-
- QPointer<KoPageLayoutDialog> layoutDlg(new KoPageLayoutDialog(this, pageLayout));
- layoutDlg->setWindowModality(Qt::WindowModal);
- if (layoutDlg->exec() != QDialog::Accepted || !layoutDlg) {
- delete layoutDlg;
- return 0;
- }
- pageLayout = layoutDlg->pageLayout();
- delete layoutDlg;
-
- KoFileDialog dialog(this, KoFileDialog::SaveFile, "OpenDocument");
- dialog.setCaption(i18n("Export as PDF"));
- dialog.setDefaultDir(startUrl.toLocalFile());
- dialog.setMimeTypeFilters(QStringList() << "application/pdf");
- QUrl url = QUrl::fromUserInput(dialog.filename());
-
- pdfFileName = url.toLocalFile();
- if (pdfFileName.isEmpty())
- return 0;
- }
-
- KisPrintJob *printJob = activeView()->createPrintJob();
- if (printJob == 0)
- return 0;
- if (isHidden()) {
- printJob->setProperty("noprogressdialog", true);
- }
-
- applyDefaultSettings(printJob->printer());
- // TODO for remote files we have to first save locally and then upload.
- printJob->printer().setOutputFileName(pdfFileName);
- printJob->printer().setDocName(pdfFileName);
- printJob->printer().setColorMode(QPrinter::Color);
-
- if (pageLayout.format == KoPageFormat::CustomSize) {
- printJob->printer().setPaperSize(QSizeF(pageLayout.width, pageLayout.height), QPrinter::Millimeter);
- } else {
- printJob->printer().setPaperSize(KoPageFormat::printerPageSize(pageLayout.format));
- }
-
- printJob->printer().setPageMargins(pageLayout.leftMargin, pageLayout.topMargin, pageLayout.rightMargin, pageLayout.bottomMargin, QPrinter::Millimeter);
-
- switch (pageLayout.orientation) {
- case KoPageFormat::Portrait:
- printJob->printer().setOrientation(QPrinter::Portrait);
- break;
- case KoPageFormat::Landscape:
- printJob->printer().setOrientation(QPrinter::Landscape);
- break;
- }
-
- //before printing check if the printer can handle printing
- if (!printJob->canPrint()) {
- QMessageBox::critical(this, i18nc("@title:window", "Krita"), i18n("Cannot export to the specified file"));
- }
-
- printJob->startPrinting(KisPrintJob::DeleteWhenDone);
- return printJob;
-}
-
void KisMainWindow::importAnimation()
{
if (!activeView()) return;
KisDocument *document = activeView()->document();
if (!document) return;
KisDlgImportImageSequence dlg(this, document);
if (dlg.exec() == QDialog::Accepted) {
QStringList files = dlg.files();
int firstFrame = dlg.firstFrame();
int step = dlg.step();
KoUpdaterPtr updater =
!document->fileBatchMode() ? viewManager()->createUnthreadedUpdater(i18n("Import frames")) : 0;
KisAnimationImporter importer(document->image(), updater);
KisImportExportErrorCode status = importer.import(files, firstFrame, step);
if (!status.isOk() && !status.isInternalError()) {
QString msg = status.errorMessage();
if (!msg.isEmpty())
QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not finish import animation:\n%1", msg));
}
activeView()->canvasBase()->refetchDataFromImage();
}
}
void KisMainWindow::slotConfigureToolbars()
{
saveWindowState();
KEditToolBar edit(factory(), this);
connect(&edit, SIGNAL(newToolBarConfig()), this, SLOT(slotNewToolbarConfig()));
(void) edit.exec();
applyToolBarLayout();
}
void KisMainWindow::slotResetConfigurations()
{
KisApplication *kisApp = static_cast<KisApplication*>(qApp);
kisApp->askresetConfig();
}
void KisMainWindow::slotNewToolbarConfig()
{
applyMainWindowSettings(d->windowStateConfig);
KXMLGUIFactory *factory = guiFactory();
Q_UNUSED(factory);
// Check if there's an active view
if (!d->activeView)
return;
plugActionList("toolbarlist", d->toolbarList);
applyToolBarLayout();
}
void KisMainWindow::slotToolbarToggled(bool toggle)
{
//dbgUI <<"KisMainWindow::slotToolbarToggled" << sender()->name() <<" toggle=" << true;
// The action (sender) and the toolbar have the same name
KToolBar * bar = toolBar(sender()->objectName());
if (bar) {
if (toggle) {
bar->show();
}
else {
bar->hide();
}
if (d->activeView && d->activeView->document()) {
saveWindowState();
}
} else
warnUI << "slotToolbarToggled : Toolbar " << sender()->objectName() << " not found!";
}
void KisMainWindow::viewFullscreen(bool fullScreen)
{
KisConfig cfg(false);
cfg.setFullscreenMode(fullScreen);
if (fullScreen) {
setWindowState(windowState() | Qt::WindowFullScreen); // set
} else {
setWindowState(windowState() & ~Qt::WindowFullScreen); // reset
}
d->fullScreenMode->setChecked(isFullScreen());
}
void KisMainWindow::setMaxRecentItems(uint _number)
{
d->recentFiles->setMaxItems(_number);
}
-void KisMainWindow::slotReloadFile()
-{
- KisDocument* document = d->activeView->document();
- if (!document || document->url().isEmpty())
- return;
-
- if (document->isModified()) {
- bool ok = QMessageBox::question(this,
- i18nc("@title:window", "Krita"),
- i18n("You will lose all changes made since your last save\n"
- "Do you want to continue?"),
- QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes;
- if (!ok)
- return;
- }
-
- QUrl url = document->url();
-
- saveWindowSettings();
- if (!document->reload()) {
- QMessageBox::critical(this, i18nc("@title:window", "Krita"), i18n("Error: Could not reload this document"));
- }
-
- return;
-
-}
-
QDockWidget* KisMainWindow::createDockWidget(KoDockFactoryBase* factory)
{
QDockWidget* dockWidget = 0;
bool lockAllDockers = KisConfig(true).readEntry<bool>("LockAllDockerPanels", false);
if (!d->dockWidgetsMap.contains(factory->id())) {
dockWidget = factory->createDockWidget();
// It is quite possible that a dock factory cannot create the dock; don't
// do anything in that case.
if (!dockWidget) {
warnKrita << "Could not create docker for" << factory->id();
return 0;
}
dockWidget->setFont(KoDockRegistry::dockFont());
dockWidget->setObjectName(factory->id());
dockWidget->setParent(this);
if (lockAllDockers) {
if (dockWidget->titleBarWidget()) {
dockWidget->titleBarWidget()->setVisible(false);
}
dockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures);
}
if (dockWidget->widget() && dockWidget->widget()->layout())
dockWidget->widget()->layout()->setContentsMargins(1, 1, 1, 1);
Qt::DockWidgetArea side = Qt::RightDockWidgetArea;
bool visible = true;
switch (factory->defaultDockPosition()) {
case KoDockFactoryBase::DockTornOff:
dockWidget->setFloating(true); // position nicely?
break;
case KoDockFactoryBase::DockTop:
side = Qt::TopDockWidgetArea; break;
case KoDockFactoryBase::DockLeft:
side = Qt::LeftDockWidgetArea; break;
case KoDockFactoryBase::DockBottom:
side = Qt::BottomDockWidgetArea; break;
case KoDockFactoryBase::DockRight:
side = Qt::RightDockWidgetArea; break;
case KoDockFactoryBase::DockMinimized:
default:
side = Qt::RightDockWidgetArea;
visible = false;
}
KConfigGroup group = d->windowStateConfig.group("DockWidget " + factory->id());
side = static_cast<Qt::DockWidgetArea>(group.readEntry("DockArea", static_cast<int>(side)));
if (side == Qt::NoDockWidgetArea) side = Qt::RightDockWidgetArea;
addDockWidget(side, dockWidget);
if (!visible) {
dockWidget->hide();
}
d->dockWidgetsMap.insert(factory->id(), dockWidget);
}
else {
dockWidget = d->dockWidgetsMap[factory->id()];
}
#ifdef Q_OS_MACOS
dockWidget->setAttribute(Qt::WA_MacSmallSize, true);
#endif
dockWidget->setFont(KoDockRegistry::dockFont());
connect(dockWidget, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(forceDockTabFonts()));
return dockWidget;
}
void KisMainWindow::forceDockTabFonts()
{
Q_FOREACH (QObject *child, children()) {
if (child->inherits("QTabBar")) {
((QTabBar *)child)->setFont(KoDockRegistry::dockFont());
}
}
}
+void KisMainWindow::slotUpdateWidgetStyle()
+{
+ KisConfig cfg(true);
+ QString themeFromConfig = cfg.widgetStyle();
+
+ Q_FOREACH (auto key, d->actionMap.keys()) { // find checked style to save to config
+ if(d->actionMap.value(key)->isChecked()) {
+ cfg.setWidgetStyle(key);
+ qApp->setStyle(key);
+ }
+ }
+}
+
QList<QDockWidget*> KisMainWindow::dockWidgets() const
{
return d->dockWidgetsMap.values();
}
QDockWidget* KisMainWindow::dockWidget(const QString &id)
{
if (!d->dockWidgetsMap.contains(id)) return 0;
return d->dockWidgetsMap[id];
}
QList<KoCanvasObserverBase*> KisMainWindow::canvasObservers() const
{
QList<KoCanvasObserverBase*> observers;
Q_FOREACH (QDockWidget *docker, dockWidgets()) {
KoCanvasObserverBase *observer = dynamic_cast<KoCanvasObserverBase*>(docker);
if (observer) {
observers << observer;
}
else {
warnKrita << docker << "is not a canvas observer";
}
}
return observers;
}
void KisMainWindow::toggleDockersVisibility(bool visible)
{
if (!visible) {
d->dockerStateBeforeHiding = saveState();
Q_FOREACH (QObject* widget, children()) {
if (widget->inherits("QDockWidget")) {
QDockWidget* dw = static_cast<QDockWidget*>(widget);
if (dw->isVisible()) {
dw->hide();
}
}
}
}
else {
restoreState(d->dockerStateBeforeHiding);
}
}
void KisMainWindow::slotDocumentTitleModified()
{
updateCaption();
- updateReloadFileAction(d->activeView ? d->activeView->document() : 0);
}
void KisMainWindow::subWindowActivated()
{
bool enabled = (activeKisView() != 0);
d->mdiCascade->setEnabled(enabled);
d->mdiNextWindow->setEnabled(enabled);
d->mdiPreviousWindow->setEnabled(enabled);
d->mdiTile->setEnabled(enabled);
d->close->setEnabled(enabled);
d->closeAll->setEnabled(enabled);
setActiveSubWindow(d->mdiArea->activeSubWindow());
Q_FOREACH (QToolBar *tb, toolBars()) {
if (tb->objectName() == "BrushesAndStuff") {
tb->setEnabled(enabled);
}
}
/**
* Qt has a weirdness, it has hardcoded shortcuts added to an action
* in the window menu. We need to reset the shortcuts for that menu
* to nothing, otherwise the shortcuts cannot be made configurable.
*
* See: https://bugs.kde.org/show_bug.cgi?id=352205
* https://bugs.kde.org/show_bug.cgi?id=375524
* https://bugs.kde.org/show_bug.cgi?id=398729
*/
QMdiSubWindow *subWindow = d->mdiArea->currentSubWindow();
if (subWindow) {
QMenu *menu = subWindow->systemMenu();
if (menu && menu->actions().size() == 8) {
Q_FOREACH (QAction *action, menu->actions()) {
action->setShortcut(QKeySequence());
}
menu->actions().last()->deleteLater();
}
}
updateCaption();
d->actionManager()->updateGUI();
}
void KisMainWindow::windowFocused()
{
/**
* Notify selection manager so that it could update selection mask overlay
*/
if (viewManager() && viewManager()->selectionManager()) {
viewManager()->selectionManager()->selectionChanged();
}
KisPart *kisPart = KisPart::instance();
KisWindowLayoutManager *layoutManager = KisWindowLayoutManager::instance();
if (!layoutManager->primaryWorkspaceFollowsFocus()) return;
QUuid primary = layoutManager->primaryWindowId();
if (primary.isNull()) return;
if (d->id == primary) {
if (!d->workspaceBorrowedBy.isNull()) {
KisMainWindow *borrower = kisPart->windowById(d->workspaceBorrowedBy);
if (!borrower) return;
swapWorkspaces(this, borrower);
}
} else {
if (d->workspaceBorrowedBy == primary) return;
KisMainWindow *primaryWindow = kisPart->windowById(primary);
if (!primaryWindow) return;
swapWorkspaces(this, primaryWindow);
}
}
void KisMainWindow::updateWindowMenu()
{
QMenu *menu = d->windowMenu->menu();
menu->clear();
menu->addAction(d->newWindow);
menu->addAction(d->documentMenu);
QMenu *docMenu = d->documentMenu->menu();
docMenu->clear();
QFontMetrics fontMetrics = docMenu->fontMetrics();
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
QRect geom = this->geometry();
QPoint p(geom.width() / 2 + geom.left(), geom.height() / 2 + geom.top());
QScreen *screen = qApp->screenAt(p);
int fileStringWidth = 300;
if (screen) {
fileStringWidth = int(screen->availableGeometry().width() * .40f);
}
#else
int fileStringWidth = int(QApplication::desktop()->screenGeometry(this).width() * .40f);
#endif
Q_FOREACH (QPointer<KisDocument> doc, KisPart::instance()->documents()) {
if (doc) {
QString title = fontMetrics.elidedText(doc->url().toDisplayString(QUrl::PreferLocalFile), Qt::ElideMiddle, fileStringWidth);
if (title.isEmpty() && doc->image()) {
title = doc->image()->objectName();
}
QAction *action = docMenu->addAction(title);
action->setIcon(qApp->windowIcon());
connect(action, SIGNAL(triggered()), d->documentMapper, SLOT(map()));
d->documentMapper->setMapping(action, doc);
}
}
menu->addAction(d->workspaceMenu);
QMenu *workspaceMenu = d->workspaceMenu->menu();
workspaceMenu->clear();
KisResourceIterator resourceIterator(KisResourceModelProvider::resourceModel(ResourceType::Workspaces));
KisMainWindow *m_this = this;
while (resourceIterator.hasNext()) {
KisResourceItemSP resource = resourceIterator.next();
QAction *action = workspaceMenu->addAction(resource->name());
connect(action, &QAction::triggered, this, [=]() {
m_this->restoreWorkspace(resource->id());
});
}
workspaceMenu->addSeparator();
connect(workspaceMenu->addAction(i18nc("@action:inmenu", "&Import Workspace...")),
&QAction::triggered,
this,
[&]()
{
QStringList mimeTypes = KisResourceLoaderRegistry::instance()->mimeTypes(ResourceType::Workspaces);
KoFileDialog dialog(0, KoFileDialog::OpenFile, "OpenDocument");
dialog.setMimeTypeFilters(mimeTypes);
dialog.setCaption(i18nc("@title:window", "Choose File to Add"));
QString filename = dialog.filename();
d->workspacemodel->importResourceFile(filename);
});
connect(workspaceMenu->addAction(i18nc("@action:inmenu", "&New Workspace...")),
&QAction::triggered,
[=]() {
QString name;
auto rserver = KisResourceServerProvider::instance()->workspaceServer();
KisWorkspaceResourceSP workspace(new KisWorkspaceResource(""));
workspace->setDockerState(m_this->saveState());
d->viewManager->canvasResourceProvider()->notifySavingWorkspace(workspace);
workspace->setValid(true);
QString saveLocation = rserver->saveLocation();
QFileInfo fileInfo(saveLocation + name + workspace->defaultFileExtension());
bool fileOverWriteAccepted = false;
while(!fileOverWriteAccepted) {
name = QInputDialog::getText(this, i18nc("@title:window", "New Workspace..."),
i18nc("@label:textbox", "Name:"));
if (name.isNull() || name.isEmpty()) {
return;
} else {
fileInfo = QFileInfo(saveLocation + name.split(" ").join("_") + workspace->defaultFileExtension());
if (fileInfo.exists()) {
int res = QMessageBox::warning(this, i18nc("@title:window", "Name Already Exists")
, i18n("The name '%1' already exists, do you wish to overwrite it?", name)
, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
if (res == QMessageBox::Yes) fileOverWriteAccepted = true;
} else {
fileOverWriteAccepted = true;
}
}
}
workspace->setFilename(fileInfo.fileName());
workspace->setName(name);
rserver->addResource(workspace);
});
// TODO: What to do about delete?
// workspaceMenu->addAction(i18nc("@action:inmenu", "&Delete Workspace..."));
menu->addSeparator();
menu->addAction(d->close);
menu->addAction(d->closeAll);
if (d->mdiArea->viewMode() == QMdiArea::SubWindowView) {
menu->addSeparator();
menu->addAction(d->mdiTile);
menu->addAction(d->mdiCascade);
}
menu->addSeparator();
menu->addAction(d->mdiNextWindow);
menu->addAction(d->mdiPreviousWindow);
menu->addSeparator();
QList<QMdiSubWindow *> windows = d->mdiArea->subWindowList();
for (int i = 0; i < windows.size(); ++i) {
QPointer<KisView>child = qobject_cast<KisView*>(windows.at(i)->widget());
if (child && child->document()) {
QString text;
if (i < 9) {
text = i18n("&%1 %2", i + 1, fontMetrics.elidedText(child->document()->url().toDisplayString(QUrl::PreferLocalFile), Qt::ElideMiddle, fileStringWidth));
}
else {
text = i18n("%1 %2", i + 1, fontMetrics.elidedText(child->document()->url().toDisplayString(QUrl::PreferLocalFile), Qt::ElideMiddle, fileStringWidth));
}
QAction *action = menu->addAction(text);
action->setIcon(qApp->windowIcon());
action->setCheckable(true);
action->setChecked(child == activeKisView());
connect(action, SIGNAL(triggered()), d->windowMapper, SLOT(map()));
d->windowMapper->setMapping(action, windows.at(i));
}
}
bool showMdiArea = windows.count( ) > 0;
if (!showMdiArea) {
showWelcomeScreen(true); // see workaround in function in header
// keep the recent file list updated when going back to welcome screen
reloadRecentFileList();
d->welcomePage->populateRecentDocuments();
}
// enable/disable the toolbox docker if there are no documents open
Q_FOREACH (QObject* widget, children()) {
if (widget->inherits("QDockWidget")) {
QDockWidget* dw = static_cast<QDockWidget*>(widget);
if ( dw->objectName() == "ToolBox") {
dw->setEnabled(showMdiArea);
}
}
}
updateCaption();
}
void KisMainWindow::updateSubwindowFlags()
{
bool onlyOne = false;
if (d->mdiArea->subWindowList().size() == 1 && d->mdiArea->viewMode() == QMdiArea::SubWindowView) {
onlyOne = true;
}
Q_FOREACH (QMdiSubWindow *subwin, d->mdiArea->subWindowList()) {
if (onlyOne) {
subwin->setWindowFlags(subwin->windowFlags() | Qt::FramelessWindowHint);
subwin->showMaximized();
} else {
subwin->setWindowFlags((subwin->windowFlags() | Qt::FramelessWindowHint) ^ Qt::FramelessWindowHint);
}
}
}
void KisMainWindow::setActiveSubWindow(QWidget *window)
{
if (!window) return;
QMdiSubWindow *subwin = qobject_cast<QMdiSubWindow *>(window);
//dbgKrita << "setActiveSubWindow();" << subwin << d->activeSubWindow;
if (subwin && subwin != d->activeSubWindow) {
KisView *view = qobject_cast<KisView *>(subwin->widget());
//dbgKrita << "\t" << view << activeView();
if (view && view != activeView()) {
d->mdiArea->setActiveSubWindow(subwin);
setActiveView(view);
}
d->activeSubWindow = subwin;
}
updateWindowMenu();
d->actionManager()->updateGUI();
}
void KisMainWindow::configChanged()
{
KisConfig cfg(true);
QMdiArea::ViewMode viewMode = (QMdiArea::ViewMode)cfg.readEntry<int>("mdi_viewmode", (int)QMdiArea::TabbedView);
d->mdiArea->setViewMode(viewMode);
Q_FOREACH (QMdiSubWindow *subwin, d->mdiArea->subWindowList()) {
subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.readEntry<int>("mdi_rubberband", cfg.useOpenGL()));
subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.readEntry<int>("mdi_rubberband", cfg.useOpenGL()));
/**
* Dirty workaround for a bug in Qt (checked on Qt 5.6.1):
*
* If you make a window "Show on top" and then switch to the tabbed mode
* the window will continue to be painted in its initial "mid-screen"
* position. It will persist here until you explicitly switch to its tab.
*/
if (viewMode == QMdiArea::TabbedView) {
Qt::WindowFlags oldFlags = subwin->windowFlags();
Qt::WindowFlags flags = oldFlags;
flags &= ~Qt::WindowStaysOnTopHint;
flags &= ~Qt::WindowStaysOnBottomHint;
if (flags != oldFlags) {
subwin->setWindowFlags(flags);
subwin->showMaximized();
}
}
}
#ifdef Q_OS_MACOS
updateSubwindowFlags();
#endif
KConfigGroup group( KSharedConfig::openConfig(), "theme");
d->themeManager->setCurrentTheme(group.readEntry("Theme", "Krita dark"));
d->actionManager()->updateGUI();
QString s = cfg.getMDIBackgroundColor();
KoColor c = KoColor::fromXML(s);
QBrush brush(c.toQColor());
d->mdiArea->setBackground(brush);
QString backgroundImage = cfg.getMDIBackgroundImage();
if (backgroundImage != "") {
QImage image(backgroundImage);
QBrush brush(image);
d->mdiArea->setBackground(brush);
}
d->mdiArea->update();
}
KisView* KisMainWindow::newView(QObject *document, QMdiSubWindow *subWindow)
{
KisDocument *doc = qobject_cast<KisDocument*>(document);
KisView *view = addViewAndNotifyLoadingCompleted(doc, subWindow);
d->actionManager()->updateGUI();
return view;
}
void KisMainWindow::newWindow()
{
KisMainWindow *mainWindow = KisPart::instance()->createMainWindow();
mainWindow->initializeGeometry();
mainWindow->show();
}
void KisMainWindow::closeCurrentWindow()
{
if (d->mdiArea->currentSubWindow()) {
d->mdiArea->currentSubWindow()->close();
d->actionManager()->updateGUI();
}
}
void KisMainWindow::checkSanity()
{
// print error if the lcms engine is not available
if (!KoColorSpaceEngineRegistry::instance()->contains("icc")) {
// need to wait 1 event since exiting here would not work.
m_errorMessage = i18n("The Krita LittleCMS color management plugin is not installed. Krita will quit now.");
m_dieOnError = true;
QTimer::singleShot(0, this, SLOT(showErrorAndDie()));
return;
}
KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer();
if (rserver->resourceCount() == 0) {
m_errorMessage = i18n("Krita cannot find any brush presets! Krita will quit now.");
m_dieOnError = true;
QTimer::singleShot(0, this, SLOT(showErrorAndDie()));
return;
}
}
void KisMainWindow::showErrorAndDie()
{
QMessageBox::critical(0, i18nc("@title:window", "Installation error"), m_errorMessage);
if (m_dieOnError) {
exit(10);
}
}
void KisMainWindow::showAboutApplication()
{
KisAboutApplication dlg(this);
dlg.exec();
}
QPointer<KisView> KisMainWindow::activeKisView()
{
if (!d->mdiArea) return 0;
QMdiSubWindow *activeSubWindow = d->mdiArea->activeSubWindow();
//dbgKrita << "activeKisView" << activeSubWindow;
if (!activeSubWindow) return 0;
return qobject_cast<KisView*>(activeSubWindow->widget());
}
void KisMainWindow::newOptionWidgets(KoCanvasController *controller, const QList<QPointer<QWidget> > &optionWidgetList)
{
KIS_ASSERT_RECOVER_NOOP(controller == KoToolManager::instance()->activeCanvasController());
bool isOurOwnView = false;
Q_FOREACH (QPointer<KisView> view, KisPart::instance()->views()) {
if (view && view->canvasController() == controller) {
isOurOwnView = view->mainWindow() == this;
}
}
if (!isOurOwnView) return;
Q_FOREACH (QWidget *w, optionWidgetList) {
#ifdef Q_OS_MACOS
w->setAttribute(Qt::WA_MacSmallSize, true);
#endif
w->setFont(KoDockRegistry::dockFont());
}
if (d->toolOptionsDocker) {
d->toolOptionsDocker->setOptionWidgets(optionWidgetList);
}
else {
d->viewManager->paintOpBox()->newOptionWidgets(optionWidgetList);
}
}
-void KisMainWindow::applyDefaultSettings(QPrinter &printer) {
-
- if (!d->activeView) return;
-
- QString title = d->activeView->document()->documentInfo()->aboutInfo("title");
- if (title.isEmpty()) {
- QFileInfo info(d->activeView->document()->url().fileName());
- title = info.completeBaseName();
- }
-
- if (title.isEmpty()) {
- // #139905
- title = i18n("%1 unsaved document (%2)", qApp->applicationDisplayName(),
- QLocale().toString(QDate::currentDate(), QLocale::ShortFormat));
- }
- printer.setDocName(title);
-}
-
void KisMainWindow::createActions()
{
KisActionManager *actionManager = d->actionManager();
actionManager->createStandardAction(KStandardAction::New, this, SLOT(slotFileNew()));
actionManager->createStandardAction(KStandardAction::Open, this, SLOT(slotFileOpen()));
actionManager->createStandardAction(KStandardAction::Quit, this, SLOT(slotFileQuit()));
actionManager->createStandardAction(KStandardAction::ConfigureToolbars, this, SLOT(slotConfigureToolbars()));
d->fullScreenMode = actionManager->createStandardAction(KStandardAction::FullScreen, this, SLOT(viewFullscreen(bool)));
d->recentFiles = KStandardAction::openRecent(this, SLOT(slotFileOpenRecent(QUrl)), actionCollection());
connect(d->recentFiles, SIGNAL(recentListCleared()), this, SLOT(saveRecentFiles()));
KSharedConfigPtr configPtr = KSharedConfig::openConfig();
d->recentFiles->loadEntries(configPtr->group("RecentFiles"));
d->saveAction = actionManager->createStandardAction(KStandardAction::Save, this, SLOT(slotFileSave()));
d->saveAction->setActivationFlags(KisAction::ACTIVE_IMAGE);
d->saveActionAs = actionManager->createStandardAction(KStandardAction::SaveAs, this, SLOT(slotFileSaveAs()));
d->saveActionAs->setActivationFlags(KisAction::ACTIVE_IMAGE);
- // d->printAction = actionManager->createStandardAction(KStandardAction::Print, this, SLOT(slotFilePrint()));
- // d->printAction->setActivationFlags(KisAction::ACTIVE_IMAGE);
-
- // d->printActionPreview = actionManager->createStandardAction(KStandardAction::PrintPreview, this, SLOT(slotFilePrintPreview()));
- // d->printActionPreview->setActivationFlags(KisAction::ACTIVE_IMAGE);
-
d->undo = actionManager->createStandardAction(KStandardAction::Undo, this, SLOT(undo()));
d->undo->setActivationFlags(KisAction::ACTIVE_IMAGE);
d->redo = actionManager->createStandardAction(KStandardAction::Redo, this, SLOT(redo()));
d->redo->setActivationFlags(KisAction::ACTIVE_IMAGE);
d->undoActionsUpdateManager.reset(new KisUndoActionsUpdateManager(d->undo, d->redo));
d->undoActionsUpdateManager->setCurrentDocument(d->activeView ? d->activeView->document() : 0);
- // d->exportPdf = actionManager->createAction("file_export_pdf");
- // connect(d->exportPdf, SIGNAL(triggered()), this, SLOT(exportToPdf()));
-
d->importAnimation = actionManager->createAction("file_import_animation");
connect(d->importAnimation, SIGNAL(triggered()), this, SLOT(importAnimation()));
d->closeAll = actionManager->createAction("file_close_all");
connect(d->closeAll, SIGNAL(triggered()), this, SLOT(slotFileCloseAll()));
- // d->reloadFile = actionManager->createAction("file_reload_file");
- // d->reloadFile->setActivationFlags(KisAction::CURRENT_IMAGE_MODIFIED);
- // connect(d->reloadFile, SIGNAL(triggered(bool)), this, SLOT(slotReloadFile()));
-
d->importFile = actionManager->createAction("file_import_file");
connect(d->importFile, SIGNAL(triggered(bool)), this, SLOT(slotImportFile()));
d->exportFile = actionManager->createAction("file_export_file");
connect(d->exportFile, SIGNAL(triggered(bool)), this, SLOT(slotExportFile()));
/* The following entry opens the document information dialog. Since the action is named so it
intends to show data this entry should not have a trailing ellipses (...). */
d->showDocumentInfo = actionManager->createAction("file_documentinfo");
connect(d->showDocumentInfo, SIGNAL(triggered(bool)), this, SLOT(slotDocumentInfo()));
d->themeManager->setThemeMenuAction(new KActionMenu(i18nc("@action:inmenu", "&Themes"), this));
d->themeManager->registerThemeActions(actionCollection());
connect(d->themeManager, SIGNAL(signalThemeChanged()), this, SLOT(slotThemeChanged()));
connect(d->themeManager, SIGNAL(signalThemeChanged()), d->welcomePage, SLOT(slotUpdateThemeColors()));
d->toggleDockers = actionManager->createAction("view_toggledockers");
KisConfig(true).showDockers(true);
d->toggleDockers->setChecked(true);
connect(d->toggleDockers, SIGNAL(toggled(bool)), SLOT(toggleDockersVisibility(bool)));
d->resetConfigurations = actionManager->createAction("reset_configurations");
connect(d->resetConfigurations, SIGNAL(triggered()), this, SLOT(slotResetConfigurations()));
d->toggleDetachCanvas = actionManager->createAction("view_detached_canvas");
d->toggleDetachCanvas->setChecked(false);
connect(d->toggleDetachCanvas, SIGNAL(toggled(bool)), SLOT(setCanvasDetached(bool)));
setCanvasDetached(false);
actionCollection()->addAction("settings_dockers_menu", d->dockWidgetMenu);
actionCollection()->addAction("window", d->windowMenu);
+ actionCollection()->addAction("style_menu", d->styleMenu); // for widget styles: breeze, fusion, etc
+
d->mdiCascade = actionManager->createAction("windows_cascade");
connect(d->mdiCascade, SIGNAL(triggered()), d->mdiArea, SLOT(cascadeSubWindows()));
d->mdiTile = actionManager->createAction("windows_tile");
connect(d->mdiTile, SIGNAL(triggered()), d->mdiArea, SLOT(tileSubWindows()));
d->mdiNextWindow = actionManager->createAction("windows_next");
connect(d->mdiNextWindow, SIGNAL(triggered()), d->mdiArea, SLOT(activateNextSubWindow()));
d->mdiPreviousWindow = actionManager->createAction("windows_previous");
connect(d->mdiPreviousWindow, SIGNAL(triggered()), d->mdiArea, SLOT(activatePreviousSubWindow()));
d->newWindow = actionManager->createAction("view_newwindow");
connect(d->newWindow, SIGNAL(triggered(bool)), this, SLOT(newWindow()));
d->close = actionManager->createStandardAction(KStandardAction::Close, this, SLOT(closeCurrentWindow()));
d->showSessionManager = actionManager->createAction("file_sessions");
connect(d->showSessionManager, SIGNAL(triggered(bool)), this, SLOT(slotShowSessionManager()));
actionManager->createStandardAction(KStandardAction::Preferences, this, SLOT(slotPreferences()));
for (int i = 0; i < 2; i++) {
d->expandingSpacers[i] = new KisAction(i18n("Expanding Spacer"));
d->expandingSpacers[i]->setDefaultWidget(new QWidget(this));
d->expandingSpacers[i]->defaultWidget()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
actionManager->addAction(QString("expanding_spacer_%1").arg(i), d->expandingSpacers[i]);
}
}
void KisMainWindow::applyToolBarLayout()
{
const bool isPlastiqueStyle = style()->objectName() == "plastique";
Q_FOREACH (KToolBar *toolBar, toolBars()) {
toolBar->layout()->setSpacing(4);
if (isPlastiqueStyle) {
toolBar->setContentsMargins(0, 0, 0, 2);
}
//Hide text for buttons with an icon in the toolbar
Q_FOREACH (QAction *ac, toolBar->actions()){
if (ac->icon().pixmap(QSize(1,1)).isNull() == false){
ac->setPriority(QAction::LowPriority);
}else {
ac->setIcon(QIcon());
}
}
}
}
void KisMainWindow::initializeGeometry()
{
// if the user didn's specify the geometry on the command line (does anyone do that still?),
// we first figure out some good default size and restore the x,y position. See bug 285804Z.
KConfigGroup cfg = d->windowStateConfig;
QByteArray geom = QByteArray::fromBase64(cfg.readEntry("ko_geometry", QByteArray()));
if (!restoreGeometry(geom)) {
const int scnum = QApplication::desktop()->screenNumber(parentWidget());
QRect desk = QGuiApplication::screens().at(scnum)->availableVirtualGeometry();
quint32 x = desk.x();
quint32 y = desk.y();
quint32 w = 0;
quint32 h = 0;
// Default size -- maximize on small screens, something useful on big screens
const int deskWidth = desk.width();
if (deskWidth > 1024) {
// a nice width, and slightly less than total available
// height to compensate for the window decs
w = (deskWidth / 3) * 2;
h = (desk.height() / 3) * 2;
}
else {
w = desk.width();
h = desk.height();
}
x += (desk.width() - w) / 2;
y += (desk.height() - h) / 2;
move(x,y);
setGeometry(geometry().x(), geometry().y(), w, h);
}
d->fullScreenMode->setChecked(isFullScreen());
}
void KisMainWindow::showManual()
{
QDesktopServices::openUrl(QUrl("https://docs.krita.org"));
}
void KisMainWindow::windowScreenChanged(QScreen *screen)
{
emit screenChanged();
d->screenConnectionsStore.clear();
d->screenConnectionsStore.addConnection(screen, SIGNAL(physicalDotsPerInchChanged(qreal)),
this, SIGNAL(screenChanged()));
}
void KisMainWindow::slotXmlGuiMakingChanges(bool finished)
{
if (finished) {
subWindowActivated();
}
}
#include <moc_KisMainWindow.cpp>
diff --git a/libs/ui/KisMainWindow.h b/libs/ui/KisMainWindow.h
index ab6dbb4033..e67fdf77be 100644
--- a/libs/ui/KisMainWindow.h
+++ b/libs/ui/KisMainWindow.h
@@ -1,535 +1,517 @@
/* This file is part of the KDE project
Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
Copyright (C) 2000-2004 David Faure <faure@kde.org>
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 KIS_MAIN_WINDOW_H
#define KIS_MAIN_WINDOW_H
#include "kritaui_export.h"
#include <QPointer>
#include <QPrinter>
#include <QUuid>
#include <QUrl>
#include <xmlgui/kxmlguiwindow.h>
#include <KoCanvasObserverBase.h>
#include <KoCanvasSupervisor.h>
#include "KisView.h"
#include <kis_workspace_resource.h>
class QCloseEvent;
class QMoveEvent;
-struct KoPageLayout;
class KoCanvasResourceProvider;
class KisDocument;
-class KisPrintJob;
class KoDockFactoryBase;
class QDockWidget;
class KisView;
class KisViewManager;
class KoCanvasController;
/**
* @brief Main window for Krita
*
* This class is used to represent a main window within a Krita session. Each
* main window contains a menubar and some toolbars, and potentially several
* views of several canvases.
*
*/
class KRITAUI_EXPORT KisMainWindow : public KXmlGuiWindow, public KoCanvasSupervisor
{
Q_OBJECT
public:
enum OpenFlag {
None = 0,
Import = 0x1,
BatchMode = 0x2,
RecoveryFile = 0x4
};
Q_DECLARE_FLAGS(OpenFlags, OpenFlag)
public:
/**
* Constructor.
*
* Initializes a Calligra main window (with its basic GUI etc.).
*/
explicit KisMainWindow(QUuid id = QUuid());
/**
* Destructor.
*/
~KisMainWindow() override;
QUuid id() const;
/**
* @brief showView shows the given view, in @p subWindow if not
* null, in a new tab otherwise.
*/
virtual void showView(KisView *view, QMdiSubWindow *subWindow = 0);
/**
* @returns the currently active view
*/
KisView *activeView() const;
/**
* Sets the maximum number of recent documents entries.
*/
void setMaxRecentItems(uint _number);
/**
* The document opened a URL -> store into recent documents list.
* @param oldUrl if not empty, @p url will replace @p oldUrl if present
*/
void addRecentURL(const QUrl &url, const QUrl &oldUrl = QUrl());
/**
* get list of URL strings for recent files
*/
QList<QUrl> recentFilesUrls();
/**
* removes the given url from the list of recent files
*/
void removeRecentUrl(const QUrl &url);
/**
* Load the desired document and show it.
* @param url the URL to open
*
* @return TRUE on success.
*/
bool openDocument(const QUrl &url, OpenFlags flags);
/**
* Activate a view containing the document in this window, creating one if needed.
*/
void showDocument(KisDocument *document);
/**
* Toggles between showing the welcome screen and the MDI area
*
* hack: There seems to be a bug that prevents events happening to the MDI area if it
* isn't actively displayed (set in the widgetStack). This can cause things like the title bar
* not to update correctly Before doing any actions related to opening or creating documents,
* make sure to switch this first to make sure everything can communicate to the MDI area correctly
*/
void showWelcomeScreen(bool show);
/**
* Saves the document, asking for a filename if necessary.
*
* @param saveas if set to TRUE the user is always prompted for a filename
* @param silent if set to TRUE rootDocument()->setTitleModified will not be called.
*
* @return TRUE on success, false on error or cancel
* (don't display anything in this case, the error dialog box is also implemented here
* but restore the original URL in slotFileSaveAs)
*/
bool saveDocument(KisDocument *document, bool saveas, bool isExporting);
void setReadWrite(bool readwrite);
/// Return the list of dock widgets belonging to this main window.
QList<QDockWidget*> dockWidgets() const;
QDockWidget* dockWidget(const QString &id);
QList<KoCanvasObserverBase*> canvasObservers() const override;
KoCanvasResourceProvider *resourceManager() const;
int viewCount() const;
void saveWindowState(bool restoreNormalState =false);
const KConfigGroup &windowStateConfig() const;
/**
* A wrapper around restoreState
* @param state the saved state
* @return TRUE on success
*/
bool restoreWorkspace(int workspaceId);
bool restoreWorkspaceState(const QByteArray &state);
static void swapWorkspaces(KisMainWindow *a, KisMainWindow *b);
KisViewManager *viewManager() const;
KisView *addViewAndNotifyLoadingCompleted(KisDocument *document,
QMdiSubWindow *subWindow = 0);
QStringList showOpenFileDialog(bool isImporting);
/**
* The top-level window used for a detached canvas.
*/
QWidget *canvasWindow() const;
bool canvasDetached() const;
/**
* Shows if the main window is saving anything right now. If the
* user presses Ctrl+W too fast, then the document can be close
* before the saving is completed. I'm not sure if it is fixable
* in any way without avoiding using porcessEvents()
* everywhere (DK)
*
* Don't use it unless you have no option.
*/
bool hackIsSaving() const;
/// Copy the given file into the bundle directory.
bool installBundle(const QString &fileName) const;
/**
* @brief layoutThumbnail
* @return image for the workspaces.
*/
QImage layoutThumbnail();
Q_SIGNALS:
/**
* This signal is emitted if the document has been saved successfully.
*/
void documentSaved();
/// This signal is emitted when this windows has finished loading of a
/// document. The document may be opened in another window in the end.
/// In this case, the signal means there is no link between the window
/// and the document anymore.
void loadCompleted();
/// This signal is emitted right after the docker states have been succefully restored from config
void restoringDone();
/// This signal is emitted when the color theme changes
void themeChanged();
/// This signal is emitted when the shortcut key configuration has changed
void keyBindingsChanged();
void guiLoadingFinished();
/// emitted when the window is migrated among different screens
void screenChanged();
public Q_SLOTS:
/**
* clears the list of the recent files
*/
void clearRecentFiles();
/**
* Slot for opening a new document.
*
* If the current document is empty, the new document replaces it.
* If not, a new mainwindow will be opened for showing the document.
*/
void slotFileNew();
/**
* Slot for opening a saved file.
*
* If the current document is empty, the opened document replaces it.
* If not a new mainwindow will be opened for showing the opened file.
*/
void slotFileOpen(bool isImporting = false);
/**
* Slot for opening a file among the recently opened files.
*
* If the current document is empty, the opened document replaces it.
* If not a new mainwindow will be opened for showing the opened file.
*/
void slotFileOpenRecent(const QUrl &);
/**
* @brief slotPreferences open the preferences dialog
*/
void slotPreferences();
/**
* Update caption from document info - call when document info
* (title in the about page) changes.
*/
void updateCaption();
/**
* Saves the current document with the current name.
*/
void slotFileSave();
void slotShowSessionManager();
- // XXX: disabled
- KisPrintJob* exportToPdf(QString pdfFileName = QString());
-
/**
* Update the option widgets to the argument ones, removing the currently set widgets.
*/
void newOptionWidgets(KoCanvasController *controller, const QList<QPointer<QWidget> > & optionWidgetList);
KisView *newView(QObject *document, QMdiSubWindow *subWindow = 0);
void notifyChildViewDestroyed(KisView *view);
/// Set the active view, this will update the undo/redo actions
void setActiveView(KisView *view);
void subWindowActivated();
void windowFocused();
/**
* Reloads the recent documents list.
*/
void reloadRecentFileList();
/**
* Detach canvas onto a separate window, or restore it back to to main window.
*/
void setCanvasDetached(bool detached);
void slotFileSelected(QString path);
void slotEmptyFilePath();
/**
* Toggle full screen on/off.
*/
void viewFullscreen(bool fullScreen);
private Q_SLOTS:
/**
* Save the list of recent files.
*/
void saveRecentFiles();
void slotLoadCompleted();
void slotLoadCanceled(const QString &);
void slotSaveCompleted();
void slotSaveCanceled(const QString &);
void forceDockTabFonts();
+ void slotUpdateWidgetStyle();
+
/**
* @internal
*/
void slotDocumentTitleModified();
- /**
- * Prints the actual document.
- */
- void slotFilePrint();
-
/**
* Saves the current document with a new name.
*/
void slotFileSaveAs();
- void slotFilePrintPreview();
-
void importAnimation();
/**
* Show a dialog with author and document information.
*/
void slotDocumentInfo();
/**
* Closes all open documents.
*/
bool slotFileCloseAll();
/**
* @brief showAboutApplication show the about box
*/
virtual void showAboutApplication();
/**
* Closes the mainwindow.
*/
void slotFileQuit();
/**
* Configure toolbars.
*/
void slotConfigureToolbars();
/**
* Post toolbar config.
* (Plug action lists back in, etc.)
*/
void slotNewToolbarConfig();
/**
* Reset User Configurations.
*/
void slotResetConfigurations();
/**
* Shows or hides a toolbar
*/
void slotToolbarToggled(bool toggle);
- /**
- * Reload file
- */
- void slotReloadFile();
-
/**
* File --> Import
*
* This will call slotFileOpen().
*/
void slotImportFile();
/**
* File --> Export
*
* This will call slotFileSaveAs().
*/
void slotExportFile();
/**
* Hide the dockers
*/
void toggleDockersVisibility(bool visible);
/**
* Handle theme changes from theme manager
*/
void slotThemeChanged();
void undo();
void redo();
void updateWindowMenu();
void updateSubwindowFlags();
void setActiveSubWindow(QWidget *window);
void configChanged();
void newWindow();
void closeCurrentWindow();
void checkSanity();
/// Quits Krita with error message from m_errorMessage.
void showErrorAndDie();
void initializeGeometry();
void showManual();
void switchTab(int index);
void windowScreenChanged(QScreen *screen);
void slotXmlGuiMakingChanges(bool finished);
protected:
void closeEvent(QCloseEvent * e) override;
void resizeEvent(QResizeEvent * e) override;
// QWidget overrides
private:
friend class KisWelcomePageWidget;
void dragMove(QDragMoveEvent *event);
void dragLeave();
private:
/**
* Add a the given view to the list of views of this mainwindow.
* This is a private implementation. For public usage please use
* newView() and addViewAndNotifyLoadingCompleted().
*/
void addView(KisView *view, QMdiSubWindow *subWindow = 0);
friend class KisPart;
/**
* Returns the dockwidget specified by the @p factory. If the dock widget doesn't exist yet it's created.
* Add a "view_palette_action_menu" action to your view menu if you want to use closable dock widgets.
* @param factory the factory used to create the dock widget if needed
* @return the dock widget specified by @p factory (may be 0)
*/
QDockWidget* createDockWidget(KoDockFactoryBase* factory);
bool openDocumentInternal(const QUrl &url, KisMainWindow::OpenFlags flags = 0);
/**
* Updates the window caption based on the document info and path.
*/
void updateCaption(const QString & caption, bool modified);
- void updateReloadFileAction(KisDocument *doc);
void saveWindowSettings();
QPointer<KisView> activeKisView();
- void applyDefaultSettings(QPrinter &printer);
-
void createActions();
void applyToolBarLayout();
QByteArray borrowWorkspace(KisMainWindow *borrower);
private:
/**
* Struct used in the list created by createCustomDocumentWidgets()
*/
struct CustomDocumentWidgetItem {
/// Pointer to the custom document widget
QWidget *widget;
/// title used in the sidebar. If left empty it will be displayed as "Custom Document"
QString title;
/// icon used in the sidebar. If left empty it will use the unknown icon
QString icon;
};
class Private;
Private * const d;
QString m_errorMessage;
bool m_dieOnError;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(KisMainWindow::OpenFlags)
#endif
diff --git a/libs/ui/KisPrintJob.cpp b/libs/ui/KisPrintJob.cpp
deleted file mode 100644
index 6237278c74..0000000000
--- a/libs/ui/KisPrintJob.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 "KisPrintJob.h"
-
-#include <QWidget>
-#include <QPainter>
-
-#include <KoColorSpaceRegistry.h>
-
-#include <kis_image.h>
-
-#include "canvas/kis_canvas2.h"
-#include "kis_config.h"
-#include "kis_canvas_resource_provider.h"
-
-KisPrintJob::KisPrintJob(KisImageWSP image)
- : QObject(image.data())
- , m_image(image)
-{
- m_printer.setFromTo(1, 1);
-}
-
-KisPrintJob::~KisPrintJob()
-{
-}
-
-QAbstractPrintDialog::PrintDialogOptions KisPrintJob::printDialogOptions() const
-{
- return QAbstractPrintDialog::PrintToFile |
- QAbstractPrintDialog::PrintPageRange |
- QAbstractPrintDialog::PrintCollateCopies |
- QAbstractPrintDialog::DontUseSheet |
- QAbstractPrintDialog::PrintShowPageSize;
-}
-
-bool KisPrintJob::canPrint()
-{
- if (! printer().isValid()) {
- return false;
- }
-
- QPainter testPainter(&printer());
- if (testPainter.isActive()) {
- return true;
- }
-
- return false;
-}
-
-void KisPrintJob::startPrinting(RemovePolicy removePolicy)
-{
- QPainter gc(&m_printer);
-
- if (!m_image) return;
-
- gc.setClipping(false);
-
- KisConfig cfg(true);
- QString printerProfileName = cfg.printerProfile();
- const KoColorProfile *printerProfile = KoColorSpaceRegistry::instance()->profileByName(printerProfileName);
-
- double scaleX = m_printer.resolution() / (72.0 * m_image->xRes());
- double scaleY = m_printer.resolution() / (72.0 * m_image->yRes());
-
- QRect r = m_image->bounds();
-
- gc.scale(scaleX, scaleY);
-
- QImage image = m_image->convertToQImage(0, 0, r.width(), r.height(), printerProfile);
- gc.drawImage(r.x(), r.y(), image, 0, 0, r.width(), r.height());
- if (removePolicy == DeleteWhenDone)
- deleteLater();
-}
diff --git a/libs/ui/KisPrintJob.h b/libs/ui/KisPrintJob.h
deleted file mode 100644
index 0698448f15..0000000000
--- a/libs/ui/KisPrintJob.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 KISPRINTJOB_H
-#define KISPRINTJOB_H
-
-#include <QObject>
-#include <QList>
-#include <QAbstractPrintDialog>
-#include <QPrinter>
-
-#include "kritaui_export.h"
-
-#include <kis_types.h>
-
-/**
- * A print job is an interface that the KisView uses to create an application-specific
- * class that can take care of printing.
- * The printjob should be able to print again after a print job has been completed,
- * using the same QPrinter to allow the user to alter settings on the QPrinter and
- * call print again.
- * The printjob can thus see startPrinting() called more than once, and the implementation
- * of that signal should honor the removePolicy passed to it.
- */
-class KRITAUI_EXPORT KisPrintJob : public QObject
-{
- Q_OBJECT
-public:
- /**
- * Constructor.
- * @param image the image that is passed for management purposes.
- */
- explicit KisPrintJob(KisImageWSP image);
- ~KisPrintJob() override;
-
- /// A policy to allow the printjob to delete itself after its done printing.
- enum RemovePolicy {
- DeleteWhenDone, ///< Delete the job when its done with printing.
- DoNotDelete ///< Keep the job around so it can be started again.
- };
-
- /// Returns the printer that is used for this print job so others can alter the details of the print-job.
- QPrinter &printer() { return m_printer; }
-
- int documentFirstPage() const {
- return 1;
- }
- int documentLastPage() const {
- return 1;
- }
- int documentCurrentPage() const {
- return 1;
- }
-
- QAbstractPrintDialog::PrintDialogOptions printDialogOptions() const;
-
- /**
- *@brief Check if the painter can print to the printer
- *@returns true if the print job can print to the given printer
- */
- bool canPrint();
-
-public Q_SLOTS:
- /**
- * This is called every time the job should be executed.
- * When called the document should be printed a new painter using the printer
- * of this printJob in order to honor the settings the user made on the printer.
- * canPrint() should be called before startPrinting to check if the painter can print
- * to the printer
- * @param removePolicy a policy that should be honored so the caller can make sure
- * this job doesn't leak memory after being used.
- */
- void startPrinting(RemovePolicy removePolicy = DoNotDelete);
-private:
- KisImageWSP m_image;
- QPrinter m_printer;
-};
-
-#endif
diff --git a/libs/ui/KisReferenceImage.h b/libs/ui/KisReferenceImage.h
index fdc690d34d..06328166ec 100644
--- a/libs/ui/KisReferenceImage.h
+++ b/libs/ui/KisReferenceImage.h
@@ -1,97 +1,94 @@
/*
* Copyright (C) 2017 Boudewijn Rempt <boud@valdyas.org>
*
* 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 KISREFERENCEIMAGE_H
#define KISREFERENCEIMAGE_H
#include <QSharedDataPointer>
#include <kundo2command.h>
#include <kritaui_export.h>
#include <KoTosContainer.h>
#include <KoColor.h>
class QImage;
class QPointF;
class QPainter;
class QRectF;
class KoStore;
class KisCoordinatesConverter;
class KisCanvas2;
/**
* @brief The KisReferenceImage class represents a single reference image
*/
class KRITAUI_EXPORT KisReferenceImage : public KoTosContainer
{
public:
struct KRITAUI_EXPORT SetSaturationCommand : public KUndo2Command {
QVector<KisReferenceImage*> images;
QVector<qreal> oldSaturations;
qreal newSaturation;
explicit SetSaturationCommand(const QList<KoShape *> &images, qreal newSaturation, KUndo2Command *parent = 0);
void undo() override;
void redo() override;
};
KisReferenceImage();
KisReferenceImage(const KisReferenceImage &rhs);
~KisReferenceImage();
KoShape *cloneShape() const override;
/**
* Load a reference image from specified file.
* If parent is provided and the image cannot be loaded, a warning message will be displayed to user.
* @return reference image or null if one could not be loaded
*/
static KisReferenceImage * fromFile(const QString &filename, const KisCoordinatesConverter &converter, QWidget *parent /*= nullptr*/);
static KisReferenceImage * fromClipboard(const KisCoordinatesConverter &converter);
void setSaturation(qreal saturation);
qreal saturation() const;
void setEmbed(bool embed);
bool embed();
bool hasLocalFile();
void setFilename(const QString &filename);
QString filename() const;
QString internalFile() const;
void paint(QPainter &gc, KoShapePaintingContext &paintcontext) const override;
- bool loadOdf(const KoXmlElement &/*element*/, KoShapeLoadingContext &/*context*/) override { return false; }
- void saveOdf(KoShapeSavingContext &/*context*/) const override {}
-
QColor getPixel(QPointF position);
void saveXml(QDomDocument &document, QDomElement &parentElement, int id);
bool saveImage(KoStore *store) const;
static KisReferenceImage * fromXml(const QDomElement &elem);
bool loadImage(KoStore *store);
private:
struct Private;
QSharedDataPointer<Private> d;
};
#endif // KISREFERENCEIMAGE_H
diff --git a/libs/ui/KisView.cpp b/libs/ui/KisView.cpp
index b18e6b4439..11644f97bb 100644
--- a/libs/ui/KisView.cpp
+++ b/libs/ui/KisView.cpp
@@ -1,1045 +1,1028 @@
/*
* Copyright (C) 2014 Boudewijn Rempt <boud@valdyas.org>
*
* 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 "KisView.h"
#include "KisView_p.h"
#include <KoDockFactoryBase.h>
#include <KoDockRegistry.h>
#include <KoDocumentInfo.h>
-#include "KoPageLayout.h"
#include <KoToolManager.h>
#include <kis_icon.h>
#include <kactioncollection.h>
#include <klocalizedstring.h>
#include <kis_debug.h>
#include <kselectaction.h>
#include <kconfiggroup.h>
#include <QMenu>
#include <QMessageBox>
#include <QUrl>
#include <QTemporaryFile>
#include <QApplication>
#include <QDesktopWidget>
#include <QDockWidget>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QImage>
#include <QList>
#include <QPrintDialog>
#include <QToolBar>
#include <QStatusBar>
#include <QMoveEvent>
#include <QMdiSubWindow>
#include <kis_image.h>
#include <kis_node.h>
#include <kis_group_layer.h>
#include <kis_layer.h>
#include <kis_mask.h>
#include <kis_selection.h>
#include "kis_canvas2.h"
#include "kis_canvas_controller.h"
#include "kis_canvas_resource_provider.h"
#include "kis_config.h"
#include "KisDocument.h"
#include "kis_image_manager.h"
#include "KisMainWindow.h"
#include "kis_mimedata.h"
#include "kis_mirror_axis.h"
#include "kis_node_commands_adapter.h"
#include "kis_node_manager.h"
#include "KisPart.h"
-#include "KisPrintJob.h"
#include "kis_shape_controller.h"
#include "kis_tool_freehand.h"
#include "KisViewManager.h"
#include "kis_zoom_manager.h"
#include "kis_statusbar.h"
#include "kis_painting_assistants_decoration.h"
#include "KisReferenceImagesDecoration.h"
#include "kis_progress_widget.h"
#include "kis_signal_compressor.h"
#include "kis_filter_manager.h"
#include "kis_file_layer.h"
#include "krita_utils.h"
#include "input/kis_input_manager.h"
#include "KisRemoteFileFetcher.h"
#include "kis_selection_manager.h"
//static
QString KisView::newObjectName()
{
static int s_viewIFNumber = 0;
QString name; name.setNum(s_viewIFNumber++); name.prepend("view_");
return name;
}
bool KisView::s_firstView = true;
class Q_DECL_HIDDEN KisView::Private
{
public:
Private(KisView *_q,
KisDocument *document,
KisViewManager *viewManager)
: actionCollection(viewManager->actionCollection())
, viewConverter()
, canvasController(_q, viewManager->mainWindow(), viewManager->actionCollection())
, canvas(&viewConverter, viewManager->canvasResourceProvider()->resourceManager(), viewManager->mainWindow(), _q, document->shapeController())
, zoomManager(_q, &this->viewConverter, &this->canvasController)
, viewManager(viewManager)
, paintingAssistantsDecoration(new KisPaintingAssistantsDecoration(_q))
, referenceImagesDecoration(new KisReferenceImagesDecoration(_q, document))
, floatingMessageCompressor(100, KisSignalCompressor::POSTPONE)
{
}
bool inOperation; //in the middle of an operation (no screen refreshing)?
QPointer<KisDocument> document; // our KisDocument
QWidget *tempActiveWidget = 0;
KActionCollection* actionCollection;
KisCoordinatesConverter viewConverter;
KisCanvasController canvasController;
KisCanvas2 canvas;
KisZoomManager zoomManager;
KisViewManager *viewManager = 0;
KisNodeSP currentNode;
KisPaintingAssistantsDecorationSP paintingAssistantsDecoration;
KisReferenceImagesDecorationSP referenceImagesDecoration;
bool isCurrent = false;
bool showFloatingMessage = false;
QPointer<KisFloatingMessage> savedFloatingMessage;
KisSignalCompressor floatingMessageCompressor;
QMdiSubWindow *subWindow{nullptr};
bool softProofing = false;
bool gamutCheck = false;
// Hmm sorry for polluting the private class with such a big inner class.
// At the beginning it was a little struct :)
class StatusBarItem
{
public:
StatusBarItem(QWidget * widget, int stretch, bool permanent)
: m_widget(widget),
m_stretch(stretch),
m_permanent(permanent),
m_connected(false),
m_hidden(false) {}
bool operator==(const StatusBarItem& rhs) {
return m_widget == rhs.m_widget;
}
bool operator!=(const StatusBarItem& rhs) {
return m_widget != rhs.m_widget;
}
QWidget * widget() const {
return m_widget;
}
void ensureItemShown(QStatusBar * sb) {
Q_ASSERT(m_widget);
if (!m_connected) {
if (m_permanent)
sb->addPermanentWidget(m_widget, m_stretch);
else
sb->addWidget(m_widget, m_stretch);
if(!m_hidden)
m_widget->show();
m_connected = true;
}
}
void ensureItemHidden(QStatusBar * sb) {
if (m_connected) {
m_hidden = m_widget->isHidden();
sb->removeWidget(m_widget);
m_widget->hide();
m_connected = false;
}
}
private:
QWidget * m_widget = 0;
int m_stretch;
bool m_permanent;
bool m_connected = false;
bool m_hidden = false;
};
};
KisView::KisView(KisDocument *document, KisViewManager *viewManager, QWidget *parent)
: QWidget(parent)
, d(new Private(this, document, viewManager))
{
Q_ASSERT(document);
connect(document, SIGNAL(titleModified(QString,bool)), this, SIGNAL(titleModified(QString,bool)));
setObjectName(newObjectName());
d->document = document;
setFocusPolicy(Qt::StrongFocus);
QStatusBar * sb = statusBar();
if (sb) { // No statusbar in e.g. konqueror
connect(d->document, SIGNAL(statusBarMessage(QString,int)),
this, SLOT(slotSavingStatusMessage(QString,int)));
connect(d->document, SIGNAL(clearStatusBarMessage()),
this, SLOT(slotClearStatusText()));
}
d->canvas.setup();
KisConfig cfg(false);
d->canvasController.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
d->canvasController.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
d->canvasController.setVastScrolling(cfg.vastScrolling());
d->canvasController.setCanvas(&d->canvas);
d->zoomManager.setup(d->actionCollection);
connect(&d->canvasController, SIGNAL(documentSizeChanged()), &d->zoomManager, SLOT(slotScrollAreaSizeChanged()));
setAcceptDrops(true);
connect(d->document, SIGNAL(sigLoadingFinished()), this, SLOT(slotLoadingFinished()));
connect(d->document, SIGNAL(sigSavingFinished()), this, SLOT(slotSavingFinished()));
d->canvas.addDecoration(d->referenceImagesDecoration);
d->referenceImagesDecoration->setVisible(true);
d->canvas.addDecoration(d->paintingAssistantsDecoration);
d->paintingAssistantsDecoration->setVisible(true);
d->showFloatingMessage = cfg.showCanvasMessages();
d->zoomManager.updateScreenResolution(this);
}
KisView::~KisView()
{
if (d->viewManager) {
if (d->viewManager->filterManager()->isStrokeRunning()) {
d->viewManager->filterManager()->cancel();
}
d->viewManager->mainWindow()->notifyChildViewDestroyed(this);
}
KoToolManager::instance()->removeCanvasController(&d->canvasController);
d->canvasController.setCanvas(0);
KisPart::instance()->removeView(this);
delete d;
}
void KisView::notifyCurrentStateChanged(bool isCurrent)
{
d->isCurrent = isCurrent;
if (!d->isCurrent && d->savedFloatingMessage) {
d->savedFloatingMessage->removeMessage();
}
KisInputManager *inputManager = globalInputManager();
if (d->isCurrent) {
inputManager->attachPriorityEventFilter(&d->canvasController);
} else {
inputManager->detachPriorityEventFilter(&d->canvasController);
}
/**
* When current view is changed, currently selected node is also changed,
* therefore we should update selection overlay mask
*/
viewManager()->selectionManager()->selectionChanged();
}
bool KisView::isCurrent() const
{
return d->isCurrent;
}
void KisView::setShowFloatingMessage(bool show)
{
d->showFloatingMessage = show;
}
void KisView::showFloatingMessage(const QString &message, const QIcon& icon, int timeout, KisFloatingMessage::Priority priority, int alignment)
{
if (!d->viewManager) return;
if(d->isCurrent && d->showFloatingMessage && d->viewManager->qtMainWindow()) {
if (d->savedFloatingMessage) {
d->savedFloatingMessage->tryOverrideMessage(message, icon, timeout, priority, alignment);
} else {
d->savedFloatingMessage = new KisFloatingMessage(message, this->canvasBase()->canvasWidget(), false, timeout, priority, alignment);
d->savedFloatingMessage->setShowOverParent(true);
d->savedFloatingMessage->setIcon(icon);
connect(&d->floatingMessageCompressor, SIGNAL(timeout()), d->savedFloatingMessage, SLOT(showMessage()));
d->floatingMessageCompressor.start();
}
}
}
bool KisView::canvasIsMirrored() const
{
return d->canvas.xAxisMirrored() || d->canvas.yAxisMirrored();
}
void KisView::setViewManager(KisViewManager *view)
{
d->viewManager = view;
KoToolManager::instance()->addController(&d->canvasController);
KoToolManager::instance()->registerToolActions(d->actionCollection, &d->canvasController);
dynamic_cast<KisShapeController*>(d->document->shapeController())->setInitialShapeForCanvas(&d->canvas);
if (resourceProvider()) {
resourceProvider()->slotImageSizeChanged();
}
if (d->viewManager && d->viewManager->nodeManager()) {
d->viewManager->nodeManager()->nodesUpdated();
}
connect(image(), SIGNAL(sigSizeChanged(QPointF,QPointF)), this, SLOT(slotImageSizeChanged(QPointF,QPointF)));
connect(image(), SIGNAL(sigResolutionChanged(double,double)), this, SLOT(slotImageResolutionChanged()));
// executed in a context of an image thread
connect(image(), SIGNAL(sigNodeAddedAsync(KisNodeSP)),
SLOT(slotImageNodeAdded(KisNodeSP)),
Qt::DirectConnection);
// executed in a context of the gui thread
connect(this, SIGNAL(sigContinueAddNode(KisNodeSP)),
SLOT(slotContinueAddNode(KisNodeSP)),
Qt::AutoConnection);
// executed in a context of an image thread
connect(image(), SIGNAL(sigRemoveNodeAsync(KisNodeSP)),
SLOT(slotImageNodeRemoved(KisNodeSP)),
Qt::DirectConnection);
// executed in a context of the gui thread
connect(this, SIGNAL(sigContinueRemoveNode(KisNodeSP)),
SLOT(slotContinueRemoveNode(KisNodeSP)),
Qt::AutoConnection);
d->viewManager->updateGUI();
KoToolManager::instance()->switchToolRequested("KritaShape/KisToolBrush");
}
KisViewManager* KisView::viewManager() const
{
return d->viewManager;
}
void KisView::slotImageNodeAdded(KisNodeSP node)
{
emit sigContinueAddNode(node);
}
void KisView::slotContinueAddNode(KisNodeSP newActiveNode)
{
/**
* When deleting the last layer, root node got selected. We should
* fix it when the first layer is added back.
*
* Here we basically reimplement what Qt's view/model do. But
* since they are not connected, we should do it manually.
*/
if (!d->isCurrent &&
(!d->currentNode || !d->currentNode->parent())) {
d->currentNode = newActiveNode;
}
}
void KisView::slotImageNodeRemoved(KisNodeSP node)
{
emit sigContinueRemoveNode(KritaUtils::nearestNodeAfterRemoval(node));
}
void KisView::slotContinueRemoveNode(KisNodeSP newActiveNode)
{
if (!d->isCurrent) {
d->currentNode = newActiveNode;
}
}
KoZoomController *KisView::zoomController() const
{
return d->zoomManager.zoomController();
}
KisZoomManager *KisView::zoomManager() const
{
return &d->zoomManager;
}
KisCanvasController *KisView::canvasController() const
{
return &d->canvasController;
}
KisCanvasResourceProvider *KisView::resourceProvider() const
{
if (d->viewManager) {
return d->viewManager->canvasResourceProvider();
}
return 0;
}
KisInputManager* KisView::globalInputManager() const
{
return d->viewManager ? d->viewManager->inputManager() : 0;
}
KisCanvas2 *KisView::canvasBase() const
{
return &d->canvas;
}
KisImageWSP KisView::image() const
{
if (d->document) {
return d->document->image();
}
return 0;
}
KisCoordinatesConverter *KisView::viewConverter() const
{
return &d->viewConverter;
}
void KisView::dragEnterEvent(QDragEnterEvent *event)
{
//qDebug() << "KisView::dragEnterEvent formats" << event->mimeData()->formats() << "urls" << event->mimeData()->urls() << "has images" << event->mimeData()->hasImage();
if (event->mimeData()->hasImage()
|| event->mimeData()->hasUrls()
|| event->mimeData()->hasFormat("application/x-krita-node")) {
event->accept();
// activate view if it should accept the drop
this->setFocus();
} else {
event->ignore();
}
}
void KisView::dropEvent(QDropEvent *event)
{
KisImageWSP kisimage = image();
Q_ASSERT(kisimage);
QPoint cursorPos = canvasBase()->coordinatesConverter()->widgetToImage(event->pos()).toPoint();
QRect imageBounds = kisimage->bounds();
QPoint pasteCenter;
bool forceRecenter;
if (event->keyboardModifiers() & Qt::ShiftModifier &&
imageBounds.contains(cursorPos)) {
pasteCenter = cursorPos;
forceRecenter = true;
} else {
pasteCenter = imageBounds.center();
forceRecenter = false;
}
//qDebug() << "KisView::dropEvent() formats" << event->mimeData()->formats() << "urls" << event->mimeData()->urls() << "has images" << event->mimeData()->hasImage();
if (event->mimeData()->hasFormat("application/x-krita-node") ||
event->mimeData()->hasImage())
{
KisShapeController *kritaShapeController =
dynamic_cast<KisShapeController*>(d->document->shapeController());
QList<KisNodeSP> nodes =
KisMimeData::loadNodes(event->mimeData(), imageBounds,
pasteCenter, forceRecenter,
kisimage, kritaShapeController);
Q_FOREACH (KisNodeSP node, nodes) {
if (node) {
KisNodeCommandsAdapter adapter(viewManager());
if (!viewManager()->nodeManager()->activeLayer()) {
adapter.addNode(node, kisimage->rootLayer() , 0);
} else {
adapter.addNode(node,
viewManager()->nodeManager()->activeLayer()->parent(),
viewManager()->nodeManager()->activeLayer());
}
}
}
}
else if (event->mimeData()->hasUrls()) {
QList<QUrl> urls = event->mimeData()->urls();
if (urls.length() > 0) {
QMenu popup;
popup.setObjectName("drop_popup");
QAction *insertAsNewLayer = new QAction(i18n("Insert as New Layer"), &popup);
QAction *insertManyLayers = new QAction(i18n("Insert Many Layers"), &popup);
QAction *insertAsNewFileLayer = new QAction(i18n("Insert as New File Layer"), &popup);
QAction *insertManyFileLayers = new QAction(i18n("Insert Many File Layers"), &popup);
QAction *openInNewDocument = new QAction(i18n("Open in New Document"), &popup);
QAction *openManyDocuments = new QAction(i18n("Open Many Documents"), &popup);
QAction *insertAsReferenceImage = new QAction(i18n("Insert as Reference Image"), &popup);
QAction *insertAsReferenceImages = new QAction(i18n("Insert as Reference Images"), &popup);
QAction *cancel = new QAction(i18n("Cancel"), &popup);
popup.addAction(insertAsNewLayer);
popup.addAction(insertAsNewFileLayer);
popup.addAction(openInNewDocument);
popup.addAction(insertAsReferenceImage);
popup.addAction(insertManyLayers);
popup.addAction(insertManyFileLayers);
popup.addAction(openManyDocuments);
popup.addAction(insertAsReferenceImages);
insertAsNewLayer->setEnabled(image() && urls.count() == 1);
insertAsNewFileLayer->setEnabled(image() && urls.count() == 1);
openInNewDocument->setEnabled(urls.count() == 1);
insertAsReferenceImage->setEnabled(image() && urls.count() == 1);
insertManyLayers->setEnabled(image() && urls.count() > 1);
insertManyFileLayers->setEnabled(image() && urls.count() > 1);
openManyDocuments->setEnabled(urls.count() > 1);
insertAsReferenceImages->setEnabled(image() && urls.count() > 1);
popup.addSeparator();
popup.addAction(cancel);
QAction *action = popup.exec(QCursor::pos());
if (action != 0 && action != cancel) {
QTemporaryFile *tmp = 0;
for (QUrl url : urls) {
if (!url.isLocalFile()) {
// download the file and substitute the url
KisRemoteFileFetcher fetcher;
tmp = new QTemporaryFile();
tmp->setAutoRemove(true);
if (!fetcher.fetchFile(url, tmp)) {
qWarning() << "Fetching" << url << "failed";
continue;
}
url = url.fromLocalFile(tmp->fileName());
}
if (url.isLocalFile()) {
if (action == insertAsNewLayer || action == insertManyLayers) {
d->viewManager->imageManager()->importImage(url);
activateWindow();
}
else if (action == insertAsNewFileLayer || action == insertManyFileLayers) {
KisNodeCommandsAdapter adapter(viewManager());
KisFileLayer *fileLayer = new KisFileLayer(image(), "", url.toLocalFile(),
KisFileLayer::None, image()->nextLayerName(), OPACITY_OPAQUE_U8);
adapter.addNode(fileLayer, viewManager()->activeNode()->parent(), viewManager()->activeNode());
}
else if (action == openInNewDocument || action == openManyDocuments) {
if (mainWindow()) {
mainWindow()->openDocument(url, KisMainWindow::None);
}
}
else if (action == insertAsReferenceImage || action == insertAsReferenceImages) {
auto *reference = KisReferenceImage::fromFile(url.toLocalFile(), d->viewConverter, this);
if (reference) {
reference->setPosition(d->viewConverter.imageToDocument(cursorPos));
d->referenceImagesDecoration->addReferenceImage(reference);
KoToolManager::instance()->switchToolRequested("ToolReferenceImages");
}
}
}
delete tmp;
tmp = 0;
}
}
}
}
}
void KisView::dragMoveEvent(QDragMoveEvent *event)
{
//qDebug() << "KisView::dragMoveEvent";
if (event->mimeData()->hasUrls() ||
event->mimeData()->hasFormat("application/x-krita-node") ||
event->mimeData()->hasFormat("application/x-qt-image")) {
event->accept();
}
}
KisDocument *KisView::document() const
{
return d->document;
}
KisView *KisView::replaceBy(KisDocument *document)
{
KisMainWindow *window = mainWindow();
QMdiSubWindow *subWindow = d->subWindow;
delete this;
return window->newView(document, subWindow);
}
-QPrintDialog *KisView::createPrintDialog(KisPrintJob *printJob, QWidget *parent)
-{
- Q_UNUSED(parent);
- QPrintDialog *printDialog = new QPrintDialog(&printJob->printer(), this);
- printDialog->setMinMax(printJob->printer().fromPage(), printJob->printer().toPage());
- printDialog->setEnabledOptions(printJob->printDialogOptions());
- return printDialog;
-}
-
-
KisMainWindow * KisView::mainWindow() const
{
return d->viewManager->mainWindow();
}
void KisView::setSubWindow(QMdiSubWindow *subWindow)
{
d->subWindow = subWindow;
}
QStatusBar * KisView::statusBar() const
{
KisMainWindow *mw = mainWindow();
return mw ? mw->statusBar() : 0;
}
void KisView::slotSavingStatusMessage(const QString &text, int timeout, bool isAutoSaving)
{
QStatusBar *sb = statusBar();
if (sb) {
sb->showMessage(text, timeout);
}
KisConfig cfg(true);
if (!sb || sb->isHidden() ||
(!isAutoSaving && cfg.forceShowSaveMessages()) ||
(cfg.forceShowAutosaveMessages() && isAutoSaving)) {
viewManager()->showFloatingMessage(text, QIcon());
}
}
void KisView::slotClearStatusText()
{
QStatusBar *sb = statusBar();
if (sb) {
sb->clearMessage();
}
}
QList<QAction*> KisView::createChangeUnitActions(bool addPixelUnit)
{
UnitActionGroup* unitActions = new UnitActionGroup(d->document, addPixelUnit, this);
return unitActions->actions();
}
void KisView::closeEvent(QCloseEvent *event)
{
// Check whether we're the last (user visible) view
int viewCount = KisPart::instance()->viewCount(document());
if (viewCount > 1 || !isVisible()) {
// there are others still, so don't bother the user
event->accept();
return;
}
if (queryClose()) {
event->accept();
return;
}
event->ignore();
}
bool KisView::queryClose()
{
if (!document())
return true;
document()->waitForSavingToComplete();
if (document()->isModified()) {
QString name;
if (document()->documentInfo()) {
name = document()->documentInfo()->aboutInfo("title");
}
if (name.isEmpty())
name = document()->url().fileName();
if (name.isEmpty())
name = i18n("Untitled");
int res = QMessageBox::warning(this,
i18nc("@title:window", "Krita"),
i18n("<p>The document <b>'%1'</b> has been modified.</p><p>Do you want to save it?</p>", name),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes);
switch (res) {
case QMessageBox::Yes : {
bool isNative = (document()->mimeType() == document()->nativeFormatMimeType());
if (!viewManager()->mainWindow()->saveDocument(document(), !isNative, false))
return false;
break;
}
case QMessageBox::No : {
KisImageSP image = document()->image();
image->requestStrokeCancellation();
viewManager()->blockUntilOperationsFinishedForced(image);
document()->removeAutoSaveFiles(document()->localFilePath(), document()->isRecovered());
document()->setModified(false); // Now when queryClose() is called by closeEvent it won't do anything.
break;
}
default : // case QMessageBox::Cancel :
return false;
}
}
return true;
}
void KisView::slotScreenChanged()
{
d->zoomManager.updateScreenResolution(this);
}
void KisView::slotThemeChanged(QPalette pal)
{
this->setPalette(pal);
for (int i=0; i<this->children().size();i++) {
QWidget *w = qobject_cast<QWidget*> ( this->children().at(i));
if (w) {
w->setPalette(pal);
}
}
if (canvasBase()) {
canvasBase()->canvasWidget()->setPalette(pal);
}
if (canvasController()) {
canvasController()->setPalette(pal);
}
}
void KisView::resetImageSizeAndScroll(bool changeCentering,
const QPointF &oldImageStillPoint,
const QPointF &newImageStillPoint)
{
const KisCoordinatesConverter *converter = d->canvas.coordinatesConverter();
QPointF oldPreferredCenter = d->canvasController.preferredCenter();
/**
* Calculating the still point in old coordinates depending on the
* parameters given
*/
QPointF oldStillPoint;
if (changeCentering) {
oldStillPoint =
converter->imageToWidget(oldImageStillPoint) +
converter->documentOffset();
} else {
QSizeF oldDocumentSize = d->canvasController.documentSize();
oldStillPoint = QPointF(0.5 * oldDocumentSize.width(), 0.5 * oldDocumentSize.height());
}
/**
* Updating the document size
*/
QSizeF size(image()->width() / image()->xRes(), image()->height() / image()->yRes());
KoZoomController *zc = d->zoomManager.zoomController();
zc->setZoom(KoZoomMode::ZOOM_CONSTANT, zc->zoomAction()->effectiveZoom(),
d->zoomManager.resolutionX(), d->zoomManager.resolutionY());
zc->setPageSize(size);
zc->setDocumentSize(size, true);
/**
* Calculating the still point in new coordinates depending on the
* parameters given
*/
QPointF newStillPoint;
if (changeCentering) {
newStillPoint =
converter->imageToWidget(newImageStillPoint) +
converter->documentOffset();
} else {
QSizeF newDocumentSize = d->canvasController.documentSize();
newStillPoint = QPointF(0.5 * newDocumentSize.width(), 0.5 * newDocumentSize.height());
}
d->canvasController.setPreferredCenter(oldPreferredCenter - oldStillPoint + newStillPoint);
}
void KisView::syncLastActiveNodeToDocument()
{
KisDocument *doc = document();
if (doc) {
doc->setPreActivatedNode(d->currentNode);
}
}
void KisView::saveViewState(KisPropertiesConfiguration &config) const
{
config.setProperty("file", d->document->url());
config.setProperty("window", mainWindow()->windowStateConfig().name());
if (d->subWindow) {
config.setProperty("geometry", d->subWindow->saveGeometry().toBase64());
}
config.setProperty("zoomMode", (int)zoomController()->zoomMode());
config.setProperty("zoom", d->canvas.coordinatesConverter()->zoom());
d->canvasController.saveCanvasState(config);
}
void KisView::restoreViewState(const KisPropertiesConfiguration &config)
{
if (d->subWindow) {
QByteArray geometry = QByteArray::fromBase64(config.getString("geometry", "").toLatin1());
d->subWindow->restoreGeometry(QByteArray::fromBase64(geometry));
}
qreal zoom = config.getFloat("zoom", 1.0f);
int zoomMode = config.getInt("zoomMode", (int)KoZoomMode::ZOOM_PAGE);
d->zoomManager.zoomController()->setZoom((KoZoomMode::Mode)zoomMode, zoom);
d->canvasController.restoreCanvasState(config);
}
void KisView::setCurrentNode(KisNodeSP node)
{
d->currentNode = node;
d->canvas.slotTrySwitchShapeManager();
syncLastActiveNodeToDocument();
}
KisNodeSP KisView::currentNode() const
{
return d->currentNode;
}
KisLayerSP KisView::currentLayer() const
{
KisNodeSP node;
KisMaskSP mask = currentMask();
if (mask) {
node = mask->parent();
}
else {
node = d->currentNode;
}
return qobject_cast<KisLayer*>(node.data());
}
KisMaskSP KisView::currentMask() const
{
return dynamic_cast<KisMask*>(d->currentNode.data());
}
KisSelectionSP KisView::selection()
{
KisLayerSP layer = currentLayer();
if (layer)
return layer->selection(); // falls through to the global
// selection, or 0 in the end
if (image()) {
return image()->globalSelection();
}
return 0;
}
void KisView::slotSoftProofing(bool softProofing)
{
d->softProofing = softProofing;
QString message;
if (canvasBase()->image()->colorSpace()->colorDepthId().id().contains("F"))
{
message = i18n("Soft Proofing doesn't work in floating point.");
viewManager()->showFloatingMessage(message,QIcon());
return;
}
if (softProofing){
message = i18n("Soft Proofing turned on.");
} else {
message = i18n("Soft Proofing turned off.");
}
viewManager()->showFloatingMessage(message,QIcon());
canvasBase()->slotSoftProofing(softProofing);
}
void KisView::slotGamutCheck(bool gamutCheck)
{
d->gamutCheck = gamutCheck;
QString message;
if (canvasBase()->image()->colorSpace()->colorDepthId().id().contains("F"))
{
message = i18n("Gamut Warnings don't work in floating point.");
viewManager()->showFloatingMessage(message,QIcon());
return;
}
if (gamutCheck){
message = i18n("Gamut Warnings turned on.");
if (!d->softProofing){
message += "\n "+i18n("But Soft Proofing is still off.");
}
} else {
message = i18n("Gamut Warnings turned off.");
}
viewManager()->showFloatingMessage(message,QIcon());
canvasBase()->slotGamutCheck(gamutCheck);
}
bool KisView::softProofing()
{
return d->softProofing;
}
bool KisView::gamutCheck()
{
return d->gamutCheck;
}
void KisView::slotLoadingFinished()
{
if (!document()) return;
/**
* Cold-start of image size/resolution signals
*/
slotImageResolutionChanged();
if (image()->locked()) {
// If this is the first view on the image, the image will have been locked
// so unlock it.
image()->blockSignals(false);
image()->unlock();
}
canvasBase()->initializeImage();
/**
* Dirty hack alert
*/
d->zoomManager.zoomController()->setAspectMode(true);
if (viewConverter()) {
viewConverter()->setZoomMode(KoZoomMode::ZOOM_PAGE);
}
connect(image(), SIGNAL(sigColorSpaceChanged(const KoColorSpace*)), this, SIGNAL(sigColorSpaceChanged(const KoColorSpace*)));
connect(image(), SIGNAL(sigProfileChanged(const KoColorProfile*)), this, SIGNAL(sigProfileChanged(const KoColorProfile*)));
connect(image(), SIGNAL(sigSizeChanged(QPointF,QPointF)), this, SIGNAL(sigSizeChanged(QPointF,QPointF)));
KisNodeSP activeNode = document()->preActivatedNode();
if (!activeNode) {
activeNode = image()->rootLayer()->lastChild();
}
while (activeNode && !activeNode->inherits("KisLayer")) {
activeNode = activeNode->prevSibling();
}
setCurrentNode(activeNode);
connect(d->viewManager->mainWindow(), SIGNAL(screenChanged()), SLOT(slotScreenChanged()));
zoomManager()->updateImageBoundsSnapping();
}
void KisView::slotSavingFinished()
{
if (d->viewManager && d->viewManager->mainWindow()) {
d->viewManager->mainWindow()->updateCaption();
}
}
-KisPrintJob * KisView::createPrintJob()
-{
- return new KisPrintJob(image());
-}
-
void KisView::slotImageResolutionChanged()
{
resetImageSizeAndScroll(false);
zoomManager()->updateImageBoundsSnapping();
zoomManager()->updateGuiAfterDocumentSize();
// update KoUnit value for the document
if (resourceProvider()) {
resourceProvider()->resourceManager()->
setResource(KoCanvasResourceProvider::Unit, d->canvas.unit());
}
}
void KisView::slotImageSizeChanged(const QPointF &oldStillPoint, const QPointF &newStillPoint)
{
resetImageSizeAndScroll(true, oldStillPoint, newStillPoint);
zoomManager()->updateImageBoundsSnapping();
zoomManager()->updateGuiAfterDocumentSize();
}
void KisView::closeView()
{
d->subWindow->close();
}
diff --git a/libs/ui/KisView.h b/libs/ui/KisView.h
index 383771b109..b58e282d89 100644
--- a/libs/ui/KisView.h
+++ b/libs/ui/KisView.h
@@ -1,300 +1,286 @@
/* This file is part of the KDE project
Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
Copyright (C) 2007 Thomas Zander <zander@kde.org>
Copyright (C) 2010 Benjamin Port <port.benjamin@gmail.com>
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 KIS_VIEW_H
#define KIS_VIEW_H
#include <QWidget>
#include <KoColorSpace.h>
#include <KoColorProfile.h>
#include <kis_types.h>
#include "kritaui_export.h"
#include "widgets/kis_floating_message.h"
class KisDocument;
class KisMainWindow;
-class KisPrintJob;
class KisCanvasController;
class KisZoomManager;
class KisCanvas2;
class KisViewManager;
class KisDocument;
class KisCanvasResourceProvider;
class KisCoordinatesConverter;
class KisInputManager;
class KoZoomController;
class KoZoomController;
-struct KoPageLayout;
class KoCanvasResourceProvider;
// KDE classes
class QAction;
class KActionCollection;
class KConfigGroup;
// Qt classes
class QDragEnterEvent;
class QDragMoveEvent;
class QDropEvent;
class QPrintDialog;
class QCloseEvent;
class QStatusBar;
class QMdiSubWindow;
/**
* This class is used to display a @ref KisDocument.
*
* Multiple views can be attached to one document at a time.
*/
class KRITAUI_EXPORT KisView : public QWidget
{
Q_OBJECT
public:
/**
* Creates a new view for the document.
*/
KisView(KisDocument *document, KisViewManager *viewManager, QWidget *parent = 0);
~KisView() override;
// Temporary while teasing apart view and mainwindow
void setViewManager(KisViewManager *view);
KisViewManager *viewManager() const;
public:
/**
* Retrieves the document object of this view.
*/
KisDocument *document() const;
/**
* Deletes the view and creates a new one, displaying @p document,
* in the same sub-window.
*
* @return the new view
*/
KisView *replaceBy(KisDocument *document);
- /**
- * In order to print the document represented by this view a new print job should
- * be constructed that is capable of doing the printing.
- * The default implementation returns 0, which silently cancels printing.
- */
- KisPrintJob * createPrintJob();
-
- /**
- * Create a QPrintDialog based on the @p printJob
- */
- QPrintDialog *createPrintDialog(KisPrintJob *printJob, QWidget *parent);
-
/**
* @return the KisMainWindow in which this view is currently.
*/
KisMainWindow *mainWindow() const;
/**
* Tells this view which subwindow it is part of.
*/
void setSubWindow(QMdiSubWindow *subWindow);
/**
* @return the statusbar of the KisMainWindow in which this view is currently.
*/
QStatusBar *statusBar() const;
/**
* This adds a widget to the statusbar for this view.
* If you use this method instead of using statusBar() directly,
* KisView will take care of removing the items when the view GUI is deactivated
* and readding them when it is reactivated.
* The parameters are the same as QStatusBar::addWidget().
*/
void addStatusBarItem(QWidget * widget, int stretch = 0, bool permanent = false);
/**
* Remove a widget from the statusbar for this view.
*/
void removeStatusBarItem(QWidget * widget);
/**
* Return the zoomController for this view.
*/
KoZoomController *zoomController() const;
/// create a list of actions that when activated will change the unit on the document.
QList<QAction*> createChangeUnitActions(bool addPixelUnit = false);
void closeView();
public:
/**
* The zoommanager handles everything action-related to zooming
*/
KisZoomManager *zoomManager() const;
/**
* The CanvasController decorates the canvas with scrollbars
* and knows where to start painting on the canvas widget, i.e.,
* the document offset.
*/
KisCanvasController *canvasController() const;
KisCanvasResourceProvider *resourceProvider() const;
/**
* Filters events and sends them to canvas actions. Shared
* among all the views/canvases
*
* NOTE: May be null while initialization!
*/
KisInputManager* globalInputManager() const;
/**
* @return the canvas object
*/
KisCanvas2 *canvasBase() const;
/// @return the image this view is displaying
KisImageWSP image() const;
KisCoordinatesConverter *viewConverter() const;
void resetImageSizeAndScroll(bool changeCentering,
const QPointF &oldImageStillPoint = QPointF(),
const QPointF &newImageStillPoint = QPointF());
void setCurrentNode(KisNodeSP node);
KisNodeSP currentNode() const;
KisLayerSP currentLayer() const;
KisMaskSP currentMask() const;
/**
* @brief softProofing
* @return whether or not we're softproofing in this view.
*/
bool softProofing();
/**
* @brief gamutCheck
* @return whether or not we're using gamut warnings in this view.
*/
bool gamutCheck();
/// Convenience method to get at the active selection (the
/// selection of the current layer, or, if that does not exist,
/// the global selection.
KisSelectionSP selection();
void notifyCurrentStateChanged(bool isCurrent);
bool isCurrent() const;
void setShowFloatingMessage(bool show);
void showFloatingMessage(const QString &message, const QIcon& icon, int timeout = 4500,
KisFloatingMessage::Priority priority = KisFloatingMessage::Medium,
int alignment = Qt::AlignCenter | Qt::TextWordWrap);
bool canvasIsMirrored() const;
void syncLastActiveNodeToDocument();
void saveViewState(KisPropertiesConfiguration &config) const;
void restoreViewState(const KisPropertiesConfiguration &config);
public Q_SLOTS:
/**
* Display a message in the status bar (calls QStatusBar::message())
* @todo rename to something more generic
* @param value determines autosaving
*/
void slotSavingStatusMessage(const QString &text, int timeout, bool isAutoSaving = false);
/**
* End of the message in the status bar (calls QStatusBar::clear())
* @todo rename to something more generic
*/
void slotClearStatusText();
/**
* @brief slotSoftProofing set whether or not we're softproofing in this view.
* Will be setting the same in the canvas belonging to the view.
*/
void slotSoftProofing(bool softProofing);
/**
* @brief slotGamutCheck set whether or not we're gamutchecking in this view.
* Will be setting the same in the vans belonging to the view.
*/
void slotGamutCheck(bool gamutCheck);
bool queryClose();
void slotScreenChanged();
void slotThemeChanged(QPalette pal);
private Q_SLOTS:
void slotImageNodeAdded(KisNodeSP node);
void slotContinueAddNode(KisNodeSP newActiveNode);
void slotImageNodeRemoved(KisNodeSP node);
void slotContinueRemoveNode(KisNodeSP newActiveNode);
Q_SIGNALS:
// From KisImage
void sigSizeChanged(const QPointF &oldStillPoint, const QPointF &newStillPoint);
void sigProfileChanged(const KoColorProfile * profile);
void sigColorSpaceChanged(const KoColorSpace* cs);
void titleModified(QString,bool);
void sigContinueAddNode(KisNodeSP newActiveNode);
void sigContinueRemoveNode(KisNodeSP newActiveNode);
protected:
// QWidget overrides
void dragEnterEvent(QDragEnterEvent *event) override;
void dropEvent(QDropEvent *event) override;
void dragMoveEvent(QDragMoveEvent *event) override;
void closeEvent(QCloseEvent *event) override;
/**
* Generate a name for this view.
*/
QString newObjectName();
public Q_SLOTS:
void slotLoadingFinished();
void slotSavingFinished();
void slotImageResolutionChanged();
void slotImageSizeChanged(const QPointF &oldStillPoint, const QPointF &newStillPoint);
private:
class Private;
Private * const d;
static bool s_firstView;
};
#endif
diff --git a/libs/ui/KisViewManager.cpp b/libs/ui/KisViewManager.cpp
index 8899411453..57bf7ad252 100644
--- a/libs/ui/KisViewManager.cpp
+++ b/libs/ui/KisViewManager.cpp
@@ -1,1453 +1,1452 @@
/*
* This file is part of KimageShop^WKrayon^WKrita
*
* Copyright (c) 1999 Matthias Elter <me@kde.org>
* 1999 Michael Koch <koch@kde.org>
* 1999 Carsten Pfeiffer <pfeiffer@kde.org>
* 2002 Patrick Julien <freak@codepimps.org>
* 2003-2011 Boudewijn Rempt <boud@valdyas.org>
* 2004 Clarence Dang <dang@kde.org>
* 2011 José Luis Vergara <pentalis@gmail.com>
* 2017 L. E. Segovia <amy@amyspark.me>
*
* 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 <stdio.h>
#include "KisViewManager.h"
#include <QPrinter>
#include <QAction>
#include <QApplication>
#include <QBuffer>
#include <QByteArray>
#include <QStandardPaths>
#include <QDesktopWidget>
#include <QDesktopServices>
#include <QGridLayout>
#include <QMainWindow>
#include <QMenu>
#include <QMenuBar>
#include <QMessageBox>
#include <QObject>
#include <QPoint>
#include <QPrintDialog>
#include <QRect>
#include <QScrollBar>
#include <QStatusBar>
#include <QToolBar>
#include <QUrl>
#include <QWidget>
#include <kactioncollection.h>
#include <klocalizedstring.h>
#include <KoResourcePaths.h>
#include <kselectaction.h>
#include <KoCanvasController.h>
#include <KoCompositeOp.h>
#include <KoDockRegistry.h>
#include <KoProperties.h>
#include <KisResourceItemChooserSync.h>
#include <KoSelection.h>
#include <KoStore.h>
#include <KoToolManager.h>
#include <KoToolRegistry.h>
#include <KoViewConverter.h>
#include <KoZoomHandler.h>
#include <KoPluginLoader.h>
#include <KoDocumentInfo.h>
#include <KoColorSpaceRegistry.h>
#include "input/kis_input_manager.h"
#include "canvas/kis_canvas2.h"
#include "canvas/kis_canvas_controller.h"
#include "canvas/kis_grid_manager.h"
#include "input/kis_input_profile_manager.h"
#include "kis_action_manager.h"
#include "kis_action.h"
#include "kis_canvas_controls_manager.h"
#include "kis_canvas_resource_provider.h"
#include "kis_composite_progress_proxy.h"
#include <KoProgressUpdater.h>
#include "kis_config.h"
#include "kis_config_notifier.h"
#include "kis_control_frame.h"
#include "kis_coordinates_converter.h"
#include "KisDocument.h"
#include "kis_favorite_resource_manager.h"
#include "kis_filter_manager.h"
#include "kis_group_layer.h"
#include <kis_image.h>
#include <kis_image_barrier_locker.h>
#include "kis_image_manager.h"
#include <kis_layer.h>
#include "kis_mainwindow_observer.h"
#include "kis_mask_manager.h"
#include "kis_mimedata.h"
#include "kis_mirror_manager.h"
#include "kis_node_commands_adapter.h"
#include "kis_node.h"
#include "kis_node_manager.h"
#include "KisDecorationsManager.h"
#include <kis_paint_layer.h>
#include "kis_paintop_box.h"
#include <brushengine/kis_paintop_preset.h>
#include "KisPart.h"
-#include "KisPrintJob.h"
#include <KoUpdater.h>
#include "KisResourceServerProvider.h"
#include "kis_selection.h"
#include "kis_selection_mask.h"
#include "kis_selection_manager.h"
#include "kis_shape_controller.h"
#include "kis_shape_layer.h"
#include <kis_signal_compressor.h>
#include "kis_statusbar.h"
#include <KisTemplateCreateDia.h>
#include <kis_tool_freehand.h>
#include "kis_tooltip_manager.h"
#include <kis_undo_adapter.h>
#include "KisView.h"
#include "kis_zoom_manager.h"
#include "widgets/kis_floating_message.h"
#include "kis_signal_auto_connection.h"
#include "kis_icon_utils.h"
#include "kis_guides_manager.h"
#include "kis_derived_resources.h"
#include "dialogs/kis_delayed_save_dialog.h"
#include <KisMainWindow.h>
#include "kis_signals_blocker.h"
class BlockingUserInputEventFilter : public QObject
{
bool eventFilter(QObject *watched, QEvent *event) override
{
Q_UNUSED(watched);
if(dynamic_cast<QWheelEvent*>(event)
|| dynamic_cast<QKeyEvent*>(event)
|| dynamic_cast<QMouseEvent*>(event)) {
return true;
}
else {
return false;
}
}
};
class KisViewManager::KisViewManagerPrivate
{
public:
KisViewManagerPrivate(KisViewManager *_q, KActionCollection *_actionCollection, QWidget *_q_parent)
: filterManager(_q)
, createTemplate(0)
, saveIncremental(0)
, saveIncrementalBackup(0)
, openResourcesDirectory(0)
, rotateCanvasRight(0)
, rotateCanvasLeft(0)
, resetCanvasRotation(0)
, wrapAroundAction(0)
, levelOfDetailAction(0)
, showRulersAction(0)
, rulersTrackMouseAction(0)
, zoomTo100pct(0)
, zoomIn(0)
, zoomOut(0)
, selectionManager(_q)
, statusBar(_q)
, controlFrame(_q, _q_parent)
, nodeManager(_q)
, imageManager(_q)
, gridManager(_q)
, canvasControlsManager(_q)
, paintingAssistantsManager(_q)
, actionManager(_q, _actionCollection)
, mainWindow(0)
, showFloatingMessage(true)
, currentImageView(0)
, canvasResourceProvider(_q)
, canvasResourceManager()
, guiUpdateCompressor(30, KisSignalCompressor::POSTPONE, _q)
, actionCollection(_actionCollection)
, mirrorManager(_q)
, inputManager(_q)
, actionAuthor(0)
, showPixelGrid(0)
{
KisViewManager::initializeResourceManager(&canvasResourceManager);
}
public:
KisFilterManager filterManager;
KisAction *createTemplate;
KisAction *createCopy;
KisAction *saveIncremental;
KisAction *saveIncrementalBackup;
KisAction *openResourcesDirectory;
KisAction *rotateCanvasRight;
KisAction *rotateCanvasLeft;
KisAction *resetCanvasRotation;
KisAction *wrapAroundAction;
KisAction *levelOfDetailAction;
KisAction *showRulersAction;
KisAction *rulersTrackMouseAction;
KisAction *zoomTo100pct;
KisAction *zoomIn;
KisAction *zoomOut;
KisAction *softProof;
KisAction *gamutCheck;
KisAction *toggleFgBg;
KisAction *resetFgBg;
KisSelectionManager selectionManager;
KisGuidesManager guidesManager;
KisStatusBar statusBar;
QPointer<KoUpdater> persistentImageProgressUpdater;
QScopedPointer<KoProgressUpdater> persistentUnthreadedProgressUpdaterRouter;
QPointer<KoUpdater> persistentUnthreadedProgressUpdater;
KisControlFrame controlFrame;
KisNodeManager nodeManager;
KisImageManager imageManager;
KisGridManager gridManager;
KisCanvasControlsManager canvasControlsManager;
KisDecorationsManager paintingAssistantsManager;
BlockingUserInputEventFilter blockingEventFilter;
KisActionManager actionManager;
QMainWindow* mainWindow;
QPointer<KisFloatingMessage> savedFloatingMessage;
bool showFloatingMessage;
QPointer<KisView> currentImageView;
KisCanvasResourceProvider canvasResourceProvider;
KoCanvasResourceProvider canvasResourceManager;
KisSignalCompressor guiUpdateCompressor;
KActionCollection *actionCollection;
KisMirrorManager mirrorManager;
KisInputManager inputManager;
KisSignalAutoConnectionsStore viewConnections;
KSelectAction *actionAuthor; // Select action for author profile.
KisAction *showPixelGrid;
QByteArray canvasState;
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
QFlags<Qt::WindowState> windowFlags;
#endif
bool blockUntilOperationsFinishedImpl(KisImageSP image, bool force);
};
KisViewManager::KisViewManager(QWidget *parent, KActionCollection *_actionCollection)
: d(new KisViewManagerPrivate(this, _actionCollection, parent))
{
d->actionCollection = _actionCollection;
d->mainWindow = dynamic_cast<QMainWindow*>(parent);
d->canvasResourceProvider.setResourceManager(&d->canvasResourceManager);
connect(&d->guiUpdateCompressor, SIGNAL(timeout()), this, SLOT(guiUpdateTimeout()));
createActions();
setupManagers();
// These initialization functions must wait until KisViewManager ctor is complete.
d->statusBar.setup();
d->persistentImageProgressUpdater =
d->statusBar.progressUpdater()->startSubtask(1, "", true);
// reset state to "completed"
d->persistentImageProgressUpdater->setRange(0,100);
d->persistentImageProgressUpdater->setValue(100);
d->persistentUnthreadedProgressUpdater =
d->statusBar.progressUpdater()->startSubtask(1, "", true);
// reset state to "completed"
d->persistentUnthreadedProgressUpdater->setRange(0,100);
d->persistentUnthreadedProgressUpdater->setValue(100);
d->persistentUnthreadedProgressUpdaterRouter.reset(
new KoProgressUpdater(d->persistentUnthreadedProgressUpdater,
KoProgressUpdater::Unthreaded));
d->persistentUnthreadedProgressUpdaterRouter->setAutoNestNames(true);
d->controlFrame.setup(parent);
//Check to draw scrollbars after "Canvas only mode" toggle is created.
this->showHideScrollbars();
QScopedPointer<KoDummyCanvasController> dummy(new KoDummyCanvasController(actionCollection()));
KoToolManager::instance()->registerToolActions(actionCollection(), dummy.data());
QTimer::singleShot(0, this, SLOT(initializeStatusBarVisibility()));
connect(KoToolManager::instance(), SIGNAL(inputDeviceChanged(KoInputDevice)),
d->controlFrame.paintopBox(), SLOT(slotInputDeviceChanged(KoInputDevice)));
connect(KoToolManager::instance(), SIGNAL(changedTool(KoCanvasController*,int)),
d->controlFrame.paintopBox(), SLOT(slotToolChanged(KoCanvasController*,int)));
connect(&d->nodeManager, SIGNAL(sigNodeActivated(KisNodeSP)),
canvasResourceProvider(), SLOT(slotNodeActivated(KisNodeSP)));
connect(KisPart::instance(), SIGNAL(sigViewAdded(KisView*)), SLOT(slotViewAdded(KisView*)));
connect(KisPart::instance(), SIGNAL(sigViewRemoved(KisView*)), SLOT(slotViewRemoved(KisView*)));
connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotUpdateAuthorProfileActions()));
connect(KisConfigNotifier::instance(), SIGNAL(pixelGridModeChanged()), SLOT(slotUpdatePixelGridAction()));
KisInputProfileManager::instance()->loadProfiles();
KisConfig cfg(true);
d->showFloatingMessage = cfg.showCanvasMessages();
const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8();
KoColor foreground(Qt::black, cs);
d->canvasResourceProvider.setFGColor(cfg.readKoColor("LastForeGroundColor",foreground));
KoColor background(Qt::white, cs);
d->canvasResourceProvider.setBGColor(cfg.readKoColor("LastBackGroundColor",background));
}
KisViewManager::~KisViewManager()
{
KisConfig cfg(false);
if (canvasResourceProvider() && canvasResourceProvider()->currentPreset()) {
cfg.writeKoColor("LastForeGroundColor",canvasResourceProvider()->fgColor());
cfg.writeKoColor("LastBackGroundColor",canvasResourceProvider()->bgColor());
}
cfg.writeEntry("baseLength", KisResourceItemChooserSync::instance()->baseLength());
cfg.writeEntry("CanvasOnlyActive", false); // We never restart in CavnasOnlyMode
delete d;
}
void KisViewManager::initializeResourceManager(KoCanvasResourceProvider *resourceManager)
{
resourceManager->addDerivedResourceConverter(toQShared(new KisCompositeOpResourceConverter));
resourceManager->addDerivedResourceConverter(toQShared(new KisEffectiveCompositeOpResourceConverter));
resourceManager->addDerivedResourceConverter(toQShared(new KisOpacityResourceConverter));
resourceManager->addDerivedResourceConverter(toQShared(new KisFlowResourceConverter));
resourceManager->addDerivedResourceConverter(toQShared(new KisSizeResourceConverter));
resourceManager->addDerivedResourceConverter(toQShared(new KisLodAvailabilityResourceConverter));
resourceManager->addDerivedResourceConverter(toQShared(new KisLodSizeThresholdResourceConverter));
resourceManager->addDerivedResourceConverter(toQShared(new KisLodSizeThresholdSupportedResourceConverter));
resourceManager->addDerivedResourceConverter(toQShared(new KisEraserModeResourceConverter));
resourceManager->addResourceUpdateMediator(toQShared(new KisPresetUpdateMediator));
}
KActionCollection *KisViewManager::actionCollection() const
{
return d->actionCollection;
}
void KisViewManager::slotViewAdded(KisView *view)
{
// WARNING: this slot is called even when a view from another main windows is added!
// Don't expect \p view be a child of this view manager!
Q_UNUSED(view);
if (viewCount() == 0) {
d->statusBar.showAllStatusBarItems();
}
}
void KisViewManager::slotViewRemoved(KisView *view)
{
// WARNING: this slot is called even when a view from another main windows is removed!
// Don't expect \p view be a child of this view manager!
Q_UNUSED(view);
if (viewCount() == 0) {
d->statusBar.hideAllStatusBarItems();
}
KisConfig cfg(false);
if (canvasResourceProvider() && canvasResourceProvider()->currentPreset()) {
cfg.writeEntry("LastPreset", canvasResourceProvider()->currentPreset()->name());
}
}
void KisViewManager::setCurrentView(KisView *view)
{
bool first = true;
if (d->currentImageView) {
d->currentImageView->notifyCurrentStateChanged(false);
d->currentImageView->canvasBase()->setCursor(QCursor(Qt::ArrowCursor));
first = false;
KisDocument* doc = d->currentImageView->document();
if (doc) {
doc->image()->compositeProgressProxy()->removeProxy(d->persistentImageProgressUpdater);
doc->disconnect(this);
}
d->currentImageView->canvasController()->proxyObject->disconnect(&d->statusBar);
d->viewConnections.clear();
}
QPointer<KisView> imageView = qobject_cast<KisView*>(view);
d->currentImageView = imageView;
if (imageView) {
d->softProof->setChecked(imageView->softProofing());
d->gamutCheck->setChecked(imageView->gamutCheck());
// Wait for the async image to have loaded
KisDocument* doc = imageView->document();
if (KisConfig(true).readEntry<bool>("EnablePositionLabel", false)) {
connect(d->currentImageView->canvasController()->proxyObject,
SIGNAL(documentMousePositionChanged(QPointF)),
&d->statusBar,
SLOT(documentMousePositionChanged(QPointF)));
}
// Restore the last used brush preset, color and background color.
if (first) {
KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer();
KisResourceModel *resourceModel = rserver->resourceModel();
QString defaultPresetName = "basic_tip_default";
for (int i = 0; i < resourceModel->rowCount(); i++) {
QModelIndex idx = resourceModel->index(i, 0);
QString resourceName = idx.data(Qt::UserRole + KisResourceModel::Name).toString().toLower();
QString fileName = idx.data(Qt::UserRole + KisResourceModel::Filename).toString().toLower();
if (resourceName.contains("basic_tip_default")) {
defaultPresetName = resourceName;
}
else if (resourceName.contains("default") || fileName.contains("default")) {
defaultPresetName = resourceName;
}
}
KisConfig cfg(true);
QString lastPreset = cfg.readEntry("LastPreset", defaultPresetName);
KisPaintOpPresetSP preset = rserver->resourceByName(lastPreset);
if (!preset) {
preset = rserver->resourceByName(defaultPresetName);
}
if (!preset && rserver->resourceCount() > 0) {
preset = rserver->firstResource();
}
if (preset) {
paintOpBox()->restoreResource(preset);
canvasResourceProvider()->setCurrentCompositeOp(preset->settings()->paintOpCompositeOp());
}
}
KisCanvasController *canvasController = dynamic_cast<KisCanvasController*>(d->currentImageView->canvasController());
d->viewConnections.addUniqueConnection(&d->nodeManager, SIGNAL(sigNodeActivated(KisNodeSP)), doc->image(), SLOT(requestStrokeEndActiveNode()));
d->viewConnections.addUniqueConnection(d->rotateCanvasRight, SIGNAL(triggered()), canvasController, SLOT(rotateCanvasRight15()));
d->viewConnections.addUniqueConnection(d->rotateCanvasLeft, SIGNAL(triggered()),canvasController, SLOT(rotateCanvasLeft15()));
d->viewConnections.addUniqueConnection(d->resetCanvasRotation, SIGNAL(triggered()),canvasController, SLOT(resetCanvasRotation()));
d->viewConnections.addUniqueConnection(d->wrapAroundAction, SIGNAL(toggled(bool)), canvasController, SLOT(slotToggleWrapAroundMode(bool)));
d->wrapAroundAction->setChecked(canvasController->wrapAroundMode());
d->viewConnections.addUniqueConnection(d->levelOfDetailAction, SIGNAL(toggled(bool)), canvasController, SLOT(slotToggleLevelOfDetailMode(bool)));
d->levelOfDetailAction->setChecked(canvasController->levelOfDetailMode());
d->viewConnections.addUniqueConnection(d->currentImageView->image(), SIGNAL(sigColorSpaceChanged(const KoColorSpace*)), d->controlFrame.paintopBox(), SLOT(slotColorSpaceChanged(const KoColorSpace*)));
d->viewConnections.addUniqueConnection(d->showRulersAction, SIGNAL(toggled(bool)), imageView->zoomManager(), SLOT(setShowRulers(bool)));
d->viewConnections.addUniqueConnection(d->rulersTrackMouseAction, SIGNAL(toggled(bool)), imageView->zoomManager(), SLOT(setRulersTrackMouse(bool)));
d->viewConnections.addUniqueConnection(d->zoomTo100pct, SIGNAL(triggered()), imageView->zoomManager(), SLOT(zoomTo100()));
d->viewConnections.addUniqueConnection(d->zoomIn, SIGNAL(triggered()), imageView->zoomController()->zoomAction(), SLOT(zoomIn()));
d->viewConnections.addUniqueConnection(d->zoomOut, SIGNAL(triggered()), imageView->zoomController()->zoomAction(), SLOT(zoomOut()));
d->viewConnections.addUniqueConnection(d->softProof, SIGNAL(toggled(bool)), view, SLOT(slotSoftProofing(bool)) );
d->viewConnections.addUniqueConnection(d->gamutCheck, SIGNAL(toggled(bool)), view, SLOT(slotGamutCheck(bool)) );
// set up progrress reporting
doc->image()->compositeProgressProxy()->addProxy(d->persistentImageProgressUpdater);
d->viewConnections.addUniqueConnection(&d->statusBar, SIGNAL(sigCancellationRequested()), doc->image(), SLOT(requestStrokeCancellation()));
d->viewConnections.addUniqueConnection(d->showPixelGrid, SIGNAL(toggled(bool)), canvasController, SLOT(slotTogglePixelGrid(bool)));
imageView->zoomManager()->setShowRulers(d->showRulersAction->isChecked());
imageView->zoomManager()->setRulersTrackMouse(d->rulersTrackMouseAction->isChecked());
showHideScrollbars();
}
d->filterManager.setView(imageView);
d->selectionManager.setView(imageView);
d->guidesManager.setView(imageView);
d->nodeManager.setView(imageView);
d->imageManager.setView(imageView);
d->canvasControlsManager.setView(imageView);
d->actionManager.setView(imageView);
d->gridManager.setView(imageView);
d->statusBar.setView(imageView);
d->paintingAssistantsManager.setView(imageView);
d->mirrorManager.setView(imageView);
if (d->currentImageView) {
d->currentImageView->notifyCurrentStateChanged(true);
d->currentImageView->canvasController()->activate();
d->currentImageView->canvasController()->setFocus();
d->viewConnections.addUniqueConnection(
image(), SIGNAL(sigSizeChanged(QPointF,QPointF)),
canvasResourceProvider(), SLOT(slotImageSizeChanged()));
d->viewConnections.addUniqueConnection(
image(), SIGNAL(sigResolutionChanged(double,double)),
canvasResourceProvider(), SLOT(slotOnScreenResolutionChanged()));
d->viewConnections.addUniqueConnection(
image(), SIGNAL(sigNodeChanged(KisNodeSP)),
this, SLOT(updateGUI()));
d->viewConnections.addUniqueConnection(
d->currentImageView->zoomManager()->zoomController(),
SIGNAL(zoomChanged(KoZoomMode::Mode,qreal)),
canvasResourceProvider(), SLOT(slotOnScreenResolutionChanged()));
}
d->actionManager.updateGUI();
canvasResourceProvider()->slotImageSizeChanged();
canvasResourceProvider()->slotOnScreenResolutionChanged();
Q_EMIT viewChanged();
}
KoZoomController *KisViewManager::zoomController() const
{
if (d->currentImageView) {
return d->currentImageView->zoomController();
}
return 0;
}
KisImageWSP KisViewManager::image() const
{
if (document()) {
return document()->image();
}
return 0;
}
KisCanvasResourceProvider * KisViewManager::canvasResourceProvider()
{
return &d->canvasResourceProvider;
}
KisCanvas2 * KisViewManager::canvasBase() const
{
if (d && d->currentImageView) {
return d->currentImageView->canvasBase();
}
return 0;
}
QWidget* KisViewManager::canvas() const
{
if (d && d->currentImageView && d->currentImageView->canvasBase()->canvasWidget()) {
return d->currentImageView->canvasBase()->canvasWidget();
}
return 0;
}
KisStatusBar * KisViewManager::statusBar() const
{
return &d->statusBar;
}
KisPaintopBox* KisViewManager::paintOpBox() const
{
return d->controlFrame.paintopBox();
}
QPointer<KoUpdater> KisViewManager::createUnthreadedUpdater(const QString &name)
{
return d->persistentUnthreadedProgressUpdaterRouter->startSubtask(1, name, false);
}
QPointer<KoUpdater> KisViewManager::createThreadedUpdater(const QString &name)
{
return d->statusBar.progressUpdater()->startSubtask(1, name, false);
}
KisSelectionManager * KisViewManager::selectionManager()
{
return &d->selectionManager;
}
KisNodeSP KisViewManager::activeNode()
{
return d->nodeManager.activeNode();
}
KisLayerSP KisViewManager::activeLayer()
{
return d->nodeManager.activeLayer();
}
KisPaintDeviceSP KisViewManager::activeDevice()
{
return d->nodeManager.activePaintDevice();
}
KisZoomManager * KisViewManager::zoomManager()
{
if (d->currentImageView) {
return d->currentImageView->zoomManager();
}
return 0;
}
KisFilterManager * KisViewManager::filterManager()
{
return &d->filterManager;
}
KisImageManager * KisViewManager::imageManager()
{
return &d->imageManager;
}
KisInputManager* KisViewManager::inputManager() const
{
return &d->inputManager;
}
KisSelectionSP KisViewManager::selection()
{
if (d->currentImageView) {
return d->currentImageView->selection();
}
return 0;
}
bool KisViewManager::selectionEditable()
{
KisLayerSP layer = activeLayer();
if (layer) {
KisSelectionMaskSP mask = layer->selectionMask();
if (mask) {
return mask->isEditable();
}
}
// global selection is always editable
return true;
}
KisUndoAdapter * KisViewManager::undoAdapter()
{
if (!document()) return 0;
KisImageWSP image = document()->image();
Q_ASSERT(image);
return image->undoAdapter();
}
void KisViewManager::createActions()
{
KisConfig cfg(true);
d->saveIncremental = actionManager()->createAction("save_incremental_version");
connect(d->saveIncremental, SIGNAL(triggered()), this, SLOT(slotSaveIncremental()));
d->saveIncrementalBackup = actionManager()->createAction("save_incremental_backup");
connect(d->saveIncrementalBackup, SIGNAL(triggered()), this, SLOT(slotSaveIncrementalBackup()));
connect(mainWindow(), SIGNAL(documentSaved()), this, SLOT(slotDocumentSaved()));
d->saveIncremental->setEnabled(false);
d->saveIncrementalBackup->setEnabled(false);
KisAction *tabletDebugger = actionManager()->createAction("tablet_debugger");
connect(tabletDebugger, SIGNAL(triggered()), this, SLOT(toggleTabletLogger()));
d->createTemplate = actionManager()->createAction("create_template");
connect(d->createTemplate, SIGNAL(triggered()), this, SLOT(slotCreateTemplate()));
d->createCopy = actionManager()->createAction("create_copy");
connect(d->createCopy, SIGNAL(triggered()), this, SLOT(slotCreateCopy()));
d->openResourcesDirectory = actionManager()->createAction("open_resources_directory");
connect(d->openResourcesDirectory, SIGNAL(triggered()), SLOT(openResourcesDirectory()));
d->rotateCanvasRight = actionManager()->createAction("rotate_canvas_right");
d->rotateCanvasLeft = actionManager()->createAction("rotate_canvas_left");
d->resetCanvasRotation = actionManager()->createAction("reset_canvas_rotation");
d->wrapAroundAction = actionManager()->createAction("wrap_around_mode");
d->levelOfDetailAction = actionManager()->createAction("level_of_detail_mode");
d->softProof = actionManager()->createAction("softProof");
d->gamutCheck = actionManager()->createAction("gamutCheck");
KisAction *tAction = actionManager()->createAction("showStatusBar");
tAction->setChecked(cfg.showStatusBar());
connect(tAction, SIGNAL(toggled(bool)), this, SLOT(showStatusBar(bool)));
tAction = actionManager()->createAction("view_show_canvas_only");
tAction->setChecked(false);
connect(tAction, SIGNAL(toggled(bool)), this, SLOT(switchCanvasOnly(bool)));
//Workaround, by default has the same shortcut as mirrorCanvas
KisAction *a = dynamic_cast<KisAction*>(actionCollection()->action("format_italic"));
if (a) {
a->setDefaultShortcut(QKeySequence());
}
actionManager()->createAction("ruler_pixel_multiple2");
d->showRulersAction = actionManager()->createAction("view_ruler");
d->showRulersAction->setChecked(cfg.showRulers());
connect(d->showRulersAction, SIGNAL(toggled(bool)), SLOT(slotSaveShowRulersState(bool)));
d->rulersTrackMouseAction = actionManager()->createAction("rulers_track_mouse");
d->rulersTrackMouseAction->setChecked(cfg.rulersTrackMouse());
connect(d->rulersTrackMouseAction, SIGNAL(toggled(bool)), SLOT(slotSaveRulersTrackMouseState(bool)));
d->zoomTo100pct = actionManager()->createAction("zoom_to_100pct");
d->zoomIn = actionManager()->createStandardAction(KStandardAction::ZoomIn, 0, "");
d->zoomOut = actionManager()->createStandardAction(KStandardAction::ZoomOut, 0, "");
d->actionAuthor = new KSelectAction(KisIconUtils::loadIcon("im-user"), i18n("Active Author Profile"), this);
connect(d->actionAuthor, SIGNAL(triggered(QString)), this, SLOT(changeAuthorProfile(QString)));
actionCollection()->addAction("settings_active_author", d->actionAuthor);
slotUpdateAuthorProfileActions();
d->showPixelGrid = actionManager()->createAction("view_pixel_grid");
slotUpdatePixelGridAction();
d->toggleFgBg = actionManager()->createAction("toggle_fg_bg");
connect(d->toggleFgBg, SIGNAL(triggered(bool)), this, SLOT(slotToggleFgBg()));
d->resetFgBg = actionManager()->createAction("reset_fg_bg");
connect(d->resetFgBg, SIGNAL(triggered(bool)), this, SLOT(slotResetFgBg()));
}
void KisViewManager::setupManagers()
{
// Create the managers for filters, selections, layers etc.
// XXX: When the currentlayer changes, call updateGUI on all
// managers
d->filterManager.setup(actionCollection(), actionManager());
d->selectionManager.setup(actionManager());
d->guidesManager.setup(actionManager());
d->nodeManager.setup(actionCollection(), actionManager());
d->imageManager.setup(actionManager());
d->gridManager.setup(actionManager());
d->paintingAssistantsManager.setup(actionManager());
d->canvasControlsManager.setup(actionManager());
d->mirrorManager.setup(actionCollection());
}
void KisViewManager::updateGUI()
{
d->guiUpdateCompressor.start();
}
KisNodeManager * KisViewManager::nodeManager() const
{
return &d->nodeManager;
}
KisActionManager* KisViewManager::actionManager() const
{
return &d->actionManager;
}
KisGridManager * KisViewManager::gridManager() const
{
return &d->gridManager;
}
KisGuidesManager * KisViewManager::guidesManager() const
{
return &d->guidesManager;
}
KisDocument *KisViewManager::document() const
{
if (d->currentImageView && d->currentImageView->document()) {
return d->currentImageView->document();
}
return 0;
}
int KisViewManager::viewCount() const
{
KisMainWindow *mw = qobject_cast<KisMainWindow*>(d->mainWindow);
if (mw) {
return mw->viewCount();
}
return 0;
}
bool KisViewManager::KisViewManagerPrivate::blockUntilOperationsFinishedImpl(KisImageSP image, bool force)
{
const int busyWaitDelay = 1000;
KisDelayedSaveDialog dialog(image, !force ? KisDelayedSaveDialog::GeneralDialog : KisDelayedSaveDialog::ForcedDialog, busyWaitDelay, mainWindow);
dialog.blockIfImageIsBusy();
return dialog.result() == QDialog::Accepted;
}
bool KisViewManager::blockUntilOperationsFinished(KisImageSP image)
{
return d->blockUntilOperationsFinishedImpl(image, false);
}
void KisViewManager::blockUntilOperationsFinishedForced(KisImageSP image)
{
d->blockUntilOperationsFinishedImpl(image, true);
}
void KisViewManager::slotCreateTemplate()
{
if (!document()) return;
KisTemplateCreateDia::createTemplate( QStringLiteral("templates/"), ".kra", document(), mainWindow());
}
void KisViewManager::slotCreateCopy()
{
KisDocument *srcDoc = document();
if (!srcDoc) return;
if (!this->blockUntilOperationsFinished(srcDoc->image())) return;
KisDocument *doc = 0;
{
KisImageBarrierLocker l(srcDoc->image());
doc = srcDoc->clone();
}
KIS_SAFE_ASSERT_RECOVER_RETURN(doc);
QString name = srcDoc->documentInfo()->aboutInfo("name");
if (name.isEmpty()) {
name = document()->url().toLocalFile();
}
name = i18n("%1 (Copy)", name);
doc->documentInfo()->setAboutInfo("title", name);
KisPart::instance()->addDocument(doc);
KisMainWindow *mw = qobject_cast<KisMainWindow*>(d->mainWindow);
mw->addViewAndNotifyLoadingCompleted(doc);
}
QMainWindow* KisViewManager::qtMainWindow() const
{
if (d->mainWindow)
return d->mainWindow;
//Fallback for when we have not yet set the main window.
QMainWindow* w = qobject_cast<QMainWindow*>(qApp->activeWindow());
if(w)
return w;
return mainWindow();
}
void KisViewManager::setQtMainWindow(QMainWindow* newMainWindow)
{
d->mainWindow = newMainWindow;
}
void KisViewManager::slotDocumentSaved()
{
d->saveIncremental->setEnabled(true);
d->saveIncrementalBackup->setEnabled(true);
}
void KisViewManager::slotSaveIncremental()
{
if (!document()) return;
if (document()->url().isEmpty()) {
KisMainWindow *mw = qobject_cast<KisMainWindow*>(d->mainWindow);
mw->saveDocument(document(), true, false);
return;
}
bool foundVersion;
bool fileAlreadyExists;
bool isBackup;
QString version = "000";
QString newVersion;
QString letter;
QString path = QFileInfo(document()->localFilePath()).canonicalPath();
QString fileName = QFileInfo(document()->localFilePath()).fileName();
// Find current version filenames
// v v Regexp to find incremental versions in the filename, taking our backup scheme into account as well
// Considering our incremental version and backup scheme, format is filename_001~001.ext
QRegExp regex("_\\d{1,4}[.]|_\\d{1,4}[a-z][.]|_\\d{1,4}[~]|_\\d{1,4}[a-z][~]");
regex.indexIn(fileName); // Perform the search
QStringList matches = regex.capturedTexts();
foundVersion = matches.at(0).isEmpty() ? false : true;
// Ensure compatibility with Save Incremental Backup
// If this regex is not kept separate, the entire algorithm needs modification;
// It's simpler to just add this.
QRegExp regexAux("_\\d{1,4}[~]|_\\d{1,4}[a-z][~]");
regexAux.indexIn(fileName); // Perform the search
QStringList matchesAux = regexAux.capturedTexts();
isBackup = matchesAux.at(0).isEmpty() ? false : true;
// If the filename has a version, prepare it for incrementation
if (foundVersion) {
version = matches.at(matches.count() - 1); // Look at the last index, we don't care about other matches
if (version.contains(QRegExp("[a-z]"))) {
version.chop(1); // Trim "."
letter = version.right(1); // Save letter
version.chop(1); // Trim letter
} else {
version.chop(1); // Trim "."
}
version.remove(0, 1); // Trim "_"
} else {
// TODO: this will not work with files extensions like jp2
// ...else, simply add a version to it so the next loop works
QRegExp regex2("[.][a-z]{2,4}$"); // Heuristic to find file extension
regex2.indexIn(fileName);
QStringList matches2 = regex2.capturedTexts();
QString extensionPlusVersion = matches2.at(0);
extensionPlusVersion.prepend(version);
extensionPlusVersion.prepend("_");
fileName.replace(regex2, extensionPlusVersion);
}
// Prepare the base for new version filename
int intVersion = version.toInt(0);
++intVersion;
QString baseNewVersion = QString::number(intVersion);
while (baseNewVersion.length() < version.length()) {
baseNewVersion.prepend("0");
}
// Check if the file exists under the new name and search until options are exhausted (test appending a to z)
do {
newVersion = baseNewVersion;
newVersion.prepend("_");
if (!letter.isNull()) newVersion.append(letter);
if (isBackup) {
newVersion.append("~");
} else {
newVersion.append(".");
}
fileName.replace(regex, newVersion);
- fileAlreadyExists = QFile(fileName).exists();
+ bool fileAlreadyExists = QFileInfo(path + '/' + fileName).exists();
if (fileAlreadyExists) {
if (!letter.isNull()) {
char letterCh = letter.at(0).toLatin1();
++letterCh;
letter = QString(QChar(letterCh));
} else {
letter = 'a';
}
}
} while (fileAlreadyExists && letter != "{"); // x, y, z, {...
if (letter == "{") {
QMessageBox::critical(mainWindow(), i18nc("@title:window", "Couldn't save incremental version"), i18n("Alternative names exhausted, try manually saving with a higher number"));
return;
}
QUrl newUrl = QUrl::fromUserInput(path + '/' + fileName);
document()->setFileBatchMode(true);
document()->saveAs(newUrl, document()->mimeType(), true);
document()->setFileBatchMode(false);
KisPart::instance()->addRecentURLToAllMainWindows(newUrl, document()->url());
if (mainWindow()) {
mainWindow()->updateCaption();
}
}
void KisViewManager::slotSaveIncrementalBackup()
{
if (!document()) return;
if (document()->url().isEmpty()) {
KisMainWindow *mw = qobject_cast<KisMainWindow*>(d->mainWindow);
mw->saveDocument(document(), true, false);
return;
}
bool workingOnBackup;
bool fileAlreadyExists;
QString version = "000";
QString newVersion;
QString letter;
QString path = QFileInfo(document()->localFilePath()).canonicalPath();
QString fileName = QFileInfo(document()->localFilePath()).fileName();
// First, discover if working on a backup file, or a normal file
QRegExp regex("~\\d{1,4}[.]|~\\d{1,4}[a-z][.]");
regex.indexIn(fileName); // Perform the search
QStringList matches = regex.capturedTexts();
workingOnBackup = matches.at(0).isEmpty() ? false : true;
if (workingOnBackup) {
// Try to save incremental version (of backup), use letter for alt versions
version = matches.at(matches.count() - 1); // Look at the last index, we don't care about other matches
if (version.contains(QRegExp("[a-z]"))) {
version.chop(1); // Trim "."
letter = version.right(1); // Save letter
version.chop(1); // Trim letter
} else {
version.chop(1); // Trim "."
}
version.remove(0, 1); // Trim "~"
// Prepare the base for new version filename
int intVersion = version.toInt(0);
++intVersion;
QString baseNewVersion = QString::number(intVersion);
QString backupFileName = document()->localFilePath();
while (baseNewVersion.length() < version.length()) {
baseNewVersion.prepend("0");
}
// Check if the file exists under the new name and search until options are exhausted (test appending a to z)
do {
newVersion = baseNewVersion;
newVersion.prepend("~");
if (!letter.isNull()) newVersion.append(letter);
newVersion.append(".");
backupFileName.replace(regex, newVersion);
fileAlreadyExists = QFile(backupFileName).exists();
if (fileAlreadyExists) {
if (!letter.isNull()) {
char letterCh = letter.at(0).toLatin1();
++letterCh;
letter = QString(QChar(letterCh));
} else {
letter = 'a';
}
}
} while (fileAlreadyExists && letter != "{"); // x, y, z, {...
if (letter == "{") {
QMessageBox::critical(mainWindow(), i18nc("@title:window", "Couldn't save incremental backup"), i18n("Alternative names exhausted, try manually saving with a higher number"));
return;
}
QFile::copy(path + '/' + fileName, path + '/' + backupFileName);
document()->saveAs(QUrl::fromUserInput(path + '/' + fileName), document()->mimeType(), true);
if (mainWindow()) mainWindow()->updateCaption();
}
else { // if NOT working on a backup...
// Navigate directory searching for latest backup version, ignore letters
const quint8 HARDCODED_DIGIT_COUNT = 3;
QString baseNewVersion = "000";
QString backupFileName = QFileInfo(document()->localFilePath()).fileName();
QRegExp regex2("[.][a-z]{2,4}$"); // Heuristic to find file extension
regex2.indexIn(backupFileName);
QStringList matches2 = regex2.capturedTexts();
QString extensionPlusVersion = matches2.at(0);
extensionPlusVersion.prepend(baseNewVersion);
extensionPlusVersion.prepend("~");
backupFileName.replace(regex2, extensionPlusVersion);
// Save version with 1 number higher than the highest version found ignoring letters
do {
newVersion = baseNewVersion;
newVersion.prepend("~");
newVersion.append(".");
backupFileName.replace(regex, newVersion);
fileAlreadyExists = QFile(backupFileName).exists();
if (fileAlreadyExists) {
// Prepare the base for new version filename, increment by 1
int intVersion = baseNewVersion.toInt(0);
++intVersion;
baseNewVersion = QString::number(intVersion);
while (baseNewVersion.length() < HARDCODED_DIGIT_COUNT) {
baseNewVersion.prepend("0");
}
}
} while (fileAlreadyExists);
// Save both as backup and on current file for interapplication workflow
document()->setFileBatchMode(true);
QFile::copy(path + '/' + fileName, path + '/' + backupFileName);
document()->saveAs(QUrl::fromUserInput(path + '/' + fileName), document()->mimeType(), true);
document()->setFileBatchMode(false);
if (mainWindow()) mainWindow()->updateCaption();
}
}
void KisViewManager::disableControls()
{
// prevents possible crashes, if somebody changes the paintop during dragging by using the mousewheel
// this is for Bug 250944
// the solution blocks all wheel, mouse and key event, while dragging with the freehand tool
// see KisToolFreehand::initPaint() and endPaint()
d->controlFrame.paintopBox()->installEventFilter(&d->blockingEventFilter);
Q_FOREACH (QObject* child, d->controlFrame.paintopBox()->children()) {
child->installEventFilter(&d->blockingEventFilter);
}
}
void KisViewManager::enableControls()
{
d->controlFrame.paintopBox()->removeEventFilter(&d->blockingEventFilter);
Q_FOREACH (QObject* child, d->controlFrame.paintopBox()->children()) {
child->removeEventFilter(&d->blockingEventFilter);
}
}
void KisViewManager::showStatusBar(bool toggled)
{
KisMainWindow *mw = mainWindow();
if(mw && mw->statusBar()) {
mw->statusBar()->setVisible(toggled);
KisConfig cfg(false);
cfg.setShowStatusBar(toggled);
}
}
void KisViewManager::switchCanvasOnly(bool toggled)
{
KisConfig cfg(false);
KisMainWindow *main = mainWindow();
if(!main) {
dbgUI << "Unable to switch to canvas-only mode, main window not found";
return;
}
cfg.writeEntry("CanvasOnlyActive", toggled);
if (toggled) {
d->canvasState = qtMainWindow()->saveState();
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
d->windowFlags = main->windowState();
#endif
}
if (cfg.hideStatusbarFullscreen()) {
if (main->statusBar()) {
if (!toggled) {
if (main->statusBar()->dynamicPropertyNames().contains("wasvisible")) {
if (main->statusBar()->property("wasvisible").toBool()) {
main->statusBar()->setVisible(true);
}
}
}
else {
main->statusBar()->setProperty("wasvisible", main->statusBar()->isVisible());
main->statusBar()->setVisible(false);
}
}
}
if (cfg.hideDockersFullscreen()) {
KisAction* action = qobject_cast<KisAction*>(main->actionCollection()->action("view_toggledockers"));
if (action) {
action->setCheckable(true);
if (toggled) {
if (action->isChecked()) {
cfg.setShowDockers(action->isChecked());
action->setChecked(false);
} else {
cfg.setShowDockers(false);
}
} else {
action->setChecked(cfg.showDockers());
}
}
}
// QT in windows does not return to maximized upon 4th tab in a row
// https://bugreports.qt.io/browse/QTBUG-57882, https://bugreports.qt.io/browse/QTBUG-52555, https://codereview.qt-project.org/#/c/185016/
if (cfg.hideTitlebarFullscreen() && !cfg.fullscreenMode()) {
if(toggled) {
main->setWindowState( main->windowState() | Qt::WindowFullScreen);
} else {
main->setWindowState( main->windowState() & ~Qt::WindowFullScreen);
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
// If window was maximized prior to fullscreen, restore that
if (d->windowFlags & Qt::WindowMaximized) {
main->setWindowState( main->windowState() | Qt::WindowMaximized);
}
#endif
}
}
if (cfg.hideMenuFullscreen()) {
if (!toggled) {
if (main->menuBar()->dynamicPropertyNames().contains("wasvisible")) {
if (main->menuBar()->property("wasvisible").toBool()) {
main->menuBar()->setVisible(true);
}
}
}
else {
main->menuBar()->setProperty("wasvisible", main->menuBar()->isVisible());
main->menuBar()->setVisible(false);
}
}
if (cfg.hideToolbarFullscreen()) {
QList<QToolBar*> toolBars = main->findChildren<QToolBar*>();
Q_FOREACH (QToolBar* toolbar, toolBars) {
if (!toggled) {
if (toolbar->dynamicPropertyNames().contains("wasvisible")) {
if (toolbar->property("wasvisible").toBool()) {
toolbar->setVisible(true);
}
}
}
else {
toolbar->setProperty("wasvisible", toolbar->isVisible());
toolbar->setVisible(false);
}
}
}
showHideScrollbars();
if (toggled) {
// show a fading heads-up display about the shortcut to go back
showFloatingMessage(i18n("Going into Canvas-Only mode.\nPress %1 to go back.",
actionCollection()->action("view_show_canvas_only")->shortcut().toString()), QIcon());
}
else {
main->restoreState(d->canvasState);
}
}
void KisViewManager::toggleTabletLogger()
{
d->inputManager.toggleTabletLogger();
}
void KisViewManager::openResourcesDirectory()
{
QString dir = KoResourcePaths::locateLocal("data", "");
QDesktopServices::openUrl(QUrl::fromLocalFile(dir));
}
void KisViewManager::updateIcons()
{
if (mainWindow()) {
QList<QDockWidget*> dockers = mainWindow()->dockWidgets();
Q_FOREACH (QDockWidget* dock, dockers) {
QObjectList objects;
objects.append(dock);
while (!objects.isEmpty()) {
QObject* object = objects.takeFirst();
objects.append(object->children());
KisIconUtils::updateIconCommon(object);
}
}
}
}
void KisViewManager::initializeStatusBarVisibility()
{
KisConfig cfg(true);
d->mainWindow->statusBar()->setVisible(cfg.showStatusBar());
}
void KisViewManager::guiUpdateTimeout()
{
d->nodeManager.updateGUI();
d->selectionManager.updateGUI();
d->filterManager.updateGUI();
if (zoomManager()) {
zoomManager()->updateGuiAfterDocumentSize();
}
d->gridManager.updateGUI();
d->actionManager.updateGUI();
}
void KisViewManager::showFloatingMessage(const QString &message, const QIcon& icon, int timeout, KisFloatingMessage::Priority priority, int alignment)
{
if (!d->currentImageView) return;
d->currentImageView->showFloatingMessage(message, icon, timeout, priority, alignment);
emit floatingMessageRequested(message, icon.name());
}
KisMainWindow *KisViewManager::mainWindow() const
{
return qobject_cast<KisMainWindow*>(d->mainWindow);
}
void KisViewManager::showHideScrollbars()
{
if (!d->currentImageView) return;
if (!d->currentImageView->canvasController()) return;
KisConfig cfg(true);
bool toggled = actionCollection()->action("view_show_canvas_only")->isChecked();
if ( (toggled && cfg.hideScrollbarsFullscreen()) || (!toggled && cfg.hideScrollbars()) ) {
d->currentImageView->canvasController()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
d->currentImageView->canvasController()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
} else {
d->currentImageView->canvasController()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
d->currentImageView->canvasController()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
}
}
void KisViewManager::slotSaveShowRulersState(bool value)
{
KisConfig cfg(false);
cfg.setShowRulers(value);
}
void KisViewManager::slotSaveRulersTrackMouseState(bool value)
{
KisConfig cfg(false);
cfg.setRulersTrackMouse(value);
}
void KisViewManager::setShowFloatingMessage(bool show)
{
d->showFloatingMessage = show;
}
void KisViewManager::changeAuthorProfile(const QString &profileName)
{
KConfigGroup appAuthorGroup(KSharedConfig::openConfig(), "Author");
if (profileName.isEmpty() || profileName == i18nc("choice for author profile", "Anonymous")) {
appAuthorGroup.writeEntry("active-profile", "");
} else {
appAuthorGroup.writeEntry("active-profile", profileName);
}
appAuthorGroup.sync();
Q_FOREACH (KisDocument *doc, KisPart::instance()->documents()) {
doc->documentInfo()->updateParameters();
}
}
void KisViewManager::slotUpdateAuthorProfileActions()
{
Q_ASSERT(d->actionAuthor);
if (!d->actionAuthor) {
return;
}
d->actionAuthor->clear();
d->actionAuthor->addAction(i18nc("choice for author profile", "Anonymous"));
KConfigGroup authorGroup(KSharedConfig::openConfig(), "Author");
QStringList profiles = authorGroup.readEntry("profile-names", QStringList());
QString authorInfo = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/authorinfo/";
QStringList filters = QStringList() << "*.authorinfo";
QDir dir(authorInfo);
Q_FOREACH(QString entry, dir.entryList(filters)) {
int ln = QString(".authorinfo").size();
entry.chop(ln);
if (!profiles.contains(entry)) {
profiles.append(entry);
}
}
Q_FOREACH (const QString &profile , profiles) {
d->actionAuthor->addAction(profile);
}
KConfigGroup appAuthorGroup(KSharedConfig::openConfig(), "Author");
QString profileName = appAuthorGroup.readEntry("active-profile", "");
if (profileName == "anonymous" || profileName.isEmpty()) {
d->actionAuthor->setCurrentItem(0);
} else if (profiles.contains(profileName)) {
d->actionAuthor->setCurrentAction(profileName);
}
}
void KisViewManager::slotUpdatePixelGridAction()
{
KIS_SAFE_ASSERT_RECOVER_RETURN(d->showPixelGrid);
KisSignalsBlocker b(d->showPixelGrid);
KisConfig cfg(true);
d->showPixelGrid->setChecked(cfg.pixelGridEnabled() && cfg.useOpenGL());
}
void KisViewManager::slotActivateTransformTool()
{
if(KoToolManager::instance()->activeToolId() == "KisToolTransform") {
KoToolBase* tool = KoToolManager::instance()->toolById(canvasBase(), "KisToolTransform");
QSet<KoShape*> dummy;
// Start a new stroke
tool->deactivate();
tool->activate(KoToolBase::DefaultActivation, dummy);
}
KoToolManager::instance()->switchToolRequested("KisToolTransform");
}
void KisViewManager::slotToggleFgBg()
{
KoColor newFg = d->canvasResourceManager.backgroundColor();
KoColor newBg = d->canvasResourceManager.foregroundColor();
/**
* NOTE: Some of color selectors do not differentiate foreground
* and background colors, so if one wants them to end up
* being set up to foreground color, it should be set the
* last.
*/
d->canvasResourceManager.setBackgroundColor(newBg);
d->canvasResourceManager.setForegroundColor(newFg);
}
void KisViewManager::slotResetFgBg()
{
// see a comment in slotToggleFgBg()
d->canvasResourceManager.setBackgroundColor(KoColor(Qt::white, KoColorSpaceRegistry::instance()->rgb8()));
d->canvasResourceManager.setForegroundColor(KoColor(Qt::black, KoColorSpaceRegistry::instance()->rgb8()));
}
void KisViewManager::slotResetRotation()
{
KisCanvasController *canvasController = d->currentImageView->canvasController();
canvasController->resetCanvasRotation();
}
void KisViewManager::slotToggleFullscreen()
{
KisConfig cfg(false);
KisMainWindow *main = mainWindow();
main->viewFullscreen(!main->isFullScreen());
cfg.fullscreenMode(main->isFullScreen());
}
diff --git a/libs/odf/KoDocumentInfo.cpp b/libs/ui/KoDocumentInfo.cpp
similarity index 98%
rename from libs/odf/KoDocumentInfo.cpp
rename to libs/ui/KoDocumentInfo.cpp
index 76b9753047..e96c2d833e 100644
--- a/libs/odf/KoDocumentInfo.cpp
+++ b/libs/ui/KoDocumentInfo.cpp
@@ -1,467 +1,465 @@
/* This file is part of the KDE project
Copyright (C) 1998, 1999, 2000 Torben Weis <weis@kde.org>
Copyright (C) 2004 David Faure <faure@kde.org>
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 "KoDocumentInfo.h"
-#include "KoDocumentBase.h"
-#include "KoOdfWriteStore.h"
+#include "KisDocument.h"
#include "KoXmlNS.h"
#include <QDateTime>
#include <KoStoreDevice.h>
#include <KoXmlWriter.h>
#include <QDomDocument>
#include <KoXmlReader.h>
#include <QDir>
#include <kconfig.h>
#include <kconfiggroup.h>
-#include <OdfDebug.h>
#include <klocalizedstring.h>
#include <kuser.h>
#include <kemailsettings.h>
#include <KritaVersionWrapper.h>
KoDocumentInfo::KoDocumentInfo(QObject *parent) : QObject(parent)
{
m_aboutTags << "title" << "description" << "subject" << "abstract"
<< "keyword" << "initial-creator" << "editing-cycles" << "editing-time"
<< "date" << "creation-date" << "language" << "license";
m_authorTags << "creator" << "creator-first-name" << "creator-last-name" << "initial" << "author-title" << "position" << "company";
m_contactTags << "email" << "telephone" << "telephone-work" << "fax" << "country" << "postal-code" << "city" << "street";
setAboutInfo("editing-cycles", "0");
setAboutInfo("time-elapsed", "0");
setAboutInfo("initial-creator", i18n("Unknown"));
setAboutInfo("creation-date", QDateTime::currentDateTime()
.toString(Qt::ISODate));
}
KoDocumentInfo::KoDocumentInfo(const KoDocumentInfo &rhs, QObject *parent)
: QObject(parent),
m_aboutTags(rhs.m_aboutTags),
m_authorTags(rhs.m_authorTags),
m_contact(rhs.m_contact),
m_authorInfo(rhs.m_authorInfo),
m_authorInfoOverride(rhs.m_authorInfoOverride),
m_aboutInfo(rhs.m_aboutInfo),
m_generator(rhs.m_generator)
{
}
KoDocumentInfo::~KoDocumentInfo()
{
}
bool KoDocumentInfo::load(const KoXmlDocument &doc)
{
m_authorInfo.clear();
if (!loadAboutInfo(doc.documentElement()))
return false;
if (!loadAuthorInfo(doc.documentElement()))
return false;
return true;
}
QDomDocument KoDocumentInfo::save(QDomDocument &doc)
{
updateParametersAndBumpNumCycles();
QDomElement s = saveAboutInfo(doc);
if (!s.isNull())
doc.documentElement().appendChild(s);
s = saveAuthorInfo(doc);
if (!s.isNull())
doc.documentElement().appendChild(s);
if (doc.documentElement().isNull())
return QDomDocument();
return doc;
}
void KoDocumentInfo::setAuthorInfo(const QString &info, const QString &data)
{
if (!m_authorTags.contains(info) && !m_contactTags.contains(info) && !info.contains("contact-mode-")) {
return;
}
m_authorInfoOverride.insert(info, data);
}
void KoDocumentInfo::setActiveAuthorInfo(const QString &info, const QString &data)
{
if (!m_authorTags.contains(info) && !m_contactTags.contains(info) && !info.contains("contact-mode-")) {
return;
}
if (m_contactTags.contains(info)) {
m_contact.insert(data, info);
} else {
m_authorInfo.insert(info, data);
}
emit infoUpdated(info, data);
}
QString KoDocumentInfo::authorInfo(const QString &info) const
{
if (!m_authorTags.contains(info) && !m_contactTags.contains(info) && !info.contains("contact-mode-"))
return QString();
return m_authorInfo[ info ];
}
QStringList KoDocumentInfo::authorContactInfo() const
{
return m_contact.keys();
}
void KoDocumentInfo::setAboutInfo(const QString &info, const QString &data)
{
if (!m_aboutTags.contains(info))
return;
m_aboutInfo.insert(info, data);
emit infoUpdated(info, data);
}
QString KoDocumentInfo::aboutInfo(const QString &info) const
{
if (!m_aboutTags.contains(info)) {
return QString();
}
return m_aboutInfo[info];
}
bool KoDocumentInfo::saveOasisAuthorInfo(KoXmlWriter &xmlWriter)
{
Q_FOREACH (const QString & tag, m_authorTags) {
if (!authorInfo(tag).isEmpty() && tag == "creator") {
xmlWriter.startElement("dc:creator");
xmlWriter.addTextNode(authorInfo("creator"));
xmlWriter.endElement();
} else if (!authorInfo(tag).isEmpty()) {
xmlWriter.startElement("meta:user-defined");
xmlWriter.addAttribute("meta:name", tag);
xmlWriter.addTextNode(authorInfo(tag));
xmlWriter.endElement();
}
}
return true;
}
bool KoDocumentInfo::loadOasisAuthorInfo(const KoXmlNode &metaDoc)
{
KoXmlElement e = KoXml::namedItemNS(metaDoc, KoXmlNS::dc, "creator");
if (!e.isNull() && !e.text().isEmpty())
setActiveAuthorInfo("creator", e.text());
KoXmlNode n = metaDoc.firstChild();
for (; !n.isNull(); n = n.nextSibling()) {
if (!n.isElement())
continue;
KoXmlElement e = n.toElement();
if (!(e.namespaceURI() == KoXmlNS::meta &&
e.localName() == "user-defined" && !e.text().isEmpty()))
continue;
QString name = e.attributeNS(KoXmlNS::meta, "name", QString());
setActiveAuthorInfo(name, e.text());
}
return true;
}
bool KoDocumentInfo::loadAuthorInfo(const KoXmlElement &e)
{
m_contact.clear();
KoXmlNode n = e.namedItem("author").firstChild();
for (; !n.isNull(); n = n.nextSibling()) {
KoXmlElement e = n.toElement();
if (e.isNull())
continue;
if (e.tagName() == "full-name") {
setActiveAuthorInfo("creator", e.text().trimmed());
} else if (e.tagName() == "contact") {
m_contact.insert(e.text(), e.attribute("type"));
} else {
setActiveAuthorInfo(e.tagName(), e.text().trimmed());
}
}
return true;
}
QDomElement KoDocumentInfo::saveAuthorInfo(QDomDocument &doc)
{
QDomElement e = doc.createElement("author");
QDomElement t;
Q_FOREACH (const QString &tag, m_authorTags) {
if (tag == "creator")
t = doc.createElement("full-name");
else
t = doc.createElement(tag);
e.appendChild(t);
t.appendChild(doc.createTextNode(authorInfo(tag)));
}
for (int i=0; i<m_contact.keys().size(); i++) {
t = doc.createElement("contact");
e.appendChild(t);
QString key = m_contact.keys().at(i);
t.setAttribute("type", m_contact[key]);
t.appendChild(doc.createTextNode(key));
}
return e;
}
bool KoDocumentInfo::saveOasisAboutInfo(KoXmlWriter &xmlWriter)
{
Q_FOREACH (const QString &tag, m_aboutTags) {
if (!aboutInfo(tag).isEmpty() || tag == "title") {
if (tag == "keyword") {
Q_FOREACH (const QString & tmp, aboutInfo("keyword").split(';')) {
xmlWriter.startElement("meta:keyword");
xmlWriter.addTextNode(tmp);
xmlWriter.endElement();
}
} else if (tag == "title" || tag == "description" || tag == "subject" ||
tag == "date" || tag == "language") {
QByteArray elementName(QString("dc:" + tag).toLatin1());
xmlWriter.startElement(elementName.constData());
xmlWriter.addTextNode(aboutInfo(tag));
xmlWriter.endElement();
} else {
QByteArray elementName(QString("meta:" + tag).toLatin1());
xmlWriter.startElement(elementName.constData());
xmlWriter.addTextNode(aboutInfo(tag));
xmlWriter.endElement();
}
}
}
return true;
}
bool KoDocumentInfo::loadOasisAboutInfo(const KoXmlNode &metaDoc)
{
QStringList keywords;
KoXmlElement e;
forEachElement(e, metaDoc) {
QString tag(e.localName());
if (! m_aboutTags.contains(tag) && tag != "generator") {
continue;
}
//debugOdf<<"localName="<<e.localName();
if (tag == "keyword") {
if (!e.text().isEmpty())
keywords << e.text().trimmed();
} else if (tag == "description") {
//this is the odf way but add meta:comment if is already loaded
KoXmlElement e = KoXml::namedItemNS(metaDoc, KoXmlNS::dc, tag);
if (!e.isNull() && !e.text().isEmpty())
setAboutInfo("description", aboutInfo("description") + e.text().trimmed());
} else if (tag == "abstract") {
//this was the old way so add it to dc:description
KoXmlElement e = KoXml::namedItemNS(metaDoc, KoXmlNS::meta, tag);
if (!e.isNull() && !e.text().isEmpty())
setAboutInfo("description", aboutInfo("description") + e.text().trimmed());
} else if (tag == "title"|| tag == "subject"
|| tag == "date" || tag == "language") {
KoXmlElement e = KoXml::namedItemNS(metaDoc, KoXmlNS::dc, tag);
if (!e.isNull() && !e.text().isEmpty())
setAboutInfo(tag, e.text().trimmed());
} else if (tag == "generator") {
setOriginalGenerator(e.text().trimmed());
} else {
KoXmlElement e = KoXml::namedItemNS(metaDoc, KoXmlNS::meta, tag);
if (!e.isNull() && !e.text().isEmpty())
setAboutInfo(tag, e.text().trimmed());
}
}
if (keywords.count() > 0) {
setAboutInfo("keyword", keywords.join(", "));
}
return true;
}
bool KoDocumentInfo::loadAboutInfo(const KoXmlElement &e)
{
KoXmlNode n = e.namedItem("about").firstChild();
KoXmlElement tmp;
for (; !n.isNull(); n = n.nextSibling()) {
tmp = n.toElement();
if (tmp.isNull())
continue;
if (tmp.tagName() == "abstract")
setAboutInfo("abstract", tmp.text());
setAboutInfo(tmp.tagName(), tmp.text());
}
return true;
}
QDomElement KoDocumentInfo::saveAboutInfo(QDomDocument &doc)
{
QDomElement e = doc.createElement("about");
QDomElement t;
Q_FOREACH (const QString &tag, m_aboutTags) {
if (tag == "abstract") {
t = doc.createElement("abstract");
e.appendChild(t);
t.appendChild(doc.createCDATASection(aboutInfo(tag)));
} else {
t = doc.createElement(tag);
e.appendChild(t);
t.appendChild(doc.createTextNode(aboutInfo(tag)));
}
}
return e;
}
void KoDocumentInfo::updateParametersAndBumpNumCycles()
{
- KoDocumentBase *doc = dynamic_cast< KoDocumentBase *>(parent());
+ KisDocument *doc = dynamic_cast< KisDocument *>(parent());
if (doc && doc->isAutosaving()) {
return;
}
setAboutInfo("editing-cycles", QString::number(aboutInfo("editing-cycles").toInt() + 1));
setAboutInfo("date", QDateTime::currentDateTime().toString(Qt::ISODate));
updateParameters();
}
void KoDocumentInfo::updateParameters()
{
- KoDocumentBase *doc = dynamic_cast< KoDocumentBase *>(parent());
+ KisDocument *doc = dynamic_cast< KisDocument *>(parent());
if (doc && (!doc->isModified())) {
return;
}
KConfig config("kritarc");
config.reparseConfiguration();
KConfigGroup appAuthorGroup(&config, "Author");
QString profile = appAuthorGroup.readEntry("active-profile", "");
QString authorInfo = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/authorinfo/";
QDir dir(authorInfo);
QStringList filters = QStringList() << "*.authorinfo";
//Anon case
setActiveAuthorInfo("creator", QString());
setActiveAuthorInfo("initial", "");
setActiveAuthorInfo("author-title", "");
setActiveAuthorInfo("position", "");
setActiveAuthorInfo("company", "");
if (dir.entryList(filters).contains(profile+".authorinfo")) {
QFile file(dir.absoluteFilePath(profile+".authorinfo"));
if (file.exists()) {
file.open(QFile::ReadOnly);
QByteArray ba = file.readAll();
file.close();
QDomDocument doc = QDomDocument();
doc.setContent(ba);
QDomElement root = doc.firstChildElement();
QDomElement el = root.firstChildElement("nickname");
if (!el.isNull()) {
setActiveAuthorInfo("creator", el.text());
}
el = root.firstChildElement("givenname");
if (!el.isNull()) {
setActiveAuthorInfo("creator-first-name", el.text());
}
el = root.firstChildElement("middlename");
if (!el.isNull()) {
setActiveAuthorInfo("initial", el.text());
}
el = root.firstChildElement("familyname");
if (!el.isNull()) {
setActiveAuthorInfo("creator-last-name", el.text());
}
el = root.firstChildElement("title");
if (!el.isNull()) {
setActiveAuthorInfo("author-title", el.text());
}
el = root.firstChildElement("position");
if (!el.isNull()) {
setActiveAuthorInfo("position", el.text());
}
el = root.firstChildElement("company");
if (!el.isNull()) {
setActiveAuthorInfo("company", el.text());
}
m_contact.clear();
el = root.firstChildElement("contact");
while (!el.isNull()) {
m_contact.insert(el.text(), el.attribute("type"));
el = el.nextSiblingElement("contact");
}
}
}
//allow author info set programmatically to override info from author profile
Q_FOREACH (const QString &tag, m_authorTags) {
if (m_authorInfoOverride.contains(tag)) {
setActiveAuthorInfo(tag, m_authorInfoOverride.value(tag));
}
}
}
void KoDocumentInfo::resetMetaData()
{
setAboutInfo("editing-cycles", QString::number(0));
setAboutInfo("initial-creator", authorInfo("creator"));
setAboutInfo("creation-date", QDateTime::currentDateTime().toString(Qt::ISODate));
setAboutInfo("editing-time", QString::number(0));
}
QString KoDocumentInfo::originalGenerator() const
{
return m_generator;
}
void KoDocumentInfo::setOriginalGenerator(const QString &generator)
{
m_generator = generator;
}
diff --git a/libs/odf/KoDocumentInfo.h b/libs/ui/KoDocumentInfo.h
similarity index 98%
rename from libs/odf/KoDocumentInfo.h
rename to libs/ui/KoDocumentInfo.h
index 019b0b45fb..b73932c88c 100644
--- a/libs/odf/KoDocumentInfo.h
+++ b/libs/ui/KoDocumentInfo.h
@@ -1,224 +1,224 @@
/* This file is part of the KDE project
Copyright (C) 1998, 1999, 2000 Torben Weis <weis@kde.org>
Copyright (C) 2004 David Faure <faure@kde.org>
Copyright (C) 2006 Martin Pfeiffer <hubipete@gmx.net>
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_DOCUMENT_INFO_H
#define KO_DOCUMENT_INFO_H
#include <QObject>
#include <QMap>
#include <QString>
#include <QStringList>
-#include "kritaodf_export.h"
+#include "kritaui_export.h"
#include <KoXmlReaderForward.h>
class QDomDocument;
class QDomElement;
class KoStore;
class KoXmlWriter;
/**
* @short The class containing all meta information about a document
*
* @author Torben Weis <weis@kde.org>
* @author David Faure <faure@kde.org>
* @author Martin Pfeiffer <hubipete@gmx.net>
* @see KoDocumentInfoDlg
*
* This class contains the meta information for a document. They are
* stored in two QMap and can be accessed through aboutInfo() and authorInfo().
* The about info can be changed with setAboutInfo() and setAuthorInfo()
*/
-class KRITAODF_EXPORT KoDocumentInfo : public QObject
+class KRITAUI_EXPORT KoDocumentInfo : public QObject
{
Q_OBJECT
public:
/**
* The constructor
* @param parent a pointer to the parent object
*/
explicit KoDocumentInfo(QObject *parent = 0);
explicit KoDocumentInfo(const KoDocumentInfo &rhs, QObject *parent = 0);
/** The destructor */
~KoDocumentInfo() override;
/**
* Load the KoDocumentInfo from an Calligra-1.3 DomDocument
* @param doc the QDomDocument to load from
* @return true if success
*/
bool load(const KoXmlDocument& doc);
/**
* Save the KoDocumentInfo to an Calligra-1.3 DomDocument
* @return the QDomDocument to which was saved
*/
QDomDocument save(QDomDocument &doc);
/**
* Set information about the author.
* This will override any information retrieved from the author profile
* But it does not change the author profile
* Note: authorInfo() will not return the new value until the document has been
* saved by the user.(autosave doesn't count)
* @param info the kind of information to set
* @param data the data to set for this information
*/
void setAuthorInfo(const QString& info, const QString& data);
/**
* Obtain information about the author
* @param info the kind of information to obtain
* @return a QString with the information
*/
QString authorInfo(const QString& info) const;
/**
* @brief authorContactInfo
* @return returns list of contact info for author.
*/
QStringList authorContactInfo() const;
/**
* Set information about the document
* @param info the kind of information to set
* @param data the data to set for this information
*/
void setAboutInfo(const QString& info, const QString& data);
/**
* Obtain information about the document
* @param info the kind of information to obtain
* @return a QString with the information
*/
QString aboutInfo(const QString& info) const;
/**
* Obtain the generator of the document, as it was loaded from the document
*/
QString originalGenerator() const;
/**
* Sets the original generator of the document. This does not affect what gets
* saved to a document in the meta:generator field, it only changes what
* originalGenerator() will return.
*/
void setOriginalGenerator(const QString& generator);
/** Resets part of the meta data */
void resetMetaData();
/** Takes care of updating the document info from configuration correctly */
void updateParameters();
private:
/// Bumps the editing cycles count and save date, and then calls updateParameters
void updateParametersAndBumpNumCycles();
/**
* Set information about the author
* This sets what is actually saved to file. The public method setAuthorInfo() can be used to set
* values that override what is fetched from the author profile. During saveParameters() author
* profile and any overrides is combined resulting in calls to this method.
* @param info the kind of information to set
* @param data the data to set for this information
*/
void setActiveAuthorInfo(const QString& info, const QString& data);
/**
* Load the information about the document from an OASIS file
* @param metaDoc a reference to the information node
* @return true if success
*/
bool loadOasisAboutInfo(const KoXmlNode& metaDoc);
/**
* Save the information about the document to an OASIS file
* @param xmlWriter a reference to the KoXmlWriter to write in
* @return true if success
*/
bool saveOasisAboutInfo(KoXmlWriter &xmlWriter);
/**
* Load the information about the document from a Calligra-1.3 file
* @param e the element to load from
* @return true if success
*/
bool loadAboutInfo(const KoXmlElement& e);
/**
* Save the information about the document to a Calligra-1.3 file
* @param doc the QDomDocument to save in
* @return the QDomElement to which was saved
*/
QDomElement saveAboutInfo(QDomDocument& doc);
/**
* Load the information about the document from an OASIS file
* @param metaDoc a reference to the information node
* @return true if success
*/
bool loadOasisAuthorInfo(const KoXmlNode& metaDoc);
/**
* Load the information about the document from a Calligra-1.3 file
* @param e the element to load from
* @return true if success
*/
bool loadAuthorInfo(const KoXmlElement& e);
/**
* Save the information about the author to a Calligra-1.3 file
* @param doc the QDomDocument to save in
* @return the QDomElement to which was saved
*/
QDomElement saveAuthorInfo(QDomDocument& doc);
/**
* Save the information about the document to an OASIS file
* @param xmlWriter a reference to the KoXmlWriter to write in
* @return true if success
*/
bool saveOasisAuthorInfo(KoXmlWriter &xmlWriter);
/** A QStringList containing all tags for the document information */
QStringList m_aboutTags;
/** A QStringList containing all tags for the author information */
QStringList m_authorTags;
/** A QStringList containing all valid contact tags */
QStringList m_contactTags;
/** A QMap with the contact modes and their type in the second string */
QMap <QString, QString> m_contact;
/** The map containing information about the author */
QMap<QString, QString> m_authorInfo;
/** The map containing information about the author set programmatically*/
QMap<QString, QString> m_authorInfoOverride;
/** The map containing information about the document */
QMap<QString, QString> m_aboutInfo;
/** The original meta:generator of the document */
QString m_generator;
Q_SIGNALS:
void infoUpdated(const QString &info, const QString &data);
};
#endif
diff --git a/libs/widgets/KoDocumentInfoDlg.cpp b/libs/ui/KoDocumentInfoDlg.cpp
similarity index 98%
rename from libs/widgets/KoDocumentInfoDlg.cpp
rename to libs/ui/KoDocumentInfoDlg.cpp
index a08f3af681..c4b762f5ce 100644
--- a/libs/widgets/KoDocumentInfoDlg.cpp
+++ b/libs/ui/KoDocumentInfoDlg.cpp
@@ -1,327 +1,327 @@
/* This file is part of the KDE project
Copyright (c) 2000 Simon Hausmann <hausmann@kde.org>
2006 Martin Pfeiffer <hubipete@gmx.net>
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 "KoDocumentInfoDlg.h"
#include "ui_koDocumentInfoAboutWidget.h"
#include "ui_koDocumentInfoAuthorWidget.h"
#include "KoDocumentInfo.h"
-#include "KoDocumentBase.h"
+#include "KisDocument.h"
#include "KoPageWidgetItem.h"
#include <KoIcon.h>
#include <klocalizedstring.h>
#include <kmainwindow.h>
#include <KoDialog.h>
#include <QUrl>
#include <QCompleter>
#include <QLineEdit>
#include <QDateTime>
#include <KisMimeDatabase.h>
class KoPageWidgetItemAdapter : public KPageWidgetItem
{
public:
KoPageWidgetItemAdapter(KoPageWidgetItem *item)
: KPageWidgetItem(item->widget(), item->name())
, m_item(item)
{
setHeader(item->name());
setIcon(KisIconUtils::loadIcon(item->iconName()));
}
~KoPageWidgetItemAdapter() override { delete m_item; }
bool shouldDialogCloseBeVetoed() { return m_item->shouldDialogCloseBeVetoed(); }
void apply() { m_item->apply(); }
private:
KoPageWidgetItem * const m_item;
};
class KoDocumentInfoDlg::KoDocumentInfoDlgPrivate
{
public:
KoDocumentInfoDlgPrivate() :
documentSaved(false) {}
~KoDocumentInfoDlgPrivate() {}
KoDocumentInfo* info;
QList<KPageWidgetItem*> pages;
Ui::KoDocumentInfoAboutWidget* aboutUi;
Ui::KoDocumentInfoAuthorWidget* authorUi;
bool documentSaved;
};
KoDocumentInfoDlg::KoDocumentInfoDlg(QWidget* parent, KoDocumentInfo* docInfo)
: KPageDialog(parent)
, d(new KoDocumentInfoDlgPrivate)
{
d->info = docInfo;
setWindowTitle(i18n("Document Information"));
// setInitialSize(QSize(500, 500));
setFaceType(KPageDialog::List);
setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
button(QDialogButtonBox::Ok)->setDefault(true);
d->aboutUi = new Ui::KoDocumentInfoAboutWidget();
QWidget *infodlg = new QWidget();
d->aboutUi->setupUi(infodlg);
QStringList licenseExamples;
licenseExamples << "CC-BY 4.0" << "CC-BY-SA 4.0" << "CC-BY-SA-NC 4.0" << "CC-0";
QCompleter *examples = new QCompleter(licenseExamples);
examples->setCaseSensitivity(Qt::CaseInsensitive);
examples->setCompletionMode(QCompleter::PopupCompletion);
d->aboutUi->leLicense->setCompleter(examples);
KPageWidgetItem *page = new KPageWidgetItem(infodlg, i18n("General"));
page->setHeader(i18n("General"));
// Ugly hack, the mimetype should be a parameter, instead
- KoDocumentBase* doc = dynamic_cast< KoDocumentBase* >(d->info->parent());
+ KisDocument* doc = dynamic_cast< KisDocument* >(d->info->parent());
if (doc) {
page->setIcon(KisIconUtils::loadIcon(KisMimeDatabase::iconNameForMimeType(doc->mimeType())));
} else {
// hide all entries not used in pages for KoDocumentInfoPropsPage
d->aboutUi->filePathInfoLabel->setVisible(false);
d->aboutUi->filePathLabel->setVisible(false);
d->aboutUi->filePathSeparatorLine->setVisible(false);
d->aboutUi->lblTypeDesc->setVisible(false);
d->aboutUi->lblType->setVisible(false);
}
addPage(page);
d->pages.append(page);
initAboutTab();
d->authorUi = new Ui::KoDocumentInfoAuthorWidget();
QWidget *authordlg = new QWidget();
d->authorUi->setupUi(authordlg);
page = new KPageWidgetItem(authordlg, i18n("Author"));
page->setHeader(i18n("Last saved by"));
page->setIcon(koIcon("user-identity"));
addPage(page);
d->pages.append(page);
initAuthorTab();
}
KoDocumentInfoDlg::~KoDocumentInfoDlg()
{
delete d->authorUi;
delete d->aboutUi;
delete d;
}
void KoDocumentInfoDlg::accept()
{
// check if any pages veto the close
Q_FOREACH (KPageWidgetItem* item, d->pages) {
KoPageWidgetItemAdapter *page = dynamic_cast<KoPageWidgetItemAdapter*>(item);
if (page) {
if (page->shouldDialogCloseBeVetoed()) {
return;
}
}
}
// all fine, go and apply
saveAboutData();
Q_FOREACH (KPageWidgetItem* item, d->pages) {
KoPageWidgetItemAdapter *page = dynamic_cast<KoPageWidgetItemAdapter*>(item);
if (page) {
page->apply();
}
}
KPageDialog::accept();
}
bool KoDocumentInfoDlg::isDocumentSaved()
{
return d->documentSaved;
}
void KoDocumentInfoDlg::initAboutTab()
{
- KoDocumentBase* doc = dynamic_cast< KoDocumentBase* >(d->info->parent());
+ KisDocument* doc = dynamic_cast< KisDocument* >(d->info->parent());
if (doc) {
d->aboutUi->filePathLabel->setText(doc->localFilePath());
}
d->aboutUi->leTitle->setText(d->info->aboutInfo("title"));
d->aboutUi->leSubject->setText(d->info->aboutInfo("subject"));
d->aboutUi->leKeywords->setToolTip(i18n("Use ';' (Example: Office;KDE;Calligra)"));
if (!d->info->aboutInfo("keyword").isEmpty())
d->aboutUi->leKeywords->setText(d->info->aboutInfo("keyword"));
if (!d->info->aboutInfo("license").isEmpty()) {
d->aboutUi->leLicense->setText(d->info->aboutInfo("license"));
}
d->aboutUi->meDescription->setPlainText(d->info->aboutInfo("abstract"));
if (doc && !doc->mimeType().isEmpty()) {
d->aboutUi->lblType->setText(KisMimeDatabase::descriptionForMimeType(doc->mimeType()));
}
if (!d->info->aboutInfo("creation-date").isEmpty()) {
QDateTime t = QDateTime::fromString(d->info->aboutInfo("creation-date"),
Qt::ISODate);
QString s = QLocale().toString(t);
d->aboutUi->lblCreated->setText(s + ", " +
d->info->aboutInfo("initial-creator"));
}
if (!d->info->aboutInfo("date").isEmpty()) {
QDateTime t = QDateTime::fromString(d->info->aboutInfo("date"), Qt::ISODate);
QString s = QLocale().toString(t);
d->aboutUi->lblModified->setText(s + ", " + d->info->authorInfo("creator"));
}
d->aboutUi->lblRevision->setText(d->info->aboutInfo("editing-cycles"));
updateEditingTime();
connect(d->aboutUi->pbReset, SIGNAL(clicked()),
this, SLOT(slotResetMetaData()));
}
void KoDocumentInfoDlg::initAuthorTab()
{
d->authorUi->nickName->setText(d->info->authorInfo("creator"));
d->authorUi->firstName->setText(d->info->authorInfo("creator-first-name"));
d->authorUi->lastName->setText(d->info->authorInfo("creator-last-name"));
d->authorUi->initials->setText(d->info->authorInfo("initial"));
d->authorUi->title->setText(d->info->authorInfo("author-title"));
d->authorUi->company->setText(d->info->authorInfo("company"));
d->authorUi->position->setText(d->info->authorInfo("position"));
QListWidget *contact = d->authorUi->leContact;
Q_FOREACH(QString contactMode, d->info->authorContactInfo()) {
if (!contactMode.isEmpty()) {
contact->addItem(contactMode);
}
}
}
void KoDocumentInfoDlg::saveAboutData()
{
d->info->setAboutInfo("keyword", d->aboutUi->leKeywords->text());
d->info->setAboutInfo("title", d->aboutUi->leTitle->text());
d->info->setAboutInfo("subject", d->aboutUi->leSubject->text());
d->info->setAboutInfo("abstract", d->aboutUi->meDescription->toPlainText());
d->info->setAboutInfo("license", d->aboutUi->leLicense->text());
}
void KoDocumentInfoDlg::hideEvent( QHideEvent *event )
{
Q_UNUSED(event);
}
void KoDocumentInfoDlg::slotResetMetaData()
{
d->info->resetMetaData();
if (!d->info->aboutInfo("creation-date").isEmpty()) {
QDateTime t = QDateTime::fromString(d->info->aboutInfo("creation-date"),
Qt::ISODate);
QString s = QLocale().toString(t);
d->aboutUi->lblCreated->setText(s + ", " +
d->info->aboutInfo("initial-creator"));
}
if (!d->info->aboutInfo("date").isEmpty()) {
QDateTime t = QDateTime::fromString(d->info->aboutInfo("date"), Qt::ISODate);
QString s = QLocale().toString(t);
d->aboutUi->lblModified->setText(s + ", " + d->info->authorInfo("creator"));
}
d->aboutUi->lblRevision->setText(d->info->aboutInfo("editing-cycles"));
}
QList<KPageWidgetItem*> KoDocumentInfoDlg::pages() const
{
return d->pages;
}
void KoDocumentInfoDlg::setReadOnly(bool ro)
{
d->aboutUi->meDescription->setReadOnly(ro);
Q_FOREACH(KPageWidgetItem* page, d->pages) {
Q_FOREACH(QLineEdit* le, page->widget()->findChildren<QLineEdit *>()) {
le->setReadOnly(ro);
}
Q_FOREACH(QPushButton* le, page->widget()->findChildren<QPushButton *>()) {
le->setDisabled(ro);
}
}
}
void KoDocumentInfoDlg::addPageItem(KoPageWidgetItem *item)
{
KPageWidgetItem * page = new KoPageWidgetItemAdapter(item);
addPage(page);
d->pages.append(page);
}
void KoDocumentInfoDlg::updateEditingTime()
{
const int timeElapsed = d->info->aboutInfo("editing-time").toInt();
const int secondsElapsed = timeElapsed % 60;
const int minutesElapsed = (timeElapsed / 60) % 60;
const int hoursElapsed = (timeElapsed / 3600) % 24;
const int daysElapsed = (timeElapsed / 86400) % 7;
const int weeksElapsed = timeElapsed / 604800;
QString majorTimeUnit;
QString minorTimeUnit;
if (weeksElapsed > 0) {
majorTimeUnit = i18np("%1 week", "%1 weeks", weeksElapsed);
minorTimeUnit = i18np("%1 day", "%1 days", daysElapsed);
} else if (daysElapsed > 0) {
majorTimeUnit = i18np("%1 day", "%1 days", daysElapsed);
minorTimeUnit = i18np("%1 hour", "%1 hours", hoursElapsed);
} else if (hoursElapsed > 0) {
majorTimeUnit = i18np("%1 hour", "%1 hours", hoursElapsed);
minorTimeUnit = i18np("%1 minute", "%1 minutes", minutesElapsed);
} else if (minutesElapsed > 0) {
majorTimeUnit = i18np("%1 minute", "%1 minutes", minutesElapsed);
minorTimeUnit = i18np("%1 second", "%1 seconds", secondsElapsed);
} else {
d->aboutUi->lblEditing->setText(i18np("%1 second", "%1 seconds", secondsElapsed));
return;
}
d->aboutUi->lblEditing->setText(i18nc(
"major time unit and minor time unit",
"%1 and %2",
majorTimeUnit,
minorTimeUnit
));
}
diff --git a/libs/widgets/KoDocumentInfoDlg.h b/libs/ui/KoDocumentInfoDlg.h
similarity index 96%
rename from libs/widgets/KoDocumentInfoDlg.h
rename to libs/ui/KoDocumentInfoDlg.h
index 10d626a645..50deb3c627 100644
--- a/libs/widgets/KoDocumentInfoDlg.h
+++ b/libs/ui/KoDocumentInfoDlg.h
@@ -1,102 +1,102 @@
/* This file is part of the KDE project
Copyright (c) 2000 Simon Hausmann <hausmann@kde.org>
2006 Martin Pfeiffer <hubipete@gmx.net>
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 __koDocumentInfoDlg_h__
#define __koDocumentInfoDlg_h__
#include <kpagedialog.h>
class KoDocumentInfo;
class KPageWidgetItem;
class KoPageWidgetItem;
-#include "kritawidgets_export.h"
+#include "kritaui_export.h"
/**
* @short The dialog that shows information about the document
* @author Simon Hausmann <hausmann@kde.org>
* @author Martin Pfeiffer <hubipete@gmx.net>
* @see KoDocumentInfo
*
* This dialog is invoked by KoMainWindow and shows the content
* of the given KoDocumentInfo class. It consists of several pages,
* one showing general information about the document and an other
* showing information about the author.
* This dialog implements only things that are stored in the OASIS
* meta.xml file and therefore available through the KoDocumentInfo
* class.
* The widgets shown in the tabs are koDocumentInfoAboutWidget and
* koDocumentInfoAuthorWidget. This class here is derived from
* KPageDialog and uses the face type Tabbed.
*/
-class KRITAWIDGETS_EXPORT KoDocumentInfoDlg : public KPageDialog
+class KRITAUI_EXPORT KoDocumentInfoDlg : public KPageDialog
{
Q_OBJECT
public:
/**
* The constructor
* @param parent a pointer to the parent widget
* @param docInfo a pointer to the shown KoDocumentInfo
*/
KoDocumentInfoDlg(QWidget *parent, KoDocumentInfo* docInfo);
/** The destructor */
~KoDocumentInfoDlg() override;
QList<KPageWidgetItem*> pages() const;
/** Returns true if the document was saved when the dialog was closed */
bool isDocumentSaved();
/** Sets all fields to read-only mode. Used by the property dialog. */
void setReadOnly(bool ro);
void addPageItem(KoPageWidgetItem *item);
public Q_SLOTS: // QDialog API
void accept() override;
protected: // QWidget API
void hideEvent(QHideEvent * event) override;
private Q_SLOTS:
/** Connected with clicked() from pbReset - Reset parts of the metadata */
void slotResetMetaData();
Q_SIGNALS:
void saveRequested();
private:
/** Sets up the aboutWidget and fills the widgets with content */
void initAboutTab();
/** Sets up the authorWidget and fills the widgets with content */
void initAuthorTab();
/** Saves the changed data back to the KoDocumentInfo class */
void saveAboutData();
void updateEditingTime();
class KoDocumentInfoDlgPrivate;
KoDocumentInfoDlgPrivate * const d;
};
#endif
diff --git a/libs/ui/actions/kis_selection_action_factories.cpp b/libs/ui/actions/kis_selection_action_factories.cpp
index 7d84a53dea..32ebdd0ee1 100644
--- a/libs/ui/actions/kis_selection_action_factories.cpp
+++ b/libs/ui/actions/kis_selection_action_factories.cpp
@@ -1,622 +1,624 @@
/*
* Copyright (c) 2012 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_selection_action_factories.h"
#include <QMimeData>
#include <klocalizedstring.h>
#include <kundo2command.h>
#include <KisMainWindow.h>
#include <KisDocument.h>
#include <KisPart.h>
#include <KoPathShape.h>
#include <KoShapeController.h>
#include <KoShapeRegistry.h>
#include <KoCompositeOpRegistry.h>
#include <KoShapeManager.h>
#include <KoSelection.h>
#include <KoDocumentResourceManager.h>
#include <KoShapeStroke.h>
#include <KoDocumentInfo.h>
+#include <KoCanvasBase.h>
#include "KisViewManager.h"
#include "kis_canvas_resource_provider.h"
#include "kis_clipboard.h"
#include "kis_pixel_selection.h"
#include "kis_paint_layer.h"
#include "kis_image.h"
#include "kis_image_barrier_locker.h"
#include "kis_fill_painter.h"
#include "kis_transaction.h"
#include "kis_iterator_ng.h"
#include "kis_processing_applicator.h"
#include "kis_group_layer.h"
#include "commands/kis_selection_commands.h"
#include "commands/kis_image_layer_add_command.h"
#include "kis_tool_proxy.h"
#include "kis_canvas2.h"
#include "kis_canvas_controller.h"
#include "kis_selection_manager.h"
#include "commands_new/kis_transaction_based_command.h"
#include "kis_selection_filters.h"
#include "kis_shape_selection.h"
#include "kis_shape_layer.h"
#include <kis_shape_controller.h>
#include "kis_image_animation_interface.h"
#include "kis_time_range.h"
#include "kis_keyframe_channel.h"
#include <processing/fill_processing_visitor.h>
#include <kis_selection_tool_helper.h>
#include "kis_figure_painting_tool_helper.h"
#include "kis_update_outline_job.h"
namespace ActionHelper {
void copyFromDevice(KisViewManager *view,
KisPaintDeviceSP device,
bool makeSharpClip = false,
const KisTimeRange &range = KisTimeRange())
{
KisImageWSP image = view->image();
if (!image) return;
KisSelectionSP selection = view->selection();
QRect rc = (selection) ? selection->selectedExactRect() : image->bounds();
KisPaintDeviceSP clip = new KisPaintDevice(device->colorSpace());
Q_CHECK_PTR(clip);
const KoColorSpace *cs = clip->colorSpace();
// TODO if the source is linked... copy from all linked layers?!?
// Copy image data
KisPainter::copyAreaOptimized(QPoint(), device, clip, rc);
if (selection) {
// Apply selection mask.
KisPaintDeviceSP selectionProjection = selection->projection();
KisHLineIteratorSP layerIt = clip->createHLineIteratorNG(0, 0, rc.width());
KisHLineConstIteratorSP selectionIt = selectionProjection->createHLineIteratorNG(rc.x(), rc.y(), rc.width());
const KoColorSpace *selCs = selection->projection()->colorSpace();
for (qint32 y = 0; y < rc.height(); y++) {
for (qint32 x = 0; x < rc.width(); x++) {
/**
* Sharp method is an exact reverse of COMPOSITE_OVER
* so if you cover the cut/copied piece over its source
* you get an exactly the same image without any seams
*/
if (makeSharpClip) {
qreal dstAlpha = cs->opacityF(layerIt->rawData());
qreal sel = selCs->opacityF(selectionIt->oldRawData());
qreal newAlpha = sel * dstAlpha / (1.0 - dstAlpha + sel * dstAlpha);
float mask = newAlpha / dstAlpha;
cs->applyAlphaNormedFloatMask(layerIt->rawData(), &mask, 1);
} else {
cs->applyAlphaU8Mask(layerIt->rawData(), selectionIt->oldRawData(), 1);
}
layerIt->nextPixel();
selectionIt->nextPixel();
}
layerIt->nextRow();
selectionIt->nextRow();
}
}
KisClipboard::instance()->setClip(clip, rc.topLeft(), range);
}
}
void KisSelectAllActionFactory::run(KisViewManager *view)
{
KisImageWSP image = view->image();
if (!image) return;
KisProcessingApplicator *ap = beginAction(view, kundo2_i18n("Select All"));
if (!image->globalSelection()) {
ap->applyCommand(new KisSetEmptyGlobalSelectionCommand(image),
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::EXCLUSIVE);
}
struct SelectAll : public KisTransactionBasedCommand {
SelectAll(KisImageSP image) : m_image(image) {}
KisImageSP m_image;
KUndo2Command* paint() override {
KisSelectionSP selection = m_image->globalSelection();
KisSelectionTransaction transaction(selection->pixelSelection());
selection->pixelSelection()->clear();
selection->pixelSelection()->select(m_image->bounds());
return transaction.endAndTake();
}
};
ap->applyCommand(new SelectAll(image),
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::EXCLUSIVE);
endAction(ap, KisOperationConfiguration(id()).toXML());
}
void KisDeselectActionFactory::run(KisViewManager *view)
{
KisImageWSP image = view->image();
if (!image) return;
KUndo2Command *cmd = new KisDeselectActiveSelectionCommand(view->selection(), image);
KisProcessingApplicator *ap = beginAction(view, cmd->text());
ap->applyCommand(cmd, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE);
endAction(ap, KisOperationConfiguration(id()).toXML());
}
void KisReselectActionFactory::run(KisViewManager *view)
{
KisImageWSP image = view->image();
if (!image) return;
KUndo2Command *cmd = new KisReselectActiveSelectionCommand(view->activeNode(), image);
KisProcessingApplicator *ap = beginAction(view, cmd->text());
ap->applyCommand(cmd, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE);
endAction(ap, KisOperationConfiguration(id()).toXML());
}
void KisFillActionFactory::run(const QString &fillSource, KisViewManager *view)
{
KisNodeSP node = view->activeNode();
if (!node || !node->hasEditablePaintDevice()) return;
KisSelectionSP selection = view->selection();
QRect selectedRect = selection ?
selection->selectedRect() : view->image()->bounds();
Q_UNUSED(selectedRect);
KisPaintDeviceSP filled = node->paintDevice()->createCompositionSourceDevice();
Q_UNUSED(filled);
bool usePattern = false;
bool useBgColor = false;
if (fillSource.contains("pattern")) {
usePattern = true;
} else if (fillSource.contains("bg")) {
useBgColor = true;
}
KisProcessingApplicator applicator(view->image(), node,
KisProcessingApplicator::NONE,
KisImageSignalVector() << ModifiedSignal,
kundo2_i18n("Flood Fill Layer"));
KisResourcesSnapshotSP resources =
new KisResourcesSnapshot(view->image(), node, view->canvasResourceProvider()->resourceManager());
if (!fillSource.contains("opacity")) {
resources->setOpacity(1.0);
}
KisProcessingVisitorSP visitor =
new FillProcessingVisitor(resources->image()->projection(),
QPoint(0, 0), // start position
selection,
resources,
false, // fast mode
usePattern,
true, // fill only selection,
0, // feathering radius
0, // sizemod
80, // threshold,
false, // use unmerged
useBgColor);
applicator.applyVisitor(visitor,
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::EXCLUSIVE);
applicator.end();
view->canvasResourceProvider()->slotPainting();
}
void KisClearActionFactory::run(KisViewManager *view)
{
// XXX: "Add saving of XML data for Clear action"
view->canvasBase()->toolProxy()->deleteSelection();
}
void KisImageResizeToSelectionActionFactory::run(KisViewManager *view)
{
// XXX: "Add saving of XML data for Image Resize To Selection action"
KisSelectionSP selection = view->selection();
if (!selection) return;
view->image()->cropImage(selection->selectedExactRect());
}
void KisCutCopyActionFactory::run(bool willCut, bool makeSharpClip, KisViewManager *view)
{
KisImageSP image = view->image();
if (!image) return;
bool haveShapesSelected = view->selectionManager()->haveShapesSelected();
if (haveShapesSelected) {
// XXX: "Add saving of XML data for Cut/Copy of shapes"
KisImageBarrierLocker locker(image);
if (willCut) {
view->canvasBase()->toolProxy()->cut();
} else {
view->canvasBase()->toolProxy()->copy();
}
} else {
KisNodeSP node = view->activeNode();
if (!node) return;
KisSelectionSP selection = view->selection();
if (selection.isNull()) return;
{
KisImageBarrierLocker locker(image);
KisPaintDeviceSP dev = node->paintDevice();
if (!dev) {
dev = node->projection();
}
if (!dev) {
view->showFloatingMessage(
i18nc("floating message when cannot copy from a node",
"Cannot copy pixels from this type of layer "),
QIcon(), 3000, KisFloatingMessage::Medium);
return;
}
if (dev->exactBounds().isEmpty()) {
view->showFloatingMessage(
i18nc("floating message when copying empty selection",
"Selection is empty: no pixels were copied "),
QIcon(), 3000, KisFloatingMessage::Medium);
return;
}
KisTimeRange range;
KisKeyframeChannel *channel = node->getKeyframeChannel(KisKeyframeChannel::Content.id());
if (channel) {
const int currentTime = image->animationInterface()->currentTime();
range = channel->affectedFrames(currentTime);
}
ActionHelper::copyFromDevice(view, dev, makeSharpClip, range);
}
KUndo2Command *command = 0;
if (willCut && node->hasEditablePaintDevice()) {
struct ClearSelection : public KisTransactionBasedCommand {
ClearSelection(KisNodeSP node, KisSelectionSP sel)
: m_node(node), m_sel(sel) {}
KisNodeSP m_node;
KisSelectionSP m_sel;
KUndo2Command* paint() override {
KisSelectionSP cutSelection = m_sel;
// Shrinking the cutting area was previously used
// for getting seamless cut-paste. Now we use makeSharpClip
// instead.
// QRect originalRect = cutSelection->selectedExactRect();
// static const int preciseSelectionThreshold = 16;
//
// if (originalRect.width() > preciseSelectionThreshold ||
// originalRect.height() > preciseSelectionThreshold) {
// cutSelection = new KisSelection(*m_sel);
// delete cutSelection->flatten();
//
// KisSelectionFilter* filter = new KisShrinkSelectionFilter(1, 1, false);
//
// QRect processingRect = filter->changeRect(originalRect);
// filter->process(cutSelection->pixelSelection(), processingRect);
// }
KisTransaction transaction(m_node->paintDevice());
m_node->paintDevice()->clearSelection(cutSelection);
m_node->setDirty(cutSelection->selectedRect());
return transaction.endAndTake();
}
};
command = new ClearSelection(node, selection);
}
KUndo2MagicString actionName = willCut ?
kundo2_i18n("Cut") :
kundo2_i18n("Copy");
KisProcessingApplicator *ap = beginAction(view, actionName);
if (command) {
ap->applyCommand(command,
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::NORMAL);
}
KisOperationConfiguration config(id());
config.setProperty("will-cut", willCut);
endAction(ap, config.toXML());
}
}
void KisCopyMergedActionFactory::run(KisViewManager *view)
{
KisImageWSP image = view->image();
if (!image) return;
if (!view->blockUntilOperationsFinished(image)) return;
image->barrierLock();
KisPaintDeviceSP dev = image->root()->projection();
ActionHelper::copyFromDevice(view, dev);
image->unlock();
KisProcessingApplicator *ap = beginAction(view, kundo2_i18n("Copy Merged"));
endAction(ap, KisOperationConfiguration(id()).toXML());
}
void KisInvertSelectionOperation::runFromXML(KisViewManager* view, const KisOperationConfiguration& config)
{
KisSelectionFilter* filter = new KisInvertSelectionFilter();
runFilter(filter, view, config);
}
void KisSelectionToVectorActionFactory::run(KisViewManager *view)
{
KisSelectionSP selection = view->selection();
if (selection->hasShapeSelection()) {
view->showFloatingMessage(i18nc("floating message",
"Selection is already in a vector format "),
QIcon(), 2000, KisFloatingMessage::Low);
return;
}
if (!selection->outlineCacheValid()) {
view->image()->addSpontaneousJob(new KisUpdateOutlineJob(selection, false, Qt::transparent));
if (!view->blockUntilOperationsFinished(view->image())) {
return;
}
}
QPainterPath selectionOutline = selection->outlineCache();
QTransform transform = view->canvasBase()->coordinatesConverter()->imageToDocumentTransform();
KoShape *shape = KoPathShape::createShapeFromPainterPath(transform.map(selectionOutline));
shape->setShapeId(KoPathShapeId);
/**
* Mark a shape that it belongs to a shape selection
*/
if(!shape->userData()) {
shape->setUserData(new KisShapeSelectionMarker);
}
KisProcessingApplicator *ap = beginAction(view, kundo2_i18n("Convert to Vector Selection"));
ap->applyCommand(view->canvasBase()->shapeController()->addShape(shape, 0),
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::EXCLUSIVE);
endAction(ap, KisOperationConfiguration(id()).toXML());
}
void KisSelectionToRasterActionFactory::run(KisViewManager *view)
{
KisSelectionSP selection = view->selection();
if (!selection->hasShapeSelection()) {
view->showFloatingMessage(i18nc("floating message",
"Selection is already in a raster format "),
QIcon(), 2000, KisFloatingMessage::Low);
return;
}
KisProcessingApplicator *ap = beginAction(view, kundo2_i18n("Convert to Vector Selection"));
struct RasterizeSelection : public KisTransactionBasedCommand {
RasterizeSelection(KisSelectionSP sel)
: m_sel(sel) {}
KisSelectionSP m_sel;
KUndo2Command* paint() override {
// just create an empty transaction: it will rasterize the
// selection and emit the necessary signals
KisTransaction transaction(m_sel->pixelSelection());
return transaction.endAndTake();
}
};
ap->applyCommand(new RasterizeSelection(selection),
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::EXCLUSIVE);
endAction(ap, KisOperationConfiguration(id()).toXML());
}
void KisShapesToVectorSelectionActionFactory::run(KisViewManager* view)
{
const QList<KoShape*> originalShapes = view->canvasBase()->shapeManager()->selection()->selectedShapes();
bool hasSelectionShapes = false;
QList<KoShape*> clonedShapes;
Q_FOREACH (KoShape *shape, originalShapes) {
if (dynamic_cast<KisShapeSelectionMarker*>(shape->userData())) {
hasSelectionShapes = true;
continue;
}
clonedShapes << shape->cloneShape();
}
if (clonedShapes.isEmpty()) {
if (hasSelectionShapes) {
view->showFloatingMessage(i18nc("floating message",
"The shape already belongs to a selection"),
QIcon(), 2000, KisFloatingMessage::Low);
}
return;
}
KisSelectionToolHelper helper(view->canvasBase(), kundo2_i18n("Convert shapes to vector selection"));
helper.addSelectionShapes(clonedShapes);
}
void KisSelectionToShapeActionFactory::run(KisViewManager *view)
{
KisSelectionSP selection = view->selection();
if (!selection->outlineCacheValid()) {
return;
}
QPainterPath selectionOutline = selection->outlineCache();
QTransform transform = view->canvasBase()->coordinatesConverter()->imageToDocumentTransform();
KoShape *shape = KoPathShape::createShapeFromPainterPath(transform.map(selectionOutline));
shape->setShapeId(KoPathShapeId);
KoColor fgColor = view->canvasBase()->resourceManager()->resource(KoCanvasResourceProvider::ForegroundColor).value<KoColor>();
KoShapeStrokeSP border(new KoShapeStroke(1.0, fgColor.toQColor()));
shape->setStroke(border);
- view->document()->shapeController()->addShape(shape);
+ KUndo2Command *cmd = view->canvasBase()->shapeController()->addShapeDirect(shape, 0);
+ KisProcessingApplicator::runSingleCommandStroke(view->image(), cmd);
}
void KisStrokeSelectionActionFactory::run(KisViewManager *view, StrokeSelectionOptions params)
{
KisImageWSP image = view->image();
if (!image) {
return;
}
KisSelectionSP selection = view->selection();
if (!selection) {
return;
}
int size = params.lineSize;
KisPixelSelectionSP pixelSelection = selection->projection();
if (!pixelSelection->outlineCacheValid()) {
pixelSelection->recalculateOutlineCache();
}
QPainterPath outline = pixelSelection->outlineCache();
QColor color = params.color.toQColor();
KisNodeSP currentNode = view->canvasResourceProvider()->resourceManager()->resource(KisCanvasResourceProvider::CurrentKritaNode).value<KisNodeWSP>();
if (!currentNode->inherits("KisShapeLayer") && currentNode->paintDevice()) {
KoCanvasResourceProvider * rManager = view->canvasResourceProvider()->resourceManager();
KisToolShapeUtils::StrokeStyle strokeStyle = KisToolShapeUtils::StrokeStyleForeground;
KisToolShapeUtils::FillStyle fillStyle = params.fillStyle();
KisFigurePaintingToolHelper helper(kundo2_i18n("Draw Polyline"),
image,
currentNode,
rManager ,
strokeStyle,
fillStyle);
helper.setFGColorOverride(params.color);
helper.setSelectionOverride(0);
QPen pen(Qt::red, size);
pen.setJoinStyle(Qt::RoundJoin);
if (fillStyle != KisToolShapeUtils::FillStyleNone) {
helper.paintPainterPathQPenFill(outline, pen, params.fillColor);
}
else {
helper.paintPainterPathQPen(outline, pen, params.fillColor);
}
}
else if (currentNode->inherits("KisShapeLayer")) {
QTransform transform = view->canvasBase()->coordinatesConverter()->imageToDocumentTransform();
KoShape *shape = KoPathShape::createShapeFromPainterPath(transform.map(outline));
shape->setShapeId(KoPathShapeId);
KoShapeStrokeSP border(new KoShapeStroke(size, color));
shape->setStroke(border);
- view->document()->shapeController()->addShape(shape);
+ KUndo2Command *cmd = view->canvasBase()->shapeController()->addShapeDirect(shape, 0);
+ KisProcessingApplicator::runSingleCommandStroke(view->image(), cmd);
}
image->setModified();
-
}
void KisStrokeBrushSelectionActionFactory::run(KisViewManager *view, StrokeSelectionOptions params)
{
KisImageWSP image = view->image();
if (!image) {
return;
}
KisSelectionSP selection = view->selection();
if (!selection) {
return;
}
KisPixelSelectionSP pixelSelection = selection->projection();
if (!pixelSelection->outlineCacheValid()) {
pixelSelection->recalculateOutlineCache();
}
KisNodeSP currentNode = view->canvasResourceProvider()->resourceManager()->resource(KisCanvasResourceProvider::CurrentKritaNode).value<KisNodeWSP>();
if (!currentNode->inherits("KisShapeLayer") && currentNode->paintDevice())
{
KoCanvasResourceProvider * rManager = view->canvasResourceProvider()->resourceManager();
QPainterPath outline = pixelSelection->outlineCache();
KisToolShapeUtils::StrokeStyle strokeStyle = KisToolShapeUtils::StrokeStyleForeground;
KisToolShapeUtils::FillStyle fillStyle = KisToolShapeUtils::FillStyleNone;
KoColor color = params.color;
KisFigurePaintingToolHelper helper(kundo2_i18n("Draw Polyline"),
image,
currentNode,
rManager,
strokeStyle,
fillStyle);
helper.setFGColorOverride(color);
helper.setSelectionOverride(0);
helper.paintPainterPath(outline);
image->setModified();
}
}
diff --git a/libs/ui/canvas/kis_canvas2.cpp b/libs/ui/canvas/kis_canvas2.cpp
index 176ec9a78a..c600b6b0e9 100644
--- a/libs/ui/canvas/kis_canvas2.cpp
+++ b/libs/ui/canvas/kis_canvas2.cpp
@@ -1,1278 +1,1282 @@
/* This file is part of the KDE project
*
* Copyright (C) 2006, 2010 Boudewijn Rempt <boud@valdyas.org>
* Copyright (C) Lukáš Tvrdý <lukast.dev@gmail.com>, (C) 2010
* Copyright (C) 2011 Silvio Heinrich <plassy@web.de>
*
* 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_canvas2.h"
#include <functional>
#include <numeric>
#include <QApplication>
#include <QWidget>
#include <QVBoxLayout>
#include <QTime>
#include <QLabel>
#include <QMouseEvent>
#include <QDesktopWidget>
#include <QScreen>
#include <QWindow>
#include <kis_debug.h>
#include <KoUnit.h>
#include <KoShapeManager.h>
#include <KisSelectedShapesProxy.h>
#include <KoColorProfile.h>
#include <KoCanvasControllerWidget.h>
#include <KisDocument.h>
#include <KoSelection.h>
#include <KoShapeController.h>
#include <KisUsageLogger.h>
#include <kis_lod_transform.h>
#include "kis_tool_proxy.h"
#include "kis_coordinates_converter.h"
#include "kis_prescaled_projection.h"
#include "kis_image.h"
#include "kis_image_barrier_locker.h"
#include "kis_undo_adapter.h"
#include "flake/kis_shape_layer.h"
#include "kis_canvas_resource_provider.h"
#include "KisViewManager.h"
#include "kis_config.h"
#include "kis_config_notifier.h"
#include "kis_abstract_canvas_widget.h"
#include "kis_qpainter_canvas.h"
#include "kis_group_layer.h"
#include "flake/kis_shape_controller.h"
#include "kis_node_manager.h"
#include "kis_selection.h"
#include "kis_selection_component.h"
#include "flake/kis_shape_selection.h"
#include "kis_selection_mask.h"
#include "kis_image_config.h"
#include "kis_infinity_manager.h"
#include "kis_signal_compressor.h"
#include "kis_display_color_converter.h"
#include "kis_exposure_gamma_correction_interface.h"
#include "KisView.h"
#include "kis_canvas_controller.h"
#include "kis_grid_config.h"
#include "kis_animation_player.h"
#include "kis_animation_frame_cache.h"
#include "opengl/kis_opengl_canvas2.h"
#include "opengl/kis_opengl.h"
#include "kis_fps_decoration.h"
#include "KoColorConversionTransformation.h"
#include "KisProofingConfiguration.h"
#include <kis_favorite_resource_manager.h>
#include <kis_popup_palette.h>
#include "input/kis_input_manager.h"
#include "kis_painting_assistants_decoration.h"
#include "kis_canvas_updates_compressor.h"
#include "KoZoomController.h"
#include <KisStrokeSpeedMonitor.h>
#include "opengl/kis_opengl_canvas_debugger.h"
#include "kis_algebra_2d.h"
#include "kis_image_signal_router.h"
#include "KisSnapPixelStrategy.h"
class Q_DECL_HIDDEN KisCanvas2::KisCanvas2Private
{
public:
KisCanvas2Private(KoCanvasBase *parent, KisCoordinatesConverter* coordConverter, QPointer<KisView> view, KoCanvasResourceProvider* resourceManager)
: coordinatesConverter(coordConverter)
, view(view)
, shapeManager(parent)
, selectedShapesProxy(&shapeManager)
, toolProxy(parent)
, displayColorConverter(resourceManager, view)
, regionOfInterestUpdateCompressor(100, KisSignalCompressor::FIRST_INACTIVE)
{
}
KisCoordinatesConverter *coordinatesConverter;
QPointer<KisView>view;
KisAbstractCanvasWidget *canvasWidget = 0;
KoShapeManager shapeManager;
KisSelectedShapesProxy selectedShapesProxy;
bool currentCanvasIsOpenGL;
int openGLFilterMode;
KisToolProxy toolProxy;
KisPrescaledProjectionSP prescaledProjection;
bool vastScrolling;
KisSignalCompressor canvasUpdateCompressor;
QRect savedUpdateRect;
QBitArray channelFlags;
KisProofingConfigurationSP proofingConfig;
bool softProofing = false;
bool gamutCheck = false;
bool proofingConfigUpdated = false;
KisPopupPalette *popupPalette = 0;
KisDisplayColorConverter displayColorConverter;
KisCanvasUpdatesCompressor projectionUpdatesCompressor;
KisAnimationPlayer *animationPlayer;
KisAnimationFrameCacheSP frameCache;
bool lodAllowedInImage = false;
bool bootstrapLodBlocked;
QPointer<KoShapeManager> currentlyActiveShapeManager;
KisInputActionGroupsMask inputActionGroupsMask = AllActionGroup;
KisSignalCompressor frameRenderStartCompressor;
KisSignalCompressor regionOfInterestUpdateCompressor;
QRect regionOfInterest;
qreal regionOfInterestMargin = 0.25;
QRect renderingLimit;
int isBatchUpdateActive = 0;
bool effectiveLodAllowedInImage() {
return lodAllowedInImage && !bootstrapLodBlocked;
}
void setActiveShapeManager(KoShapeManager *shapeManager);
};
namespace {
KoShapeManager* fetchShapeManagerFromNode(KisNodeSP node)
{
KoShapeManager *shapeManager = 0;
KisSelectionSP selection;
if (KisLayer *layer = dynamic_cast<KisLayer*>(node.data())) {
KisShapeLayer *shapeLayer = dynamic_cast<KisShapeLayer*>(layer);
if (shapeLayer) {
shapeManager = shapeLayer->shapeManager();
}
} else if (KisSelectionMask *mask = dynamic_cast<KisSelectionMask*>(node.data())) {
selection = mask->selection();
}
if (!shapeManager && selection && selection->hasShapeSelection()) {
KisShapeSelection *shapeSelection = dynamic_cast<KisShapeSelection*>(selection->shapeSelection());
KIS_ASSERT_RECOVER_RETURN_VALUE(shapeSelection, 0);
shapeManager = shapeSelection->shapeManager();
}
return shapeManager;
}
}
KisCanvas2::KisCanvas2(KisCoordinatesConverter *coordConverter, KoCanvasResourceProvider *resourceManager, KisMainWindow *mainWindow, KisView *view, KoShapeControllerBase *sc)
: KoCanvasBase(sc, resourceManager)
, m_d(new KisCanvas2Private(this, coordConverter, view, resourceManager))
{
/**
* While loading LoD should be blocked. Only when GUI has finished
* loading and zoom level settled down, LoD is given a green
* light.
*/
m_d->bootstrapLodBlocked = true;
connect(mainWindow, SIGNAL(guiLoadingFinished()), SLOT(bootstrapFinished()));
connect(mainWindow, SIGNAL(screenChanged()), SLOT(slotConfigChanged()));
KisImageConfig config(false);
m_d->canvasUpdateCompressor.setDelay(1000 / config.fpsLimit());
m_d->canvasUpdateCompressor.setMode(KisSignalCompressor::FIRST_ACTIVE);
m_d->frameRenderStartCompressor.setDelay(1000 / config.fpsLimit());
m_d->frameRenderStartCompressor.setMode(KisSignalCompressor::FIRST_ACTIVE);
snapGuide()->overrideSnapStrategy(KoSnapGuide::PixelSnapping, new KisSnapPixelStrategy());
}
void KisCanvas2::setup()
{
// a bit of duplication from slotConfigChanged()
KisConfig cfg(true);
m_d->vastScrolling = cfg.vastScrolling();
m_d->lodAllowedInImage = cfg.levelOfDetailEnabled();
m_d->regionOfInterestMargin = KisImageConfig(true).animationCacheRegionOfInterestMargin();
createCanvas(cfg.useOpenGL());
setLodAllowedInCanvas(m_d->lodAllowedInImage);
m_d->animationPlayer = new KisAnimationPlayer(this);
connect(m_d->view->canvasController()->proxyObject, SIGNAL(moveDocumentOffset(QPoint)), SLOT(documentOffsetMoved(QPoint)));
connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged()));
/**
* We switch the shape manager every time vector layer or
* shape selection is activated. Flake does not expect this
* and connects all the signals of the global shape manager
* to the clients in the constructor. To workaround this we
* forward the signals of local shape managers stored in the
* vector layers to the signals of global shape manager. So the
* sequence of signal deliveries is the following:
*
* shapeLayer.m_d.canvas.m_shapeManager.selection() ->
* shapeLayer ->
* shapeController ->
* globalShapeManager.selection()
*/
KisShapeController *kritaShapeController = static_cast<KisShapeController*>(shapeController()->documentBase());
connect(kritaShapeController, SIGNAL(selectionChanged()),
this, SLOT(slotSelectionChanged()));
connect(kritaShapeController, SIGNAL(selectionContentChanged()),
selectedShapesProxy(), SIGNAL(selectionContentChanged()));
connect(kritaShapeController, SIGNAL(currentLayerChanged(const KoShapeLayer*)),
selectedShapesProxy(), SIGNAL(currentLayerChanged(const KoShapeLayer*)));
connect(&m_d->canvasUpdateCompressor, SIGNAL(timeout()), SLOT(slotDoCanvasUpdate()));
connect(this, SIGNAL(sigCanvasCacheUpdated()), &m_d->frameRenderStartCompressor, SLOT(start()));
connect(&m_d->frameRenderStartCompressor, SIGNAL(timeout()), SLOT(updateCanvasProjection()));
connect(this, SIGNAL(sigContinueResizeImage(qint32,qint32)), SLOT(finishResizingImage(qint32,qint32)));
connect(&m_d->regionOfInterestUpdateCompressor, SIGNAL(timeout()), SLOT(slotUpdateRegionOfInterest()));
connect(m_d->view->document(), SIGNAL(sigReferenceImagesChanged()), this, SLOT(slotReferenceImagesChanged()));
initializeFpsDecoration();
}
void KisCanvas2::initializeFpsDecoration()
{
KisConfig cfg(true);
const bool shouldShowDebugOverlay =
(canvasIsOpenGL() && cfg.enableOpenGLFramerateLogging()) ||
cfg.enableBrushSpeedLogging();
if (shouldShowDebugOverlay && !decoration(KisFpsDecoration::idTag)) {
addDecoration(new KisFpsDecoration(imageView()));
if (cfg.enableBrushSpeedLogging()) {
connect(KisStrokeSpeedMonitor::instance(), SIGNAL(sigStatsUpdated()), this, SLOT(updateCanvas()));
}
} else if (!shouldShowDebugOverlay && decoration(KisFpsDecoration::idTag)) {
m_d->canvasWidget->removeDecoration(KisFpsDecoration::idTag);
disconnect(KisStrokeSpeedMonitor::instance(), SIGNAL(sigStatsUpdated()), this, SLOT(updateCanvas()));
}
}
KisCanvas2::~KisCanvas2()
{
if (m_d->animationPlayer->isPlaying()) {
m_d->animationPlayer->forcedStopOnExit();
}
delete m_d;
}
void KisCanvas2::setCanvasWidget(KisAbstractCanvasWidget *widget)
{
if (m_d->popupPalette) {
m_d->popupPalette->setParent(widget->widget());
}
- if (m_d->canvasWidget != 0) {
+ if (m_d->canvasWidget) {
+ /**
+ * We are switching the canvas type. We should reinitialize our
+ * connections to decorations and input manager
+ */
+
widget->setDecorations(m_d->canvasWidget->decorations());
- // Redundant check for the constructor case, see below
- if(viewManager() != 0)
+ if(viewManager()) {
viewManager()->inputManager()->removeTrackedCanvas(this);
+ m_d->canvasWidget = widget;
+ viewManager()->inputManager()->addTrackedCanvas(this);
+ } else {
+ m_d->canvasWidget = widget;
+ }
+ } else {
+ m_d->canvasWidget = widget;
}
- m_d->canvasWidget = widget;
-
- // Either tmp was null or we are being called by KisCanvas2 constructor that is called by KisView
- // constructor, so the view manager still doesn't exists.
- if(m_d->canvasWidget != 0 && viewManager() != 0)
- viewManager()->inputManager()->addTrackedCanvas(this);
-
if (!m_d->canvasWidget->decoration(INFINITY_DECORATION_ID)) {
KisInfinityManager *manager = new KisInfinityManager(m_d->view, this);
manager->setVisible(true);
m_d->canvasWidget->addDecoration(manager);
}
widget->widget()->setAutoFillBackground(false);
widget->widget()->setAttribute(Qt::WA_OpaquePaintEvent);
widget->widget()->setMouseTracking(true);
widget->widget()->setAcceptDrops(true);
KoCanvasControllerWidget *controller = dynamic_cast<KoCanvasControllerWidget*>(canvasController());
if (controller && controller->canvas() == this) {
controller->changeCanvasWidget(widget->widget());
}
}
bool KisCanvas2::canvasIsOpenGL() const
{
return m_d->currentCanvasIsOpenGL;
}
KisOpenGL::FilterMode KisCanvas2::openGLFilterMode() const
{
return KisOpenGL::FilterMode(m_d->openGLFilterMode);
}
void KisCanvas2::gridSize(QPointF *offset, QSizeF *spacing) const
{
QTransform transform = coordinatesConverter()->imageToDocumentTransform();
const QPoint intSpacing = m_d->view->document()->gridConfig().spacing();
const QPoint intOffset = m_d->view->document()->gridConfig().offset();
QPointF size = transform.map(QPointF(intSpacing));
spacing->rwidth() = size.x();
spacing->rheight() = size.y();
*offset = transform.map(QPointF(intOffset));
}
bool KisCanvas2::snapToGrid() const
{
return m_d->view->document()->gridConfig().snapToGrid();
}
qreal KisCanvas2::rotationAngle() const
{
return m_d->coordinatesConverter->rotationAngle();
}
bool KisCanvas2::xAxisMirrored() const
{
return m_d->coordinatesConverter->xAxisMirrored();
}
bool KisCanvas2::yAxisMirrored() const
{
return m_d->coordinatesConverter->yAxisMirrored();
}
void KisCanvas2::channelSelectionChanged()
{
KisImageSP image = this->image();
m_d->channelFlags = image->rootLayer()->channelFlags();
m_d->view->viewManager()->blockUntilOperationsFinishedForced(image);
image->barrierLock();
m_d->canvasWidget->channelSelectionChanged(m_d->channelFlags);
startUpdateInPatches(image->bounds());
image->unlock();
}
void KisCanvas2::addCommand(KUndo2Command *command)
{
// This method exists to support flake-related operations
m_d->view->document()->addCommand(command);
}
void KisCanvas2::KisCanvas2Private::setActiveShapeManager(KoShapeManager *shapeManager)
{
if (shapeManager != currentlyActiveShapeManager) {
currentlyActiveShapeManager = shapeManager;
selectedShapesProxy.setShapeManager(shapeManager);
}
}
KoShapeManager* KisCanvas2::shapeManager() const
{
KoShapeManager *localShapeManager = this->localShapeManager();
// sanity check for consistency of the local shape manager
KIS_SAFE_ASSERT_RECOVER (localShapeManager == m_d->currentlyActiveShapeManager) {
localShapeManager = globalShapeManager();
}
return localShapeManager ? localShapeManager : globalShapeManager();
}
KoSelectedShapesProxy* KisCanvas2::selectedShapesProxy() const
{
return &m_d->selectedShapesProxy;
}
KoShapeManager* KisCanvas2::globalShapeManager() const
{
return &m_d->shapeManager;
}
KoShapeManager *KisCanvas2::localShapeManager() const
{
KisNodeSP node = m_d->view->currentNode();
KoShapeManager *localShapeManager = fetchShapeManagerFromNode(node);
if (localShapeManager != m_d->currentlyActiveShapeManager) {
m_d->setActiveShapeManager(localShapeManager);
}
return localShapeManager;
}
void KisCanvas2::updateInputMethodInfo()
{
// TODO call (the protected) QWidget::updateMicroFocus() on the proper canvas widget...
}
const KisCoordinatesConverter* KisCanvas2::coordinatesConverter() const
{
return m_d->coordinatesConverter;
}
KoViewConverter* KisCanvas2::viewConverter() const
{
return m_d->coordinatesConverter;
}
KisInputManager* KisCanvas2::globalInputManager() const
{
return m_d->view->globalInputManager();
}
KisInputActionGroupsMask KisCanvas2::inputActionGroupsMask() const
{
return m_d->inputActionGroupsMask;
}
void KisCanvas2::setInputActionGroupsMask(KisInputActionGroupsMask mask)
{
m_d->inputActionGroupsMask = mask;
}
QWidget* KisCanvas2::canvasWidget()
{
return m_d->canvasWidget->widget();
}
const QWidget* KisCanvas2::canvasWidget() const
{
return m_d->canvasWidget->widget();
}
KoUnit KisCanvas2::unit() const
{
KoUnit unit(KoUnit::Pixel);
KisImageWSP image = m_d->view->image();
if (image) {
if (!qFuzzyCompare(image->xRes(), image->yRes())) {
warnKrita << "WARNING: resolution of the image is anisotropic"
<< ppVar(image->xRes())
<< ppVar(image->yRes());
}
const qreal resolution = image->xRes();
unit.setFactor(resolution);
}
return unit;
}
KoToolProxy * KisCanvas2::toolProxy() const
{
return &m_d->toolProxy;
}
void KisCanvas2::createQPainterCanvas()
{
m_d->currentCanvasIsOpenGL = false;
KisQPainterCanvas * canvasWidget = new KisQPainterCanvas(this, m_d->coordinatesConverter, m_d->view);
m_d->prescaledProjection = new KisPrescaledProjection();
m_d->prescaledProjection->setCoordinatesConverter(m_d->coordinatesConverter);
m_d->prescaledProjection->setMonitorProfile(m_d->displayColorConverter.monitorProfile(),
m_d->displayColorConverter.renderingIntent(),
m_d->displayColorConverter.conversionFlags());
m_d->prescaledProjection->setDisplayFilter(m_d->displayColorConverter.displayFilter());
canvasWidget->setPrescaledProjection(m_d->prescaledProjection);
setCanvasWidget(canvasWidget);
}
void KisCanvas2::createOpenGLCanvas()
{
KisConfig cfg(true);
m_d->openGLFilterMode = cfg.openGLFilteringMode();
m_d->currentCanvasIsOpenGL = true;
KisOpenGLCanvas2 *canvasWidget = new KisOpenGLCanvas2(this, m_d->coordinatesConverter, 0, m_d->view->image(), &m_d->displayColorConverter);
m_d->frameCache = KisAnimationFrameCache::getFrameCache(canvasWidget->openGLImageTextures());
setCanvasWidget(canvasWidget);
}
void KisCanvas2::createCanvas(bool useOpenGL)
{
// deinitialize previous canvas structures
m_d->prescaledProjection = 0;
m_d->frameCache = 0;
KisConfig cfg(true);
QDesktopWidget dw;
const KoColorProfile *profile = cfg.displayProfile(dw.screenNumber(imageView()));
m_d->displayColorConverter.notifyOpenGLCanvasIsActive(useOpenGL && KisOpenGL::hasOpenGL());
m_d->displayColorConverter.setMonitorProfile(profile);
if (useOpenGL && !KisOpenGL::hasOpenGL()) {
warnKrita << "Tried to create OpenGL widget when system doesn't have OpenGL\n";
useOpenGL = false;
}
m_d->displayColorConverter.notifyOpenGLCanvasIsActive(useOpenGL);
if (useOpenGL) {
createOpenGLCanvas();
if (cfg.canvasState() == "OPENGL_FAILED") {
// Creating the opengl canvas failed, fall back
warnKrita << "OpenGL Canvas initialization returned OPENGL_FAILED. Falling back to QPainter.";
m_d->displayColorConverter.notifyOpenGLCanvasIsActive(false);
createQPainterCanvas();
}
} else {
createQPainterCanvas();
}
if (m_d->popupPalette) {
m_d->popupPalette->setParent(m_d->canvasWidget->widget());
}
}
void KisCanvas2::initializeImage()
{
KisImageSP image = m_d->view->image();
m_d->displayColorConverter.setImageColorSpace(image->colorSpace());
m_d->coordinatesConverter->setImage(image);
m_d->toolProxy.initializeImage(image);
connect(image, SIGNAL(sigImageUpdated(QRect)), SLOT(startUpdateCanvasProjection(QRect)), Qt::DirectConnection);
connect(image->signalRouter(), SIGNAL(sigNotifyBatchUpdateStarted()), SLOT(slotBeginUpdatesBatch()), Qt::DirectConnection);
connect(image->signalRouter(), SIGNAL(sigNotifyBatchUpdateEnded()), SLOT(slotEndUpdatesBatch()), Qt::DirectConnection);
connect(image->signalRouter(), SIGNAL(sigRequestLodPlanesSyncBlocked(bool)), SLOT(slotSetLodUpdatesBlocked(bool)), Qt::DirectConnection);
connect(image, SIGNAL(sigProofingConfigChanged()), SLOT(slotChangeProofingConfig()));
connect(image, SIGNAL(sigSizeChanged(QPointF,QPointF)), SLOT(startResizingImage()), Qt::DirectConnection);
connect(image->undoAdapter(), SIGNAL(selectionChanged()), SLOT(slotTrySwitchShapeManager()));
connect(image, SIGNAL(sigColorSpaceChanged(const KoColorSpace*)), SLOT(slotImageColorSpaceChanged()));
connect(image, SIGNAL(sigProfileChanged(const KoColorProfile*)), SLOT(slotImageColorSpaceChanged()));
connectCurrentCanvas();
}
void KisCanvas2::connectCurrentCanvas()
{
KisImageWSP image = m_d->view->image();
if (!m_d->currentCanvasIsOpenGL) {
Q_ASSERT(m_d->prescaledProjection);
m_d->prescaledProjection->setImage(image);
}
startResizingImage();
setLodAllowedInCanvas(m_d->lodAllowedInImage);
emit sigCanvasEngineChanged();
}
void KisCanvas2::resetCanvas(bool useOpenGL)
{
// we cannot reset the canvas before it's created, but this method might be called,
// for instance when setting the monitor profile.
if (!m_d->canvasWidget) {
return;
}
KisConfig cfg(true);
bool needReset = (m_d->currentCanvasIsOpenGL != useOpenGL) ||
(m_d->currentCanvasIsOpenGL &&
m_d->openGLFilterMode != cfg.openGLFilteringMode());
if (needReset) {
createCanvas(useOpenGL);
connectCurrentCanvas();
notifyZoomChanged();
}
updateCanvasWidgetImpl();
}
void KisCanvas2::startUpdateInPatches(const QRect &imageRect)
{
/**
* We don't do patched loading for openGL canvas, because it loads
* the tiles, which are basically "patches". Therefore, big chunks
* of memory are never allocated.
*/
if (m_d->currentCanvasIsOpenGL) {
startUpdateCanvasProjection(imageRect);
} else {
KisImageConfig imageConfig(true);
int patchWidth = imageConfig.updatePatchWidth();
int patchHeight = imageConfig.updatePatchHeight();
for (int y = 0; y < imageRect.height(); y += patchHeight) {
for (int x = 0; x < imageRect.width(); x += patchWidth) {
QRect patchRect(x, y, patchWidth, patchHeight);
startUpdateCanvasProjection(patchRect);
}
}
}
}
void KisCanvas2::setDisplayFilter(QSharedPointer<KisDisplayFilter> displayFilter)
{
m_d->displayColorConverter.setDisplayFilter(displayFilter);
KisImageSP image = this->image();
m_d->view->viewManager()->blockUntilOperationsFinishedForced(image);
image->barrierLock();
m_d->canvasWidget->setDisplayFilter(displayFilter);
image->unlock();
}
QSharedPointer<KisDisplayFilter> KisCanvas2::displayFilter() const
{
return m_d->displayColorConverter.displayFilter();
}
void KisCanvas2::slotImageColorSpaceChanged()
{
KisImageSP image = this->image();
m_d->view->viewManager()->blockUntilOperationsFinishedForced(image);
m_d->displayColorConverter.setImageColorSpace(image->colorSpace());
image->barrierLock();
m_d->canvasWidget->notifyImageColorSpaceChanged(image->colorSpace());
image->unlock();
}
KisDisplayColorConverter* KisCanvas2::displayColorConverter() const
{
return &m_d->displayColorConverter;
}
KisExposureGammaCorrectionInterface* KisCanvas2::exposureGammaCorrectionInterface() const
{
QSharedPointer<KisDisplayFilter> displayFilter = m_d->displayColorConverter.displayFilter();
return displayFilter ?
displayFilter->correctionInterface() :
KisDumbExposureGammaCorrectionInterface::instance();
}
void KisCanvas2::setProofingOptions(bool softProof, bool gamutCheck)
{
m_d->proofingConfig = this->image()->proofingConfiguration();
if (!m_d->proofingConfig) {
KisImageConfig cfg(false);
m_d->proofingConfig = cfg.defaultProofingconfiguration();
}
KoColorConversionTransformation::ConversionFlags conversionFlags = m_d->proofingConfig->conversionFlags;
if (this->image()->colorSpace()->colorDepthId().id().contains("U")) {
conversionFlags.setFlag(KoColorConversionTransformation::SoftProofing, softProof);
if (softProof) {
conversionFlags.setFlag(KoColorConversionTransformation::GamutCheck, gamutCheck);
}
}
m_d->proofingConfig->conversionFlags = conversionFlags;
m_d->proofingConfigUpdated = true;
startUpdateInPatches(this->image()->bounds());
}
void KisCanvas2::slotSoftProofing(bool softProofing)
{
m_d->softProofing = softProofing;
setProofingOptions(m_d->softProofing, m_d->gamutCheck);
}
void KisCanvas2::slotGamutCheck(bool gamutCheck)
{
m_d->gamutCheck = gamutCheck;
setProofingOptions(m_d->softProofing, m_d->gamutCheck);
}
void KisCanvas2::slotChangeProofingConfig()
{
setProofingOptions(m_d->softProofing, m_d->gamutCheck);
}
void KisCanvas2::setProofingConfigUpdated(bool updated)
{
m_d->proofingConfigUpdated = updated;
}
bool KisCanvas2::proofingConfigUpdated()
{
return m_d->proofingConfigUpdated;
}
KisProofingConfigurationSP KisCanvas2::proofingConfiguration() const
{
if (!m_d->proofingConfig) {
m_d->proofingConfig = this->image()->proofingConfiguration();
if (!m_d->proofingConfig) {
m_d->proofingConfig = KisImageConfig(true).defaultProofingconfiguration();
}
}
return m_d->proofingConfig;
}
void KisCanvas2::startResizingImage()
{
KisImageWSP image = this->image();
qint32 w = image->width();
qint32 h = image->height();
emit sigContinueResizeImage(w, h);
QRect imageBounds(0, 0, w, h);
startUpdateInPatches(imageBounds);
}
void KisCanvas2::finishResizingImage(qint32 w, qint32 h)
{
m_d->canvasWidget->finishResizingImage(w, h);
}
void KisCanvas2::startUpdateCanvasProjection(const QRect & rc)
{
KisUpdateInfoSP info = m_d->canvasWidget->startUpdateCanvasProjection(rc, m_d->channelFlags);
if (m_d->projectionUpdatesCompressor.putUpdateInfo(info)) {
emit sigCanvasCacheUpdated();
}
}
void KisCanvas2::updateCanvasProjection()
{
auto tryIssueCanvasUpdates = [this](const QRect &vRect) {
if (!m_d->isBatchUpdateActive) {
// TODO: Implement info->dirtyViewportRect() for KisOpenGLCanvas2 to avoid updating whole canvas
if (m_d->currentCanvasIsOpenGL) {
m_d->savedUpdateRect = QRect();
// we already had a compression in frameRenderStartCompressor, so force the update directly
slotDoCanvasUpdate();
} else if (/* !m_d->currentCanvasIsOpenGL && */ !vRect.isEmpty()) {
m_d->savedUpdateRect = m_d->coordinatesConverter->viewportToWidget(vRect).toAlignedRect();
// we already had a compression in frameRenderStartCompressor, so force the update directly
slotDoCanvasUpdate();
}
}
};
auto uploadData = [this, tryIssueCanvasUpdates](const QVector<KisUpdateInfoSP> &infoObjects) {
QVector<QRect> viewportRects = m_d->canvasWidget->updateCanvasProjection(infoObjects);
const QRect vRect = std::accumulate(viewportRects.constBegin(), viewportRects.constEnd(),
QRect(), std::bit_or<QRect>());
tryIssueCanvasUpdates(vRect);
};
bool shouldExplicitlyIssueUpdates = false;
QVector<KisUpdateInfoSP> infoObjects;
KisUpdateInfoList originalInfoObjects;
m_d->projectionUpdatesCompressor.takeUpdateInfo(originalInfoObjects);
for (auto it = originalInfoObjects.constBegin();
it != originalInfoObjects.constEnd();
++it) {
KisUpdateInfoSP info = *it;
const KisMarkerUpdateInfo *batchInfo = dynamic_cast<const KisMarkerUpdateInfo*>(info.data());
if (batchInfo) {
if (!infoObjects.isEmpty()) {
uploadData(infoObjects);
infoObjects.clear();
}
if (batchInfo->type() == KisMarkerUpdateInfo::StartBatch) {
m_d->isBatchUpdateActive++;
} else if (batchInfo->type() == KisMarkerUpdateInfo::EndBatch) {
m_d->isBatchUpdateActive--;
KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->isBatchUpdateActive >= 0);
if (m_d->isBatchUpdateActive == 0) {
shouldExplicitlyIssueUpdates = true;
}
} else if (batchInfo->type() == KisMarkerUpdateInfo::BlockLodUpdates) {
m_d->canvasWidget->setLodResetInProgress(true);
} else if (batchInfo->type() == KisMarkerUpdateInfo::UnblockLodUpdates) {
m_d->canvasWidget->setLodResetInProgress(false);
shouldExplicitlyIssueUpdates = true;
}
} else {
infoObjects << info;
}
}
if (!infoObjects.isEmpty()) {
uploadData(infoObjects);
} else if (shouldExplicitlyIssueUpdates) {
tryIssueCanvasUpdates(m_d->coordinatesConverter->imageRectInImagePixels());
}
}
void KisCanvas2::slotBeginUpdatesBatch()
{
KisUpdateInfoSP info =
new KisMarkerUpdateInfo(KisMarkerUpdateInfo::StartBatch,
m_d->coordinatesConverter->imageRectInImagePixels());
m_d->projectionUpdatesCompressor.putUpdateInfo(info);
emit sigCanvasCacheUpdated();
}
void KisCanvas2::slotEndUpdatesBatch()
{
KisUpdateInfoSP info =
new KisMarkerUpdateInfo(KisMarkerUpdateInfo::EndBatch,
m_d->coordinatesConverter->imageRectInImagePixels());
m_d->projectionUpdatesCompressor.putUpdateInfo(info);
emit sigCanvasCacheUpdated();
}
void KisCanvas2::slotSetLodUpdatesBlocked(bool value)
{
KisUpdateInfoSP info =
new KisMarkerUpdateInfo(value ?
KisMarkerUpdateInfo::BlockLodUpdates :
KisMarkerUpdateInfo::UnblockLodUpdates,
m_d->coordinatesConverter->imageRectInImagePixels());
m_d->projectionUpdatesCompressor.putUpdateInfo(info);
emit sigCanvasCacheUpdated();
}
void KisCanvas2::slotDoCanvasUpdate()
{
/**
* WARNING: in isBusy() we access openGL functions without making the painting
* context current. We hope that currently active context will be Qt's one,
* which is shared with our own.
*/
if (m_d->canvasWidget->isBusy()) {
// just restarting the timer
updateCanvasWidgetImpl(m_d->savedUpdateRect);
return;
}
if (m_d->savedUpdateRect.isEmpty()) {
m_d->canvasWidget->widget()->update();
emit updateCanvasRequested(m_d->canvasWidget->widget()->rect());
} else {
emit updateCanvasRequested(m_d->savedUpdateRect);
m_d->canvasWidget->widget()->update(m_d->savedUpdateRect);
}
m_d->savedUpdateRect = QRect();
}
void KisCanvas2::updateCanvasWidgetImpl(const QRect &rc)
{
if (!m_d->canvasUpdateCompressor.isActive() ||
!m_d->savedUpdateRect.isEmpty()) {
m_d->savedUpdateRect |= rc;
}
m_d->canvasUpdateCompressor.start();
}
void KisCanvas2::updateCanvas()
{
updateCanvasWidgetImpl();
}
void KisCanvas2::updateCanvas(const QRectF& documentRect)
{
if (m_d->currentCanvasIsOpenGL && m_d->canvasWidget->decorations().size() > 0) {
updateCanvasWidgetImpl();
}
else {
// updateCanvas is called from tools, never from the projection
// updates, so no need to prescale!
QRect widgetRect = m_d->coordinatesConverter->documentToWidget(documentRect).toAlignedRect();
widgetRect.adjust(-2, -2, 2, 2);
if (!widgetRect.isEmpty()) {
updateCanvasWidgetImpl(widgetRect);
}
}
}
void KisCanvas2::disconnectCanvasObserver(QObject *object)
{
KoCanvasBase::disconnectCanvasObserver(object);
m_d->view->disconnect(object);
}
void KisCanvas2::notifyZoomChanged()
{
if (!m_d->currentCanvasIsOpenGL) {
Q_ASSERT(m_d->prescaledProjection);
m_d->prescaledProjection->notifyZoomChanged();
}
notifyLevelOfDetailChange();
updateCanvas(); // update the canvas, because that isn't done when zooming using KoZoomAction
m_d->regionOfInterestUpdateCompressor.start();
}
QRect KisCanvas2::regionOfInterest() const
{
return m_d->regionOfInterest;
}
void KisCanvas2::slotUpdateRegionOfInterest()
{
const QRect oldRegionOfInterest = m_d->regionOfInterest;
const qreal ratio = m_d->regionOfInterestMargin;
const QRect proposedRoi = KisAlgebra2D::blowRect(m_d->coordinatesConverter->widgetRectInImagePixels(), ratio).toAlignedRect();
const QRect imageRect = m_d->coordinatesConverter->imageRectInImagePixels();
m_d->regionOfInterest = proposedRoi & imageRect;
if (m_d->regionOfInterest != oldRegionOfInterest) {
emit sigRegionOfInterestChanged(m_d->regionOfInterest);
}
}
void KisCanvas2::slotReferenceImagesChanged()
{
canvasController()->resetScrollBars();
}
void KisCanvas2::setRenderingLimit(const QRect &rc)
{
m_d->renderingLimit = rc;
}
QRect KisCanvas2::renderingLimit() const
{
return m_d->renderingLimit;
}
void KisCanvas2::slotTrySwitchShapeManager()
{
KisNodeSP node = m_d->view->currentNode();
QPointer<KoShapeManager> newManager;
newManager = fetchShapeManagerFromNode(node);
m_d->setActiveShapeManager(newManager);
}
void KisCanvas2::notifyLevelOfDetailChange()
{
if (!m_d->effectiveLodAllowedInImage()) return;
const qreal effectiveZoom = m_d->coordinatesConverter->effectiveZoom();
KisConfig cfg(true);
const int maxLod = cfg.numMipmapLevels();
const int lod = KisLodTransform::scaleToLod(effectiveZoom, maxLod);
if (m_d->effectiveLodAllowedInImage()) {
KisImageSP image = this->image();
image->setDesiredLevelOfDetail(lod);
}
}
const KoColorProfile * KisCanvas2::monitorProfile()
{
return m_d->displayColorConverter.monitorProfile();
}
KisViewManager* KisCanvas2::viewManager() const
{
if (m_d->view) {
return m_d->view->viewManager();
}
return 0;
}
QPointer<KisView>KisCanvas2::imageView() const
{
return m_d->view;
}
KisImageWSP KisCanvas2::image() const
{
return m_d->view->image();
}
KisImageWSP KisCanvas2::currentImage() const
{
return m_d->view->image();
}
void KisCanvas2::documentOffsetMoved(const QPoint &documentOffset)
{
QPointF offsetBefore = m_d->coordinatesConverter->imageRectInViewportPixels().topLeft();
// The given offset is in widget logical pixels. In order to prevent fuzzy
// canvas rendering at 100% pixel-perfect zoom level when devicePixelRatio
// is not integral, we adjusts the offset to map to whole device pixels.
//
// FIXME: This is a temporary hack for fixing the canvas under fractional
// DPI scaling before a new coordinate system is introduced.
QPointF offsetAdjusted = m_d->coordinatesConverter->snapToDevicePixel(documentOffset);
m_d->coordinatesConverter->setDocumentOffset(offsetAdjusted);
QPointF offsetAfter = m_d->coordinatesConverter->imageRectInViewportPixels().topLeft();
QPointF moveOffset = offsetAfter - offsetBefore;
if (!m_d->currentCanvasIsOpenGL)
m_d->prescaledProjection->viewportMoved(moveOffset);
emit documentOffsetUpdateFinished();
updateCanvas();
m_d->regionOfInterestUpdateCompressor.start();
}
void KisCanvas2::slotConfigChanged()
{
KisConfig cfg(true);
m_d->vastScrolling = cfg.vastScrolling();
m_d->regionOfInterestMargin = KisImageConfig(true).animationCacheRegionOfInterestMargin();
resetCanvas(cfg.useOpenGL());
// HACK: Sometimes screenNumber(this->canvasWidget()) is not able to get the
// proper screenNumber when moving the window across screens. Using
// the coordinates should be able to work around this.
// FIXME: We should change to associate the display profiles with the screen
// model and serial number instead. See https://bugs.kde.org/show_bug.cgi?id=407498
int canvasScreenNumber = QApplication::desktop()->screenNumber(this->canvasWidget());
if (canvasScreenNumber != -1) {
setDisplayProfile(cfg.displayProfile(canvasScreenNumber));
} else {
warnUI << "Failed to get screenNumber for updating display profile.";
}
initializeFpsDecoration();
}
void KisCanvas2::refetchDataFromImage()
{
KisImageSP image = this->image();
KisImageBarrierLocker l(image);
startUpdateInPatches(image->bounds());
}
void KisCanvas2::setDisplayProfile(const KoColorProfile *monitorProfile)
{
if (m_d->displayColorConverter.monitorProfile() == monitorProfile) return;
m_d->displayColorConverter.setMonitorProfile(monitorProfile);
{
KisImageSP image = this->image();
KisImageBarrierLocker l(image);
m_d->canvasWidget->setDisplayColorConverter(&m_d->displayColorConverter);
}
refetchDataFromImage();
}
void KisCanvas2::addDecoration(KisCanvasDecorationSP deco)
{
m_d->canvasWidget->addDecoration(deco);
}
KisCanvasDecorationSP KisCanvas2::decoration(const QString& id) const
{
return m_d->canvasWidget->decoration(id);
}
QPoint KisCanvas2::documentOrigin() const
{
/**
* In Krita we don't use document origin anymore.
* All the centering when needed (vastScrolling < 0.5) is done
* automatically by the KisCoordinatesConverter.
*/
return QPoint();
}
QPoint KisCanvas2::documentOffset() const
{
return m_d->coordinatesConverter->documentOffset();
}
void KisCanvas2::setFavoriteResourceManager(KisFavoriteResourceManager* favoriteResourceManager)
{
m_d->popupPalette = new KisPopupPalette(viewManager(), m_d->coordinatesConverter, favoriteResourceManager, displayColorConverter()->displayRendererInterface(),
m_d->view->resourceProvider(), m_d->canvasWidget->widget());
connect(m_d->popupPalette, SIGNAL(zoomLevelChanged(int)), this, SLOT(slotPopupPaletteRequestedZoomChange(int)));
connect(m_d->popupPalette, SIGNAL(sigUpdateCanvas()), this, SLOT(updateCanvas()));
connect(m_d->view->mainWindow(), SIGNAL(themeChanged()), m_d->popupPalette, SLOT(slotUpdateIcons()));
m_d->popupPalette->showPopupPalette(false);
}
void KisCanvas2::slotPopupPaletteRequestedZoomChange(int zoom ) {
m_d->view->viewManager()->zoomController()->setZoom(KoZoomMode::ZOOM_CONSTANT, (qreal)(zoom/100.0)); // 1.0 is 100% zoom
notifyZoomChanged();
}
void KisCanvas2::setCursor(const QCursor &cursor)
{
canvasWidget()->setCursor(cursor);
}
KisAnimationFrameCacheSP KisCanvas2::frameCache() const
{
return m_d->frameCache;
}
KisAnimationPlayer *KisCanvas2::animationPlayer() const
{
return m_d->animationPlayer;
}
void KisCanvas2::slotSelectionChanged()
{
KisShapeLayer* shapeLayer = dynamic_cast<KisShapeLayer*>(viewManager()->activeLayer().data());
if (!shapeLayer) {
return;
}
m_d->shapeManager.selection()->deselectAll();
Q_FOREACH (KoShape* shape, shapeLayer->shapeManager()->selection()->selectedShapes()) {
m_d->shapeManager.selection()->select(shape);
}
}
bool KisCanvas2::isPopupPaletteVisible() const
{
if (!m_d->popupPalette) {
return false;
}
return m_d->popupPalette->isVisible();
}
void KisCanvas2::setWrapAroundViewingMode(bool value)
{
KisCanvasDecorationSP infinityDecoration =
m_d->canvasWidget->decoration(INFINITY_DECORATION_ID);
if (infinityDecoration) {
infinityDecoration->setVisible(!value);
}
m_d->canvasWidget->setWrapAroundViewingMode(value);
}
bool KisCanvas2::wrapAroundViewingMode() const
{
KisCanvasDecorationSP infinityDecoration =
m_d->canvasWidget->decoration(INFINITY_DECORATION_ID);
if (infinityDecoration) {
return !(infinityDecoration->visible());
}
return false;
}
void KisCanvas2::bootstrapFinished()
{
if (!m_d->bootstrapLodBlocked) return;
m_d->bootstrapLodBlocked = false;
setLodAllowedInCanvas(m_d->lodAllowedInImage);
}
void KisCanvas2::setLodAllowedInCanvas(bool value)
{
if (!KisOpenGL::supportsLoD()) {
qWarning() << "WARNING: Level of Detail functionality is available only with openGL + GLSL 1.3 support";
}
m_d->lodAllowedInImage =
value &&
m_d->currentCanvasIsOpenGL &&
KisOpenGL::supportsLoD() &&
(m_d->openGLFilterMode == KisOpenGL::TrilinearFilterMode ||
m_d->openGLFilterMode == KisOpenGL::HighQualityFiltering);
KisImageSP image = this->image();
if (m_d->effectiveLodAllowedInImage() != !image->levelOfDetailBlocked()) {
image->setLevelOfDetailBlocked(!m_d->effectiveLodAllowedInImage());
}
notifyLevelOfDetailChange();
KisConfig cfg(false);
cfg.setLevelOfDetailEnabled(m_d->lodAllowedInImage);
}
bool KisCanvas2::lodAllowedInCanvas() const
{
return m_d->lodAllowedInImage;
}
void KisCanvas2::slotShowPopupPalette(const QPoint &p)
{
if (!m_d->popupPalette) {
return;
}
m_d->popupPalette->showPopupPalette(p);
}
KisPaintingAssistantsDecorationSP KisCanvas2::paintingAssistantsDecoration() const
{
KisCanvasDecorationSP deco = decoration("paintingAssistantsDecoration");
return qobject_cast<KisPaintingAssistantsDecoration*>(deco.data());
}
KisReferenceImagesDecorationSP KisCanvas2::referenceImagesDecoration() const
{
KisCanvasDecorationSP deco = decoration("referenceImagesDecoration");
return qobject_cast<KisReferenceImagesDecoration*>(deco.data());
}
diff --git a/libs/ui/dialogs/kis_dlg_preferences.cc b/libs/ui/dialogs/kis_dlg_preferences.cc
index 22c25cae85..d4e1109305 100644
--- a/libs/ui/dialogs/kis_dlg_preferences.cc
+++ b/libs/ui/dialogs/kis_dlg_preferences.cc
@@ -1,1808 +1,1811 @@
/*
* preferencesdlg.cc - part of KImageShop
*
* Copyright (c) 1999 Michael Koch <koch@kde.org>
* Copyright (c) 2003-2011 Boudewijn Rempt <boud@valdyas.org>
*
* 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_dlg_preferences.h"
#include <config-hdr.h>
#include <opengl/kis_opengl.h>
#include <QBitmap>
#include <QCheckBox>
+#include <QComboBox>
#include <QCursor>
#include <QDesktopWidget>
#include <QFileDialog>
#include <QFormLayout>
#include <QGridLayout>
#include <QGroupBox>
#include <QLabel>
#include <QLayout>
#include <QLineEdit>
#include <QMdiArea>
#include <QMessageBox>
#include <QPushButton>
#include <QRadioButton>
#include <QSettings>
#include <QSlider>
#include <QStandardPaths>
#include <QThread>
#include <QToolButton>
+#include <QStyleFactory>
#include <KisApplication.h>
#include <KisDocument.h>
#include <kis_icon.h>
#include <KisPart.h>
#include <KoColorProfile.h>
#include <KoColorSpaceEngine.h>
#include <KoConfigAuthorPage.h>
#include <KoConfig.h>
#include <KoFileDialog.h>
#include "KoID.h"
#include <KoVBox.h>
#include <klocalizedstring.h>
#include <kformat.h>
#include <kundo2stack.h>
#include <KoResourcePaths.h>
#include <KisResourceCacheDb.h>
#include <KisResourceLocator.h>
#include "KisProofingConfiguration.h"
#include "KoColorConversionTransformation.h"
#include "kis_action_registry.h"
#include <kis_image.h>
#include <KisSqueezedComboBox.h>
#include "kis_clipboard.h"
#include "widgets/kis_cmb_idlist.h"
#include "KoColorSpace.h"
#include "KoColorSpaceRegistry.h"
#include "kis_canvas_resource_provider.h"
#include "kis_color_manager.h"
#include "kis_config.h"
#include "kis_cursor.h"
#include "kis_image_config.h"
#include "kis_preference_set_registry.h"
#include "kis_file_name_requester.h"
#include "slider_and_spin_box_sync.h"
// for the performance update
#include <kis_cubic_curve.h>
#include <kis_signals_blocker.h>
#include "input/config/kis_input_configuration_page.h"
#include "input/wintab/drawpile_tablettester/tablettester.h"
#ifdef Q_OS_WIN
#include "config_use_qt_tablet_windows.h"
# ifndef USE_QT_TABLET_WINDOWS
# include <kis_tablet_support_win8.h>
# endif
#include "config-high-dpi-scale-factor-rounding-policy.h"
#endif
struct BackupSuffixValidator : public QValidator {
BackupSuffixValidator(QObject *parent)
: QValidator(parent)
, invalidCharacters(QStringList()
<< "0" << "1" << "2" << "3" << "4" << "5" << "6" << "7" << "8" << "9"
<< "/" << "\\" << ":" << ";" << " ")
{}
~BackupSuffixValidator() override {}
const QStringList invalidCharacters;
State validate(QString &line, int &/*pos*/) const override
{
Q_FOREACH(const QString invalidChar, invalidCharacters) {
if (line.contains(invalidChar)) {
return Invalid;
}
}
return Acceptable;
}
};
GeneralTab::GeneralTab(QWidget *_parent, const char *_name)
: WdgGeneralSettings(_parent, _name)
{
KisConfig cfg(true);
//
// Cursor Tab
//
m_cmbCursorShape->addItem(i18n("No Cursor"));
m_cmbCursorShape->addItem(i18n("Tool Icon"));
m_cmbCursorShape->addItem(i18n("Arrow"));
m_cmbCursorShape->addItem(i18n("Small Circle"));
m_cmbCursorShape->addItem(i18n("Crosshair"));
m_cmbCursorShape->addItem(i18n("Triangle Righthanded"));
m_cmbCursorShape->addItem(i18n("Triangle Lefthanded"));
m_cmbCursorShape->addItem(i18n("Black Pixel"));
m_cmbCursorShape->addItem(i18n("White Pixel"));
m_cmbCursorShape->setCurrentIndex(cfg.newCursorStyle());
m_cmbOutlineShape->addItem(i18n("No Outline"));
m_cmbOutlineShape->addItem(i18n("Circle Outline"));
m_cmbOutlineShape->addItem(i18n("Preview Outline"));
m_cmbOutlineShape->addItem(i18n("Tilt Outline"));
m_cmbOutlineShape->setCurrentIndex(cfg.newOutlineStyle());
m_showOutlinePainting->setChecked(cfg.showOutlineWhilePainting());
m_changeBrushOutline->setChecked(!cfg.forceAlwaysFullSizedOutline());
KoColor cursorColor(KoColorSpaceRegistry::instance()->rgb8());
cursorColor.fromQColor(cfg.getCursorMainColor());
cursorColorBtutton->setColor(cursorColor);
//
// Window Tab
//
m_cmbMDIType->setCurrentIndex(cfg.readEntry<int>("mdi_viewmode", (int)QMdiArea::TabbedView));
m_backgroundimage->setText(cfg.getMDIBackgroundImage());
connect(m_bnFileName, SIGNAL(clicked()), SLOT(getBackgroundImage()));
connect(clearBgImageButton, SIGNAL(clicked()), SLOT(clearBackgroundImage()));
QString xml = cfg.getMDIBackgroundColor();
KoColor mdiColor = KoColor::fromXML(xml);
m_mdiColor->setColor(mdiColor);
m_chkRubberBand->setChecked(cfg.readEntry<int>("mdi_rubberband", cfg.useOpenGL()));
m_chkCanvasMessages->setChecked(cfg.showCanvasMessages());
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
m_chkHiDPI->setChecked(kritarc.value("EnableHiDPI", true).toBool());
#ifdef HAVE_HIGH_DPI_SCALE_FACTOR_ROUNDING_POLICY
m_chkHiDPIFractionalScaling->setChecked(kritarc.value("EnableHiDPIFractionalScaling", true).toBool());
#else
m_chkHiDPIFractionalScaling->setVisible(false);
#endif
chkUsageLogging->setChecked(kritarc.value("LogUsage", true).toBool());
//
// Tools tab
//
m_radioToolOptionsInDocker->setChecked(cfg.toolOptionsInDocker());
cmbFlowMode->setCurrentIndex((int)!cfg.readEntry<bool>("useCreamyAlphaDarken", true));
m_chkSwitchSelectionCtrlAlt->setChecked(cfg.switchSelectionCtrlAlt());
chkEnableTouch->setChecked(!cfg.disableTouchOnCanvas());
chkEnableTouchRotation->setChecked(!cfg.disableTouchRotation());
chkEnableTranformToolAfterPaste->setChecked(cfg.activateTransformToolAfterPaste());
m_groupBoxKineticScrollingSettings->setChecked(cfg.kineticScrollingEnabled());
m_cmbKineticScrollingGesture->addItem(i18n("On Touch Drag"));
m_cmbKineticScrollingGesture->addItem(i18n("On Click Drag"));
m_cmbKineticScrollingGesture->addItem(i18n("On Middle-Click Drag"));
//m_cmbKineticScrollingGesture->addItem(i18n("On Right Click Drag"));
m_cmbKineticScrollingGesture->setCurrentIndex(cfg.kineticScrollingGesture());
m_kineticScrollingSensitivitySlider->setRange(0, 100);
m_kineticScrollingSensitivitySlider->setValue(cfg.kineticScrollingSensitivity());
m_chkKineticScrollingHideScrollbars->setChecked(cfg.kineticScrollingHiddenScrollbars());
//
// File handling
//
int autosaveInterval = cfg.autoSaveInterval();
//convert to minutes
m_autosaveSpinBox->setValue(autosaveInterval / 60);
m_autosaveCheckBox->setChecked(autosaveInterval > 0);
chkHideAutosaveFiles->setChecked(cfg.readEntry<bool>("autosavefileshidden", true));
m_chkCompressKra->setChecked(cfg.compressKra());
chkZip64->setChecked(cfg.useZip64());
m_chkTrimKra->setChecked(cfg.trimKra());
m_backupFileCheckBox->setChecked(cfg.backupFile());
cmbBackupFileLocation->setCurrentIndex(cfg.readEntry<int>("backupfilelocation", 0));
txtBackupFileSuffix->setText(cfg.readEntry<QString>("backupfilesuffix", "~"));
QValidator *validator = new BackupSuffixValidator(txtBackupFileSuffix);
txtBackupFileSuffix->setValidator(validator);
intNumBackupFiles->setValue(cfg.readEntry<int>("numberofbackupfiles", 1));
//
// Miscellaneous
//
cmbStartupSession->addItem(i18n("Open default window"));
cmbStartupSession->addItem(i18n("Load previous session"));
cmbStartupSession->addItem(i18n("Show session manager"));
cmbStartupSession->setCurrentIndex(cfg.sessionOnStartup());
chkSaveSessionOnQuit->setChecked(cfg.saveSessionOnQuit(false));
m_chkConvertOnImport->setChecked(cfg.convertToImageColorspaceOnImport());
m_undoStackSize->setValue(cfg.undoStackLimit());
m_favoritePresetsSpinBox->setValue(cfg.favoritePresets());
chkShowRootLayer->setChecked(cfg.showRootLayer());
m_chkAutoPin->setChecked(cfg.autoPinLayersToTimeline());
KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs");
bool dontUseNative = true;
#ifdef Q_OS_UNIX
if (qgetenv("XDG_CURRENT_DESKTOP") == "KDE") {
dontUseNative = false;
}
#endif
#ifdef Q_OS_WIN
dontUseNative = false;
#endif
m_chkNativeFileDialog->setChecked(!group.readEntry("DontUseNativeFileDialog", dontUseNative));
intMaxBrushSize->setValue(cfg.readEntry("maximumBrushSize", 1000));
//
// Resources
//
m_urlCacheDbLocation->setMode(KoFileDialog::OpenDirectory);
m_urlCacheDbLocation->setConfigurationName("cachedb_location");
m_urlCacheDbLocation->setFileName(cfg.readEntry<QString>(KisResourceCacheDb::dbLocationKey, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)));
m_urlResourceFolder->setMode(KoFileDialog::OpenDirectory);
m_urlResourceFolder->setConfigurationName("resource_directory");
m_urlResourceFolder->setFileName(cfg.readEntry<QString>(KisResourceLocator::resourceLocationKey, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)));
}
void GeneralTab::setDefault()
{
KisConfig cfg(true);
m_cmbCursorShape->setCurrentIndex(cfg.newCursorStyle(true));
m_cmbOutlineShape->setCurrentIndex(cfg.newOutlineStyle(true));
chkShowRootLayer->setChecked(cfg.showRootLayer(true));
m_autosaveCheckBox->setChecked(cfg.autoSaveInterval(true) > 0);
//convert to minutes
m_autosaveSpinBox->setValue(cfg.autoSaveInterval(true) / 60);
chkHideAutosaveFiles->setChecked(true);
m_undoStackSize->setValue(cfg.undoStackLimit(true));
m_backupFileCheckBox->setChecked(cfg.backupFile(true));
cmbBackupFileLocation->setCurrentIndex(0);
txtBackupFileSuffix->setText("~");
intNumBackupFiles->setValue(1);
m_showOutlinePainting->setChecked(cfg.showOutlineWhilePainting(true));
m_changeBrushOutline->setChecked(!cfg.forceAlwaysFullSizedOutline(true));
m_chkNativeFileDialog->setChecked(false);
intMaxBrushSize->setValue(1000);
m_cmbMDIType->setCurrentIndex((int)QMdiArea::TabbedView);
m_chkRubberBand->setChecked(cfg.useOpenGL(true));
m_favoritePresetsSpinBox->setValue(cfg.favoritePresets(true));
KoColor mdiColor;
mdiColor.fromXML(cfg.getMDIBackgroundColor(true));
m_mdiColor->setColor(mdiColor);
m_backgroundimage->setText(cfg.getMDIBackgroundImage(true));
m_chkCanvasMessages->setChecked(cfg.showCanvasMessages(true));
m_chkCompressKra->setChecked(cfg.compressKra(true));
m_chkTrimKra->setChecked(cfg.trimKra(true));
chkZip64->setChecked(cfg.useZip64(true));
m_chkHiDPI->setChecked(false);
m_chkHiDPI->setChecked(true);
#ifdef HAVE_HIGH_DPI_SCALE_FACTOR_ROUNDING_POLICY
m_chkHiDPIFractionalScaling->setChecked(true);
#endif
chkUsageLogging->setChecked(true);
m_radioToolOptionsInDocker->setChecked(cfg.toolOptionsInDocker(true));
cmbFlowMode->setCurrentIndex(0);
m_groupBoxKineticScrollingSettings->setChecked(cfg.kineticScrollingEnabled(true));
m_cmbKineticScrollingGesture->setCurrentIndex(cfg.kineticScrollingGesture(true));
m_kineticScrollingSensitivitySlider->setValue(cfg.kineticScrollingSensitivity(true));
m_chkKineticScrollingHideScrollbars->setChecked(cfg.kineticScrollingHiddenScrollbars(true));
m_chkSwitchSelectionCtrlAlt->setChecked(cfg.switchSelectionCtrlAlt(true));
chkEnableTouch->setChecked(!cfg.disableTouchOnCanvas(true));
chkEnableTouchRotation->setChecked(!cfg.disableTouchRotation(true));
chkEnableTranformToolAfterPaste->setChecked(cfg.activateTransformToolAfterPaste(true));
m_chkConvertOnImport->setChecked(cfg.convertToImageColorspaceOnImport(true));
KoColor cursorColor(KoColorSpaceRegistry::instance()->rgb8());
cursorColor.fromQColor(cfg.getCursorMainColor(true));
cursorColorBtutton->setColor(cursorColor);
m_chkAutoPin->setChecked(cfg.autoPinLayersToTimeline(true));
m_urlCacheDbLocation->setFileName(cfg.readEntry<QString>(KisResourceCacheDb::dbLocationKey, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)));
m_urlResourceFolder->setFileName(cfg.readEntry<QString>(KisResourceLocator::resourceLocationKey, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)));
}
CursorStyle GeneralTab::cursorStyle()
{
return (CursorStyle)m_cmbCursorShape->currentIndex();
}
OutlineStyle GeneralTab::outlineStyle()
{
return (OutlineStyle)m_cmbOutlineShape->currentIndex();
}
KisConfig::SessionOnStartup GeneralTab::sessionOnStartup() const
{
return (KisConfig::SessionOnStartup)cmbStartupSession->currentIndex();
}
bool GeneralTab::saveSessionOnQuit() const
{
return chkSaveSessionOnQuit->isChecked();
}
bool GeneralTab::showRootLayer()
{
return chkShowRootLayer->isChecked();
}
int GeneralTab::autoSaveInterval()
{
//convert to seconds
return m_autosaveCheckBox->isChecked() ? m_autosaveSpinBox->value() * 60 : 0;
}
int GeneralTab::undoStackSize()
{
return m_undoStackSize->value();
}
bool GeneralTab::showOutlineWhilePainting()
{
return m_showOutlinePainting->isChecked();
}
int GeneralTab::mdiMode()
{
return m_cmbMDIType->currentIndex();
}
int GeneralTab::favoritePresets()
{
return m_favoritePresetsSpinBox->value();
}
bool GeneralTab::showCanvasMessages()
{
return m_chkCanvasMessages->isChecked();
}
bool GeneralTab::compressKra()
{
return m_chkCompressKra->isChecked();
}
bool GeneralTab::trimKra()
{
return m_chkTrimKra->isChecked();
}
bool GeneralTab::useZip64()
{
return chkZip64->isChecked();
}
bool GeneralTab::toolOptionsInDocker()
{
return m_radioToolOptionsInDocker->isChecked();
}
bool GeneralTab::kineticScrollingEnabled()
{
return m_groupBoxKineticScrollingSettings->isChecked();
}
int GeneralTab::kineticScrollingGesture()
{
return m_cmbKineticScrollingGesture->currentIndex();
}
int GeneralTab::kineticScrollingSensitivity()
{
return m_kineticScrollingSensitivitySlider->value();
}
bool GeneralTab::kineticScrollingHiddenScrollbars()
{
return m_chkKineticScrollingHideScrollbars->isChecked();
}
bool GeneralTab::switchSelectionCtrlAlt()
{
return m_chkSwitchSelectionCtrlAlt->isChecked();
}
bool GeneralTab::convertToImageColorspaceOnImport()
{
return m_chkConvertOnImport->isChecked();
}
bool GeneralTab::autopinLayersToTimeline()
{
return m_chkAutoPin->isChecked();
}
void GeneralTab::getBackgroundImage()
{
KoFileDialog dialog(this, KoFileDialog::OpenFile, "BackgroundImages");
dialog.setCaption(i18n("Select a Background Image"));
dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
dialog.setImageFilters();
QString fn = dialog.filename();
// dialog box was canceled or somehow no file was selected
if (fn.isEmpty()) {
return;
}
QImage image(fn);
if (image.isNull()) {
QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("%1 is not a valid image file!", fn));
}
else {
m_backgroundimage->setText(fn);
}
}
void GeneralTab::clearBackgroundImage()
{
// clearing the background image text will implicitly make the background color be used
m_backgroundimage->setText("");
}
#include "kactioncollection.h"
#include "KisActionsSnapshot.h"
ShortcutSettingsTab::ShortcutSettingsTab(QWidget *parent, const char *name)
: QWidget(parent)
{
setObjectName(name);
QGridLayout * l = new QGridLayout(this);
l->setMargin(0);
m_page = new WdgShortcutSettings(this);
l->addWidget(m_page, 0, 0);
m_snapshot.reset(new KisActionsSnapshot);
KActionCollection *collection =
KisPart::instance()->currentMainwindow()->actionCollection();
Q_FOREACH (QAction *action, collection->actions()) {
m_snapshot->addAction(action->objectName(), action);
}
QMap<QString, KActionCollection*> sortedCollections =
m_snapshot->actionCollections();
for (auto it = sortedCollections.constBegin(); it != sortedCollections.constEnd(); ++it) {
m_page->addCollection(it.value(), it.key());
}
}
ShortcutSettingsTab::~ShortcutSettingsTab()
{
}
void ShortcutSettingsTab::setDefault()
{
m_page->allDefault();
}
void ShortcutSettingsTab::saveChanges()
{
m_page->save();
KisActionRegistry::instance()->settingsPageSaved();
}
void ShortcutSettingsTab::cancelChanges()
{
m_page->undo();
}
ColorSettingsTab::ColorSettingsTab(QWidget *parent, const char *name)
: QWidget(parent)
{
setObjectName(name);
// XXX: Make sure only profiles that fit the specified color model
// are shown in the profile combos
QGridLayout * l = new QGridLayout(this);
l->setMargin(0);
m_page = new WdgColorSettings(this);
l->addWidget(m_page, 0, 0);
KisConfig cfg(true);
m_page->chkUseSystemMonitorProfile->setChecked(cfg.useSystemMonitorProfile());
connect(m_page->chkUseSystemMonitorProfile, SIGNAL(toggled(bool)), this, SLOT(toggleAllowMonitorProfileSelection(bool)));
m_page->cmbWorkingColorSpace->setIDList(KoColorSpaceRegistry::instance()->listKeys());
m_page->cmbWorkingColorSpace->setCurrent(cfg.workingColorSpace());
m_page->bnAddColorProfile->setIcon(KisIconUtils::loadIcon("document-open"));
m_page->bnAddColorProfile->setToolTip( i18n("Open Color Profile") );
connect(m_page->bnAddColorProfile, SIGNAL(clicked()), SLOT(installProfile()));
QFormLayout *monitorProfileGrid = new QFormLayout(m_page->monitorprofileholder);
for(int i = 0; i < QGuiApplication::screens().count(); ++i) {
QLabel *lbl = new QLabel(i18nc("The number of the screen", "Screen %1:", i + 1));
m_monitorProfileLabels << lbl;
KisSqueezedComboBox *cmb = new KisSqueezedComboBox();
cmb->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
monitorProfileGrid->addRow(lbl, cmb);
m_monitorProfileWidgets << cmb;
}
// disable if not Linux as KisColorManager is not yet implemented outside Linux
#ifndef Q_OS_LINUX
m_page->chkUseSystemMonitorProfile->setChecked(false);
m_page->chkUseSystemMonitorProfile->setDisabled(true);
m_page->chkUseSystemMonitorProfile->setHidden(true);
#endif
refillMonitorProfiles(KoID("RGBA"));
for(int i = 0; i < QApplication::screens().count(); ++i) {
if (m_monitorProfileWidgets[i]->contains(cfg.monitorProfile(i))) {
m_monitorProfileWidgets[i]->setCurrent(cfg.monitorProfile(i));
}
}
m_page->chkBlackpoint->setChecked(cfg.useBlackPointCompensation());
m_page->chkAllowLCMSOptimization->setChecked(cfg.allowLCMSOptimization());
m_page->chkForcePaletteColor->setChecked(cfg.forcePaletteColors());
KisImageConfig cfgImage(true);
KisProofingConfigurationSP proofingConfig = cfgImage.defaultProofingconfiguration();
m_page->sldAdaptationState->setMaximum(20);
m_page->sldAdaptationState->setMinimum(0);
m_page->sldAdaptationState->setValue((int)proofingConfig->adaptationState*20);
//probably this should become the screenprofile?
KoColor ga(KoColorSpaceRegistry::instance()->rgb8());
ga.fromKoColor(proofingConfig->warningColor);
m_page->gamutAlarm->setColor(ga);
const KoColorSpace *proofingSpace = KoColorSpaceRegistry::instance()->colorSpace(proofingConfig->proofingModel,
proofingConfig->proofingDepth,
proofingConfig->proofingProfile);
if (proofingSpace) {
m_page->proofingSpaceSelector->setCurrentColorSpace(proofingSpace);
}
m_page->cmbProofingIntent->setCurrentIndex((int)proofingConfig->intent);
m_page->ckbProofBlackPoint->setChecked(proofingConfig->conversionFlags.testFlag(KoColorConversionTransformation::BlackpointCompensation));
m_pasteBehaviourGroup.addButton(m_page->radioPasteWeb, PASTE_ASSUME_WEB);
m_pasteBehaviourGroup.addButton(m_page->radioPasteMonitor, PASTE_ASSUME_MONITOR);
m_pasteBehaviourGroup.addButton(m_page->radioPasteAsk, PASTE_ASK);
QAbstractButton *button = m_pasteBehaviourGroup.button(cfg.pasteBehaviour());
Q_ASSERT(button);
if (button) {
button->setChecked(true);
}
m_page->cmbMonitorIntent->setCurrentIndex(cfg.monitorRenderIntent());
toggleAllowMonitorProfileSelection(cfg.useSystemMonitorProfile());
}
void ColorSettingsTab::installProfile()
{
KoFileDialog dialog(this, KoFileDialog::OpenFiles, "OpenDocumentICC");
dialog.setCaption(i18n("Install Color Profiles"));
dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
dialog.setMimeTypeFilters(QStringList() << "application/vnd.iccprofile", "application/vnd.iccprofile");
QStringList profileNames = dialog.filenames();
KoColorSpaceEngine *iccEngine = KoColorSpaceEngineRegistry::instance()->get("icc");
Q_ASSERT(iccEngine);
QString saveLocation = KoResourcePaths::saveLocation("icc_profiles");
Q_FOREACH (const QString &profileName, profileNames) {
if (!QFile::copy(profileName, saveLocation + QFileInfo(profileName).fileName())) {
qWarning() << "Could not install profile!" << saveLocation + QFileInfo(profileName).fileName();
continue;
}
iccEngine->addProfile(saveLocation + QFileInfo(profileName).fileName());
}
KisConfig cfg(true);
refillMonitorProfiles(KoID("RGBA"));
for(int i = 0; i < QApplication::screens().count(); ++i) {
if (m_monitorProfileWidgets[i]->contains(cfg.monitorProfile(i))) {
m_monitorProfileWidgets[i]->setCurrent(cfg.monitorProfile(i));
}
}
}
void ColorSettingsTab::toggleAllowMonitorProfileSelection(bool useSystemProfile)
{
KisConfig cfg(true);
if (useSystemProfile) {
QStringList devices = KisColorManager::instance()->devices();
if (devices.size() == QApplication::screens().count()) {
for(int i = 0; i < QApplication::screens().count(); ++i) {
m_monitorProfileWidgets[i]->clear();
QString monitorForScreen = cfg.monitorForScreen(i, devices[i]);
Q_FOREACH (const QString &device, devices) {
m_monitorProfileLabels[i]->setText(i18nc("The display/screen we got from Qt", "Screen %1:", i + 1));
m_monitorProfileWidgets[i]->addSqueezedItem(KisColorManager::instance()->deviceName(device), device);
if (devices[i] == monitorForScreen) {
m_monitorProfileWidgets[i]->setCurrentIndex(i);
}
}
}
}
}
else {
refillMonitorProfiles(KoID("RGBA"));
for(int i = 0; i < QApplication::screens().count(); ++i) {
if (m_monitorProfileWidgets[i]->contains(cfg.monitorProfile(i))) {
m_monitorProfileWidgets[i]->setCurrent(cfg.monitorProfile(i));
}
}
}
}
void ColorSettingsTab::setDefault()
{
m_page->cmbWorkingColorSpace->setCurrent("RGBA");
refillMonitorProfiles(KoID("RGBA"));
KisConfig cfg(true);
KisImageConfig cfgImage(true);
KisProofingConfigurationSP proofingConfig = cfgImage.defaultProofingconfiguration();
const KoColorSpace *proofingSpace = KoColorSpaceRegistry::instance()->colorSpace(proofingConfig->proofingModel,proofingConfig->proofingDepth,proofingConfig->proofingProfile);
if (proofingSpace) {
m_page->proofingSpaceSelector->setCurrentColorSpace(proofingSpace);
}
m_page->cmbProofingIntent->setCurrentIndex((int)proofingConfig->intent);
m_page->ckbProofBlackPoint->setChecked(proofingConfig->conversionFlags.testFlag(KoColorConversionTransformation::BlackpointCompensation));
m_page->sldAdaptationState->setValue(0);
//probably this should become the screenprofile?
KoColor ga(KoColorSpaceRegistry::instance()->rgb8());
ga.fromKoColor(proofingConfig->warningColor);
m_page->gamutAlarm->setColor(ga);
m_page->chkBlackpoint->setChecked(cfg.useBlackPointCompensation(true));
m_page->chkAllowLCMSOptimization->setChecked(cfg.allowLCMSOptimization(true));
m_page->chkForcePaletteColor->setChecked(cfg.forcePaletteColors(true));
m_page->cmbMonitorIntent->setCurrentIndex(cfg.monitorRenderIntent(true));
m_page->chkUseSystemMonitorProfile->setChecked(cfg.useSystemMonitorProfile(true));
QAbstractButton *button = m_pasteBehaviourGroup.button(cfg.pasteBehaviour(true));
Q_ASSERT(button);
if (button) {
button->setChecked(true);
}
}
void ColorSettingsTab::refillMonitorProfiles(const KoID & colorSpaceId)
{
for (int i = 0; i < QApplication::screens().count(); ++i) {
m_monitorProfileWidgets[i]->clear();
}
QMap<QString, const KoColorProfile *> profileList;
Q_FOREACH(const KoColorProfile *profile, KoColorSpaceRegistry::instance()->profilesFor(colorSpaceId.id())) {
profileList[profile->name()] = profile;
}
Q_FOREACH (const KoColorProfile *profile, profileList.values()) {
//qDebug() << "Profile" << profile->name() << profile->isSuitableForDisplay() << csf->defaultProfile();
if (profile->isSuitableForDisplay()) {
for (int i = 0; i < QApplication::screens().count(); ++i) {
m_monitorProfileWidgets[i]->addSqueezedItem(profile->name());
}
}
}
for (int i = 0; i < QApplication::screens().count(); ++i) {
m_monitorProfileLabels[i]->setText(i18nc("The number of the screen", "Screen %1:", i + 1));
m_monitorProfileWidgets[i]->setCurrent(KoColorSpaceRegistry::instance()->defaultProfileForColorSpace(colorSpaceId.id()));
}
}
//---------------------------------------------------------------------------------------------------
void TabletSettingsTab::setDefault()
{
KisCubicCurve curve;
curve.fromString(DEFAULT_CURVE_STRING);
m_page->pressureCurve->setCurve(curve);
m_page->chkUseRightMiddleClickWorkaround->setChecked(
KisConfig(true).useRightMiddleTabletButtonWorkaround(true));
#if defined Q_OS_WIN && (!defined USE_QT_TABLET_WINDOWS || defined QT_HAS_WINTAB_SWITCH)
#ifdef USE_QT_TABLET_WINDOWS
// ask Qt if WinInk is actually available
const bool isWinInkAvailable = true;
#else
const bool isWinInkAvailable = KisTabletSupportWin8::isAvailable();
#endif
if (isWinInkAvailable) {
KisConfig cfg(true);
m_page->radioWintab->setChecked(!cfg.useWin8PointerInput(true));
m_page->radioWin8PointerInput->setChecked(cfg.useWin8PointerInput(true));
} else {
m_page->radioWintab->setChecked(true);
m_page->radioWin8PointerInput->setChecked(false);
}
#else
m_page->grpTabletApi->setVisible(false);
#endif
}
TabletSettingsTab::TabletSettingsTab(QWidget* parent, const char* name): QWidget(parent)
{
setObjectName(name);
QGridLayout * l = new QGridLayout(this);
l->setMargin(0);
m_page = new WdgTabletSettings(this);
l->addWidget(m_page, 0, 0);
KisConfig cfg(true);
KisCubicCurve curve;
curve.fromString( cfg.pressureTabletCurve() );
m_page->pressureCurve->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
m_page->pressureCurve->setCurve(curve);
m_page->chkUseRightMiddleClickWorkaround->setChecked(
cfg.useRightMiddleTabletButtonWorkaround());
#if defined Q_OS_WIN && (!defined USE_QT_TABLET_WINDOWS || defined QT_HAS_WINTAB_SWITCH)
#ifdef USE_QT_TABLET_WINDOWS
// ask Qt if WinInk is actually available
const bool isWinInkAvailable = true;
#else
const bool isWinInkAvailable = KisTabletSupportWin8::isAvailable();
#endif
if (isWinInkAvailable) {
m_page->radioWintab->setChecked(!cfg.useWin8PointerInput());
m_page->radioWin8PointerInput->setChecked(cfg.useWin8PointerInput());
} else {
m_page->radioWintab->setChecked(true);
m_page->radioWin8PointerInput->setChecked(false);
m_page->grpTabletApi->setVisible(false);
}
#ifdef USE_QT_TABLET_WINDOWS
connect(m_page->btnResolutionSettings, SIGNAL(clicked()), SLOT(slotResolutionSettings()));
connect(m_page->radioWintab, SIGNAL(toggled(bool)), m_page->btnResolutionSettings, SLOT(setEnabled(bool)));
m_page->btnResolutionSettings->setEnabled(m_page->radioWintab->isChecked());
#else
m_page->btnResolutionSettings->setVisible(false);
#endif
#else
m_page->grpTabletApi->setVisible(false);
#endif
connect(m_page->btnTabletTest, SIGNAL(clicked()), SLOT(slotTabletTest()));
}
void TabletSettingsTab::slotTabletTest()
{
TabletTestDialog tabletTestDialog(this);
tabletTestDialog.exec();
}
#if defined Q_OS_WIN && defined USE_QT_TABLET_WINDOWS
#include "KisDlgCustomTabletResolution.h"
#endif
void TabletSettingsTab::slotResolutionSettings()
{
#if defined Q_OS_WIN && defined USE_QT_TABLET_WINDOWS
KisDlgCustomTabletResolution dlg(this);
dlg.exec();
#endif
}
//---------------------------------------------------------------------------------------------------
#include "kis_acyclic_signal_connector.h"
int getTotalRAM()
{
return KisImageConfig(true).totalRAM();
}
int PerformanceTab::realTilesRAM()
{
return intMemoryLimit->value() - intPoolLimit->value();
}
PerformanceTab::PerformanceTab(QWidget *parent, const char *name)
: WdgPerformanceSettings(parent, name)
{
KisImageConfig cfg(true);
const double totalRAM = cfg.totalRAM();
lblTotalMemory->setText(KFormat().formatByteSize(totalRAM * 1024 * 1024, 0, KFormat::IECBinaryDialect, KFormat::UnitMegaByte));
sliderMemoryLimit->setSuffix(i18n(" %"));
sliderMemoryLimit->setRange(1, 100, 2);
sliderMemoryLimit->setSingleStep(0.01);
sliderPoolLimit->setSuffix(i18n(" %"));
sliderPoolLimit->setRange(0, 20, 2);
sliderMemoryLimit->setSingleStep(0.01);
sliderUndoLimit->setSuffix(i18n(" %"));
sliderUndoLimit->setRange(0, 50, 2);
sliderMemoryLimit->setSingleStep(0.01);
intMemoryLimit->setMinimumWidth(80);
intPoolLimit->setMinimumWidth(80);
intUndoLimit->setMinimumWidth(80);
SliderAndSpinBoxSync *sync1 =
new SliderAndSpinBoxSync(sliderMemoryLimit,
intMemoryLimit,
getTotalRAM);
sync1->slotParentValueChanged();
m_syncs << sync1;
SliderAndSpinBoxSync *sync2 =
new SliderAndSpinBoxSync(sliderPoolLimit,
intPoolLimit,
std::bind(&KisIntParseSpinBox::value,
intMemoryLimit));
connect(intMemoryLimit, SIGNAL(valueChanged(int)), sync2, SLOT(slotParentValueChanged()));
sync2->slotParentValueChanged();
m_syncs << sync2;
SliderAndSpinBoxSync *sync3 =
new SliderAndSpinBoxSync(sliderUndoLimit,
intUndoLimit,
std::bind(&PerformanceTab::realTilesRAM,
this));
connect(intPoolLimit, SIGNAL(valueChanged(int)), sync3, SLOT(slotParentValueChanged()));
connect(intMemoryLimit, SIGNAL(valueChanged(int)), sync3, SLOT(slotParentValueChanged()));
sync3->slotParentValueChanged();
m_syncs << sync3;
sliderSwapSize->setSuffix(i18n(" GiB"));
sliderSwapSize->setRange(1, 64);
intSwapSize->setRange(1, 64);
KisAcyclicSignalConnector *swapSizeConnector = new KisAcyclicSignalConnector(this);
swapSizeConnector->connectForwardInt(sliderSwapSize, SIGNAL(valueChanged(int)),
intSwapSize, SLOT(setValue(int)));
swapSizeConnector->connectBackwardInt(intSwapSize, SIGNAL(valueChanged(int)),
sliderSwapSize, SLOT(setValue(int)));
lblSwapFileLocation->setText(cfg.swapDir());
connect(bnSwapFile, SIGNAL(clicked()), SLOT(selectSwapDir()));
sliderThreadsLimit->setRange(1, QThread::idealThreadCount());
sliderFrameClonesLimit->setRange(1, QThread::idealThreadCount());
sliderFpsLimit->setRange(20, 300);
sliderFpsLimit->setSuffix(i18n(" fps"));
connect(sliderThreadsLimit, SIGNAL(valueChanged(int)), SLOT(slotThreadsLimitChanged(int)));
connect(sliderFrameClonesLimit, SIGNAL(valueChanged(int)), SLOT(slotFrameClonesLimitChanged(int)));
intCachedFramesSizeLimit->setRange(1, 10000);
intCachedFramesSizeLimit->setSuffix(i18n(" px"));
intCachedFramesSizeLimit->setSingleStep(1);
intCachedFramesSizeLimit->setPageStep(1000);
intRegionOfInterestMargin->setRange(1, 100);
intRegionOfInterestMargin->setSuffix(i18n(" %"));
intRegionOfInterestMargin->setSingleStep(1);
intRegionOfInterestMargin->setPageStep(10);
connect(chkCachedFramesSizeLimit, SIGNAL(toggled(bool)), intCachedFramesSizeLimit, SLOT(setEnabled(bool)));
connect(chkUseRegionOfInterest, SIGNAL(toggled(bool)), intRegionOfInterestMargin, SLOT(setEnabled(bool)));
#ifndef Q_OS_WIN
// AVX workaround is needed on Windows+GCC only
chkDisableAVXOptimizations->setVisible(false);
#endif
load(false);
}
PerformanceTab::~PerformanceTab()
{
qDeleteAll(m_syncs);
}
void PerformanceTab::load(bool requestDefault)
{
KisImageConfig cfg(true);
sliderMemoryLimit->setValue(cfg.memoryHardLimitPercent(requestDefault));
sliderPoolLimit->setValue(cfg.memoryPoolLimitPercent(requestDefault));
sliderUndoLimit->setValue(cfg.memorySoftLimitPercent(requestDefault));
chkPerformanceLogging->setChecked(cfg.enablePerfLog(requestDefault));
chkProgressReporting->setChecked(cfg.enableProgressReporting(requestDefault));
sliderSwapSize->setValue(cfg.maxSwapSize(requestDefault) / 1024);
lblSwapFileLocation->setText(cfg.swapDir(requestDefault));
m_lastUsedThreadsLimit = cfg.maxNumberOfThreads(requestDefault);
m_lastUsedClonesLimit = cfg.frameRenderingClones(requestDefault);
sliderThreadsLimit->setValue(m_lastUsedThreadsLimit);
sliderFrameClonesLimit->setValue(m_lastUsedClonesLimit);
sliderFpsLimit->setValue(cfg.fpsLimit(requestDefault));
{
KisConfig cfg2(true);
chkOpenGLFramerateLogging->setChecked(cfg2.enableOpenGLFramerateLogging(requestDefault));
chkBrushSpeedLogging->setChecked(cfg2.enableBrushSpeedLogging(requestDefault));
chkDisableVectorOptimizations->setChecked(cfg2.enableAmdVectorizationWorkaround(requestDefault));
#ifdef Q_OS_WIN
chkDisableAVXOptimizations->setChecked(cfg2.disableAVXOptimizations(requestDefault));
#endif
chkBackgroundCacheGeneration->setChecked(cfg2.calculateAnimationCacheInBackground(requestDefault));
}
if (cfg.useOnDiskAnimationCacheSwapping(requestDefault)) {
optOnDisk->setChecked(true);
} else {
optInMemory->setChecked(true);
}
chkCachedFramesSizeLimit->setChecked(cfg.useAnimationCacheFrameSizeLimit(requestDefault));
intCachedFramesSizeLimit->setValue(cfg.animationCacheFrameSizeLimit(requestDefault));
intCachedFramesSizeLimit->setEnabled(chkCachedFramesSizeLimit->isChecked());
chkUseRegionOfInterest->setChecked(cfg.useAnimationCacheRegionOfInterest(requestDefault));
intRegionOfInterestMargin->setValue(cfg.animationCacheRegionOfInterestMargin(requestDefault) * 100.0);
intRegionOfInterestMargin->setEnabled(chkUseRegionOfInterest->isChecked());
}
void PerformanceTab::save()
{
KisImageConfig cfg(false);
cfg.setMemoryHardLimitPercent(sliderMemoryLimit->value());
cfg.setMemorySoftLimitPercent(sliderUndoLimit->value());
cfg.setMemoryPoolLimitPercent(sliderPoolLimit->value());
cfg.setEnablePerfLog(chkPerformanceLogging->isChecked());
cfg.setEnableProgressReporting(chkProgressReporting->isChecked());
cfg.setMaxSwapSize(sliderSwapSize->value() * 1024);
cfg.setSwapDir(lblSwapFileLocation->text());
cfg.setMaxNumberOfThreads(sliderThreadsLimit->value());
cfg.setFrameRenderingClones(sliderFrameClonesLimit->value());
cfg.setFpsLimit(sliderFpsLimit->value());
{
KisConfig cfg2(true);
cfg2.setEnableOpenGLFramerateLogging(chkOpenGLFramerateLogging->isChecked());
cfg2.setEnableBrushSpeedLogging(chkBrushSpeedLogging->isChecked());
cfg2.setEnableAmdVectorizationWorkaround(chkDisableVectorOptimizations->isChecked());
#ifdef Q_OS_WIN
cfg2.setDisableAVXOptimizations(chkDisableAVXOptimizations->isChecked());
#endif
cfg2.setCalculateAnimationCacheInBackground(chkBackgroundCacheGeneration->isChecked());
}
cfg.setUseOnDiskAnimationCacheSwapping(optOnDisk->isChecked());
cfg.setUseAnimationCacheFrameSizeLimit(chkCachedFramesSizeLimit->isChecked());
cfg.setAnimationCacheFrameSizeLimit(intCachedFramesSizeLimit->value());
cfg.setUseAnimationCacheRegionOfInterest(chkUseRegionOfInterest->isChecked());
cfg.setAnimationCacheRegionOfInterestMargin(intRegionOfInterestMargin->value() / 100.0);
}
void PerformanceTab::selectSwapDir()
{
KisImageConfig cfg(true);
QString swapDir = cfg.swapDir();
swapDir = QFileDialog::getExistingDirectory(0, i18nc("@title:window", "Select a swap directory"), swapDir);
if (swapDir.isEmpty()) {
return;
}
lblSwapFileLocation->setText(swapDir);
}
void PerformanceTab::slotThreadsLimitChanged(int value)
{
KisSignalsBlocker b(sliderFrameClonesLimit);
sliderFrameClonesLimit->setValue(qMin(m_lastUsedClonesLimit, value));
m_lastUsedThreadsLimit = value;
}
void PerformanceTab::slotFrameClonesLimitChanged(int value)
{
KisSignalsBlocker b(sliderThreadsLimit);
sliderThreadsLimit->setValue(qMax(m_lastUsedThreadsLimit, value));
m_lastUsedClonesLimit = value;
}
//---------------------------------------------------------------------------------------------------
#include "KoColor.h"
#include "opengl/KisOpenGLModeProber.h"
#include "opengl/KisScreenInformationAdapter.h"
#include <QOpenGLContext>
#include <QScreen>
QString colorSpaceString(KisSurfaceColorSpace cs, int depth)
{
const QString csString =
#ifdef HAVE_HDR
cs == KisSurfaceColorSpace::bt2020PQColorSpace ? "Rec. 2020 PQ" :
cs == KisSurfaceColorSpace::scRGBColorSpace ? "Rec. 709 Linear" :
#endif
cs == KisSurfaceColorSpace::sRGBColorSpace ? "sRGB" :
cs == KisSurfaceColorSpace::DefaultColorSpace ? "sRGB" :
"Unknown Color Space";
return QString("%1 (%2 bit)").arg(csString).arg(depth);
}
int formatToIndex(KisConfig::RootSurfaceFormat fmt)
{
return fmt == KisConfig::BT2020_PQ ? 1 :
fmt == KisConfig::BT709_G10 ? 2 :
0;
}
KisConfig::RootSurfaceFormat indexToFormat(int value)
{
return value == 1 ? KisConfig::BT2020_PQ :
value == 2 ? KisConfig::BT709_G10 :
KisConfig::BT709_G22;
}
DisplaySettingsTab::DisplaySettingsTab(QWidget *parent, const char *name)
: WdgDisplaySettings(parent, name)
{
KisConfig cfg(true);
const QString rendererOpenGLText = i18nc("canvas renderer", "OpenGL");
const QString rendererSoftwareText = i18nc("canvas renderer", "Software Renderer (very slow)");
#ifdef Q_OS_WIN
const QString rendererOpenGLESText = i18nc("canvas renderer", "Direct3D 11 via ANGLE");
#else
const QString rendererOpenGLESText = i18nc("canvas renderer", "OpenGL ES");
#endif
const KisOpenGL::OpenGLRenderer renderer = KisOpenGL::getCurrentOpenGLRenderer();
lblCurrentRenderer->setText(renderer == KisOpenGL::RendererOpenGLES ? rendererOpenGLESText :
renderer == KisOpenGL::RendererDesktopGL ? rendererOpenGLText :
renderer == KisOpenGL::RendererSoftware ? rendererSoftwareText :
i18nc("canvas renderer", "Unknown"));
cmbPreferredRenderer->clear();
const KisOpenGL::OpenGLRenderers supportedRenderers = KisOpenGL::getSupportedOpenGLRenderers();
const bool onlyOneRendererSupported =
supportedRenderers == KisOpenGL::RendererDesktopGL ||
supportedRenderers == KisOpenGL::RendererOpenGLES ||
supportedRenderers == KisOpenGL::RendererSoftware;
if (!onlyOneRendererSupported) {
QString qtPreferredRendererText;
if (KisOpenGL::getQtPreferredOpenGLRenderer() == KisOpenGL::RendererOpenGLES) {
qtPreferredRendererText = rendererOpenGLESText;
} else if (KisOpenGL::getQtPreferredOpenGLRenderer() == KisOpenGL::RendererSoftware) {
qtPreferredRendererText = rendererSoftwareText;
} else {
qtPreferredRendererText = rendererOpenGLText;
}
cmbPreferredRenderer->addItem(i18nc("canvas renderer", "Auto (%1)", qtPreferredRendererText), KisOpenGL::RendererAuto);
cmbPreferredRenderer->setCurrentIndex(0);
} else {
cmbPreferredRenderer->setEnabled(false);
}
if (supportedRenderers & KisOpenGL::RendererDesktopGL) {
cmbPreferredRenderer->addItem(rendererOpenGLText, KisOpenGL::RendererDesktopGL);
if (KisOpenGL::getUserPreferredOpenGLRendererConfig() == KisOpenGL::RendererDesktopGL) {
cmbPreferredRenderer->setCurrentIndex(cmbPreferredRenderer->count() - 1);
}
}
#ifdef Q_OS_ANDROID
if (onlyOneRendererSupported) {
if (KisOpenGL::getQtPreferredOpenGLRenderer() == KisOpenGL::RendererOpenGLES) {
cmbPreferredRenderer->addItem(rendererOpenGLESText, KisOpenGL::RendererOpenGLES);
cmbPreferredRenderer->setCurrentIndex(0);
}
}
#endif
#ifdef Q_OS_WIN
if (supportedRenderers & KisOpenGL::RendererOpenGLES) {
cmbPreferredRenderer->addItem(rendererOpenGLESText, KisOpenGL::RendererOpenGLES);
if (KisOpenGL::getUserPreferredOpenGLRendererConfig() == KisOpenGL::RendererOpenGLES) {
cmbPreferredRenderer->setCurrentIndex(cmbPreferredRenderer->count() - 1);
}
}
if (supportedRenderers & KisOpenGL::RendererSoftware) {
cmbPreferredRenderer->addItem(rendererSoftwareText, KisOpenGL::RendererSoftware);
if (KisOpenGL::getUserPreferredOpenGLRendererConfig() == KisOpenGL::RendererSoftware) {
cmbPreferredRenderer->setCurrentIndex(cmbPreferredRenderer->count() - 1);
}
}
#endif
if (!(supportedRenderers &
(KisOpenGL::RendererDesktopGL |
KisOpenGL::RendererOpenGLES |
KisOpenGL::RendererSoftware))) {
grpOpenGL->setEnabled(false);
grpOpenGL->setChecked(false);
chkUseTextureBuffer->setEnabled(false);
chkDisableVsync->setEnabled(false);
cmbFilterMode->setEnabled(false);
} else {
grpOpenGL->setEnabled(true);
grpOpenGL->setChecked(cfg.useOpenGL());
chkUseTextureBuffer->setEnabled(cfg.useOpenGL());
chkUseTextureBuffer->setChecked(cfg.useOpenGLTextureBuffer());
chkDisableVsync->setVisible(cfg.showAdvancedOpenGLSettings());
chkDisableVsync->setEnabled(cfg.useOpenGL());
chkDisableVsync->setChecked(cfg.disableVSync());
cmbFilterMode->setEnabled(cfg.useOpenGL());
cmbFilterMode->setCurrentIndex(cfg.openGLFilteringMode());
// Don't show the high quality filtering mode if it's not available
if (!KisOpenGL::supportsLoD()) {
cmbFilterMode->removeItem(3);
}
}
lblCurrentDisplayFormat->setText("");
lblCurrentRootSurfaceFormat->setText("");
lblHDRWarning->setText("");
cmbPreferedRootSurfaceFormat->addItem(colorSpaceString(KisSurfaceColorSpace::sRGBColorSpace, 8));
#ifdef HAVE_HDR
cmbPreferedRootSurfaceFormat->addItem(colorSpaceString(KisSurfaceColorSpace::bt2020PQColorSpace, 10));
cmbPreferedRootSurfaceFormat->addItem(colorSpaceString(KisSurfaceColorSpace::scRGBColorSpace, 16));
#endif
cmbPreferedRootSurfaceFormat->setCurrentIndex(formatToIndex(KisConfig::BT709_G22));
slotPreferredSurfaceFormatChanged(cmbPreferedRootSurfaceFormat->currentIndex());
QOpenGLContext *context = QOpenGLContext::currentContext();
if (!context) {
context = QOpenGLContext::globalShareContext();
}
if (context) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
QScreen *screen = QGuiApplication::screenAt(rect().center());
#else
QScreen *screen = 0;
#endif
KisScreenInformationAdapter adapter(context);
if (screen && adapter.isValid()) {
KisScreenInformationAdapter::ScreenInfo info = adapter.infoForScreen(screen);
if (info.isValid()) {
QStringList toolTip;
toolTip << i18n("Display Id: %1", info.screen->name());
toolTip << i18n("Display Name: %1 %2", info.screen->manufacturer(), info.screen->model());
toolTip << i18n("Min Luminance: %1", info.minLuminance);
toolTip << i18n("Max Luminance: %1", info.maxLuminance);
toolTip << i18n("Max Full Frame Luminance: %1", info.maxFullFrameLuminance);
toolTip << i18n("Red Primary: %1, %2", info.redPrimary[0], info.redPrimary[1]);
toolTip << i18n("Green Primary: %1, %2", info.greenPrimary[0], info.greenPrimary[1]);
toolTip << i18n("Blue Primary: %1, %2", info.bluePrimary[0], info.bluePrimary[1]);
toolTip << i18n("White Point: %1, %2", info.whitePoint[0], info.whitePoint[1]);
lblCurrentDisplayFormat->setToolTip(toolTip.join('\n'));
lblCurrentDisplayFormat->setText(colorSpaceString(info.colorSpace, info.bitsPerColor));
} else {
lblCurrentDisplayFormat->setToolTip("");
lblCurrentDisplayFormat->setText(i18n("Unknown"));
}
} else {
lblCurrentDisplayFormat->setToolTip("");
lblCurrentDisplayFormat->setText(i18n("Unknown"));
qWarning() << "Failed to fetch display info:" << adapter.errorString();
}
const QSurfaceFormat currentFormat = KisOpenGLModeProber::instance()->surfaceformatInUse();
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
KisSurfaceColorSpace colorSpace = currentFormat.colorSpace();
#else
KisSurfaceColorSpace colorSpace = KisSurfaceColorSpace::DefaultColorSpace;
#endif
lblCurrentRootSurfaceFormat->setText(colorSpaceString(colorSpace, currentFormat.redBufferSize()));
cmbPreferedRootSurfaceFormat->setCurrentIndex(formatToIndex(cfg.rootSurfaceFormat()));
connect(cmbPreferedRootSurfaceFormat, SIGNAL(currentIndexChanged(int)), SLOT(slotPreferredSurfaceFormatChanged(int)));
slotPreferredSurfaceFormatChanged(cmbPreferedRootSurfaceFormat->currentIndex());
}
#ifndef HAVE_HDR
grpHDRSettings->setVisible(false);
tabWidget->removeTab(tabWidget->indexOf(tabHDR));
#endif
const QStringList openglWarnings = KisOpenGL::getOpenGLWarnings();
if (openglWarnings.isEmpty()) {
lblOpenGLWarnings->setVisible(false);
} else {
QString text("<span style=\"color: yellow;\">&#x26A0;</span> ");
text.append(i18n("Warning(s):"));
text.append("<ul>");
Q_FOREACH (const QString &warning, openglWarnings) {
text.append("<li>");
text.append(warning.toHtmlEscaped());
text.append("</li>");
}
text.append("</ul>");
lblOpenGLWarnings->setText(text);
lblOpenGLWarnings->setVisible(true);
}
if (qApp->applicationName() == "kritasketch" || qApp->applicationName() == "kritagemini") {
grpOpenGL->setVisible(false);
grpOpenGL->setMaximumHeight(0);
}
KisImageConfig imageCfg(false);
KoColor c;
c.fromQColor(imageCfg.selectionOverlayMaskColor());
c.setOpacity(1.0);
btnSelectionOverlayColor->setColor(c);
sldSelectionOverlayOpacity->setRange(0.0, 1.0, 2);
sldSelectionOverlayOpacity->setSingleStep(0.05);
sldSelectionOverlayOpacity->setValue(imageCfg.selectionOverlayMaskColor().alphaF());
intCheckSize->setValue(cfg.checkSize());
chkMoving->setChecked(cfg.scrollCheckers());
KoColor ck1(KoColorSpaceRegistry::instance()->rgb8());
ck1.fromQColor(cfg.checkersColor1());
colorChecks1->setColor(ck1);
KoColor ck2(KoColorSpaceRegistry::instance()->rgb8());
ck2.fromQColor(cfg.checkersColor2());
colorChecks2->setColor(ck2);
KoColor cb(KoColorSpaceRegistry::instance()->rgb8());
cb.fromQColor(cfg.canvasBorderColor());
canvasBorder->setColor(cb);
hideScrollbars->setChecked(cfg.hideScrollbars());
chkCurveAntialiasing->setChecked(cfg.antialiasCurves());
chkSelectionOutlineAntialiasing->setChecked(cfg.antialiasSelectionOutline());
chkChannelsAsColor->setChecked(cfg.showSingleChannelAsColor());
chkHidePopups->setChecked(cfg.hidePopups());
connect(grpOpenGL, SIGNAL(toggled(bool)), SLOT(slotUseOpenGLToggled(bool)));
KoColor gridColor(KoColorSpaceRegistry::instance()->rgb8());
gridColor.fromQColor(cfg.getPixelGridColor());
pixelGridColorButton->setColor(gridColor);
pixelGridDrawingThresholdBox->setValue(cfg.getPixelGridDrawingThreshold() * 100);
}
void DisplaySettingsTab::setDefault()
{
KisConfig cfg(true);
cmbPreferredRenderer->setCurrentIndex(0);
if (!(KisOpenGL::getSupportedOpenGLRenderers() &
(KisOpenGL::RendererDesktopGL | KisOpenGL::RendererOpenGLES))) {
grpOpenGL->setEnabled(false);
grpOpenGL->setChecked(false);
chkUseTextureBuffer->setEnabled(false);
chkDisableVsync->setEnabled(false);
cmbFilterMode->setEnabled(false);
}
else {
grpOpenGL->setEnabled(true);
grpOpenGL->setChecked(cfg.useOpenGL(true));
chkUseTextureBuffer->setChecked(cfg.useOpenGLTextureBuffer(true));
chkUseTextureBuffer->setEnabled(true);
chkDisableVsync->setEnabled(true);
chkDisableVsync->setChecked(cfg.disableVSync(true));
cmbFilterMode->setEnabled(true);
cmbFilterMode->setCurrentIndex(cfg.openGLFilteringMode(true));
}
chkMoving->setChecked(cfg.scrollCheckers(true));
KisImageConfig imageCfg(false);
KoColor c;
c.fromQColor(imageCfg.selectionOverlayMaskColor(true));
c.setOpacity(1.0);
btnSelectionOverlayColor->setColor(c);
sldSelectionOverlayOpacity->setValue(imageCfg.selectionOverlayMaskColor(true).alphaF());
intCheckSize->setValue(cfg.checkSize(true));
KoColor ck1(KoColorSpaceRegistry::instance()->rgb8());
ck1.fromQColor(cfg.checkersColor1(true));
colorChecks1->setColor(ck1);
KoColor ck2(KoColorSpaceRegistry::instance()->rgb8());
ck2.fromQColor(cfg.checkersColor2(true));
colorChecks2->setColor(ck2);
KoColor cvb(KoColorSpaceRegistry::instance()->rgb8());
cvb.fromQColor(cfg.canvasBorderColor(true));
canvasBorder->setColor(cvb);
hideScrollbars->setChecked(cfg.hideScrollbars(true));
chkCurveAntialiasing->setChecked(cfg.antialiasCurves(true));
chkSelectionOutlineAntialiasing->setChecked(cfg.antialiasSelectionOutline(true));
chkChannelsAsColor->setChecked(cfg.showSingleChannelAsColor(true));
chkHidePopups->setChecked(cfg.hidePopups(true));
KoColor gridColor(KoColorSpaceRegistry::instance()->rgb8());
gridColor.fromQColor(cfg.getPixelGridColor(true));
pixelGridColorButton->setColor(gridColor);
pixelGridDrawingThresholdBox->setValue(cfg.getPixelGridDrawingThreshold(true) * 100);
cmbPreferedRootSurfaceFormat->setCurrentIndex(formatToIndex(KisConfig::BT709_G22));
slotPreferredSurfaceFormatChanged(cmbPreferedRootSurfaceFormat->currentIndex());
}
void DisplaySettingsTab::slotUseOpenGLToggled(bool isChecked)
{
chkUseTextureBuffer->setEnabled(isChecked);
chkDisableVsync->setEnabled(isChecked);
cmbFilterMode->setEnabled(isChecked);
}
void DisplaySettingsTab::slotPreferredSurfaceFormatChanged(int index)
{
Q_UNUSED(index);
QOpenGLContext *context = QOpenGLContext::currentContext();
if (context) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
QScreen *screen = QGuiApplication::screenAt(rect().center());
#else
QScreen *screen = 0;
#endif
KisScreenInformationAdapter adapter(context);
if (adapter.isValid()) {
KisScreenInformationAdapter::ScreenInfo info = adapter.infoForScreen(screen);
if (info.isValid()) {
if (cmbPreferedRootSurfaceFormat->currentIndex() != formatToIndex(KisConfig::BT709_G22) &&
info.colorSpace == KisSurfaceColorSpace::sRGBColorSpace) {
lblHDRWarning->setText(i18n("WARNING: current display doesn't support HDR rendering"));
} else {
lblHDRWarning->setText("");
}
}
}
}
}
//---------------------------------------------------------------------------------------------------
FullscreenSettingsTab::FullscreenSettingsTab(QWidget* parent) : WdgFullscreenSettingsBase(parent)
{
KisConfig cfg(true);
chkDockers->setChecked(cfg.hideDockersFullscreen());
chkMenu->setChecked(cfg.hideMenuFullscreen());
chkScrollbars->setChecked(cfg.hideScrollbarsFullscreen());
chkStatusbar->setChecked(cfg.hideStatusbarFullscreen());
chkTitlebar->setChecked(cfg.hideTitlebarFullscreen());
chkToolbar->setChecked(cfg.hideToolbarFullscreen());
}
void FullscreenSettingsTab::setDefault()
{
KisConfig cfg(true);
chkDockers->setChecked(cfg.hideDockersFullscreen(true));
chkMenu->setChecked(cfg.hideMenuFullscreen(true));
chkScrollbars->setChecked(cfg.hideScrollbarsFullscreen(true));
chkStatusbar->setChecked(cfg.hideStatusbarFullscreen(true));
chkTitlebar->setChecked(cfg.hideTitlebarFullscreen(true));
chkToolbar->setChecked(cfg.hideToolbarFullscreen(true));
}
//---------------------------------------------------------------------------------------------------
KisDlgPreferences::KisDlgPreferences(QWidget* parent, const char* name)
: KPageDialog(parent)
{
Q_UNUSED(name);
setWindowTitle(i18n("Configure Krita"));
setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::RestoreDefaults);
setFaceType(KPageDialog::List);
// General
KoVBox *vbox = new KoVBox();
KPageWidgetItem *page = new KPageWidgetItem(vbox, i18n("General"));
page->setObjectName("general");
page->setHeader(i18n("General"));
page->setIcon(KisIconUtils::loadIcon("go-home"));
m_pages << page;
addPage(page);
m_general = new GeneralTab(vbox);
// Shortcuts
vbox = new KoVBox();
page = new KPageWidgetItem(vbox, i18n("Keyboard Shortcuts"));
page->setObjectName("shortcuts");
page->setHeader(i18n("Shortcuts"));
page->setIcon(KisIconUtils::loadIcon("document-export"));
m_pages << page;
addPage(page);
m_shortcutSettings = new ShortcutSettingsTab(vbox);
connect(this, SIGNAL(accepted()), m_shortcutSettings, SLOT(saveChanges()));
connect(this, SIGNAL(rejected()), m_shortcutSettings, SLOT(cancelChanges()));
// Canvas input settings
m_inputConfiguration = new KisInputConfigurationPage();
page = addPage(m_inputConfiguration, i18n("Canvas Input Settings"));
page->setHeader(i18n("Canvas Input"));
page->setObjectName("canvasinput");
page->setIcon(KisIconUtils::loadIcon("configure"));
m_pages << page;
// Display
vbox = new KoVBox();
page = new KPageWidgetItem(vbox, i18n("Display"));
page->setObjectName("display");
page->setHeader(i18n("Display"));
page->setIcon(KisIconUtils::loadIcon("preferences-desktop-display"));
m_pages << page;
addPage(page);
m_displaySettings = new DisplaySettingsTab(vbox);
// Color
vbox = new KoVBox();
page = new KPageWidgetItem(vbox, i18n("Color Management"));
page->setObjectName("colormanagement");
page->setHeader(i18n("Color"));
page->setIcon(KisIconUtils::loadIcon("preferences-desktop-color"));
m_pages << page;
addPage(page);
m_colorSettings = new ColorSettingsTab(vbox);
// Performance
vbox = new KoVBox();
page = new KPageWidgetItem(vbox, i18n("Performance"));
page->setObjectName("performance");
page->setHeader(i18n("Performance"));
page->setIcon(KisIconUtils::loadIcon("applications-system"));
m_pages << page;
addPage(page);
m_performanceSettings = new PerformanceTab(vbox);
// Tablet
vbox = new KoVBox();
page = new KPageWidgetItem(vbox, i18n("Tablet settings"));
page->setObjectName("tablet");
page->setHeader(i18n("Tablet"));
page->setIcon(KisIconUtils::loadIcon("document-edit"));
m_pages << page;
addPage(page);
m_tabletSettings = new TabletSettingsTab(vbox);
// full-screen mode
vbox = new KoVBox();
page = new KPageWidgetItem(vbox, i18n("Canvas-only settings"));
page->setObjectName("canvasonly");
page->setHeader(i18n("Canvas-only"));
page->setIcon(KisIconUtils::loadIcon("folder-pictures"));
m_pages << page;
addPage(page);
m_fullscreenSettings = new FullscreenSettingsTab(vbox);
// Author profiles
m_authorPage = new KoConfigAuthorPage();
page = addPage(m_authorPage, i18nc("@title:tab Author page", "Author" ));
page->setObjectName("author");
page->setHeader(i18n("Author"));
page->setIcon(KisIconUtils::loadIcon("im-user"));
m_pages << page;
QPushButton *restoreDefaultsButton = button(QDialogButtonBox::RestoreDefaults);
restoreDefaultsButton->setText(i18nc("@action:button", "Restore Defaults"));
connect(this, SIGNAL(accepted()), m_inputConfiguration, SLOT(saveChanges()));
connect(this, SIGNAL(rejected()), m_inputConfiguration, SLOT(revertChanges()));
KisPreferenceSetRegistry *preferenceSetRegistry = KisPreferenceSetRegistry::instance();
QStringList keys = preferenceSetRegistry->keys();
keys.sort();
Q_FOREACH(const QString &key, keys) {
KisAbstractPreferenceSetFactory *preferenceSetFactory = preferenceSetRegistry->value(key);
KisPreferenceSet* preferenceSet = preferenceSetFactory->createPreferenceSet();
vbox = new KoVBox();
page = new KPageWidgetItem(vbox, preferenceSet->name());
page->setHeader(preferenceSet->header());
page->setIcon(preferenceSet->icon());
addPage(page);
preferenceSet->setParent(vbox);
preferenceSet->loadPreferences();
connect(restoreDefaultsButton, SIGNAL(clicked(bool)), preferenceSet, SLOT(loadDefaultPreferences()), Qt::UniqueConnection);
connect(this, SIGNAL(accepted()), preferenceSet, SLOT(savePreferences()), Qt::UniqueConnection);
}
connect(restoreDefaultsButton, SIGNAL(clicked(bool)), this, SLOT(slotDefault()));
KisConfig cfg(true);
QString currentPageName = cfg.readEntry<QString>("KisDlgPreferences/CurrentPage");
Q_FOREACH(KPageWidgetItem *page, m_pages) {
if (page->objectName() == currentPageName) {
setCurrentPage(page);
break;
}
}
}
KisDlgPreferences::~KisDlgPreferences()
{
KisConfig cfg(true);
cfg.writeEntry<QString>("KisDlgPreferences/CurrentPage", currentPage()->objectName());
}
void KisDlgPreferences::showEvent(QShowEvent *event){
KPageDialog::showEvent(event);
button(QDialogButtonBox::Cancel)->setAutoDefault(false);
button(QDialogButtonBox::Ok)->setAutoDefault(false);
button(QDialogButtonBox::RestoreDefaults)->setAutoDefault(false);
button(QDialogButtonBox::Cancel)->setDefault(false);
button(QDialogButtonBox::Ok)->setDefault(false);
button(QDialogButtonBox::RestoreDefaults)->setDefault(false);
}
void KisDlgPreferences::slotButtonClicked(QAbstractButton *button)
{
if (buttonBox()->buttonRole(button) == QDialogButtonBox::RejectRole) {
m_cancelClicked = true;
}
}
void KisDlgPreferences::slotDefault()
{
if (currentPage()->objectName() == "general") {
m_general->setDefault();
}
else if (currentPage()->objectName() == "shortcuts") {
m_shortcutSettings->setDefault();
}
else if (currentPage()->objectName() == "display") {
m_displaySettings->setDefault();
}
else if (currentPage()->objectName() == "colormanagement") {
m_colorSettings->setDefault();
}
else if (currentPage()->objectName() == "performance") {
m_performanceSettings->load(true);
}
else if (currentPage()->objectName() == "tablet") {
m_tabletSettings->setDefault();
}
else if (currentPage()->objectName() == "canvasonly") {
m_fullscreenSettings->setDefault();
}
else if (currentPage()->objectName() == "canvasinput") {
m_inputConfiguration->setDefaults();
}
}
bool KisDlgPreferences::editPreferences()
{
connect(this->buttonBox(), SIGNAL(clicked(QAbstractButton*)), this, SLOT(slotButtonClicked(QAbstractButton*)));
int retval = exec();
Q_UNUSED(retval)
if (!m_cancelClicked) {
// General settings
KisConfig cfg(false);
cfg.setNewCursorStyle(m_general->cursorStyle());
cfg.setNewOutlineStyle(m_general->outlineStyle());
cfg.setShowRootLayer(m_general->showRootLayer());
cfg.setShowOutlineWhilePainting(m_general->showOutlineWhilePainting());
cfg.setForceAlwaysFullSizedOutline(!m_general->m_changeBrushOutline->isChecked());
cfg.setSessionOnStartup(m_general->sessionOnStartup());
cfg.setSaveSessionOnQuit(m_general->saveSessionOnQuit());
KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs");
group.writeEntry("DontUseNativeFileDialog", !m_general->m_chkNativeFileDialog->isChecked());
cfg.writeEntry<int>("maximumBrushSize", m_general->intMaxBrushSize->value());
cfg.writeEntry<int>("mdi_viewmode", m_general->mdiMode());
cfg.setMDIBackgroundColor(m_general->m_mdiColor->color().toXML());
cfg.setMDIBackgroundImage(m_general->m_backgroundimage->text());
cfg.setAutoSaveInterval(m_general->autoSaveInterval());
cfg.writeEntry("autosavefileshidden", m_general->chkHideAutosaveFiles->isChecked());
cfg.setBackupFile(m_general->m_backupFileCheckBox->isChecked());
cfg.writeEntry("backupfilelocation", m_general->cmbBackupFileLocation->currentIndex());
cfg.writeEntry("backupfilesuffix", m_general->txtBackupFileSuffix->text());
cfg.writeEntry("numberofbackupfiles", m_general->intNumBackupFiles->value());
+
cfg.setShowCanvasMessages(m_general->showCanvasMessages());
cfg.setCompressKra(m_general->compressKra());
cfg.setTrimKra(m_general->trimKra());
cfg.setUseZip64(m_general->useZip64());
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
kritarc.setValue("EnableHiDPI", m_general->m_chkHiDPI->isChecked());
#ifdef HAVE_HIGH_DPI_SCALE_FACTOR_ROUNDING_POLICY
kritarc.setValue("EnableHiDPIFractionalScaling", m_general->m_chkHiDPIFractionalScaling->isChecked());
#endif
kritarc.setValue("LogUsage", m_general->chkUsageLogging->isChecked());
cfg.setToolOptionsInDocker(m_general->toolOptionsInDocker());
cfg.writeEntry<bool>("useCreamyAlphaDarken", (bool)!m_general->cmbFlowMode->currentIndex());
cfg.setKineticScrollingEnabled(m_general->kineticScrollingEnabled());
cfg.setKineticScrollingGesture(m_general->kineticScrollingGesture());
cfg.setKineticScrollingSensitivity(m_general->kineticScrollingSensitivity());
cfg.setKineticScrollingHideScrollbars(m_general->kineticScrollingHiddenScrollbars());
cfg.setSwitchSelectionCtrlAlt(m_general->switchSelectionCtrlAlt());
cfg.setDisableTouchOnCanvas(!m_general->chkEnableTouch->isChecked());
cfg.setDisableTouchRotation(!m_general->chkEnableTouchRotation->isChecked());
cfg.setActivateTransformToolAfterPaste(m_general->chkEnableTranformToolAfterPaste->isChecked());
cfg.setConvertToImageColorspaceOnImport(m_general->convertToImageColorspaceOnImport());
cfg.setUndoStackLimit(m_general->undoStackSize());
cfg.setFavoritePresets(m_general->favoritePresets());
cfg.setAutoPinLayersToTimeline(m_general->autopinLayersToTimeline());
cfg.writeEntry(KisResourceCacheDb::dbLocationKey, m_general->m_urlCacheDbLocation->fileName());
cfg.writeEntry(KisResourceLocator::resourceLocationKey, m_general->m_urlResourceFolder->fileName());
// Color settings
cfg.setUseSystemMonitorProfile(m_colorSettings->m_page->chkUseSystemMonitorProfile->isChecked());
for (int i = 0; i < QApplication::screens().count(); ++i) {
if (m_colorSettings->m_page->chkUseSystemMonitorProfile->isChecked()) {
int currentIndex = m_colorSettings->m_monitorProfileWidgets[i]->currentIndex();
QString monitorid = m_colorSettings->m_monitorProfileWidgets[i]->itemData(currentIndex).toString();
cfg.setMonitorForScreen(i, monitorid);
}
else {
cfg.setMonitorProfile(i,
m_colorSettings->m_monitorProfileWidgets[i]->currentUnsqueezedText(),
m_colorSettings->m_page->chkUseSystemMonitorProfile->isChecked());
}
}
cfg.setWorkingColorSpace(m_colorSettings->m_page->cmbWorkingColorSpace->currentItem().id());
KisImageConfig cfgImage(false);
cfgImage.setDefaultProofingConfig(m_colorSettings->m_page->proofingSpaceSelector->currentColorSpace(),
m_colorSettings->m_page->cmbProofingIntent->currentIndex(),
m_colorSettings->m_page->ckbProofBlackPoint->isChecked(),
m_colorSettings->m_page->gamutAlarm->color(),
(double)m_colorSettings->m_page->sldAdaptationState->value()/20);
cfg.setUseBlackPointCompensation(m_colorSettings->m_page->chkBlackpoint->isChecked());
cfg.setAllowLCMSOptimization(m_colorSettings->m_page->chkAllowLCMSOptimization->isChecked());
cfg.setForcePaletteColors(m_colorSettings->m_page->chkForcePaletteColor->isChecked());
cfg.setPasteBehaviour(m_colorSettings->m_pasteBehaviourGroup.checkedId());
cfg.setRenderIntent(m_colorSettings->m_page->cmbMonitorIntent->currentIndex());
// Tablet settings
cfg.setPressureTabletCurve( m_tabletSettings->m_page->pressureCurve->curve().toString() );
cfg.setUseRightMiddleTabletButtonWorkaround(
m_tabletSettings->m_page->chkUseRightMiddleClickWorkaround->isChecked());
#if defined Q_OS_WIN && (!defined USE_QT_TABLET_WINDOWS || defined QT_HAS_WINTAB_SWITCH)
#ifdef USE_QT_TABLET_WINDOWS
// ask Qt if WinInk is actually available
const bool isWinInkAvailable = true;
#else
const bool isWinInkAvailable = KisTabletSupportWin8::isAvailable();
#endif
if (isWinInkAvailable) {
cfg.setUseWin8PointerInput(m_tabletSettings->m_page->radioWin8PointerInput->isChecked());
}
#endif
m_performanceSettings->save();
if (!cfg.useOpenGL() && m_displaySettings->grpOpenGL->isChecked())
cfg.setCanvasState("TRY_OPENGL");
if (m_displaySettings->grpOpenGL->isChecked()) {
KisOpenGL::OpenGLRenderer renderer = static_cast<KisOpenGL::OpenGLRenderer>(
m_displaySettings->cmbPreferredRenderer->itemData(
m_displaySettings->cmbPreferredRenderer->currentIndex()).toInt());
KisOpenGL::setUserPreferredOpenGLRendererConfig(renderer);
} else {
KisOpenGL::setUserPreferredOpenGLRendererConfig(KisOpenGL::RendererNone);
}
cfg.setUseOpenGLTextureBuffer(m_displaySettings->chkUseTextureBuffer->isChecked());
cfg.setOpenGLFilteringMode(m_displaySettings->cmbFilterMode->currentIndex());
cfg.setDisableVSync(m_displaySettings->chkDisableVsync->isChecked());
cfg.setRootSurfaceFormat(&kritarc, indexToFormat(m_displaySettings->cmbPreferedRootSurfaceFormat->currentIndex()));
cfg.setCheckSize(m_displaySettings->intCheckSize->value());
cfg.setScrollingCheckers(m_displaySettings->chkMoving->isChecked());
cfg.setCheckersColor1(m_displaySettings->colorChecks1->color().toQColor());
cfg.setCheckersColor2(m_displaySettings->colorChecks2->color().toQColor());
cfg.setCanvasBorderColor(m_displaySettings->canvasBorder->color().toQColor());
cfg.setHideScrollbars(m_displaySettings->hideScrollbars->isChecked());
KoColor c = m_displaySettings->btnSelectionOverlayColor->color();
c.setOpacity(m_displaySettings->sldSelectionOverlayOpacity->value());
cfgImage.setSelectionOverlayMaskColor(c.toQColor());
cfg.setAntialiasCurves(m_displaySettings->chkCurveAntialiasing->isChecked());
cfg.setAntialiasSelectionOutline(m_displaySettings->chkSelectionOutlineAntialiasing->isChecked());
cfg.setShowSingleChannelAsColor(m_displaySettings->chkChannelsAsColor->isChecked());
cfg.setHidePopups(m_displaySettings->chkHidePopups->isChecked());
cfg.setHideDockersFullscreen(m_fullscreenSettings->chkDockers->checkState());
cfg.setHideMenuFullscreen(m_fullscreenSettings->chkMenu->checkState());
cfg.setHideScrollbarsFullscreen(m_fullscreenSettings->chkScrollbars->checkState());
cfg.setHideStatusbarFullscreen(m_fullscreenSettings->chkStatusbar->checkState());
cfg.setHideTitlebarFullscreen(m_fullscreenSettings->chkTitlebar->checkState());
cfg.setHideToolbarFullscreen(m_fullscreenSettings->chkToolbar->checkState());
cfg.setCursorMainColor(m_general->cursorColorBtutton->color().toQColor());
cfg.setPixelGridColor(m_displaySettings->pixelGridColorButton->color().toQColor());
cfg.setPixelGridDrawingThreshold(m_displaySettings->pixelGridDrawingThresholdBox->value() / 100);
m_authorPage->apply();
cfg.logImportantSettings();
}
return !m_cancelClicked;
}
diff --git a/libs/ui/flake/kis_node_shape.cpp b/libs/ui/flake/kis_node_shape.cpp
index f7c599384a..f654c39854 100644
--- a/libs/ui/flake/kis_node_shape.cpp
+++ b/libs/ui/flake/kis_node_shape.cpp
@@ -1,152 +1,144 @@
/*
* Copyright (c) 2006 Boudewijn Rempt <boud@valdyas.org>
*
* 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_node_shape.h"
#include <KoCanvasBase.h>
#include <KoCanvasController.h>
#include <KoSelection.h>
#include <KoToolManager.h>
#include <kis_types.h>
#include <kis_layer.h>
#include <kis_node.h>
#include <KoSelectedShapesProxy.h>
#include "kis_shape_layer.h"
struct KisNodeShape::Private
{
public:
KisNodeSP node;
};
KisNodeShape::KisNodeShape(KisNodeSP node)
: KoShapeLayer()
, m_d(new Private())
{
m_d->node = node;
setShapeId(KIS_NODE_SHAPE_ID);
setSelectable(false);
connect(node, SIGNAL(sigNodeChangedInternal()), SLOT(editabilityChanged()));
editabilityChanged(); // Correctly set the lock at loading
}
KisNodeShape::~KisNodeShape()
{
if (KoToolManager::instance()) {
KoCanvasController *canvasController = KoToolManager::instance()->activeCanvasController();
// If we're the active layer, we should tell the active selection we're dead meat.
if (canvasController && canvasController->canvas()) {
KoSelection *activeSelection = canvasController->canvas()->selectedShapesProxy()->selection();
KoShapeLayer *activeLayer = activeSelection->activeLayer();
if (activeLayer == this){
activeSelection->setActiveLayer(0);
}
}
}
delete m_d;
}
KisNodeSP KisNodeShape::node()
{
return m_d->node;
}
bool KisNodeShape::checkIfDescendant(KoShapeLayer *activeLayer)
{
bool found(false);
KoShapeLayer *layer = activeLayer;
while(layer && !(found = layer == this)) {
layer = dynamic_cast<KoShapeLayer*>(layer->parent());
}
return found;
}
void KisNodeShape::editabilityChanged()
{
if (m_d->node->inherits("KisShapeLayer")) {
setGeometryProtected(!m_d->node->isEditable());
} else {
setGeometryProtected(false);
}
Q_FOREACH (KoShape *shape, this->shapes()) {
KisNodeShape *node = dynamic_cast<KisNodeShape*>(shape);
KIS_SAFE_ASSERT_RECOVER(node) { continue; }
if (node) {
node->editabilityChanged();
}
}
/**
* Editability of a child depends on the editablity
* of its parent. So when we change one's editability,
* we need to search for active children and reactivate them
*/
KoCanvasController *canvasController = KoToolManager::instance()->activeCanvasController();
if(canvasController && canvasController->canvas()) {
KoSelection *activeSelection = canvasController->canvas()->selectedShapesProxy()->selection();
KoShapeLayer *activeLayer = activeSelection->activeLayer();
KisShapeLayer *shapeLayer = dynamic_cast<KisShapeLayer*>(m_d->node.data());
if(activeLayer && (checkIfDescendant(activeLayer) || (shapeLayer && shapeLayer == activeLayer))) {
activeSelection->setActiveLayer(activeLayer);
}
}
}
QSizeF KisNodeShape::size() const
{
return boundingRect().size();
}
QRectF KisNodeShape::boundingRect() const
{
return QRectF();
}
void KisNodeShape::setPosition(const QPointF &)
{
}
void KisNodeShape::paint(QPainter &, KoShapePaintingContext &) const
{
}
-void KisNodeShape::saveOdf(KoShapeSavingContext &) const
-{
-}
-
-bool KisNodeShape::loadOdf(const KoXmlElement &, KoShapeLoadingContext &)
-{
- return false;
-}
diff --git a/libs/ui/flake/kis_node_shape.h b/libs/ui/flake/kis_node_shape.h
index dbe4b3e85d..05e598f57b 100644
--- a/libs/ui/flake/kis_node_shape.h
+++ b/libs/ui/flake/kis_node_shape.h
@@ -1,64 +1,62 @@
/*
* Copyright (c) 2006 Boudewijn Rempt <boud@valdyas.org>
*
* 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_NODE_SHAPE_H_
#define KIS_NODE_SHAPE_H_
#include <QObject>
#include <KoShapeLayer.h>
#include <kritaui_export.h>
#include <kis_types.h>
#define KIS_NODE_SHAPE_ID "KisNodeShape"
/**
* A KisNodeShape is a flake wrapper around Krita nodes. It is used
* for dealing with currently active node for tools.
*/
class KRITAUI_EXPORT KisNodeShape : public QObject, public KoShapeLayer
{
Q_OBJECT
public:
KisNodeShape(KisNodeSP node);
~KisNodeShape() override;
KisNodeSP node();
// Empty implementations as the node is not painted anywhere
QSizeF size() const override;
QRectF boundingRect() const override;
void setPosition(const QPointF &) override;
void paint(QPainter &painter, KoShapePaintingContext &paintcontext) const override;
- void saveOdf(KoShapeSavingContext & context) const override;
- bool loadOdf(const KoXmlElement & element, KoShapeLoadingContext &context) override;
private Q_SLOTS:
void editabilityChanged();
private:
bool checkIfDescendant(KoShapeLayer *activeLayer);
private:
struct Private;
Private * const m_d;
};
#endif
diff --git a/libs/ui/flake/kis_shape_controller.cpp b/libs/ui/flake/kis_shape_controller.cpp
index a399741b84..19ed55bab7 100644
--- a/libs/ui/flake/kis_shape_controller.cpp
+++ b/libs/ui/flake/kis_shape_controller.cpp
@@ -1,283 +1,267 @@
/*
* Copyright (c) 2007 Boudewijn Rempt <boud@valdyas.org>
*
* 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_shape_controller.h"
#include <klocalizedstring.h>
#include <KoShape.h>
#include <KoShapeContainer.h>
#include <KoShapeManager.h>
#include <KoCanvasBase.h>
#include <KoToolManager.h>
#include <KisView.h>
#include <KoSelection.h>
#include <KoShapeLayer.h>
#include <KoPathShape.h>
#include <KoColorSpaceConstants.h>
#include <KoCanvasController.h>
#include "kis_node_manager.h"
#include "kis_shape_selection.h"
#include "kis_selection.h"
#include "kis_selection_component.h"
#include "kis_adjustment_layer.h"
#include "kis_clone_layer.h"
#include "canvas/kis_canvas2.h"
#include "KisDocument.h"
#include "kis_image.h"
#include "kis_group_layer.h"
#include "kis_node_shape.h"
#include "kis_node_shapes_graph.h"
#include "kis_name_server.h"
#include "kis_mask.h"
#include "kis_shape_layer.h"
#include "KisViewManager.h"
#include "kis_node.h"
#include <KoDocumentResourceManager.h>
#include <KoDataCenterBase.h>
#include <commands/kis_image_layer_add_command.h>
#include <kis_undo_adapter.h>
#include "KoSelectedShapesProxy.h"
#include "kis_signal_auto_connection.h"
+#include "KoAddRemoveShapeCommands.h"
+
struct KisShapeController::Private
{
public:
KisDocument *doc;
KisNameServer *nameServer;
KisSignalAutoConnectionsStore imageConnections;
KisNodeShapesGraph shapesGraph;
};
KisShapeController::KisShapeController(KisDocument *doc, KisNameServer *nameServer)
: KisDummiesFacadeBase(doc)
, m_d(new Private())
{
m_d->doc = doc;
m_d->nameServer = nameServer;
resourceManager()->setUndoStack(doc->undoStack());
}
KisShapeController::~KisShapeController()
{
KisNodeDummy *node = m_d->shapesGraph.rootDummy();
if (node) {
m_d->shapesGraph.removeNode(node->node());
}
delete m_d;
}
void KisShapeController::slotUpdateDocumentResolution()
{
const qreal pixelsPerInch = m_d->doc->image()->xRes() * 72.0;
resourceManager()->setResource(KoDocumentResourceManager::DocumentResolution, pixelsPerInch);
}
void KisShapeController::slotUpdateDocumentSize()
{
resourceManager()->setResource(KoDocumentResourceManager::DocumentRectInPixels, m_d->doc->image()->bounds());
}
void KisShapeController::addNodeImpl(KisNodeSP node, KisNodeSP parent, KisNodeSP aboveThis)
{
KisNodeShape *newShape =
m_d->shapesGraph.addNode(node, parent, aboveThis);
// XXX: what are we going to do with this shape?
Q_UNUSED(newShape);
KisShapeLayer *shapeLayer = dynamic_cast<KisShapeLayer*>(node.data());
if (shapeLayer) {
/**
* Forward signals for global shape manager
* \see comment in the constructor of KisCanvas2
*/
connect(shapeLayer, SIGNAL(selectionChanged()),
SIGNAL(selectionChanged()));
connect(shapeLayer->shapeManager(), SIGNAL(selectionContentChanged()),
SIGNAL(selectionContentChanged()));
connect(shapeLayer, SIGNAL(currentLayerChanged(const KoShapeLayer*)),
SIGNAL(currentLayerChanged(const KoShapeLayer*)));
}
}
void KisShapeController::removeNodeImpl(KisNodeSP node)
{
KisShapeLayer *shapeLayer = dynamic_cast<KisShapeLayer*>(node.data());
if (shapeLayer) {
shapeLayer->disconnect(this);
}
m_d->shapesGraph.removeNode(node);
}
bool KisShapeController::hasDummyForNode(KisNodeSP node) const
{
return m_d->shapesGraph.containsNode(node);
}
KisNodeDummy* KisShapeController::dummyForNode(KisNodeSP node) const
{
return m_d->shapesGraph.nodeToDummy(node);
}
KisNodeDummy* KisShapeController::rootDummy() const
{
return m_d->shapesGraph.rootDummy();
}
int KisShapeController::dummiesCount() const
{
return m_d->shapesGraph.shapesCount();
}
-
static inline bool belongsToShapeSelection(KoShape* shape) {
return dynamic_cast<KisShapeSelectionMarker*>(shape->userData());
}
-void KisShapeController::addShapes(const QList<KoShape*> shapes)
+KoShapeContainer *KisShapeController::createParentForShapes(const QList<KoShape *> shapes, KUndo2Command *parentCommand)
{
- KIS_SAFE_ASSERT_RECOVER_RETURN(!shapes.isEmpty());
+ KoShapeContainer *resultParent = 0;
+ KisCommandUtils::CompositeCommand *resultCommand =
+ new KisCommandUtils::CompositeCommand(parentCommand);
+
+ KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!shapes.isEmpty(), resultParent);
+ Q_FOREACH (KoShape *shape, shapes) {
+ KIS_SAFE_ASSERT_RECOVER_BREAK(!shape->parent());
+ }
KisCanvas2 *canvas = dynamic_cast<KisCanvas2*>(KoToolManager::instance()->activeCanvasController()->canvas());
- KIS_SAFE_ASSERT_RECOVER_RETURN(canvas);
+ KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(canvas, resultParent);
- const KoShape *baseShapeParent = shapes.first()->parent();
const bool baseBelongsToSelection = belongsToShapeSelection(shapes.first());
- bool allSameParent = true;
bool allSameBelongsToShapeSelection = true;
- bool hasNullParent = false;
Q_FOREACH (KoShape *shape, shapes) {
- hasNullParent |= !shape->parent();
- allSameParent &= shape->parent() == baseShapeParent;
allSameBelongsToShapeSelection &= belongsToShapeSelection(shape) == baseBelongsToSelection;
}
- KIS_SAFE_ASSERT_RECOVER_RETURN(!baseBelongsToSelection || allSameBelongsToShapeSelection);
+ KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!baseBelongsToSelection || allSameBelongsToShapeSelection, resultParent);
- if (!allSameParent || hasNullParent) {
- if (baseBelongsToSelection && allSameBelongsToShapeSelection) {
- KisSelectionSP selection = canvas->viewManager()->selection();
- if (selection) {
- if (!selection->shapeSelection()) {
- selection->setShapeSelection(new KisShapeSelection(this, image(), selection));
- }
- KisShapeSelection * shapeSelection = static_cast<KisShapeSelection*>(selection->shapeSelection());
+ if (baseBelongsToSelection && allSameBelongsToShapeSelection) {
+ KisSelectionSP selection = canvas->viewManager()->selection();
+ if (selection) {
+ KisSelectionComponent* shapeSelectionComponent = selection->shapeSelection();
- Q_FOREACH(KoShape *shape, shapes) {
- shapeSelection->addShape(shape);
- }
+ if (!shapeSelectionComponent) {
+ shapeSelectionComponent = new KisShapeSelection(this, image(), selection);
+ resultCommand->addCommand(selection->convertToVectorSelection(shapeSelectionComponent));
}
- } else {
- KisShapeLayer *shapeLayer =
+
+ KisShapeSelection * shapeSelection = static_cast<KisShapeSelection*>(shapeSelectionComponent);
+ resultParent = shapeSelection;
+ }
+ } else {
+ KisShapeLayer *shapeLayer =
dynamic_cast<KisShapeLayer*>(
canvas->selectedShapesProxy()->selection()->activeLayer());
- if (!shapeLayer) {
- shapeLayer = new KisShapeLayer(this, image(),
- i18n("Vector Layer %1", m_d->nameServer->number()),
- OPACITY_OPAQUE_U8);
+ if (!shapeLayer) {
+ shapeLayer = new KisShapeLayer(this, image(),
+ i18n("Vector Layer %1", m_d->nameServer->number()),
+ OPACITY_OPAQUE_U8);
- image()->undoAdapter()->addCommand(new KisImageLayerAddCommand(image(), shapeLayer, image()->rootLayer(), image()->rootLayer()->childCount()));
- }
-
- Q_FOREACH(KoShape *shape, shapes) {
- shapeLayer->addShape(shape);
- }
+ resultCommand->addCommand(
+ new KisImageLayerAddCommand(image(),
+ shapeLayer,
+ image()->rootLayer(),
+ image()->rootLayer()->childCount()));
}
- }
-
- m_d->doc->setModified(true);
-}
-
-void KisShapeController::removeShape(KoShape* shape)
-{
- /**
- * Krita layers have their own destruction path.
- * It goes through slotRemoveNode()
- */
- Q_ASSERT(shape->shapeId() != KIS_NODE_SHAPE_ID &&
- shape->shapeId() != KIS_SHAPE_LAYER_ID);
+ resultParent = shapeLayer;
+ }
- QRectF updateRect = shape->boundingRect();
- shape->setParent(0);
-
- KisCanvas2 *canvas = dynamic_cast<KisCanvas2*>(KoToolManager::instance()->activeCanvasController()->canvas());
- KIS_SAFE_ASSERT_RECOVER_RETURN(canvas);
- canvas->shapeManager()->update(updateRect);
-
- m_d->doc->setModified(true);
+ return resultParent;
}
QRectF KisShapeController::documentRectInPixels() const
{
return m_d->doc->image()->bounds();
}
qreal KisShapeController::pixelsPerInch() const
{
return m_d->doc->image()->xRes() * 72.0;
}
void KisShapeController::setInitialShapeForCanvas(KisCanvas2 *canvas)
{
if (!image()) return;
KisNodeSP rootNode = image()->root();
if (m_d->shapesGraph.containsNode(rootNode)) {
Q_ASSERT(canvas);
Q_ASSERT(canvas->shapeManager());
KoSelection *selection = canvas->shapeManager()->selection();
if (selection && m_d->shapesGraph.nodeToShape(rootNode)) {
selection->select(m_d->shapesGraph.nodeToShape(rootNode));
KoToolManager::instance()->switchToolRequested(KoToolManager::instance()->preferredToolForSelection(selection->selectedShapes()));
}
}
}
void KisShapeController::setImage(KisImageWSP image)
{
m_d->imageConnections.clear();
if (image) {
m_d->imageConnections.addConnection(image, SIGNAL(sigResolutionChanged(double, double)), this, SLOT(slotUpdateDocumentResolution()));
m_d->imageConnections.addConnection(image, SIGNAL(sigSizeChanged(QPointF, QPointF)), this, SLOT(slotUpdateDocumentSize()));
}
slotUpdateDocumentResolution();
slotUpdateDocumentSize();
KisDummiesFacadeBase::setImage(image);
}
KoShapeLayer* KisShapeController::shapeForNode(KisNodeSP node) const
{
if (node) {
return m_d->shapesGraph.nodeToShape(node);
}
return 0;
}
diff --git a/libs/ui/flake/kis_shape_controller.h b/libs/ui/flake/kis_shape_controller.h
index 296f714fa2..6c3c4ca388 100644
--- a/libs/ui/flake/kis_shape_controller.h
+++ b/libs/ui/flake/kis_shape_controller.h
@@ -1,93 +1,92 @@
/*
* Copyright (c) 2007 Boudewijn Rempt <boud@valdyas.org>
*
* 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_SHAPE_CONTROLLER
#define KIS_SHAPE_CONTROLLER
#include <QMap>
#include "kis_dummies_facade_base.h"
#include <KoShapeControllerBase.h>
class KisNodeDummy;
class KoShapeLayer;
class KisCanvas2;
class KisDocument;
class KisNameServer;
/**
* KisShapeController keeps track of new layers, shapes, masks and
* selections -- everything that needs to be wrapped as a shape for
* the tools to work on.
*/
class KRITAUI_EXPORT KisShapeController : public KisDummiesFacadeBase, public KoShapeControllerBase
{
Q_OBJECT
public:
KisShapeController(KisDocument *doc, KisNameServer *nameServer);
~KisShapeController() override;
bool hasDummyForNode(KisNodeSP node) const override;
KisNodeDummy* dummyForNode(KisNodeSP layer) const override;
KisNodeDummy* rootDummy() const override;
int dummiesCount() const override;
KoShapeLayer* shapeForNode(KisNodeSP layer) const;
void setInitialShapeForCanvas(KisCanvas2 *canvas);
void setImage(KisImageWSP image) override;
private:
void addNodeImpl(KisNodeSP node, KisNodeSP parent, KisNodeSP aboveThis) override;
void removeNodeImpl(KisNodeSP node) override;
private Q_SLOTS:
void slotUpdateDocumentResolution();
void slotUpdateDocumentSize();
Q_SIGNALS:
/**
* These three signals are forwarded from the local shape manager of
* KisShapeLayer. This is done because we switch KoShapeManager and
* therefore KoSelection in KisCanvas2, so we need to connect local
* managers to the UI as well.
*
* \see comment in the constructor of KisCanvas2
*/
void selectionChanged();
void selectionContentChanged();
void currentLayerChanged(const KoShapeLayer*);
public:
- void addShapes(const QList<KoShape*> shapes) override;
- void removeShape(KoShape* shape) override;
+ KoShapeContainer* createParentForShapes(const QList<KoShape*> shapes, KUndo2Command *parentCommand) override;
QRectF documentRectInPixels() const override;
qreal pixelsPerInch() const override;
private:
struct Private;
Private * const m_d;
};
#endif
diff --git a/libs/ui/flake/kis_shape_layer.cc b/libs/ui/flake/kis_shape_layer.cc
index 96eecb96cd..7c74e3977d 100644
--- a/libs/ui/flake/kis_shape_layer.cc
+++ b/libs/ui/flake/kis_shape_layer.cc
@@ -1,768 +1,682 @@
/*
* Copyright (c) 2006-2008 Boudewijn Rempt <boud@valdyas.org>
* Copyright (c) 2007 Thomas Zander <zander@kde.org>
* Copyright (c) 2009 Cyrille Berger <cberger@cberger.net>
* Copyright (c) 2011 Jan Hambrecht <jaham@gmx.net>
*
* 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_shape_layer.h"
#include <QPainter>
#include <QPainterPath>
#include <QRect>
#include <QDomElement>
#include <QDomDocument>
#include <QString>
#include <QList>
#include <QMap>
#include <kis_debug.h>
#include <kundo2command.h>
#include <commands_new/kis_node_move_command2.h>
#include <QMimeData>
#include <kis_icon.h>
#include <KoColorSpace.h>
#include <KoCompositeOp.h>
#include <KisDocument.h>
#include <KoUnit.h>
-#include <KoOdf.h>
-#include <KoOdfReadStore.h>
-#include <KoOdfStylesReader.h>
-#include <KoOdfLoadingContext.h>
-#include <KoPageLayout.h>
#include <KoShapeContainer.h>
#include <KoShapeLayer.h>
#include <KoShapeGroup.h>
#include <KoShapeLoadingContext.h>
#include <KoShapeManager.h>
#include <KoSelectedShapesProxy.h>
#include <KoShapeRegistry.h>
#include <KoShapeSavingContext.h>
#include <KoStore.h>
#include <KoShapeControllerBase.h>
#include <KoStoreDevice.h>
#include <KoViewConverter.h>
#include <KoXmlNS.h>
#include <KoXmlReader.h>
#include <KoXmlWriter.h>
#include <KoSelection.h>
#include <KoShapeMoveCommand.h>
#include <KoShapeTransformCommand.h>
#include <KoShapeShadow.h>
#include <KoShapeShadowCommand.h>
#include "SvgWriter.h"
#include "SvgParser.h"
#include <kis_types.h>
#include <kis_image.h>
#include "kis_default_bounds.h"
#include <kis_paint_device.h>
#include "kis_shape_layer_canvas.h"
#include "kis_image_view_converter.h"
#include <kis_painter.h>
#include "kis_node_visitor.h"
#include "kis_processing_visitor.h"
#include "kis_effect_mask.h"
#include "commands/KoShapeReorderCommand.h"
#include "kis_do_something_command.h"
#include <KisSafeBlockingQueueConnectionProxy.h>
#include <QThread>
#include <QApplication>
#include <SimpleShapeContainerModel.h>
class ShapeLayerContainerModel : public SimpleShapeContainerModel
{
public:
ShapeLayerContainerModel(KisShapeLayer *parent)
: q(parent)
-{}
+ {
+ }
void add(KoShape *child) override {
SimpleShapeContainerModel::add(child);
/**
* The shape is always added with the absolute transformation set appropriately.
* Here we should just squeeze it into the layer's transformation.
*/
KIS_SAFE_ASSERT_RECOVER_NOOP(inheritsTransform(child));
if (inheritsTransform(child)) {
QTransform parentTransform = q->absoluteTransformation();
child->applyAbsoluteTransformation(parentTransform.inverted());
}
}
void remove(KoShape *child) override {
KIS_SAFE_ASSERT_RECOVER_NOOP(inheritsTransform(child));
if (inheritsTransform(child)) {
QTransform parentTransform = q->absoluteTransformation();
child->applyAbsoluteTransformation(parentTransform);
}
SimpleShapeContainerModel::remove(child);
}
- void shapeHasBeenAddedToHierarchy(KoShape *shape, KoShapeContainer *addedToSubtree) override {
- q->shapeManager()->addShape(shape);
- SimpleShapeContainerModel::shapeHasBeenAddedToHierarchy(shape, addedToSubtree);
- }
-
- void shapeToBeRemovedFromHierarchy(KoShape *shape, KoShapeContainer *removedFromSubtree) override {
- q->shapeManager()->remove(shape);
- SimpleShapeContainerModel::shapeToBeRemovedFromHierarchy(shape, removedFromSubtree);
- }
-
private:
KisShapeLayer *q;
};
struct KisShapeLayer::Private
{
public:
Private()
: canvas(0)
, controller(0)
, x(0)
, y(0)
{}
KisPaintDeviceSP paintDevice;
KisShapeLayerCanvasBase * canvas;
KoShapeControllerBase* controller;
int x;
int y;
};
KisShapeLayer::KisShapeLayer(KoShapeControllerBase* controller,
KisImageWSP image,
const QString &name,
quint8 opacity)
: KisExternalLayer(image, name, opacity),
KoShapeLayer(new ShapeLayerContainerModel(this)),
m_d(new Private())
{
initShapeLayer(controller);
}
KisShapeLayer::KisShapeLayer(const KisShapeLayer& rhs)
: KisShapeLayer(rhs, rhs.m_d->controller)
{
}
KisShapeLayer::KisShapeLayer(const KisShapeLayer& _rhs, KoShapeControllerBase* controller, KisShapeLayerCanvasBase *canvas)
: KisExternalLayer(_rhs)
, KoShapeLayer(new ShapeLayerContainerModel(this)) //no _rhs here otherwise both layer have the same KoShapeContainerModel
, m_d(new Private())
{
// copy the projection to avoid extra round of updates!
initShapeLayer(controller, _rhs.m_d->paintDevice, canvas);
/**
* The transformaitons of the added shapes are automatically merged into the transformation
* of the layer, so we should apply this extra transform separately
*/
const QTransform thisInvertedTransform = this->absoluteTransformation().inverted();
m_d->canvas->shapeManager()->setUpdatesBlocked(true);
Q_FOREACH (KoShape *shape, _rhs.shapes()) {
KoShape *clonedShape = shape->cloneShape();
KIS_SAFE_ASSERT_RECOVER(clonedShape) { continue; }
clonedShape->setTransformation(shape->absoluteTransformation() * thisInvertedTransform);
addShape(clonedShape);
}
m_d->canvas->shapeManager()->setUpdatesBlocked(false);
}
KisShapeLayer::KisShapeLayer(const KisShapeLayer& _rhs, const KisShapeLayer &_addShapes)
: KisExternalLayer(_rhs)
, KoShapeLayer(new ShapeLayerContainerModel(this)) //no _merge here otherwise both layer have the same KoShapeContainerModel
, m_d(new Private())
{
// Make sure our new layer is visible otherwise the shapes cannot be painted.
setVisible(true);
initShapeLayer(_rhs.m_d->controller);
/**
* With current implementation this matrix will always be an identity, because
* we do not copy the transformation from any of the source layers. But we should
* handle this anyway, to not be caught by this in the future.
*/
const QTransform thisInvertedTransform = this->absoluteTransformation().inverted();
QList<KoShape *> shapesAbove;
QList<KoShape *> shapesBelow;
// copy in _rhs's shapes
Q_FOREACH (KoShape *shape, _rhs.shapes()) {
KoShape *clonedShape = shape->cloneShape();
KIS_SAFE_ASSERT_RECOVER(clonedShape) { continue; }
clonedShape->setTransformation(shape->absoluteTransformation() * thisInvertedTransform);
shapesBelow.append(clonedShape);
}
// copy in _addShapes's shapes
Q_FOREACH (KoShape *shape, _addShapes.shapes()) {
KoShape *clonedShape = shape->cloneShape();
KIS_SAFE_ASSERT_RECOVER(clonedShape) { continue; }
clonedShape->setTransformation(shape->absoluteTransformation() * thisInvertedTransform);
shapesAbove.append(clonedShape);
}
QList<KoShapeReorderCommand::IndexedShape> shapes =
KoShapeReorderCommand::mergeDownShapes(shapesBelow, shapesAbove);
KoShapeReorderCommand cmd(shapes);
cmd.redo();
Q_FOREACH (KoShape *shape, shapesBelow + shapesAbove) {
addShape(shape);
}
}
KisShapeLayer::KisShapeLayer(KoShapeControllerBase* controller,
KisImageWSP image,
const QString &name,
quint8 opacity,
KisShapeLayerCanvasBase *canvas)
: KisExternalLayer(image, name, opacity)
, KoShapeLayer(new ShapeLayerContainerModel(this))
, m_d(new Private())
{
initShapeLayer(controller, nullptr, canvas);
}
KisShapeLayer::~KisShapeLayer()
{
/**
* Small hack alert: we should avoid updates on shape deletion
*/
m_d->canvas->prepareForDestroying();
Q_FOREACH (KoShape *shape, shapes()) {
shape->setParent(0);
delete shape;
}
delete m_d->canvas;
delete m_d;
}
void KisShapeLayer::initShapeLayer(KoShapeControllerBase* controller, KisPaintDeviceSP copyFromProjection, KisShapeLayerCanvasBase *canvas)
{
setSupportsLodMoves(false);
setShapeId(KIS_SHAPE_LAYER_ID);
KIS_ASSERT_RECOVER_NOOP(this->image());
if (!copyFromProjection) {
m_d->paintDevice = new KisPaintDevice(image()->colorSpace());
m_d->paintDevice->setDefaultBounds(new KisDefaultBounds(this->image()));
m_d->paintDevice->setParentNode(this);
} else {
m_d->paintDevice = new KisPaintDevice(*copyFromProjection);
}
if (!canvas) {
auto *slCanvas = new KisShapeLayerCanvas(this, image());
slCanvas->setProjection(m_d->paintDevice);
canvas = slCanvas;
}
m_d->canvas = canvas;
m_d->canvas->moveToThread(this->thread());
m_d->controller = controller;
m_d->canvas->shapeManager()->selection()->disconnect(this);
connect(m_d->canvas->selectedShapesProxy(), SIGNAL(selectionChanged()), this, SIGNAL(selectionChanged()));
connect(m_d->canvas->selectedShapesProxy(), SIGNAL(currentLayerChanged(const KoShapeLayer*)),
this, SIGNAL(currentLayerChanged(const KoShapeLayer*)));
connect(this, SIGNAL(sigMoveShapes(QPointF)), SLOT(slotMoveShapes(QPointF)));
+
+ ShapeLayerContainerModel *model = dynamic_cast<ShapeLayerContainerModel*>(this->model());
+ KIS_SAFE_ASSERT_RECOVER_RETURN(model);
+ model->setAssociatedRootShapeManager(m_d->canvas->shapeManager());
}
bool KisShapeLayer::allowAsChild(KisNodeSP node) const
{
return node->inherits("KisMask");
}
void KisShapeLayer::setImage(KisImageWSP _image)
{
KisLayer::setImage(_image);
m_d->canvas->setImage(_image);
m_d->paintDevice->convertTo(_image->colorSpace());
m_d->paintDevice->setDefaultBounds(new KisDefaultBounds(_image));
}
KisLayerSP KisShapeLayer::createMergedLayerTemplate(KisLayerSP prevLayer)
{
KisShapeLayer *prevShape = dynamic_cast<KisShapeLayer*>(prevLayer.data());
if (prevShape)
return new KisShapeLayer(*prevShape, *this);
else
return KisExternalLayer::createMergedLayerTemplate(prevLayer);
}
void KisShapeLayer::fillMergedLayerTemplate(KisLayerSP dstLayer, KisLayerSP prevLayer)
{
if (!dynamic_cast<KisShapeLayer*>(dstLayer.data())) {
KisLayer::fillMergedLayerTemplate(dstLayer, prevLayer);
}
}
void KisShapeLayer::setParent(KoShapeContainer *parent)
{
Q_UNUSED(parent)
KIS_ASSERT_RECOVER_RETURN(0);
}
QIcon KisShapeLayer::icon() const
{
return KisIconUtils::loadIcon("vectorLayer");
}
KisPaintDeviceSP KisShapeLayer::original() const
{
return m_d->paintDevice;
}
KisPaintDeviceSP KisShapeLayer::paintDevice() const
{
return 0;
}
qint32 KisShapeLayer::x() const
{
return m_d->x;
}
qint32 KisShapeLayer::y() const
{
return m_d->y;
}
void KisShapeLayer::setX(qint32 x)
{
qint32 delta = x - this->x();
QPointF diff = QPointF(m_d->canvas->viewConverter()->viewToDocumentX(delta), 0);
emit sigMoveShapes(diff);
// Save new value to satisfy LSP
m_d->x = x;
}
void KisShapeLayer::setY(qint32 y)
{
qint32 delta = y - this->y();
QPointF diff = QPointF(0, m_d->canvas->viewConverter()->viewToDocumentY(delta));
emit sigMoveShapes(diff);
// Save new value to satisfy LSP
m_d->y = y;
}
namespace {
void filterTransformableShapes(QList<KoShape*> &shapes)
{
auto it = shapes.begin();
while (it != shapes.end()) {
if (shapes.size() == 1) break;
if ((*it)->inheritsTransformFromAny(shapes)) {
it = shapes.erase(it);
} else {
++it;
}
}
}
}
QList<KoShape *> KisShapeLayer::shapesToBeTransformed()
{
QList<KoShape*> shapes = shapeManager()->shapes();
// We expect that **all** the shapes inherit the transform from its parent
// SANITY_CHECK: we expect all the shapes inside the
// shape layer to inherit transform!
Q_FOREACH (KoShape *shape, shapes) {
if (shape->parent()) {
KIS_SAFE_ASSERT_RECOVER(shape->parent()->inheritsTransform(shape)) {
break;
}
}
}
shapes << this;
filterTransformableShapes(shapes);
return shapes;
}
void KisShapeLayer::slotMoveShapes(const QPointF &diff)
{
QList<KoShape*> shapes = shapesToBeTransformed();
if (shapes.isEmpty()) return;
KoShapeMoveCommand cmd(shapes, diff);
cmd.redo();
}
void KisShapeLayer::slotTransformShapes(const QTransform &newTransform)
{
KoShapeTransformCommand cmd({this}, {transformation()}, {newTransform});
cmd.redo();
}
bool KisShapeLayer::accept(KisNodeVisitor& visitor)
{
return visitor.visit(this);
}
void KisShapeLayer::accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter)
{
return visitor.visit(this, undoAdapter);
}
KoShapeManager* KisShapeLayer::shapeManager() const
{
return m_d->canvas->shapeManager();
}
KoViewConverter* KisShapeLayer::converter() const
{
return m_d->canvas->viewConverter();
}
bool KisShapeLayer::visible(bool recursive) const
{
return KisExternalLayer::visible(recursive);
}
void KisShapeLayer::setVisible(bool visible, bool isLoading)
{
const bool oldVisible = this->visible(false);
KoShapeLayer::setVisible(visible);
KisExternalLayer::setVisible(visible, isLoading);
if (visible && !oldVisible &&
m_d->canvas->hasChangedWhileBeingInvisible()) {
m_d->canvas->rerenderAfterBeingInvisible();
}
}
void KisShapeLayer::setUserLocked(bool value)
{
KoShapeLayer::setGeometryProtected(value);
KisExternalLayer::setUserLocked(value);
}
bool KisShapeLayer::isShapeEditable(bool recursive) const
{
return KoShapeLayer::isShapeEditable(recursive) && isEditable(true);
}
// we do not override KoShape::setGeometryProtected() as we consider
// the user not being able to access the layer shape from Krita UI!
void KisShapeLayer::forceUpdateTimedNode()
{
m_d->canvas->forceRepaint();
}
bool KisShapeLayer::hasPendingTimedUpdates() const
{
return m_d->canvas->hasPendingUpdates();
}
void KisShapeLayer::forceUpdateHiddenAreaOnOriginal()
{
m_d->canvas->forceRepaintWithHiddenAreas();
}
bool KisShapeLayer::saveShapesToStore(KoStore *store, QList<KoShape *> shapes, const QSizeF &sizeInPt)
{
if (!store->open("content.svg")) {
return false;
}
KoStoreDevice storeDev(store);
storeDev.open(QIODevice::WriteOnly);
std::sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
SvgWriter writer(shapes);
writer.save(storeDev, sizeInPt);
if (!store->close()) {
return false;
}
return true;
}
QList<KoShape *> KisShapeLayer::createShapesFromSvg(QIODevice *device, const QString &baseXmlDir, const QRectF &rectInPixels, qreal resolutionPPI, KoDocumentResourceManager *resourceManager, QSizeF *fragmentSize)
{
QString errorMsg;
int errorLine = 0;
int errorColumn;
KoXmlDocument doc = SvgParser::createDocumentFromSvg(device, &errorMsg, &errorLine, &errorColumn);
if (doc.isNull()) {
errKrita << "Parsing error in " << "contents.svg" << "! Aborting!" << endl
<< " In line: " << errorLine << ", column: " << errorColumn << endl
<< " Error message: " << errorMsg << endl;
errKrita << i18n("Parsing error in the main document at line %1, column %2\nError message: %3"
, errorLine , errorColumn , errorMsg);
}
SvgParser parser(resourceManager);
parser.setXmlBaseDir(baseXmlDir);
parser.setResolution(rectInPixels /* px */, resolutionPPI /* ppi */);
return parser.parseSvg(doc.documentElement(), fragmentSize);
}
bool KisShapeLayer::saveLayer(KoStore * store) const
{
// FIXME: we handle xRes() only!
const QSizeF sizeInPx = image()->bounds().size();
const QSizeF sizeInPt(sizeInPx.width() / image()->xRes(), sizeInPx.height() / image()->yRes());
return saveShapesToStore(store, this->shapes(), sizeInPt);
}
bool KisShapeLayer::loadSvg(QIODevice *device, const QString &baseXmlDir)
{
QSizeF fragmentSize; // unused!
KisImageSP image = this->image();
// FIXME: we handle xRes() only!
KIS_SAFE_ASSERT_RECOVER_NOOP(qFuzzyCompare(image->xRes(), image->yRes()));
const qreal resolutionPPI = 72.0 * image->xRes();
QList<KoShape*> shapes =
createShapesFromSvg(device, baseXmlDir,
image->bounds(), resolutionPPI,
m_d->controller->resourceManager(),
&fragmentSize);
Q_FOREACH (KoShape *shape, shapes) {
addShape(shape);
}
return true;
}
bool KisShapeLayer::loadLayer(KoStore* store)
{
if (!store) {
warnKrita << i18n("No store backend");
return false;
}
if (store->open("content.svg")) {
KoStoreDevice storeDev(store);
storeDev.open(QIODevice::ReadOnly);
loadSvg(&storeDev, "");
store->close();
return true;
}
- KoOdfReadStore odfStore(store);
- QString errorMessage;
-
- odfStore.loadAndParse(errorMessage);
-
- if (!errorMessage.isEmpty()) {
- warnKrita << errorMessage;
- return false;
- }
-
- KoXmlElement contents = odfStore.contentDoc().documentElement();
-
- // dbgKrita <<"Start loading OASIS document..." << contents.text();
- // dbgKrita <<"Start loading OASIS contents..." << contents.lastChild().localName();
- // dbgKrita <<"Start loading OASIS contents..." << contents.lastChild().namespaceURI();
- // dbgKrita <<"Start loading OASIS contents..." << contents.lastChild().isElement();
-
- KoXmlElement body(KoXml::namedItemNS(contents, KoXmlNS::office, "body"));
-
- if (body.isNull()) {
- //setErrorMessage( i18n( "Invalid OASIS document. No office:body tag found." ) );
- return false;
- }
-
- body = KoXml::namedItemNS(body, KoXmlNS::office, "drawing");
- if (body.isNull()) {
- //setErrorMessage( i18n( "Invalid OASIS document. No office:drawing tag found." ) );
- return false;
- }
-
- KoXmlElement page(KoXml::namedItemNS(body, KoXmlNS::draw, "page"));
- if (page.isNull()) {
- //setErrorMessage( i18n( "Invalid OASIS document. No draw:page tag found." ) );
- return false;
- }
-
- KoXmlElement * master = 0;
- if (odfStore.styles().masterPages().contains("Standard"))
- master = odfStore.styles().masterPages().value("Standard");
- else if (odfStore.styles().masterPages().contains("Default"))
- master = odfStore.styles().masterPages().value("Default");
- else if (! odfStore.styles().masterPages().empty())
- master = odfStore.styles().masterPages().begin().value();
-
- if (master) {
- const KoXmlElement *style = odfStore.styles().findStyle(
- master->attributeNS(KoXmlNS::style, "page-layout-name", QString()));
- KoPageLayout pageLayout;
- pageLayout.loadOdf(*style);
- setSize(QSizeF(pageLayout.width, pageLayout.height));
- }
- // We work fine without a master page
-
- KoOdfLoadingContext context(odfStore.styles(), odfStore.store());
- context.setManifestFile(QString("tar:/") + odfStore.store()->currentPath() + "META-INF/manifest.xml");
- KoShapeLoadingContext shapeContext(context, m_d->controller->resourceManager());
-
-
- KoXmlElement layerElement;
- forEachElement(layerElement, context.stylesReader().layerSet()) {
- // FIXME: investigate what is this
- // KoShapeLayer * l = new KoShapeLayer();
- if (!loadOdf(layerElement, shapeContext)) {
- dbgKrita << "Could not load vector layer!";
- return false;
- }
- }
-
- KoXmlElement child;
- forEachElement(child, page) {
- KoShape * shape = KoShapeRegistry::instance()->createShapeFromOdf(child, shapeContext);
- if (shape) {
- addShape(shape);
- }
- }
-
- return true;
+ return false;
}
void KisShapeLayer::resetCache()
{
m_d->canvas->resetCache();
}
KUndo2Command* KisShapeLayer::crop(const QRect & rect)
{
QPoint oldPos(x(), y());
QPoint newPos = oldPos - rect.topLeft();
return new KisNodeMoveCommand2(this, oldPos, newPos);
}
class TransformShapeLayerDeferred : public KUndo2Command
{
public:
TransformShapeLayerDeferred(KisShapeLayer *shapeLayer, const QTransform &globalDocTransform)
: m_shapeLayer(shapeLayer),
m_globalDocTransform(globalDocTransform),
m_blockingConnection(std::bind(&KisShapeLayer::slotTransformShapes, shapeLayer, std::placeholders::_1))
{
}
void undo()
{
KIS_SAFE_ASSERT_RECOVER_NOOP(QThread::currentThread() != qApp->thread());
m_blockingConnection.start(m_savedTransform);
}
void redo()
{
m_savedTransform = m_shapeLayer->transformation();
const QTransform globalTransform = m_shapeLayer->absoluteTransformation();
const QTransform localTransform = globalTransform * m_globalDocTransform * globalTransform.inverted();
KIS_SAFE_ASSERT_RECOVER_NOOP(QThread::currentThread() != qApp->thread());
m_blockingConnection.start(localTransform * m_savedTransform);
}
private:
KisShapeLayer *m_shapeLayer;
QTransform m_globalDocTransform;
QTransform m_savedTransform;
KisSafeBlockingQueueConnectionProxy<QTransform> m_blockingConnection;
};
KUndo2Command* KisShapeLayer::transform(const QTransform &transform)
{
QList<KoShape*> shapes = shapesToBeTransformed();
if (shapes.isEmpty()) return 0;
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(shapes.size() == 1 && shapes.first() == this, 0);
/**
* We cannot transform shapes in the worker thread. Therefor we emit blocking-queued
* signal to transform them in the GUI thread and then return.
*/
KisImageViewConverter *converter = dynamic_cast<KisImageViewConverter*>(this->converter());
QTransform docSpaceTransform = converter->documentToView() *
transform * converter->viewToDocument();
return new TransformShapeLayerDeferred(this, docSpaceTransform);
}
KUndo2Command *KisShapeLayer::setProfile(const KoColorProfile *profile)
{
using namespace KisDoSomethingCommandOps;
KUndo2Command *cmd = new KUndo2Command();
new KisDoSomethingCommand<ResetOp, KisShapeLayer*>(this, false, cmd);
m_d->paintDevice->setProfile(profile, cmd);
new KisDoSomethingCommand<ResetOp, KisShapeLayer*>(this, true, cmd);
return cmd;
}
KUndo2Command *KisShapeLayer::convertTo(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
{
using namespace KisDoSomethingCommandOps;
KUndo2Command *cmd = new KUndo2Command();
new KisDoSomethingCommand<ResetOp, KisShapeLayer*>(this, false, cmd);
m_d->paintDevice->convertTo(dstColorSpace, renderingIntent, conversionFlags, cmd);
new KisDoSomethingCommand<ResetOp, KisShapeLayer*>(this, true, cmd);
return cmd;
}
KoShapeControllerBase *KisShapeLayer::shapeController() const
{
return m_d->controller;
}
diff --git a/libs/ui/flake/kis_shape_selection.cpp b/libs/ui/flake/kis_shape_selection.cpp
index 7cb79803f0..633c79c793 100644
--- a/libs/ui/flake/kis_shape_selection.cpp
+++ b/libs/ui/flake/kis_shape_selection.cpp
@@ -1,423 +1,337 @@
/*
* Copyright (c) 2010 Sven Langkamp <sven.langkamp@gmail.com>
* Copyright (c) 2011 Jan Hambrecht <jaham@gmx.net>
*
* 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_shape_selection.h"
#include <QPainter>
#include <QTimer>
#include <kundo2command.h>
#include <QMimeData>
#include <QApplication>
#include <QThread>
#include <KoShapeStroke.h>
#include <KoPathShape.h>
#include <KoShapeGroup.h>
#include <KoCompositeOp.h>
#include <KoShapeManager.h>
#include <KisDocument.h>
-#include <KoEmbeddedDocumentSaver.h>
-#include <KoGenStyles.h>
-#include <KoOdfLoadingContext.h>
-#include <KoOdfReadStore.h>
-#include <KoOdfStylesReader.h>
-#include <KoOdfWriteStore.h>
#include <KoXmlNS.h>
#include <KoShapeRegistry.h>
#include <KoShapeLoadingContext.h>
#include <KoXmlWriter.h>
#include <KoStore.h>
#include <KoShapeController.h>
#include <KoShapeSavingContext.h>
#include <KoStoreDevice.h>
#include <KoShapeTransformCommand.h>
-#include <KoElementReference.h>
#include <kis_painter.h>
#include <kis_paint_device.h>
#include <kis_image.h>
#include <kis_iterator_ng.h>
#include <kis_selection.h>
#include "kis_shape_selection_model.h"
#include "kis_shape_selection_canvas.h"
#include "kis_take_all_shapes_command.h"
#include "kis_image_view_converter.h"
#include "kis_shape_layer.h"
#include <kis_debug.h>
KisShapeSelection::KisShapeSelection(KoShapeControllerBase *shapeControllerBase, KisImageWSP image, KisSelectionWSP selection)
: KoShapeLayer(m_model = new KisShapeSelectionModel(image, selection, this))
- , m_image(image)
- , m_shapeControllerBase(shapeControllerBase)
{
- Q_ASSERT(m_image);
- setShapeId("KisShapeSelection");
- setSelectable(false);
- m_converter = new KisImageViewConverter(image);
- m_canvas = new KisShapeSelectionCanvas(shapeControllerBase);
- m_canvas->shapeManager()->addShape(this);
-
- m_model->setObjectName("KisShapeSelectionModel");
- m_model->moveToThread(image->thread());
- m_canvas->setObjectName("KisShapeSelectionCanvas");
- m_canvas->moveToThread(image->thread());
-
- connect(this, SIGNAL(sigMoveShapes(QPointF)), SLOT(slotMoveShapes(QPointF)));
+ init(image, shapeControllerBase);
}
KisShapeSelection::~KisShapeSelection()
{
m_model->setShapeSelection(0);
delete m_canvas;
delete m_converter;
}
KisShapeSelection::KisShapeSelection(const KisShapeSelection& rhs, KisSelection* selection)
: KoShapeLayer(m_model = new KisShapeSelectionModel(rhs.m_image, selection, this))
{
- m_image = rhs.m_image;
- m_shapeControllerBase = rhs.m_shapeControllerBase;
- m_converter = new KisImageViewConverter(m_image);
- m_canvas = new KisShapeSelectionCanvas(m_shapeControllerBase);
+ init(rhs.m_image, rhs.m_shapeControllerBase);
// TODO: refactor shape selection to pass signals
// via KoShapeManager, not via the model
m_canvas->shapeManager()->setUpdatesBlocked(true);
m_model->setUpdatesEnabled(false);
m_canvas->shapeManager()->addShape(this);
Q_FOREACH (KoShape *shape, rhs.shapes()) {
KoShape *clonedShape = shape->cloneShape();
KIS_SAFE_ASSERT_RECOVER(clonedShape) { continue; }
this->addShape(clonedShape);
}
m_canvas->shapeManager()->setUpdatesBlocked(false);
m_model->setUpdatesEnabled(true);
}
-KisSelectionComponent* KisShapeSelection::clone(KisSelection* selection)
+void KisShapeSelection::init(KisImageSP image, KoShapeControllerBase *shapeControllerBase)
{
- /**
- * TODO: make cloning of vector selections safe! Right now it crashes
- * on Windows because of manipulations with timers from non-gui thread.
- */
- KIS_SAFE_ASSERT_RECOVER_NOOP(QThread::currentThread() == qApp->thread());
+ KIS_SAFE_ASSERT_RECOVER_RETURN(image);
+ KIS_SAFE_ASSERT_RECOVER_RETURN(shapeControllerBase);
+
+ m_image = image;
+ m_shapeControllerBase = shapeControllerBase;
+
+ setShapeId("KisShapeSelection");
+ setSelectable(false);
+ m_converter = new KisImageViewConverter(image);
+ m_canvas = new KisShapeSelectionCanvas(shapeControllerBase);
+ m_canvas->shapeManager()->addShape(this);
+
+ m_model->setObjectName("KisShapeSelectionModel");
+ m_model->moveToThread(image->thread());
+ m_canvas->setObjectName("KisShapeSelectionCanvas");
+ m_canvas->moveToThread(image->thread());
+
+ connect(this, SIGNAL(sigMoveShapes(QPointF)), SLOT(slotMoveShapes(QPointF)));
+}
+KisSelectionComponent* KisShapeSelection::clone(KisSelection* selection)
+{
return new KisShapeSelection(*this, selection);
}
bool KisShapeSelection::saveSelection(KoStore * store) const
{
const QSizeF sizeInPx = m_image->bounds().size();
const QSizeF sizeInPt(sizeInPx.width() / m_image->xRes(), sizeInPx.height() / m_image->yRes());
return KisShapeLayer::saveShapesToStore(store, this->shapes(), sizeInPt);
}
bool KisShapeSelection::loadSelection(KoStore* store)
{
QSizeF fragmentSize; // unused!
// FIXME: we handle xRes() only!
KIS_SAFE_ASSERT_RECOVER_NOOP(qFuzzyCompare(m_image->xRes(), m_image->yRes()));
const qreal resolutionPPI = 72.0 * m_image->xRes();
QList<KoShape*> shapes;
if (store->open("content.svg")) {
KoStoreDevice storeDev(store);
storeDev.open(QIODevice::ReadOnly);
shapes = KisShapeLayer::createShapesFromSvg(&storeDev,
"", m_image->bounds(),
resolutionPPI, m_canvas->shapeController()->resourceManager(),
&fragmentSize);
store->close();
Q_FOREACH (KoShape *shape, shapes) {
addShape(shape);
}
return true;
}
-
- KoOdfReadStore odfStore(store);
- QString errorMessage;
-
- odfStore.loadAndParse(errorMessage);
-
- if (!errorMessage.isEmpty()) {
- dbgKrita << errorMessage;
- return false;
- }
-
- KoXmlElement contents = odfStore.contentDoc().documentElement();
-
- // dbgKrita <<"Start loading OASIS document..." << contents.text();
- // dbgKrita <<"Start loading OASIS contents..." << contents.lastChild().localName();
- // dbgKrita <<"Start loading OASIS contents..." << contents.lastChild().namespaceURI();
- // dbgKrita <<"Start loading OASIS contents..." << contents.lastChild().isElement();
-
- KoXmlElement body(KoXml::namedItemNS(contents, KoXmlNS::office, "body"));
-
- if (body.isNull()) {
- dbgKrita << "No office:body found!";
- //setErrorMessage( i18n( "Invalid OASIS document. No office:body tag found." ) );
- return false;
- }
-
- body = KoXml::namedItemNS(body, KoXmlNS::office, "drawing");
- if (body.isNull()) {
- dbgKrita << "No office:drawing found!";
- //setErrorMessage( i18n( "Invalid OASIS document. No office:drawing tag found." ) );
- return false;
- }
-
- KoXmlElement page(KoXml::namedItemNS(body, KoXmlNS::draw, "page"));
- if (page.isNull()) {
- dbgKrita << "No office:drawing found!";
- //setErrorMessage( i18n( "Invalid OASIS document. No draw:page tag found." ) );
- return false;
- }
-
- KoXmlElement * master = 0;
- if (odfStore.styles().masterPages().contains("Standard"))
- master = odfStore.styles().masterPages().value("Standard");
- else if (odfStore.styles().masterPages().contains("Default"))
- master = odfStore.styles().masterPages().value("Default");
- else if (! odfStore.styles().masterPages().empty())
- master = odfStore.styles().masterPages().begin().value();
-
- if (master) {
- const KoXmlElement *style = odfStore.styles().findStyle(
- master->attributeNS(KoXmlNS::style, "page-layout-name", QString()));
- KoPageLayout pageLayout;
- pageLayout.loadOdf(*style);
- setSize(QSizeF(pageLayout.width, pageLayout.height));
- } else {
- dbgKrita << "No master page found!";
- return false;
- }
-
- KoOdfLoadingContext context(odfStore.styles(), odfStore.store());
- KoShapeLoadingContext shapeContext(context, 0);
-
- KoXmlElement layerElement;
- forEachElement(layerElement, context.stylesReader().layerSet()) {
- if (!loadOdf(layerElement, shapeContext)) {
- dbgKrita << "Could not load vector layer!";
- return false;
- }
- }
-
- KoXmlElement child;
- forEachElement(child, page) {
- KoShape * shape = KoShapeRegistry::instance()->createShapeFromOdf(child, shapeContext);
- if (shape) {
- addShape(shape);
- }
- }
-
- return true;
+ return false;
}
void KisShapeSelection::setUpdatesEnabled(bool enabled)
{
m_model->setUpdatesEnabled(enabled);
}
bool KisShapeSelection::updatesEnabled() const
{
return m_model->updatesEnabled();
}
KUndo2Command* KisShapeSelection::resetToEmpty()
{
return new KisTakeAllShapesCommand(this, true, false);
}
bool KisShapeSelection::isEmpty() const
{
return !m_model->count();
}
QPainterPath KisShapeSelection::outlineCache() const
{
return m_outline;
}
bool KisShapeSelection::outlineCacheValid() const
{
return true;
}
void KisShapeSelection::recalculateOutlineCache()
{
QTransform resolutionMatrix;
resolutionMatrix.scale(m_image->xRes(), m_image->yRes());
QList<KoShape*> shapesList = shapes();
QPainterPath outline;
Q_FOREACH (KoShape * shape, shapesList) {
/**
* WARNING: we should unite all the shapes in image coordinates,
* not in points. Boolean operations inside the QPainterPath
* linearize the curves into lines and they use absolute values
* for thresholds.
*
* See KritaUtils::pathShapeBooleanSpaceWorkaround() for more info
*/
QTransform shapeMatrix = shape->absoluteTransformation();
outline = outline.united(resolutionMatrix.map(shapeMatrix.map(shape->outline())));
}
m_outline = outline;
}
void KisShapeSelection::paintComponent(QPainter& painter, KoShapePaintingContext &) const
{
Q_UNUSED(painter);
}
void KisShapeSelection::renderToProjection(KisPaintDeviceSP projection)
{
Q_ASSERT(projection);
Q_ASSERT(m_image);
QRectF boundingRect = outlineCache().boundingRect();
renderSelection(projection, boundingRect.toAlignedRect());
}
void KisShapeSelection::renderToProjection(KisPaintDeviceSP projection, const QRect& r)
{
Q_ASSERT(projection);
renderSelection(projection, r);
}
void KisShapeSelection::renderSelection(KisPaintDeviceSP projection, const QRect& requestedRect)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(projection);
KIS_SAFE_ASSERT_RECOVER_RETURN(m_image);
const qint32 MASK_IMAGE_WIDTH = 256;
const qint32 MASK_IMAGE_HEIGHT = 256;
const QPainterPath selectionOutline = outlineCache();
if (*projection->defaultPixel().data() == OPACITY_TRANSPARENT_U8) {
projection->clear(requestedRect);
} else {
KoColor transparentColor(Qt::transparent, projection->colorSpace());
projection->fill(requestedRect, transparentColor);
}
const QRect r = requestedRect & selectionOutline.boundingRect().toAlignedRect();
QImage polygonMaskImage(MASK_IMAGE_WIDTH, MASK_IMAGE_HEIGHT, QImage::Format_ARGB32);
QPainter maskPainter(&polygonMaskImage);
maskPainter.setRenderHint(QPainter::Antialiasing, true);
// Break the mask up into chunks so we don't have to allocate a potentially very large QImage.
for (qint32 x = r.x(); x < r.x() + r.width(); x += MASK_IMAGE_WIDTH) {
for (qint32 y = r.y(); y < r.y() + r.height(); y += MASK_IMAGE_HEIGHT) {
maskPainter.fillRect(polygonMaskImage.rect(), Qt::black);
maskPainter.translate(-x, -y);
maskPainter.fillPath(selectionOutline, Qt::white);
maskPainter.translate(x, y);
qint32 rectWidth = qMin(r.x() + r.width() - x, MASK_IMAGE_WIDTH);
qint32 rectHeight = qMin(r.y() + r.height() - y, MASK_IMAGE_HEIGHT);
KisSequentialIterator it(projection, QRect(x, y, rectWidth, rectHeight));
while (it.nextPixel()) {
(*it.rawData()) = qRed(polygonMaskImage.pixel(it.x() - x, it.y() - y));
}
}
}
}
KoShapeManager* KisShapeSelection::shapeManager() const
{
return m_canvas->shapeManager();
}
KisShapeSelectionFactory::KisShapeSelectionFactory()
: KoShapeFactoryBase("KisShapeSelection", "selection shape container")
{
setHidden(true);
}
void KisShapeSelection::moveX(qint32 x)
{
const QPointF diff(x / m_image->xRes(), 0);
emit sigMoveShapes(diff);
}
void KisShapeSelection::moveY(qint32 y)
{
const QPointF diff(0, y / m_image->yRes());
emit sigMoveShapes(diff);
}
void KisShapeSelection::slotMoveShapes(const QPointF &diff)
{
Q_FOREACH (KoShape* shape, shapeManager()->shapes()) {
if (shape != this) {
QPointF pos = shape->position();
shape->setPosition(pos + diff);
}
}
}
// TODO same code as in vector layer, refactor!
KUndo2Command* KisShapeSelection::transform(const QTransform &transform) {
QList<KoShape*> shapes = m_canvas->shapeManager()->shapes();
if(shapes.isEmpty()) return 0;
QTransform realTransform = m_converter->documentToView() *
transform * m_converter->viewToDocument();
QList<QTransform> oldTransformations;
QList<QTransform> newTransformations;
// this code won't work if there are shapes, that inherit the transformation from the parent container.
// the chart and tree shapes are examples for that, but they aren't used in krita and there are no other shapes like that.
Q_FOREACH (const KoShape* shape, shapes) {
QTransform oldTransform = shape->transformation();
oldTransformations.append(oldTransform);
if (dynamic_cast<const KoShapeGroup*>(shape)) {
newTransformations.append(oldTransform);
} else {
QTransform globalTransform = shape->absoluteTransformation();
QTransform localTransform = globalTransform * realTransform * globalTransform.inverted();
newTransformations.append(localTransform*oldTransform);
}
}
return new KoShapeTransformCommand(shapes, oldTransformations, newTransformations);
}
diff --git a/libs/ui/flake/kis_shape_selection.h b/libs/ui/flake/kis_shape_selection.h
index e42ca3e2b9..a9d168c14e 100644
--- a/libs/ui/flake/kis_shape_selection.h
+++ b/libs/ui/flake/kis_shape_selection.h
@@ -1,142 +1,142 @@
/*
* Copyright (c) 2007 Sven Langkamp <sven.langkamp@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KIS_SHAPE_SELECTION_H
#define KIS_SHAPE_SELECTION_H
#include <QPainterPath>
#include <KoShapeLayer.h>
#include <KoShapeFactoryBase.h>
#include <KoShapeUserData.h>
#include <KoShapeLoadingContext.h>
#include <kis_selection_component.h>
#include <kis_types.h>
#include <kritaui_export.h>
class KoStore;
class KoShapeManager;
class KisShapeSelectionCanvas;
class KisShapeSelectionModel;
class KisImageViewConverter;
class KUndo2Command;
/**
* The marker class.
* It is added to the shape's user data to show this shape
* is a part of a shape selection
*/
class KisShapeSelectionMarker : public KoShapeUserData
{
KoShapeUserData* clone() const override {
return new KisShapeSelectionMarker(*this);
}
};
class KRITAUI_EXPORT KisShapeSelection : public QObject, public KoShapeLayer, public KisSelectionComponent
{
Q_OBJECT
KisShapeSelection(const KisShapeSelection& rhs);
public:
KisShapeSelection(KoShapeControllerBase *shapeControllerBase, KisImageWSP image, KisSelectionWSP selection);
~KisShapeSelection() override;
KisShapeSelection(const KisShapeSelection& rhs, KisSelection* selection);
KisSelectionComponent* clone(KisSelection* selection) override;
bool saveSelection(KoStore * store) const;
bool loadSelection(KoStore * store);
/**
* Renders the shapes to a selection. This method should only be called
* by KisSelection to update it's projection.
*
* @param projection the target selection
*/
void renderToProjection(KisPaintDeviceSP projection) override;
void renderToProjection(KisPaintDeviceSP projection, const QRect& r) override;
KUndo2Command* resetToEmpty() override;
bool isEmpty() const override;
QPainterPath outlineCache() const override;
bool outlineCacheValid() const override;
void recalculateOutlineCache() override;
KoShapeManager *shapeManager() const;
void moveX(qint32 x) override;
void moveY(qint32 y) override;
KUndo2Command* transform(const QTransform &transform) override;
Q_SIGNALS:
void sigMoveShapes(const QPointF &diff);
private Q_SLOTS:
void slotMoveShapes(const QPointF &diff);
protected:
void paintComponent(QPainter& painter, KoShapePaintingContext &paintcontext) const override;
private:
friend class KisTakeAllShapesCommand;
void setUpdatesEnabled(bool enabled);
bool updatesEnabled() const;
-
+ void init(KisImageSP image, KoShapeControllerBase *shapeControllerBase);
private:
void renderSelection(KisPaintDeviceSP projection, const QRect& requestedRect);
KisImageWSP m_image;
QPainterPath m_outline;
KisImageViewConverter *m_converter;
KisShapeSelectionCanvas *m_canvas;
KisShapeSelectionModel *m_model;
KoShapeControllerBase *m_shapeControllerBase;
friend class KisShapeSelectionModel;
};
class KRITAUI_EXPORT KisShapeSelectionFactory : public KoShapeFactoryBase
{
public:
KisShapeSelectionFactory();
~KisShapeSelectionFactory() override {}
KoShape *createDefaultShape(KoDocumentResourceManager *documentResources = 0) const override {
Q_UNUSED(documentResources);
return 0;
}
bool supports(const KoXmlElement & e, KoShapeLoadingContext &context) const override {
Q_UNUSED(e);
Q_UNUSED(context);
return false;
}
};
#endif
diff --git a/libs/ui/flake/kis_shape_selection_model.cpp b/libs/ui/flake/kis_shape_selection_model.cpp
index 8a1e9ab558..2cb7a29d65 100644
--- a/libs/ui/flake/kis_shape_selection_model.cpp
+++ b/libs/ui/flake/kis_shape_selection_model.cpp
@@ -1,178 +1,174 @@
/*
* Copyright (c) 2007 Sven Langkamp <sven.langkamp@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_shape_selection_model.h"
#include "kis_debug.h"
#include <KoShapeContainer.h>
#include <KoShapeBackground.h>
#include <KoShapeManager.h>
#include "kis_shape_selection.h"
#include "kis_selection.h"
#include "kis_image.h"
#include "kis_update_selection_job.h"
KisShapeSelectionModel::KisShapeSelectionModel(KisImageWSP image, KisSelectionWSP selection, KisShapeSelection* shapeSelection)
: m_image(image)
, m_parentSelection(selection)
, m_shapeSelection(shapeSelection)
, m_updatesEnabled(true)
{
}
KisShapeSelectionModel::~KisShapeSelectionModel()
{
m_image = 0;
m_parentSelection = 0;
}
void KisShapeSelectionModel::requestUpdate(const QRect &updateRect)
{
m_shapeSelection->recalculateOutlineCache();
if (m_updatesEnabled) {
m_parentSelection->requestCompressedProjectionUpdate(updateRect);
}
}
void KisShapeSelectionModel::add(KoShape *child)
{
if (!m_shapeSelection) return;
if (m_shapeMap.contains(child))
return;
child->setStroke(KoShapeStrokeModelSP());
child->setBackground( QSharedPointer<KoShapeBackground>(0));
m_shapeMap.insert(child, child->boundingRect());
m_shapeSelection->shapeManager()->addShape(child);
QRect updateRect = child->boundingRect().toAlignedRect();
if (m_image.isValid()) {
QTransform matrix;
matrix.scale(m_image->xRes(), m_image->yRes());
updateRect = matrix.mapRect(updateRect);
}
if (m_shapeMap.count() == 1) {
// The shape is the first one, so the shape selection just got created
// Pixel selection provides no longer the datamanager of the selection
// so update the whole selection
requestUpdate(QRect());
} else {
requestUpdate(updateRect);
}
}
void KisShapeSelectionModel::remove(KoShape *child)
{
if (!m_shapeMap.contains(child)) return;
QRect updateRect = child->boundingRect().toAlignedRect();
m_shapeMap.remove(child);
if (m_shapeSelection) {
m_shapeSelection->shapeManager()->remove(child);
}
if (m_image.isValid()) {
QTransform matrix;
matrix.scale(m_image->xRes(), m_image->yRes());
updateRect = matrix.mapRect(updateRect);
if (m_shapeSelection) { // No m_shapeSelection indicates the selection is being deleted
requestUpdate(updateRect);
-
- if (m_updatesEnabled && m_shapeMap.isEmpty()) {
- m_parentSelection->notifyShapeSelectionBecameEmpty();
- }
}
}
}
void KisShapeSelectionModel::setUpdatesEnabled(bool enabled)
{
m_updatesEnabled = enabled;
}
bool KisShapeSelectionModel::updatesEnabled() const
{
return m_updatesEnabled;
}
void KisShapeSelectionModel::setClipped(const KoShape *child, bool clipping)
{
Q_UNUSED(child);
Q_UNUSED(clipping);
}
bool KisShapeSelectionModel::isClipped(const KoShape *child) const
{
Q_UNUSED(child);
return false;
}
void KisShapeSelectionModel::setInheritsTransform(const KoShape *shape, bool inherit)
{
Q_UNUSED(shape);
Q_UNUSED(inherit);
}
bool KisShapeSelectionModel::inheritsTransform(const KoShape *shape) const
{
Q_UNUSED(shape);
return false;
}
int KisShapeSelectionModel::count() const
{
return m_shapeMap.count();
}
QList<KoShape*> KisShapeSelectionModel::shapes() const
{
return QList<KoShape*>(m_shapeMap.keys());
}
void KisShapeSelectionModel::containerChanged(KoShapeContainer *, KoShape::ChangeType)
{
}
void KisShapeSelectionModel::childChanged(KoShape * child, KoShape::ChangeType type)
{
if (!m_shapeSelection) return;
// TODO: check if still needed
if (type == KoShape::ParentChanged) return;
QRectF changedRect = m_shapeMap[child];
changedRect = changedRect.united(child->boundingRect());
m_shapeMap[child] = child->boundingRect();
if (m_image.isValid()) {
QTransform matrix;
matrix.scale(m_image->xRes(), m_image->yRes());
changedRect = matrix.mapRect(changedRect);
}
requestUpdate(changedRect.toAlignedRect());
}
void KisShapeSelectionModel::setShapeSelection(KisShapeSelection* selection)
{
m_shapeSelection = selection;
}
diff --git a/libs/widgets/koDocumentInfoAboutWidget.ui b/libs/ui/forms/koDocumentInfoAboutWidget.ui
similarity index 100%
rename from libs/widgets/koDocumentInfoAboutWidget.ui
rename to libs/ui/forms/koDocumentInfoAboutWidget.ui
diff --git a/libs/widgets/koDocumentInfoAuthorWidget.ui b/libs/ui/forms/koDocumentInfoAuthorWidget.ui
similarity index 100%
rename from libs/widgets/koDocumentInfoAuthorWidget.ui
rename to libs/ui/forms/koDocumentInfoAuthorWidget.ui
diff --git a/libs/ui/forms/wdgsessionmanager.ui b/libs/ui/forms/wdgsessionmanager.ui
index 75338cabc8..e378853244 100644
--- a/libs/ui/forms/wdgsessionmanager.ui
+++ b/libs/ui/forms/wdgsessionmanager.ui
@@ -1,100 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DlgSessionManager</class>
<widget class="QWidget" name="DlgSessionManager">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>363</width>
<height>238</height>
</rect>
</property>
<property name="windowTitle">
<string>Sessions</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<item>
<widget class="QListView" name="lstSessions"/>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QPushButton" name="btnNew">
<property name="text">
- <string>New...</string>
+ <string comment="New session">New...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnRename">
<property name="text">
<string>Rename...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSwitchTo">
<property name="text">
<string>Switch to</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnDelete">
<property name="text">
<string>Delete...</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnClose">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
diff --git a/libs/ui/input/kis_input_manager_p.cpp b/libs/ui/input/kis_input_manager_p.cpp
index 4016231683..28adb61266 100644
--- a/libs/ui/input/kis_input_manager_p.cpp
+++ b/libs/ui/input/kis_input_manager_p.cpp
@@ -1,689 +1,694 @@
/*
* Copyright (C) 2015 Michael Abrahams <miabraha@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_input_manager_p.h"
#include <QMap>
#include <QApplication>
#include <QScopedPointer>
#include <QtGlobal>
#include "kis_input_manager.h"
#include "kis_config.h"
#include "kis_abstract_input_action.h"
#include "kis_tool_invocation_action.h"
#include "kis_stroke_shortcut.h"
#include "kis_touch_shortcut.h"
#include "kis_native_gesture_shortcut.h"
#include "kis_input_profile_manager.h"
#include "kis_extended_modifiers_mapper.h"
#include "kis_zoom_and_rotate_action.h"
/**
* This hungry class EventEater encapsulates event masking logic.
*
* Its basic role is to kill synthetic mouseMove events sent by Xorg or Qt after
* tablet events. Those events are sent in order to allow widgets that haven't
* implemented tablet specific functionality to seamlessly behave as if one were
* using a mouse. These synthetic events are *supposed* to be optional, or at
* least come with a flag saying "This is a fake event!!" but neither of those
* methods is trustworthy. (This is correct as of Qt 5.4 + Xorg.)
*
* Qt 5.4 provides no reliable way to see if a user's tablet is being hovered
* over the pad, since it converts all tablethover events into mousemove, with
* no option to turn this off. Moreover, sometimes the MouseButtonPress event
* from the tapping their tablet happens BEFORE the TabletPress event. This
* means we have to resort to a somewhat complicated logic. What makes this
* truly a joke is that we are not guaranteed to observe TabletProximityEnter
* events when we're using a tablet, either, you may only see an Enter event.
*
* Once we see tablet events heading our way, we can say pretty confidently that
* every mouse event is fake. There are two painful cases to consider - a
* mousePress event could arrive before the tabletPress event, or it could
* arrive much later, e.g. after tabletRelease. The first was only seen on Linux
* with Qt's XInput2 code, the solution was to hold onto mousePress events
* temporarily and wait for tabletPress later, this is contained in git history
* but is now removed. The second case is currently handled by the
* eatOneMousePress function, which waits as long as necessary to detect and
* block a single mouse press event.
*/
static bool isMouseEventType(QEvent::Type t)
{
return (t == QEvent::MouseMove ||
t == QEvent::MouseButtonPress ||
t == QEvent::MouseButtonRelease ||
t == QEvent::MouseButtonDblClick);
}
KisInputManager::Private::EventEater::EventEater()
{
KisConfig cfg(true);
activateSecondaryButtonsWorkaround = cfg.useRightMiddleTabletButtonWorkaround();
}
bool KisInputManager::Private::EventEater::eventFilter(QObject* target, QEvent* event )
{
Q_UNUSED(target)
auto debugEvent = [&](int i) {
if (KisTabletDebugger::instance()->debugEnabled()) {
QString pre = QString("[BLOCKED %1:]").arg(i);
QMouseEvent *ev = static_cast<QMouseEvent*>(event);
dbgTablet << KisTabletDebugger::instance()->eventToString(*ev, pre);
}
};
auto debugTabletEvent = [&](int i) {
if (KisTabletDebugger::instance()->debugEnabled()) {
QString pre = QString("[BLOCKED %1:]").arg(i);
QTabletEvent *ev = static_cast<QTabletEvent*>(event);
dbgTablet << KisTabletDebugger::instance()->eventToString(*ev, pre);
}
};
if (peckish && event->type() == QEvent::MouseButtonPress
// Drop one mouse press following tabletPress or touchBegin
&& (static_cast<QMouseEvent*>(event)->button() == Qt::LeftButton)) {
peckish = false;
debugEvent(1);
return true;
}
if (activateSecondaryButtonsWorkaround) {
if (event->type() == QEvent::TabletPress ||
event->type() == QEvent::TabletRelease) {
QTabletEvent *te = static_cast<QTabletEvent*>(event);
if (te->button() != Qt::LeftButton) {
debugTabletEvent(3);
return true;
}
} else if (event->type() == QEvent::MouseButtonPress ||
event->type() == QEvent::MouseButtonRelease ||
event->type() == QEvent::MouseButtonDblClick) {
QMouseEvent *me = static_cast<QMouseEvent*>(event);
if (me->button() != Qt::LeftButton) {
return false;
}
}
}
if (isMouseEventType(event->type()) &&
(hungry
// On Mac, we need mouse events when the tablet is in proximity, but not pressed down
// since tablet move events are not generated until after tablet press.
#ifndef Q_OS_MAC
|| (eatSyntheticEvents && static_cast<QMouseEvent*>(event)->source() != Qt::MouseEventNotSynthesized)
#endif
)) {
// Drop mouse events if enabled or event was synthetic & synthetic events are disabled
debugEvent(2);
return true;
}
return false; // All clear - let this one through!
}
void KisInputManager::Private::EventEater::activate()
{
if (!hungry && (KisTabletDebugger::instance()->debugEnabled())) {
dbgTablet << "Start blocking mouse events";
}
hungry = true;
}
void KisInputManager::Private::EventEater::deactivate()
{
if (hungry && (KisTabletDebugger::instance()->debugEnabled())) {
dbgTablet << "Stop blocking mouse events";
}
hungry = false;
}
void KisInputManager::Private::EventEater::eatOneMousePress()
{
// Enable on other platforms if getting full-pressure splotches
peckish = true;
}
bool KisInputManager::Private::ignoringQtCursorEvents()
{
return eventEater.hungry;
}
void KisInputManager::Private::setMaskSyntheticEvents(bool value)
{
eventEater.eatSyntheticEvents = value;
}
KisInputManager::Private::Private(KisInputManager *qq)
: q(qq)
, moveEventCompressor(10 /* ms */,
KisSignalCompressor::FIRST_ACTIVE,
KisSignalCompressor::ADDITIVE_INTERVAL)
, priorityEventFilterSeqNo(0)
, canvasSwitcher(this, qq)
{
KisConfig cfg(true);
moveEventCompressor.setDelay(cfg.tabletEventsDelay());
testingAcceptCompressedTabletEvents = cfg.testingAcceptCompressedTabletEvents();
testingCompressBrushEvents = cfg.testingCompressBrushEvents();
if (cfg.trackTabletEventLatency()) {
tabletLatencyTracker = new TabletLatencyTracker();
}
matcher.setInputActionGroupsMaskCallback(
[this] () {
return this->canvas ? this->canvas->inputActionGroupsMask() : AllActionGroup;
});
}
static const int InputWidgetsThreshold = 2000;
static const int OtherWidgetsThreshold = 400;
KisInputManager::Private::CanvasSwitcher::CanvasSwitcher(Private *_d, QObject *p)
: QObject(p),
d(_d),
eatOneMouseStroke(false),
focusSwitchThreshold(InputWidgetsThreshold)
{
}
void KisInputManager::Private::CanvasSwitcher::setupFocusThreshold(QObject* object)
{
QWidget *widget = qobject_cast<QWidget*>(object);
KIS_SAFE_ASSERT_RECOVER_RETURN(widget);
thresholdConnections.clear();
thresholdConnections.addConnection(&focusSwitchThreshold, SIGNAL(timeout()), widget, SLOT(setFocus()));
}
void KisInputManager::Private::CanvasSwitcher::addCanvas(KisCanvas2 *canvas)
{
if (!canvas) return;
QObject *canvasWidget = canvas->canvasWidget();
if (!canvasResolver.contains(canvasWidget)) {
canvasResolver.insert(canvasWidget, canvas);
+ } else {
+ // just a sanity cheeck to find out if we are
+ // trying to add two canvases concurrently.
+ KIS_SAFE_ASSERT_RECOVER_NOOP(d->canvas == canvas);
+ }
+
+ if (canvas != d->canvas) {
d->q->setupAsEventFilter(canvasWidget);
canvasWidget->installEventFilter(this);
setupFocusThreshold(canvasWidget);
focusSwitchThreshold.setEnabled(false);
d->canvas = canvas;
d->toolProxy = qobject_cast<KisToolProxy*>(canvas->toolProxy());
- } else {
- KIS_ASSERT_RECOVER_RETURN(d->canvas == canvas);
}
}
void KisInputManager::Private::CanvasSwitcher::removeCanvas(KisCanvas2 *canvas)
{
QObject *widget = canvas->canvasWidget();
canvasResolver.remove(widget);
if (d->eventsReceiver == widget) {
d->q->setupAsEventFilter(0);
}
widget->removeEventFilter(this);
}
bool isInputWidget(QWidget *w)
{
if (!w) return false;
QList<QLatin1String> types;
types << QLatin1String("QAbstractSlider");
types << QLatin1String("QAbstractSpinBox");
types << QLatin1String("QLineEdit");
types << QLatin1String("QTextEdit");
types << QLatin1String("QPlainTextEdit");
types << QLatin1String("QComboBox");
types << QLatin1String("QKeySequenceEdit");
Q_FOREACH (const QLatin1String &type, types) {
if (w->inherits(type.data())) {
return true;
}
}
return false;
}
bool KisInputManager::Private::CanvasSwitcher::eventFilter(QObject* object, QEvent* event )
{
if (canvasResolver.contains(object)) {
switch (event->type()) {
case QEvent::FocusIn: {
QFocusEvent *fevent = static_cast<QFocusEvent*>(event);
KisCanvas2 *canvas = canvasResolver.value(object);
// only relevant canvases from the same main window should be
// registered in the switcher
KIS_SAFE_ASSERT_RECOVER_BREAK(canvas);
if (canvas != d->canvas) {
eatOneMouseStroke = 2 * (fevent->reason() == Qt::MouseFocusReason);
}
d->canvas = canvas;
d->toolProxy = qobject_cast<KisToolProxy*>(canvas->toolProxy());
d->q->setupAsEventFilter(object);
object->removeEventFilter(this);
object->installEventFilter(this);
setupFocusThreshold(object);
focusSwitchThreshold.setEnabled(false);
const QPoint globalPos = QCursor::pos();
const QPoint localPos = d->canvas->canvasWidget()->mapFromGlobal(globalPos);
QWidget *canvasWindow = d->canvas->canvasWidget()->window();
const QPoint windowsPos = canvasWindow ? canvasWindow->mapFromGlobal(globalPos) : localPos;
QEnterEvent event(localPos, windowsPos, globalPos);
d->q->eventFilter(object, &event);
break;
}
case QEvent::FocusOut: {
focusSwitchThreshold.setEnabled(true);
break;
}
case QEvent::Enter: {
break;
}
case QEvent::Leave: {
focusSwitchThreshold.stop();
break;
}
case QEvent::Wheel: {
QWidget *widget = static_cast<QWidget*>(object);
widget->setFocus();
break;
}
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::TabletPress:
case QEvent::TabletRelease:
focusSwitchThreshold.forceDone();
if (eatOneMouseStroke) {
eatOneMouseStroke--;
return true;
}
break;
case QEvent::MouseButtonDblClick:
focusSwitchThreshold.forceDone();
if (eatOneMouseStroke) {
return true;
}
break;
case QEvent::MouseMove:
case QEvent::TabletMove: {
QWidget *widget = static_cast<QWidget*>(object);
if (!widget->hasFocus()) {
const int delay =
isInputWidget(QApplication::focusWidget()) ?
InputWidgetsThreshold : OtherWidgetsThreshold;
focusSwitchThreshold.setDelayThreshold(delay);
focusSwitchThreshold.start();
}
}
break;
default:
break;
}
}
return QObject::eventFilter(object, event);
}
KisInputManager::Private::ProximityNotifier::ProximityNotifier(KisInputManager::Private *_d, QObject *p)
: QObject(p), d(_d)
{}
bool KisInputManager::Private::ProximityNotifier::eventFilter(QObject* object, QEvent* event )
{
/**
* All Qt builds in range 5.7.0...5.11.X on X11 had a problem that made all
* the tablet events be accepted by default. It meant that no mouse
* events were synthesized, and, therefore, no Enter/Leave were generated.
*
* The fix for this bug has been added only in Qt 5.12.0:
* https://codereview.qt-project.org/#/c/239918/
*
* To avoid this problem we should explicitly ignore all the tablet events.
*/
#if defined Q_OS_LINUX && \
QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) && \
QT_VERSION < QT_VERSION_CHECK(5, 12, 0)
if (event->type() == QEvent::TabletMove ||
event->type() == QEvent::TabletPress ||
event->type() == QEvent::TabletRelease) {
event->ignore();
}
#endif
switch (event->type()) {
case QEvent::TabletEnterProximity:
d->debugEvent<QEvent, false>(event);
// Tablet proximity events are unreliable AND fake mouse events do not
// necessarily come after tablet events, so this is insufficient.
// d->eventEater.eatOneMousePress();
// Qt sends fake mouse events instead of hover events, so not very useful.
// Don't block mouse events on tablet since tablet move events are not generated until
// after tablet press.
#ifndef Q_OS_MACOS
d->blockMouseEvents();
#endif
break;
case QEvent::TabletLeaveProximity:
d->debugEvent<QEvent, false>(event);
d->allowMouseEvents();
break;
default:
break;
}
return QObject::eventFilter(object, event);
}
void KisInputManager::Private::addStrokeShortcut(KisAbstractInputAction* action, int index,
const QList<Qt::Key> &modifiers,
Qt::MouseButtons buttons)
{
KisStrokeShortcut *strokeShortcut =
new KisStrokeShortcut(action, index);
QList<Qt::MouseButton> buttonList;
if(buttons & Qt::LeftButton) {
buttonList << Qt::LeftButton;
}
if(buttons & Qt::RightButton) {
buttonList << Qt::RightButton;
}
if(buttons & Qt::MidButton) {
buttonList << Qt::MidButton;
}
if(buttons & Qt::XButton1) {
buttonList << Qt::XButton1;
}
if(buttons & Qt::XButton2) {
buttonList << Qt::XButton2;
}
if (buttonList.size() > 0) {
#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
strokeShortcut->setButtons(QSet<Qt::Key>(modifiers.begin(), modifiers.end()), QSet<Qt::MouseButton>(buttonList.begin(), buttonList.end()));
#else
strokeShortcut->setButtons(QSet<Qt::Key>::fromList(modifiers), QSet<Qt::MouseButton>::fromList(buttonList));
#endif
matcher.addShortcut(strokeShortcut);
}
else {
delete strokeShortcut;
}
}
void KisInputManager::Private::addKeyShortcut(KisAbstractInputAction* action, int index,
const QList<Qt::Key> &keys)
{
if (keys.size() == 0) return;
KisSingleActionShortcut *keyShortcut =
new KisSingleActionShortcut(action, index);
//Note: Ordering is important here, Shift + V is different from V + Shift,
//which is the reason we use the last key here since most users will enter
//shortcuts as "Shift + V". Ideally this should not happen, but this is
//the way the shortcut matcher is currently implemented.
QList<Qt::Key> allKeys = keys;
Qt::Key key = allKeys.takeLast();
#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
QSet<Qt::Key> modifiers = QSet<Qt::Key>(allKeys.begin(), allKeys.end());
#else
QSet<Qt::Key> modifiers = QSet<Qt::Key>::fromList(allKeys);
#endif
keyShortcut->setKey(modifiers, key);
matcher.addShortcut(keyShortcut);
}
void KisInputManager::Private::addWheelShortcut(KisAbstractInputAction* action, int index,
const QList<Qt::Key> &modifiers,
KisShortcutConfiguration::MouseWheelMovement wheelAction)
{
QScopedPointer<KisSingleActionShortcut> keyShortcut(
new KisSingleActionShortcut(action, index));
KisSingleActionShortcut::WheelAction a;
switch(wheelAction) {
case KisShortcutConfiguration::WheelUp:
a = KisSingleActionShortcut::WheelUp;
break;
case KisShortcutConfiguration::WheelDown:
a = KisSingleActionShortcut::WheelDown;
break;
case KisShortcutConfiguration::WheelLeft:
a = KisSingleActionShortcut::WheelLeft;
break;
case KisShortcutConfiguration::WheelRight:
a = KisSingleActionShortcut::WheelRight;
break;
case KisShortcutConfiguration::WheelTrackpad:
a = KisSingleActionShortcut::WheelTrackpad;
break;
default:
return;
}
#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
keyShortcut->setWheel(QSet<Qt::Key>(modifiers.begin(), modifiers.end()), a);
#else
keyShortcut->setWheel(QSet<Qt::Key>::fromList(modifiers), a);
#endif
matcher.addShortcut(keyShortcut.take());
}
void KisInputManager::Private::addTouchShortcut(KisAbstractInputAction* action, int index, KisShortcutConfiguration::GestureAction gesture)
{
KisTouchShortcut *shortcut = new KisTouchShortcut(action, index, gesture);
dbgKrita << "TouchAction:" << action->name();
switch(gesture) {
case KisShortcutConfiguration::RotateGesture:
case KisShortcutConfiguration::PinchGesture:
#ifndef Q_OS_MACOS
case KisShortcutConfiguration::ZoomAndRotateGesture:
#endif
shortcut->setMinimumTouchPoints(2);
shortcut->setMaximumTouchPoints(2);
break;
case KisShortcutConfiguration::PanGesture:
shortcut->setMinimumTouchPoints(3);
shortcut->setMaximumTouchPoints(10);
break;
default:
break;
}
matcher.addShortcut(shortcut);
}
bool KisInputManager::Private::addNativeGestureShortcut(KisAbstractInputAction* action, int index, KisShortcutConfiguration::GestureAction gesture)
{
// Qt5 only implements QNativeGestureEvent for macOS
Qt::NativeGestureType type;
switch (gesture) {
#ifdef Q_OS_MACOS
case KisShortcutConfiguration::PinchGesture:
type = Qt::ZoomNativeGesture;
break;
case KisShortcutConfiguration::PanGesture:
type = Qt::PanNativeGesture;
break;
case KisShortcutConfiguration::RotateGesture:
type = Qt::RotateNativeGesture;
break;
case KisShortcutConfiguration::SmartZoomGesture:
type = Qt::SmartZoomNativeGesture;
break;
#endif
default:
return false;
}
KisNativeGestureShortcut *shortcut = new KisNativeGestureShortcut(action, index, type);
matcher.addShortcut(shortcut);
return true;
}
void KisInputManager::Private::setupActions()
{
QList<KisAbstractInputAction*> actions = KisInputProfileManager::instance()->actions();
Q_FOREACH (KisAbstractInputAction *action, actions) {
KisToolInvocationAction *toolAction =
dynamic_cast<KisToolInvocationAction*>(action);
if(toolAction) {
defaultInputAction = toolAction;
}
}
connect(KisInputProfileManager::instance(), SIGNAL(currentProfileChanged()), q, SLOT(profileChanged()));
if(KisInputProfileManager::instance()->currentProfile()) {
q->profileChanged();
}
}
bool KisInputManager::Private::processUnhandledEvent(QEvent *event)
{
bool retval = false;
if (forwardAllEventsToTool ||
event->type() == QEvent::KeyPress ||
event->type() == QEvent::KeyRelease) {
defaultInputAction->processUnhandledEvent(event);
retval = true;
}
return retval && !forwardAllEventsToTool;
}
bool KisInputManager::Private::tryHidePopupPalette()
{
if (canvas->isPopupPaletteVisible()) {
canvas->slotShowPopupPalette();
return true;
}
return false;
}
#ifdef HAVE_X11
inline QPointF dividePoints(const QPointF &pt1, const QPointF &pt2) {
return QPointF(pt1.x() / pt2.x(), pt1.y() / pt2.y());
}
inline QPointF multiplyPoints(const QPointF &pt1, const QPointF &pt2) {
return QPointF(pt1.x() * pt2.x(), pt1.y() * pt2.y());
}
#endif
void KisInputManager::Private::blockMouseEvents()
{
eventEater.activate();
}
void KisInputManager::Private::allowMouseEvents()
{
eventEater.deactivate();
}
void KisInputManager::Private::eatOneMousePress()
{
eventEater.eatOneMousePress();
}
void KisInputManager::Private::resetCompressor() {
compressedMoveEvent.reset();
moveEventCompressor.stop();
}
bool KisInputManager::Private::handleCompressedTabletEvent(QEvent *event)
{
bool retval = false;
/**
* When Krita (as an application) has no input focus, we cannot
* handle key events. But at the same time, when the user hovers
* Krita canvas, we should still show him the correct cursor.
*
* So here we just add a simple workaround to resync shortcut
* matcher's state at least against the basic modifiers, like
* Shift, Control and Alt.
*/
QWidget *recievingWidget = dynamic_cast<QWidget*>(eventsReceiver);
if (recievingWidget && !recievingWidget->hasFocus()) {
QVector<Qt::Key> guessedKeys;
KisExtendedModifiersMapper mapper;
Qt::KeyboardModifiers modifiers = mapper.queryStandardModifiers();
Q_FOREACH (Qt::Key key, mapper.queryExtendedModifiers()) {
QKeyEvent kevent(QEvent::ShortcutOverride, key, modifiers);
guessedKeys << KisExtendedModifiersMapper::workaroundShiftAltMetaHell(&kevent);
}
matcher.recoveryModifiersWithoutFocus(guessedKeys);
}
if (!matcher.pointerMoved(event) && toolProxy) {
toolProxy->forwardHoverEvent(event);
}
retval = true;
event->setAccepted(true);
return retval;
}
qint64 KisInputManager::Private::TabletLatencyTracker::currentTimestamp() const
{
// on OS X, we need to compute the timestamp that compares correctly against the native event timestamp,
// which seems to be the msecs since system startup. On Linux with WinTab, we produce the timestamp that
// we compare against ourselves in QWindowSystemInterface.
QElapsedTimer elapsed;
elapsed.start();
return elapsed.msecsSinceReference();
}
void KisInputManager::Private::TabletLatencyTracker::print(const QString &message)
{
dbgTablet << qUtf8Printable(message);
}
diff --git a/libs/ui/kis_config.cc b/libs/ui/kis_config.cc
index dc923c5aa9..b0b93fdbf1 100644
--- a/libs/ui/kis_config.cc
+++ b/libs/ui/kis_config.cc
@@ -1,2238 +1,2248 @@
/*
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
*
* 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_config.h"
#include <QtGlobal>
#include <QApplication>
#include <QDesktopWidget>
#include <QMutex>
#include <QFont>
#include <QThread>
#include <QStringList>
#include <QSettings>
#include <QStandardPaths>
#include <QDebug>
#include <QFileInfo>
#include <kconfig.h>
#include <KisDocument.h>
#include <KoColor.h>
#include <KoColorSpaceRegistry.h>
#include <KoColorModelStandardIds.h>
#include <KoColorProfile.h>
#include <kis_debug.h>
#include <kis_types.h>
#include "kis_canvas_resource_provider.h"
#include "kis_config_notifier.h"
#include "kis_snap_config.h"
#include <config-ocio.h>
#include <kis_color_manager.h>
#include <KisOcioConfiguration.h>
#include <KisUsageLogger.h>
#include <kis_image_config.h>
#ifdef Q_OS_WIN
#include "config_use_qt_tablet_windows.h"
#endif
KisConfig::KisConfig(bool readOnly)
: m_cfg( KSharedConfig::openConfig()->group(""))
, m_readOnly(readOnly)
{
if (!readOnly) {
KIS_SAFE_ASSERT_RECOVER_RETURN(qApp && qApp->thread() == QThread::currentThread());
}
}
KisConfig::~KisConfig()
{
if (m_readOnly) return;
if (qApp && qApp->thread() != QThread::currentThread()) {
dbgKrita << "WARNING: KisConfig: requested config synchronization from nonGUI thread! Called from:" << kisBacktrace();
return;
}
m_cfg.sync();
}
void KisConfig::logImportantSettings() const
{
KisUsageLogger::writeSysInfo("Current Settings\n");
KisUsageLogger::writeSysInfo(QString(" Current Swap Location: %1").arg(KisImageConfig(true).swapDir()));
KisUsageLogger::writeSysInfo(QString(" Current Swap Location writable: %1").arg(QFileInfo(KisImageConfig(true).swapDir()).isWritable() ? "true" : "false"));
KisUsageLogger::writeSysInfo(QString(" Undo Enabled: %1").arg(undoEnabled()? "true" : "false"));
KisUsageLogger::writeSysInfo(QString(" Undo Stack Limit: %1").arg(undoStackLimit()));
KisUsageLogger::writeSysInfo(QString(" Use OpenGL: %1").arg(useOpenGL() ? "true" : "false"));
KisUsageLogger::writeSysInfo(QString(" Use OpenGL Texture Buffer: %1").arg(useOpenGLTextureBuffer() ? "true" : "false"));
KisUsageLogger::writeSysInfo(QString(" Use AMD Vectorization Workaround: %1").arg(enableAmdVectorizationWorkaround() ? "true" : "false"));
KisUsageLogger::writeSysInfo(QString(" Canvas State: %1").arg(canvasState()));
KisUsageLogger::writeSysInfo(QString(" Autosave Interval: %1").arg(autoSaveInterval()));
KisUsageLogger::writeSysInfo(QString(" Use Backup Files: %1").arg(backupFile() ? "true" : "false"));
KisUsageLogger::writeSysInfo(QString(" Number of Backups Kept: %1").arg(m_cfg.readEntry("numberofbackupfiles", 1)));
KisUsageLogger::writeSysInfo(QString(" Backup File Suffix: %1").arg(m_cfg.readEntry("backupfilesuffix", "~")));
QString backupDir;
switch(m_cfg.readEntry("backupfilelocation", 0)) {
case 1:
backupDir = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
break;
case 2:
backupDir = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
break;
default:
// Do nothing: the empty string is user file location
backupDir = "Same Folder as the File";
}
KisUsageLogger::writeSysInfo(QString(" Backup Location: %1").arg(backupDir));
KisUsageLogger::writeSysInfo(QString(" Backup Location writable: %1").arg(QFileInfo(backupDir).isWritable() ? "true" : "false"));
KisUsageLogger::writeSysInfo(QString(" Use Win8 Pointer Input: %1").arg(useWin8PointerInput() ? "true" : "false"));
KisUsageLogger::writeSysInfo(QString(" Use RightMiddleTabletButton Workaround: %1").arg(useRightMiddleTabletButtonWorkaround() ? "true" : "false"));
KisUsageLogger::writeSysInfo(QString(" Levels of Detail Enabled: %1").arg(levelOfDetailEnabled() ? "true" : "false"));
KisUsageLogger::writeSysInfo(QString(" Use Zip64: %1").arg(useZip64() ? "true" : "false"));
KisUsageLogger::writeSysInfo("\n");
}
bool KisConfig::disableTouchOnCanvas(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("disableTouchOnCanvas", false));
}
void KisConfig::setDisableTouchOnCanvas(bool value) const
{
m_cfg.writeEntry("disableTouchOnCanvas", value);
}
bool KisConfig::disableTouchRotation(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("disableTouchRotation", false));
}
void KisConfig::setDisableTouchRotation(bool value) const
{
m_cfg.writeEntry("disableTouchRotation", value);
}
bool KisConfig::useProjections(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("useProjections", true));
}
void KisConfig::setUseProjections(bool useProj) const
{
m_cfg.writeEntry("useProjections", useProj);
}
bool KisConfig::undoEnabled(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("undoEnabled", true));
}
void KisConfig::setUndoEnabled(bool undo) const
{
m_cfg.writeEntry("undoEnabled", undo);
}
int KisConfig::undoStackLimit(bool defaultValue) const
{
return (defaultValue ? 30 : m_cfg.readEntry("undoStackLimit", 30));
}
void KisConfig::setUndoStackLimit(int limit) const
{
m_cfg.writeEntry("undoStackLimit", limit);
}
bool KisConfig::useCumulativeUndoRedo(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("useCumulativeUndoRedo",false));
}
void KisConfig::setCumulativeUndoRedo(bool value)
{
m_cfg.writeEntry("useCumulativeUndoRedo", value);
}
qreal KisConfig::stackT1(bool defaultValue) const
{
return (defaultValue ? 5 : m_cfg.readEntry("stackT1",5));
}
void KisConfig::setStackT1(int T1)
{
m_cfg.writeEntry("stackT1", T1);
}
qreal KisConfig::stackT2(bool defaultValue) const
{
return (defaultValue ? 1 : m_cfg.readEntry("stackT2",1));
}
void KisConfig::setStackT2(int T2)
{
m_cfg.writeEntry("stackT2", T2);
}
int KisConfig::stackN(bool defaultValue) const
{
return (defaultValue ? 5 : m_cfg.readEntry("stackN",5));
}
void KisConfig::setStackN(int N)
{
m_cfg.writeEntry("stackN", N);
}
qint32 KisConfig::defImageWidth(bool defaultValue) const
{
return (defaultValue ? 1600 : m_cfg.readEntry("imageWidthDef", 1600));
}
qint32 KisConfig::defImageHeight(bool defaultValue) const
{
return (defaultValue ? 1200 : m_cfg.readEntry("imageHeightDef", 1200));
}
qreal KisConfig::defImageResolution(bool defaultValue) const
{
return (defaultValue ? 100.0 : m_cfg.readEntry("imageResolutionDef", 100.0)) / 72.0;
}
QString KisConfig::defColorModel(bool defaultValue) const
{
return (defaultValue ? KoColorSpaceRegistry::instance()->rgb8()->colorModelId().id()
: m_cfg.readEntry("colorModelDef", KoColorSpaceRegistry::instance()->rgb8()->colorModelId().id()));
}
void KisConfig::defColorModel(const QString & model) const
{
m_cfg.writeEntry("colorModelDef", model);
}
QString KisConfig::defaultColorDepth(bool defaultValue) const
{
return (defaultValue ? KoColorSpaceRegistry::instance()->rgb8()->colorDepthId().id()
: m_cfg.readEntry("colorDepthDef", KoColorSpaceRegistry::instance()->rgb8()->colorDepthId().id()));
}
void KisConfig::setDefaultColorDepth(const QString & depth) const
{
m_cfg.writeEntry("colorDepthDef", depth);
}
QString KisConfig::defColorProfile(bool defaultValue) const
{
return (defaultValue ? KoColorSpaceRegistry::instance()->rgb8()->profile()->name() :
m_cfg.readEntry("colorProfileDef",
KoColorSpaceRegistry::instance()->rgb8()->profile()->name()));
}
void KisConfig::defColorProfile(const QString & profile) const
{
m_cfg.writeEntry("colorProfileDef", profile);
}
void KisConfig::defImageWidth(qint32 width) const
{
m_cfg.writeEntry("imageWidthDef", width);
}
void KisConfig::defImageHeight(qint32 height) const
{
m_cfg.writeEntry("imageHeightDef", height);
}
void KisConfig::defImageResolution(qreal res) const
{
m_cfg.writeEntry("imageResolutionDef", res*72.0);
}
int KisConfig::preferredVectorImportResolutionPPI(bool defaultValue) const
{
return defaultValue ? 100.0 : m_cfg.readEntry("preferredVectorImportResolution", 100.0);
}
void KisConfig::setPreferredVectorImportResolutionPPI(int value) const
{
m_cfg.writeEntry("preferredVectorImportResolution", value);
}
void cleanOldCursorStyleKeys(KConfigGroup &cfg)
{
if (cfg.hasKey("newCursorStyle") &&
cfg.hasKey("newOutlineStyle")) {
cfg.deleteEntry("cursorStyleDef");
}
}
CursorStyle KisConfig::newCursorStyle(bool defaultValue) const
{
if (defaultValue) {
return CURSOR_STYLE_NO_CURSOR;
}
int style = m_cfg.readEntry("newCursorStyle", int(-1));
if (style < 0) {
// old style format
style = m_cfg.readEntry("cursorStyleDef", int(OLD_CURSOR_STYLE_OUTLINE));
switch (style) {
case OLD_CURSOR_STYLE_TOOLICON:
style = CURSOR_STYLE_TOOLICON;
break;
case OLD_CURSOR_STYLE_CROSSHAIR:
case OLD_CURSOR_STYLE_OUTLINE_CENTER_CROSS:
style = CURSOR_STYLE_CROSSHAIR;
break;
case OLD_CURSOR_STYLE_POINTER:
style = CURSOR_STYLE_POINTER;
break;
case OLD_CURSOR_STYLE_OUTLINE:
case OLD_CURSOR_STYLE_NO_CURSOR:
style = CURSOR_STYLE_NO_CURSOR;
break;
case OLD_CURSOR_STYLE_SMALL_ROUND:
case OLD_CURSOR_STYLE_OUTLINE_CENTER_DOT:
style = CURSOR_STYLE_SMALL_ROUND;
break;
case OLD_CURSOR_STYLE_TRIANGLE_RIGHTHANDED:
case OLD_CURSOR_STYLE_OUTLINE_TRIANGLE_RIGHTHANDED:
style = CURSOR_STYLE_TRIANGLE_RIGHTHANDED;
break;
case OLD_CURSOR_STYLE_TRIANGLE_LEFTHANDED:
case OLD_CURSOR_STYLE_OUTLINE_TRIANGLE_LEFTHANDED:
style = CURSOR_STYLE_TRIANGLE_LEFTHANDED;
break;
default:
style = -1;
}
}
cleanOldCursorStyleKeys(m_cfg);
// compatibility with future versions
if (style < 0 || style >= N_CURSOR_STYLE_SIZE) {
style = CURSOR_STYLE_NO_CURSOR;
}
return (CursorStyle) style;
}
void KisConfig::setNewCursorStyle(CursorStyle style)
{
m_cfg.writeEntry("newCursorStyle", (int)style);
}
QColor KisConfig::getCursorMainColor(bool defaultValue) const
{
QColor col;
col.setRgbF(0.501961, 1.0, 0.501961);
return (defaultValue ? col : m_cfg.readEntry("cursorMaincColor", col));
}
void KisConfig::setCursorMainColor(const QColor &v) const
{
m_cfg.writeEntry("cursorMaincColor", v);
}
OutlineStyle KisConfig::newOutlineStyle(bool defaultValue) const
{
if (defaultValue) {
return OUTLINE_FULL;
}
int style = m_cfg.readEntry("newOutlineStyle", int(-1));
if (style < 0) {
// old style format
style = m_cfg.readEntry("cursorStyleDef", int(OLD_CURSOR_STYLE_OUTLINE));
switch (style) {
case OLD_CURSOR_STYLE_TOOLICON:
case OLD_CURSOR_STYLE_CROSSHAIR:
case OLD_CURSOR_STYLE_POINTER:
case OLD_CURSOR_STYLE_NO_CURSOR:
case OLD_CURSOR_STYLE_SMALL_ROUND:
case OLD_CURSOR_STYLE_TRIANGLE_RIGHTHANDED:
case OLD_CURSOR_STYLE_TRIANGLE_LEFTHANDED:
style = OUTLINE_NONE;
break;
case OLD_CURSOR_STYLE_OUTLINE:
case OLD_CURSOR_STYLE_OUTLINE_CENTER_DOT:
case OLD_CURSOR_STYLE_OUTLINE_CENTER_CROSS:
case OLD_CURSOR_STYLE_OUTLINE_TRIANGLE_RIGHTHANDED:
case OLD_CURSOR_STYLE_OUTLINE_TRIANGLE_LEFTHANDED:
style = OUTLINE_FULL;
break;
default:
style = -1;
}
}
cleanOldCursorStyleKeys(m_cfg);
// compatibility with future versions
if (style < 0 || style >= N_OUTLINE_STYLE_SIZE) {
style = OUTLINE_FULL;
}
return (OutlineStyle) style;
}
void KisConfig::setNewOutlineStyle(OutlineStyle style)
{
m_cfg.writeEntry("newOutlineStyle", (int)style);
}
QRect KisConfig::colorPreviewRect() const
{
return m_cfg.readEntry("colorPreviewRect", QVariant(QRect(32, 32, 48, 48))).toRect();
}
void KisConfig::setColorPreviewRect(const QRect &rect)
{
m_cfg.writeEntry("colorPreviewRect", QVariant(rect));
}
bool KisConfig::useDirtyPresets(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("useDirtyPresets", true));
}
void KisConfig::setUseDirtyPresets(bool value)
{
m_cfg.writeEntry("useDirtyPresets",value);
KisConfigNotifier::instance()->notifyConfigChanged();
}
bool KisConfig::useEraserBrushSize(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("useEraserBrushSize", false));
}
void KisConfig::setUseEraserBrushSize(bool value)
{
m_cfg.writeEntry("useEraserBrushSize",value);
KisConfigNotifier::instance()->notifyConfigChanged();
}
bool KisConfig::useEraserBrushOpacity(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("useEraserBrushOpacity",false));
}
void KisConfig::setUseEraserBrushOpacity(bool value)
{
m_cfg.writeEntry("useEraserBrushOpacity",value);
KisConfigNotifier::instance()->notifyConfigChanged();
}
QString KisConfig::getMDIBackgroundColor(bool defaultValue) const
{
QColor col(77, 77, 77);
KoColor kol(KoColorSpaceRegistry::instance()->rgb8());
kol.fromQColor(col);
QString xml = kol.toXML();
return (defaultValue ? xml : m_cfg.readEntry("mdiBackgroundColorXML", xml));
}
void KisConfig::setMDIBackgroundColor(const QString &v) const
{
m_cfg.writeEntry("mdiBackgroundColorXML", v);
}
QString KisConfig::getMDIBackgroundImage(bool defaultValue) const
{
return (defaultValue ? "" : m_cfg.readEntry("mdiBackgroundImage", ""));
}
void KisConfig::setMDIBackgroundImage(const QString &filename) const
{
m_cfg.writeEntry("mdiBackgroundImage", filename);
}
QString KisConfig::monitorProfile(int screen) const
{
// Note: keep this in sync with the default profile for the RGB colorspaces!
QString profile = m_cfg.readEntry("monitorProfile" + QString(screen == 0 ? "": QString("_%1").arg(screen)), "sRGB-elle-V2-srgbtrc.icc");
//dbgKrita << "KisConfig::monitorProfile()" << profile;
return profile;
}
QString KisConfig::monitorForScreen(int screen, const QString &defaultMonitor, bool defaultValue) const
{
return (defaultValue ? defaultMonitor
: m_cfg.readEntry(QString("monitor_for_screen_%1").arg(screen), defaultMonitor));
}
void KisConfig::setMonitorForScreen(int screen, const QString& monitor)
{
m_cfg.writeEntry(QString("monitor_for_screen_%1").arg(screen), monitor);
}
void KisConfig::setMonitorProfile(int screen, const QString & monitorProfile, bool override) const
{
m_cfg.writeEntry("monitorProfile/OverrideX11", override);
m_cfg.writeEntry("monitorProfile" + QString(screen == 0 ? "": QString("_%1").arg(screen)), monitorProfile);
}
const KoColorProfile *KisConfig::getScreenProfile(int screen)
{
if (screen < 0) return 0;
KisConfig cfg(true);
QString monitorId;
if (KisColorManager::instance()->devices().size() > screen) {
monitorId = cfg.monitorForScreen(screen, KisColorManager::instance()->devices()[screen]);
}
//dbgKrita << "getScreenProfile(). Screen" << screen << "monitor id" << monitorId;
if (monitorId.isEmpty()) {
return 0;
}
QByteArray bytes = KisColorManager::instance()->displayProfile(monitorId);
//dbgKrita << "\tgetScreenProfile()" << bytes.size();
const KoColorProfile * profile = 0;
if (bytes.length() > 0) {
profile = KoColorSpaceRegistry::instance()->createColorProfile(RGBAColorModelID.id(), Integer8BitsColorDepthID.id(), bytes);
//dbgKrita << "\tKisConfig::getScreenProfile for screen" << screen << profile->name();
}
return profile;
}
const KoColorProfile *KisConfig::displayProfile(int screen) const
{
if (screen < 0) return 0;
// if the user plays with the settings, they can override the display profile, in which case
// we don't want the system setting.
bool override = useSystemMonitorProfile();
//dbgKrita << "KisConfig::displayProfile(). Override X11:" << override;
const KoColorProfile *profile = 0;
if (override) {
//dbgKrita << "\tGoing to get the screen profile";
profile = KisConfig::getScreenProfile(screen);
}
// if it fails. check the configuration
if (!profile || !profile->isSuitableForDisplay()) {
//dbgKrita << "\tGoing to get the monitor profile";
QString monitorProfileName = monitorProfile(screen);
//dbgKrita << "\t\tmonitorProfileName:" << monitorProfileName;
if (!monitorProfileName.isEmpty()) {
profile = KoColorSpaceRegistry::instance()->profileByName(monitorProfileName);
}
if (profile) {
//dbgKrita << "\t\tsuitable for display" << profile->isSuitableForDisplay();
}
else {
//dbgKrita << "\t\tstill no profile";
}
}
// if we still don't have a profile, or the profile isn't suitable for display,
// we need to get a last-resort profile. the built-in sRGB is a good choice then.
if (!profile || !profile->isSuitableForDisplay()) {
//dbgKrita << "\tnothing worked, going to get sRGB built-in";
profile = KoColorSpaceRegistry::instance()->profileByName("sRGB Built-in");
}
if (profile) {
//dbgKrita << "\tKisConfig::displayProfile for screen" << screen << "is" << profile->name();
}
else {
//dbgKrita << "\tCouldn't get a display profile at all";
}
return profile;
}
QString KisConfig::workingColorSpace(bool defaultValue) const
{
return (defaultValue ? "RGBA" : m_cfg.readEntry("workingColorSpace", "RGBA"));
}
void KisConfig::setWorkingColorSpace(const QString & workingColorSpace) const
{
m_cfg.writeEntry("workingColorSpace", workingColorSpace);
}
QString KisConfig::printerColorSpace(bool /*defaultValue*/) const
{
//TODO currently only rgb8 is supported
//return (defaultValue ? "RGBA" : m_cfg.readEntry("printerColorSpace", "RGBA"));
return QString("RGBA");
}
void KisConfig::setPrinterColorSpace(const QString & printerColorSpace) const
{
m_cfg.writeEntry("printerColorSpace", printerColorSpace);
}
QString KisConfig::printerProfile(bool defaultValue) const
{
return (defaultValue ? "" : m_cfg.readEntry("printerProfile", ""));
}
void KisConfig::setPrinterProfile(const QString & printerProfile) const
{
m_cfg.writeEntry("printerProfile", printerProfile);
}
bool KisConfig::useBlackPointCompensation(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("useBlackPointCompensation", true));
}
void KisConfig::setUseBlackPointCompensation(bool useBlackPointCompensation) const
{
m_cfg.writeEntry("useBlackPointCompensation", useBlackPointCompensation);
}
bool KisConfig::allowLCMSOptimization(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("allowLCMSOptimization", true));
}
void KisConfig::setAllowLCMSOptimization(bool allowLCMSOptimization)
{
m_cfg.writeEntry("allowLCMSOptimization", allowLCMSOptimization);
}
bool KisConfig::forcePaletteColors(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("colorsettings/forcepalettecolors", false));
}
void KisConfig::setForcePaletteColors(bool forcePaletteColors)
{
m_cfg.writeEntry("colorsettings/forcepalettecolors", forcePaletteColors);
}
bool KisConfig::showRulers(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("showrulers", false));
}
void KisConfig::setShowRulers(bool rulers) const
{
m_cfg.writeEntry("showrulers", rulers);
}
bool KisConfig::forceShowSaveMessages(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("forceShowSaveMessages", false));
}
void KisConfig::setForceShowSaveMessages(bool value) const
{
m_cfg.writeEntry("forceShowSaveMessages", value);
}
bool KisConfig::forceShowAutosaveMessages(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("forceShowAutosaveMessages", false));
}
void KisConfig::setForceShowAutosaveMessages(bool value) const
{
m_cfg.writeEntry("forceShowAutosaveMessages", value);
}
bool KisConfig::rulersTrackMouse(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("rulersTrackMouse", true));
}
void KisConfig::setRulersTrackMouse(bool value) const
{
m_cfg.writeEntry("rulersTrackMouse", value);
}
qint32 KisConfig::pasteBehaviour(bool defaultValue) const
{
return (defaultValue ? 2 : m_cfg.readEntry("pasteBehaviour", 2));
}
void KisConfig::setPasteBehaviour(qint32 renderIntent) const
{
m_cfg.writeEntry("pasteBehaviour", renderIntent);
}
qint32 KisConfig::monitorRenderIntent(bool defaultValue) const
{
qint32 intent = m_cfg.readEntry("renderIntent", INTENT_PERCEPTUAL);
if (intent > 3) intent = 3;
if (intent < 0) intent = 0;
return (defaultValue ? INTENT_PERCEPTUAL : intent);
}
void KisConfig::setRenderIntent(qint32 renderIntent) const
{
if (renderIntent > 3) renderIntent = 3;
if (renderIntent < 0) renderIntent = 0;
m_cfg.writeEntry("renderIntent", renderIntent);
}
bool KisConfig::useOpenGL(bool defaultValue) const
{
if (defaultValue) {
return true;
}
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
return kritarc.value("OpenGLRenderer", "auto").toString() != "none";
}
void KisConfig::disableOpenGL() const
{
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
kritarc.setValue("OpenGLRenderer", "none");
}
int KisConfig::openGLFilteringMode(bool defaultValue) const
{
return (defaultValue ? 3 : m_cfg.readEntry("OpenGLFilterMode", 3));
}
void KisConfig::setOpenGLFilteringMode(int filteringMode)
{
m_cfg.writeEntry("OpenGLFilterMode", filteringMode);
}
+void KisConfig::setWidgetStyle(QString name)
+{
+ m_cfg.writeEntry("widgetStyle", name);
+}
+
+QString KisConfig::widgetStyle(bool defaultValue)
+{
+ return (defaultValue ? "" : m_cfg.readEntry("widgetStyle", ""));
+}
+
bool KisConfig::useOpenGLTextureBuffer(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("useOpenGLTextureBuffer", true));
}
void KisConfig::setUseOpenGLTextureBuffer(bool useBuffer)
{
m_cfg.writeEntry("useOpenGLTextureBuffer", useBuffer);
}
int KisConfig::openGLTextureSize(bool defaultValue) const
{
return (defaultValue ? 256 : m_cfg.readEntry("textureSize", 256));
}
bool KisConfig::disableVSync(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("disableVSync", true));
}
void KisConfig::setDisableVSync(bool disableVSync)
{
m_cfg.writeEntry("disableVSync", disableVSync);
}
bool KisConfig::showAdvancedOpenGLSettings(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("showAdvancedOpenGLSettings", false));
}
bool KisConfig::forceOpenGLFenceWorkaround(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("forceOpenGLFenceWorkaround", false));
}
int KisConfig::numMipmapLevels(bool defaultValue) const
{
return (defaultValue ? 4 : m_cfg.readEntry("numMipmapLevels", 4));
}
int KisConfig::textureOverlapBorder() const
{
return 1 << qMax(0, numMipmapLevels());
}
quint32 KisConfig::getGridMainStyle(bool defaultValue) const
{
int v = m_cfg.readEntry("gridmainstyle", 0);
v = qBound(0, v, 2);
return (defaultValue ? 0 : v);
}
void KisConfig::setGridMainStyle(quint32 v) const
{
m_cfg.writeEntry("gridmainstyle", v);
}
quint32 KisConfig::getGridSubdivisionStyle(bool defaultValue) const
{
quint32 v = m_cfg.readEntry("gridsubdivisionstyle", 1);
if (v > 2) v = 2;
return (defaultValue ? 1 : v);
}
void KisConfig::setGridSubdivisionStyle(quint32 v) const
{
m_cfg.writeEntry("gridsubdivisionstyle", v);
}
QColor KisConfig::getGridMainColor(bool defaultValue) const
{
QColor col(99, 99, 99);
return (defaultValue ? col : m_cfg.readEntry("gridmaincolor", col));
}
void KisConfig::setGridMainColor(const QColor & v) const
{
m_cfg.writeEntry("gridmaincolor", v);
}
QColor KisConfig::getGridSubdivisionColor(bool defaultValue) const
{
QColor col(150, 150, 150);
return (defaultValue ? col : m_cfg.readEntry("gridsubdivisioncolor", col));
}
void KisConfig::setGridSubdivisionColor(const QColor & v) const
{
m_cfg.writeEntry("gridsubdivisioncolor", v);
}
QColor KisConfig::getPixelGridColor(bool defaultValue) const
{
QColor col(255, 255, 255);
return (defaultValue ? col : m_cfg.readEntry("pixelGridColor", col));
}
void KisConfig::setPixelGridColor(const QColor & v) const
{
m_cfg.writeEntry("pixelGridColor", v);
}
qreal KisConfig::getPixelGridDrawingThreshold(bool defaultValue) const
{
qreal border = 24.0f;
return (defaultValue ? border : m_cfg.readEntry("pixelGridDrawingThreshold", border));
}
void KisConfig::setPixelGridDrawingThreshold(qreal v) const
{
m_cfg.writeEntry("pixelGridDrawingThreshold", v);
}
bool KisConfig::pixelGridEnabled(bool defaultValue) const
{
bool enabled = true;
return (defaultValue ? enabled : m_cfg.readEntry("pixelGridEnabled", enabled));
}
void KisConfig::enablePixelGrid(bool v) const
{
m_cfg.writeEntry("pixelGridEnabled", v);
}
quint32 KisConfig::guidesLineStyle(bool defaultValue) const
{
int v = m_cfg.readEntry("guidesLineStyle", 0);
v = qBound(0, v, 2);
return (defaultValue ? 0 : v);
}
void KisConfig::setGuidesLineStyle(quint32 v) const
{
m_cfg.writeEntry("guidesLineStyle", v);
}
QColor KisConfig::guidesColor(bool defaultValue) const
{
QColor col(99, 99, 99);
return (defaultValue ? col : m_cfg.readEntry("guidesColor", col));
}
void KisConfig::setGuidesColor(const QColor & v) const
{
m_cfg.writeEntry("guidesColor", v);
}
void KisConfig::loadSnapConfig(KisSnapConfig *config, bool defaultValue) const
{
KisSnapConfig defaultConfig(false);
if (defaultValue) {
*config = defaultConfig;
return;
}
config->setOrthogonal(m_cfg.readEntry("globalSnapOrthogonal", defaultConfig.orthogonal()));
config->setNode(m_cfg.readEntry("globalSnapNode", defaultConfig.node()));
config->setExtension(m_cfg.readEntry("globalSnapExtension", defaultConfig.extension()));
config->setIntersection(m_cfg.readEntry("globalSnapIntersection", defaultConfig.intersection()));
config->setBoundingBox(m_cfg.readEntry("globalSnapBoundingBox", defaultConfig.boundingBox()));
config->setImageBounds(m_cfg.readEntry("globalSnapImageBounds", defaultConfig.imageBounds()));
config->setImageCenter(m_cfg.readEntry("globalSnapImageCenter", defaultConfig.imageCenter()));
config->setToPixel(m_cfg.readEntry("globalSnapToPixel", defaultConfig.toPixel()));
}
void KisConfig::saveSnapConfig(const KisSnapConfig &config)
{
m_cfg.writeEntry("globalSnapOrthogonal", config.orthogonal());
m_cfg.writeEntry("globalSnapNode", config.node());
m_cfg.writeEntry("globalSnapExtension", config.extension());
m_cfg.writeEntry("globalSnapIntersection", config.intersection());
m_cfg.writeEntry("globalSnapBoundingBox", config.boundingBox());
m_cfg.writeEntry("globalSnapImageBounds", config.imageBounds());
m_cfg.writeEntry("globalSnapImageCenter", config.imageCenter());
m_cfg.writeEntry("globalSnapToPixel", config.toPixel());
}
qint32 KisConfig::checkSize(bool defaultValue) const
{
qint32 size = (defaultValue ? 32 : m_cfg.readEntry("checksize", 32));
if (size == 0) size = 32;
return size;
}
void KisConfig::setCheckSize(qint32 checksize) const
{
if (checksize == 0) {
checksize = 32;
}
m_cfg.writeEntry("checksize", checksize);
}
bool KisConfig::scrollCheckers(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("scrollingcheckers", false));
}
void KisConfig::setScrollingCheckers(bool sc) const
{
m_cfg.writeEntry("scrollingcheckers", sc);
}
QColor KisConfig::canvasBorderColor(bool defaultValue) const
{
QColor color(QColor(128,128,128));
return (defaultValue ? color : m_cfg.readEntry("canvasBorderColor", color));
}
void KisConfig::setCanvasBorderColor(const QColor& color) const
{
m_cfg.writeEntry("canvasBorderColor", color);
}
bool KisConfig::hideScrollbars(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("hideScrollbars", false));
}
void KisConfig::setHideScrollbars(bool value) const
{
m_cfg.writeEntry("hideScrollbars", value);
}
QColor KisConfig::checkersColor1(bool defaultValue) const
{
QColor col(220, 220, 220);
return (defaultValue ? col : m_cfg.readEntry("checkerscolor", col));
}
void KisConfig::setCheckersColor1(const QColor & v) const
{
m_cfg.writeEntry("checkerscolor", v);
}
QColor KisConfig::checkersColor2(bool defaultValue) const
{
return (defaultValue ? QColor(Qt::white) : m_cfg.readEntry("checkerscolor2", QColor(Qt::white)));
}
void KisConfig::setCheckersColor2(const QColor & v) const
{
m_cfg.writeEntry("checkerscolor2", v);
}
bool KisConfig::antialiasCurves(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("antialiascurves", true));
}
void KisConfig::setAntialiasCurves(bool v) const
{
m_cfg.writeEntry("antialiascurves", v);
}
bool KisConfig::antialiasSelectionOutline(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("AntialiasSelectionOutline", false));
}
void KisConfig::setAntialiasSelectionOutline(bool v) const
{
m_cfg.writeEntry("AntialiasSelectionOutline", v);
}
bool KisConfig::showRootLayer(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("ShowRootLayer", false));
}
void KisConfig::setShowRootLayer(bool showRootLayer) const
{
m_cfg.writeEntry("ShowRootLayer", showRootLayer);
}
bool KisConfig::showGlobalSelection(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("ShowGlobalSelection", false));
}
void KisConfig::setShowGlobalSelection(bool showGlobalSelection) const
{
m_cfg.writeEntry("ShowGlobalSelection", showGlobalSelection);
}
bool KisConfig::showOutlineWhilePainting(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("ShowOutlineWhilePainting", true));
}
void KisConfig::setShowOutlineWhilePainting(bool showOutlineWhilePainting) const
{
m_cfg.writeEntry("ShowOutlineWhilePainting", showOutlineWhilePainting);
}
bool KisConfig::forceAlwaysFullSizedOutline(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("forceAlwaysFullSizedOutline", false));
}
void KisConfig::setForceAlwaysFullSizedOutline(bool value) const
{
m_cfg.writeEntry("forceAlwaysFullSizedOutline", value);
}
KisConfig::SessionOnStartup KisConfig::sessionOnStartup(bool defaultValue) const
{
int value = defaultValue ? SOS_BlankSession : m_cfg.readEntry("sessionOnStartup", (int)SOS_BlankSession);
return (KisConfig::SessionOnStartup)value;
}
void KisConfig::setSessionOnStartup(SessionOnStartup value)
{
m_cfg.writeEntry("sessionOnStartup", (int)value);
}
bool KisConfig::saveSessionOnQuit(bool defaultValue) const
{
return defaultValue ? false : m_cfg.readEntry("saveSessionOnQuit", false);
}
void KisConfig::setSaveSessionOnQuit(bool value)
{
m_cfg.writeEntry("saveSessionOnQuit", value);
}
qreal KisConfig::outlineSizeMinimum(bool defaultValue) const
{
return (defaultValue ? 1.0 : m_cfg.readEntry("OutlineSizeMinimum", 1.0));
}
void KisConfig::setOutlineSizeMinimum(qreal outlineSizeMinimum) const
{
m_cfg.writeEntry("OutlineSizeMinimum", outlineSizeMinimum);
}
qreal KisConfig::selectionViewSizeMinimum(bool defaultValue) const
{
return (defaultValue ? 5.0 : m_cfg.readEntry("SelectionViewSizeMinimum", 5.0));
}
void KisConfig::setSelectionViewSizeMinimum(qreal outlineSizeMinimum) const
{
m_cfg.writeEntry("SelectionViewSizeMinimum", outlineSizeMinimum);
}
int KisConfig::autoSaveInterval(bool defaultValue) const
{
return (defaultValue ? 15 * 60 : m_cfg.readEntry("AutoSaveInterval", 15 * 60));
}
void KisConfig::setAutoSaveInterval(int seconds) const
{
return m_cfg.writeEntry("AutoSaveInterval", seconds);
}
bool KisConfig::backupFile(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("CreateBackupFile", true));
}
void KisConfig::setBackupFile(bool backupFile) const
{
m_cfg.writeEntry("CreateBackupFile", backupFile);
}
bool KisConfig::showFilterGallery(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("showFilterGallery", false));
}
void KisConfig::setShowFilterGallery(bool showFilterGallery) const
{
m_cfg.writeEntry("showFilterGallery", showFilterGallery);
}
bool KisConfig::showFilterGalleryLayerMaskDialog(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("showFilterGalleryLayerMaskDialog", true));
}
void KisConfig::setShowFilterGalleryLayerMaskDialog(bool showFilterGallery) const
{
m_cfg.writeEntry("setShowFilterGalleryLayerMaskDialog", showFilterGallery);
}
QString KisConfig::canvasState(bool defaultValue) const
{
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
return (defaultValue ? "OPENGL_NOT_TRIED" : kritarc.value("canvasState", "OPENGL_NOT_TRIED").toString());
}
void KisConfig::setCanvasState(const QString& state) const
{
static QStringList acceptableStates;
if (acceptableStates.isEmpty()) {
acceptableStates << "OPENGL_SUCCESS" << "TRY_OPENGL" << "OPENGL_NOT_TRIED" << "OPENGL_FAILED";
}
if (acceptableStates.contains(state)) {
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
kritarc.setValue("canvasState", state);
}
}
bool KisConfig::toolOptionsPopupDetached(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("ToolOptionsPopupDetached", false));
}
void KisConfig::setToolOptionsPopupDetached(bool detached) const
{
m_cfg.writeEntry("ToolOptionsPopupDetached", detached);
}
bool KisConfig::paintopPopupDetached(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("PaintopPopupDetached", false));
}
void KisConfig::setPaintopPopupDetached(bool detached) const
{
m_cfg.writeEntry("PaintopPopupDetached", detached);
}
QString KisConfig::pressureTabletCurve(bool defaultValue) const
{
return (defaultValue ? "0,0;1,1" : m_cfg.readEntry("tabletPressureCurve","0,0;1,1;"));
}
void KisConfig::setPressureTabletCurve(const QString& curveString) const
{
m_cfg.writeEntry("tabletPressureCurve", curveString);
}
bool KisConfig::useWin8PointerInput(bool defaultValue) const
{
#ifdef Q_OS_WIN
#ifdef USE_QT_TABLET_WINDOWS
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
return useWin8PointerInputNoApp(&kritarc, defaultValue);
#else
return (defaultValue ? false : m_cfg.readEntry("useWin8PointerInput", false));
#endif
#else
Q_UNUSED(defaultValue);
return false;
#endif
}
void KisConfig::setUseWin8PointerInput(bool value)
{
#ifdef Q_OS_WIN
// Special handling: Only set value if changed
// I don't want it to be set if the user hasn't touched it
if (useWin8PointerInput() != value) {
#ifdef USE_QT_TABLET_WINDOWS
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
setUseWin8PointerInputNoApp(&kritarc, value);
#else
m_cfg.writeEntry("useWin8PointerInput", value);
#endif
}
#else
Q_UNUSED(value)
#endif
}
bool KisConfig::useWin8PointerInputNoApp(QSettings *settings, bool defaultValue)
{
return defaultValue ? false : settings->value("useWin8PointerInput", false).toBool();
}
void KisConfig::setUseWin8PointerInputNoApp(QSettings *settings, bool value)
{
settings->setValue("useWin8PointerInput", value);
}
bool KisConfig::useRightMiddleTabletButtonWorkaround(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("useRightMiddleTabletButtonWorkaround", false));
}
void KisConfig::setUseRightMiddleTabletButtonWorkaround(bool value)
{
m_cfg.writeEntry("useRightMiddleTabletButtonWorkaround", value);
}
qreal KisConfig::vastScrolling(bool defaultValue) const
{
return (defaultValue ? 0.9 : m_cfg.readEntry("vastScrolling", 0.9));
}
void KisConfig::setVastScrolling(const qreal factor) const
{
m_cfg.writeEntry("vastScrolling", factor);
}
int KisConfig::presetChooserViewMode(bool defaultValue) const
{
return (defaultValue ? 0 : m_cfg.readEntry("presetChooserViewMode", 0));
}
void KisConfig::setPresetChooserViewMode(const int mode) const
{
m_cfg.writeEntry("presetChooserViewMode", mode);
}
int KisConfig::presetIconSize(bool defaultValue) const
{
return (defaultValue ? 60 : m_cfg.readEntry("presetIconSize", 60));
}
void KisConfig::setPresetIconSize(const int value) const
{
m_cfg.writeEntry("presetIconSize", value);
}
bool KisConfig::firstRun(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("firstRun", true));
}
void KisConfig::setFirstRun(const bool first) const
{
m_cfg.writeEntry("firstRun", first);
}
int KisConfig::horizontalSplitLines(bool defaultValue) const
{
return (defaultValue ? 1 : m_cfg.readEntry("horizontalSplitLines", 1));
}
void KisConfig::setHorizontalSplitLines(const int numberLines) const
{
m_cfg.writeEntry("horizontalSplitLines", numberLines);
}
int KisConfig::verticalSplitLines(bool defaultValue) const
{
return (defaultValue ? 1 : m_cfg.readEntry("verticalSplitLines", 1));
}
void KisConfig::setVerticalSplitLines(const int numberLines) const
{
m_cfg.writeEntry("verticalSplitLines", numberLines);
}
bool KisConfig::clicklessSpacePan(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("clicklessSpacePan", true));
}
void KisConfig::setClicklessSpacePan(const bool toggle) const
{
m_cfg.writeEntry("clicklessSpacePan", toggle);
}
bool KisConfig::hideDockersFullscreen(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("hideDockersFullScreen", true));
}
void KisConfig::setHideDockersFullscreen(const bool value) const
{
m_cfg.writeEntry("hideDockersFullScreen", value);
}
bool KisConfig::showDockers(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("showDockers", true));
}
void KisConfig::setShowDockers(const bool value) const
{
m_cfg.writeEntry("showDockers", value);
}
bool KisConfig::showStatusBar(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("showStatusBar", true));
}
void KisConfig::setShowStatusBar(const bool value) const
{
m_cfg.writeEntry("showStatusBar", value);
}
bool KisConfig::hideMenuFullscreen(bool defaultValue) const
{
return (defaultValue ? true: m_cfg.readEntry("hideMenuFullScreen", true));
}
void KisConfig::setHideMenuFullscreen(const bool value) const
{
m_cfg.writeEntry("hideMenuFullScreen", value);
}
bool KisConfig::hideScrollbarsFullscreen(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("hideScrollbarsFullScreen", true));
}
void KisConfig::setHideScrollbarsFullscreen(const bool value) const
{
m_cfg.writeEntry("hideScrollbarsFullScreen", value);
}
bool KisConfig::hideStatusbarFullscreen(bool defaultValue) const
{
return (defaultValue ? true: m_cfg.readEntry("hideStatusbarFullScreen", true));
}
void KisConfig::setHideStatusbarFullscreen(const bool value) const
{
m_cfg.writeEntry("hideStatusbarFullScreen", value);
}
bool KisConfig::hideTitlebarFullscreen(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("hideTitleBarFullscreen", true));
}
void KisConfig::setHideTitlebarFullscreen(const bool value) const
{
m_cfg.writeEntry("hideTitleBarFullscreen", value);
}
bool KisConfig::hideToolbarFullscreen(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("hideToolbarFullscreen", true));
}
void KisConfig::setHideToolbarFullscreen(const bool value) const
{
m_cfg.writeEntry("hideToolbarFullscreen", value);
}
bool KisConfig::fullscreenMode(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("fullscreenMode", true));
}
void KisConfig::setFullscreenMode(const bool value) const
{
m_cfg.writeEntry("fullscreenMode", value);
}
QStringList KisConfig::favoriteCompositeOps(bool defaultValue) const
{
return (defaultValue ? QStringList() :
m_cfg.readEntry("favoriteCompositeOps",
QString("normal,erase,multiply,burn,darken,add,dodge,screen,overlay,soft_light_svg,luminize,lighten,saturation,color,divide").split(',')));
}
void KisConfig::setFavoriteCompositeOps(const QStringList& compositeOps) const
{
m_cfg.writeEntry("favoriteCompositeOps", compositeOps);
}
QString KisConfig::exportConfigurationXML(const QString &filterId, bool defaultValue) const
{
return (defaultValue ? QString() : m_cfg.readEntry("ExportConfiguration-" + filterId, QString()));
}
KisPropertiesConfigurationSP KisConfig::exportConfiguration(const QString &filterId, bool defaultValue) const
{
KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration();
const QString xmlData = exportConfigurationXML(filterId, defaultValue);
cfg->fromXML(xmlData);
return cfg;
}
void KisConfig::setExportConfiguration(const QString &filterId, KisPropertiesConfigurationSP properties) const
{
QString exportConfig = properties->toXML();
m_cfg.writeEntry("ExportConfiguration-" + filterId, exportConfig);
}
QString KisConfig::importConfiguration(const QString &filterId, bool defaultValue) const
{
return (defaultValue ? QString() : m_cfg.readEntry("ImportConfiguration-" + filterId, QString()));
}
void KisConfig::setImportConfiguration(const QString &filterId, KisPropertiesConfigurationSP properties) const
{
QString importConfig = properties->toXML();
m_cfg.writeEntry("ImportConfiguration-" + filterId, importConfig);
}
bool KisConfig::useOcio(bool defaultValue) const
{
#ifdef HAVE_OCIO
return (defaultValue ? false : m_cfg.readEntry("Krita/Ocio/UseOcio", false));
#else
Q_UNUSED(defaultValue);
return false;
#endif
}
void KisConfig::setUseOcio(bool useOCIO) const
{
m_cfg.writeEntry("Krita/Ocio/UseOcio", useOCIO);
}
int KisConfig::favoritePresets(bool defaultValue) const
{
return (defaultValue ? 10 : m_cfg.readEntry("numFavoritePresets", 10));
}
void KisConfig::setFavoritePresets(const int value)
{
m_cfg.writeEntry("numFavoritePresets", value);
}
bool KisConfig::levelOfDetailEnabled(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("levelOfDetailEnabled", false));
}
void KisConfig::setLevelOfDetailEnabled(bool value)
{
m_cfg.writeEntry("levelOfDetailEnabled", value);
}
KisOcioConfiguration KisConfig::ocioConfiguration(bool defaultValue) const
{
KisOcioConfiguration cfg;
if (!defaultValue) {
cfg.mode = (KisOcioConfiguration::Mode)m_cfg.readEntry("Krita/Ocio/OcioColorManagementMode", 0);
cfg.configurationPath = m_cfg.readEntry("Krita/Ocio/OcioConfigPath", QString());
cfg.lutPath = m_cfg.readEntry("Krita/Ocio/OcioLutPath", QString());
cfg.inputColorSpace = m_cfg.readEntry("Krita/Ocio/InputColorSpace", QString());
cfg.displayDevice = m_cfg.readEntry("Krita/Ocio/DisplayDevice", QString());
cfg.displayView = m_cfg.readEntry("Krita/Ocio/DisplayView", QString());
cfg.look = m_cfg.readEntry("Krita/Ocio/DisplayLook", QString());
}
return cfg;
}
void KisConfig::setOcioConfiguration(const KisOcioConfiguration &cfg)
{
m_cfg.writeEntry("Krita/Ocio/OcioColorManagementMode", (int) cfg.mode);
m_cfg.writeEntry("Krita/Ocio/OcioConfigPath", cfg.configurationPath);
m_cfg.writeEntry("Krita/Ocio/OcioLutPath", cfg.lutPath);
m_cfg.writeEntry("Krita/Ocio/InputColorSpace", cfg.inputColorSpace);
m_cfg.writeEntry("Krita/Ocio/DisplayDevice", cfg.displayDevice);
m_cfg.writeEntry("Krita/Ocio/DisplayView", cfg.displayView);
m_cfg.writeEntry("Krita/Ocio/DisplayLook", cfg.look);
}
KisConfig::OcioColorManagementMode
KisConfig::ocioColorManagementMode(bool defaultValue) const
{
// FIXME: this option duplicates ocioConfiguration(), please deprecate it
return (OcioColorManagementMode)(defaultValue ? INTERNAL
: m_cfg.readEntry("Krita/Ocio/OcioColorManagementMode", (int) INTERNAL));
}
void KisConfig::setOcioColorManagementMode(OcioColorManagementMode mode) const
{
// FIXME: this option duplicates ocioConfiguration(), please deprecate it
m_cfg.writeEntry("Krita/Ocio/OcioColorManagementMode", (int) mode);
}
int KisConfig::ocioLutEdgeSize(bool defaultValue) const
{
return (defaultValue ? 64 : m_cfg.readEntry("Krita/Ocio/LutEdgeSize", 64));
}
void KisConfig::setOcioLutEdgeSize(int value)
{
m_cfg.writeEntry("Krita/Ocio/LutEdgeSize", value);
}
bool KisConfig::ocioLockColorVisualRepresentation(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("Krita/Ocio/OcioLockColorVisualRepresentation", false));
}
void KisConfig::setOcioLockColorVisualRepresentation(bool value)
{
m_cfg.writeEntry("Krita/Ocio/OcioLockColorVisualRepresentation", value);
}
QString KisConfig::defaultPalette(bool defaultValue) const
{
return (defaultValue ? QString() : m_cfg.readEntry("defaultPalette", "Default"));
}
void KisConfig::setDefaultPalette(const QString& name) const
{
m_cfg.writeEntry("defaultPalette", name);
}
QString KisConfig::toolbarSlider(int sliderNumber, bool defaultValue) const
{
QString def = "flow";
if (sliderNumber == 1) {
def = "opacity";
}
if (sliderNumber == 2) {
def = "size";
}
return (defaultValue ? def : m_cfg.readEntry(QString("toolbarslider_%1").arg(sliderNumber), def));
}
void KisConfig::setToolbarSlider(int sliderNumber, const QString &slider)
{
m_cfg.writeEntry(QString("toolbarslider_%1").arg(sliderNumber), slider);
}
int KisConfig::layerThumbnailSize(bool defaultValue) const
{
return (defaultValue ? 20 : m_cfg.readEntry("layerThumbnailSize", 20));
}
void KisConfig::setLayerThumbnailSize(int size)
{
m_cfg.writeEntry("layerThumbnailSize", size);
}
bool KisConfig::sliderLabels(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("sliderLabels", true));
}
void KisConfig::setSliderLabels(bool enabled)
{
m_cfg.writeEntry("sliderLabels", enabled);
}
QString KisConfig::currentInputProfile(bool defaultValue) const
{
return (defaultValue ? QString() : m_cfg.readEntry("currentInputProfile", QString()));
}
void KisConfig::setCurrentInputProfile(const QString& name)
{
m_cfg.writeEntry("currentInputProfile", name);
}
bool KisConfig::useSystemMonitorProfile(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("ColorManagement/UseSystemMonitorProfile", false));
}
void KisConfig::setUseSystemMonitorProfile(bool _useSystemMonitorProfile) const
{
m_cfg.writeEntry("ColorManagement/UseSystemMonitorProfile", _useSystemMonitorProfile);
}
bool KisConfig::presetStripVisible(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("presetStripVisible", true));
}
void KisConfig::setPresetStripVisible(bool visible)
{
m_cfg.writeEntry("presetStripVisible", visible);
}
bool KisConfig::scratchpadVisible(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("scratchpadVisible", true));
}
void KisConfig::setScratchpadVisible(bool visible)
{
m_cfg.writeEntry("scratchpadVisible", visible);
}
bool KisConfig::showSingleChannelAsColor(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("showSingleChannelAsColor", false));
}
void KisConfig::setShowSingleChannelAsColor(bool asColor)
{
m_cfg.writeEntry("showSingleChannelAsColor", asColor);
}
bool KisConfig::hidePopups(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("hidePopups", false));
}
void KisConfig::setHidePopups(bool hidepopups)
{
m_cfg.writeEntry("hidePopups", hidepopups);
}
int KisConfig::numDefaultLayers(bool defaultValue) const
{
return (defaultValue ? 2 : m_cfg.readEntry("NumberOfLayersForNewImage", 2));
}
void KisConfig::setNumDefaultLayers(int num)
{
m_cfg.writeEntry("NumberOfLayersForNewImage", num);
}
quint8 KisConfig::defaultBackgroundOpacity(bool defaultValue) const
{
return (defaultValue ? (int)OPACITY_OPAQUE_U8 : m_cfg.readEntry("BackgroundOpacityForNewImage", (int)OPACITY_OPAQUE_U8));
}
void KisConfig::setDefaultBackgroundOpacity(quint8 value)
{
m_cfg.writeEntry("BackgroundOpacityForNewImage", (int)value);
}
QColor KisConfig::defaultBackgroundColor(bool defaultValue) const
{
return (defaultValue ? QColor(Qt::white) : m_cfg.readEntry("BackgroundColorForNewImage", QColor(Qt::white)));
}
void KisConfig::setDefaultBackgroundColor(const QColor &value)
{
m_cfg.writeEntry("BackgroundColorForNewImage", value);
}
KisConfig::BackgroundStyle KisConfig::defaultBackgroundStyle(bool defaultValue) const
{
return (KisConfig::BackgroundStyle)(defaultValue ? RASTER_LAYER : m_cfg.readEntry("BackgroundStyleForNewImage", (int)RASTER_LAYER));
}
void KisConfig::setDefaultBackgroundStyle(KisConfig::BackgroundStyle value)
{
m_cfg.writeEntry("BackgroundStyleForNewImage", (int)value);
}
int KisConfig::lineSmoothingType(bool defaultValue) const
{
return (defaultValue ? 1 : m_cfg.readEntry("LineSmoothingType", 1));
}
void KisConfig::setLineSmoothingType(int value)
{
m_cfg.writeEntry("LineSmoothingType", value);
}
qreal KisConfig::lineSmoothingDistance(bool defaultValue) const
{
return (defaultValue ? 50.0 : m_cfg.readEntry("LineSmoothingDistance", 50.0));
}
void KisConfig::setLineSmoothingDistance(qreal value)
{
m_cfg.writeEntry("LineSmoothingDistance", value);
}
qreal KisConfig::lineSmoothingTailAggressiveness(bool defaultValue) const
{
return (defaultValue ? 0.15 : m_cfg.readEntry("LineSmoothingTailAggressiveness", 0.15));
}
void KisConfig::setLineSmoothingTailAggressiveness(qreal value)
{
m_cfg.writeEntry("LineSmoothingTailAggressiveness", value);
}
bool KisConfig::lineSmoothingSmoothPressure(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("LineSmoothingSmoothPressure", false));
}
void KisConfig::setLineSmoothingSmoothPressure(bool value)
{
m_cfg.writeEntry("LineSmoothingSmoothPressure", value);
}
bool KisConfig::lineSmoothingScalableDistance(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("LineSmoothingScalableDistance", true));
}
void KisConfig::setLineSmoothingScalableDistance(bool value)
{
m_cfg.writeEntry("LineSmoothingScalableDistance", value);
}
qreal KisConfig::lineSmoothingDelayDistance(bool defaultValue) const
{
return (defaultValue ? 50.0 : m_cfg.readEntry("LineSmoothingDelayDistance", 50.0));
}
void KisConfig::setLineSmoothingDelayDistance(qreal value)
{
m_cfg.writeEntry("LineSmoothingDelayDistance", value);
}
bool KisConfig::lineSmoothingUseDelayDistance(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("LineSmoothingUseDelayDistance", true));
}
void KisConfig::setLineSmoothingUseDelayDistance(bool value)
{
m_cfg.writeEntry("LineSmoothingUseDelayDistance", value);
}
bool KisConfig::lineSmoothingFinishStabilizedCurve(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("LineSmoothingFinishStabilizedCurve", true));
}
void KisConfig::setLineSmoothingFinishStabilizedCurve(bool value)
{
m_cfg.writeEntry("LineSmoothingFinishStabilizedCurve", value);
}
bool KisConfig::lineSmoothingStabilizeSensors(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("LineSmoothingStabilizeSensors", true));
}
void KisConfig::setLineSmoothingStabilizeSensors(bool value)
{
m_cfg.writeEntry("LineSmoothingStabilizeSensors", value);
}
int KisConfig::tabletEventsDelay(bool defaultValue) const
{
return (defaultValue ? 10 : m_cfg.readEntry("tabletEventsDelay", 10));
}
void KisConfig::setTabletEventsDelay(int value)
{
m_cfg.writeEntry("tabletEventsDelay", value);
}
bool KisConfig::trackTabletEventLatency(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("trackTabletEventLatency", false));
}
void KisConfig::setTrackTabletEventLatency(bool value)
{
m_cfg.writeEntry("trackTabletEventLatency", value);
}
bool KisConfig::testingAcceptCompressedTabletEvents(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("testingAcceptCompressedTabletEvents", false));
}
void KisConfig::setTestingAcceptCompressedTabletEvents(bool value)
{
m_cfg.writeEntry("testingAcceptCompressedTabletEvents", value);
}
bool KisConfig::shouldEatDriverShortcuts(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("shouldEatDriverShortcuts", false));
}
bool KisConfig::testingCompressBrushEvents(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("testingCompressBrushEvents", false));
}
void KisConfig::setTestingCompressBrushEvents(bool value)
{
m_cfg.writeEntry("testingCompressBrushEvents", value);
}
int KisConfig::workaroundX11SmoothPressureSteps(bool defaultValue) const
{
return (defaultValue ? 0 : m_cfg.readEntry("workaroundX11SmoothPressureSteps", 0));
}
bool KisConfig::showCanvasMessages(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("showOnCanvasMessages", true));
}
void KisConfig::setShowCanvasMessages(bool show)
{
m_cfg.writeEntry("showOnCanvasMessages", show);
}
bool KisConfig::compressKra(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("compressLayersInKra", false));
}
void KisConfig::setCompressKra(bool compress)
{
m_cfg.writeEntry("compressLayersInKra", compress);
}
bool KisConfig::trimKra(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("TrimKra", false));
}
void KisConfig::setTrimKra(bool trim)
{
m_cfg.writeEntry("TrimKra", trim);
}
bool KisConfig::toolOptionsInDocker(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("ToolOptionsInDocker", true));
}
void KisConfig::setToolOptionsInDocker(bool inDocker)
{
m_cfg.writeEntry("ToolOptionsInDocker", inDocker);
}
bool KisConfig::kineticScrollingEnabled(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("KineticScrollingEnabled", true));
}
void KisConfig::setKineticScrollingEnabled(bool value)
{
m_cfg.writeEntry("KineticScrollingEnabled", value);
}
int KisConfig::kineticScrollingGesture(bool defaultValue) const
{
#ifdef Q_OS_ANDROID
int defaultGesture = 0; // TouchGesture
#else
int defaultGesture = 2; // MiddleMouseButtonGesture
#endif
return (defaultValue ? defaultGesture : m_cfg.readEntry("KineticScrollingGesture", defaultGesture));
}
void KisConfig::setKineticScrollingGesture(int gesture)
{
m_cfg.writeEntry("KineticScrollingGesture", gesture);
}
int KisConfig::kineticScrollingSensitivity(bool defaultValue) const
{
return (defaultValue ? 75 : m_cfg.readEntry("KineticScrollingSensitivity", 75));
}
void KisConfig::setKineticScrollingSensitivity(int sensitivity)
{
m_cfg.writeEntry("KineticScrollingSensitivity", sensitivity);
}
bool KisConfig::kineticScrollingHiddenScrollbars(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("KineticScrollingHideScrollbar", false));
}
void KisConfig::setKineticScrollingHideScrollbars(bool scrollbar)
{
m_cfg.writeEntry("KineticScrollingHideScrollbar", scrollbar);
}
const KoColorSpace* KisConfig::customColorSelectorColorSpace(bool defaultValue) const
{
const KoColorSpace *cs = 0;
KConfigGroup cfg = KSharedConfig::openConfig()->group("advancedColorSelector");
if (defaultValue || cfg.readEntry("useCustomColorSpace", true)) {
KoColorSpaceRegistry* csr = KoColorSpaceRegistry::instance();
QString modelID = cfg.readEntry("customColorSpaceModel", "RGBA");
QString depthID = cfg.readEntry("customColorSpaceDepthID", "U8");
QString profile = cfg.readEntry("customColorSpaceProfile", "sRGB built-in - (lcms internal)");
if (profile == "default") {
// qDebug() << "Falling back to default color profile.";
profile = "sRGB built-in - (lcms internal)";
}
cs = csr->colorSpace(modelID, depthID, profile);
}
return cs;
}
void KisConfig::setCustomColorSelectorColorSpace(const KoColorSpace *cs)
{
KConfigGroup cfg = KSharedConfig::openConfig()->group("advancedColorSelector");
cfg.writeEntry("useCustomColorSpace", bool(cs));
if(cs) {
cfg.writeEntry("customColorSpaceModel", cs->colorModelId().id());
cfg.writeEntry("customColorSpaceDepthID", cs->colorDepthId().id());
cfg.writeEntry("customColorSpaceProfile", cs->profile()->name());
}
KisConfigNotifier::instance()->notifyConfigChanged();
}
bool KisConfig::enableOpenGLFramerateLogging(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("enableOpenGLFramerateLogging", false));
}
void KisConfig::setEnableOpenGLFramerateLogging(bool value) const
{
m_cfg.writeEntry("enableOpenGLFramerateLogging", value);
}
bool KisConfig::enableBrushSpeedLogging(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("enableBrushSpeedLogging", false));
}
void KisConfig::setEnableBrushSpeedLogging(bool value) const
{
m_cfg.writeEntry("enableBrushSpeedLogging", value);
}
void KisConfig::setEnableAmdVectorizationWorkaround(bool value)
{
m_cfg.writeEntry("amdDisableVectorWorkaround", value);
}
bool KisConfig::enableAmdVectorizationWorkaround(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("amdDisableVectorWorkaround", false));
}
void KisConfig::setDisableAVXOptimizations(bool value)
{
m_cfg.writeEntry("disableAVXOptimizations", value);
}
bool KisConfig::disableAVXOptimizations(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("disableAVXOptimizations", false));
}
void KisConfig::setAnimationDropFrames(bool value)
{
bool oldValue = animationDropFrames();
if (value == oldValue) return;
m_cfg.writeEntry("animationDropFrames", value);
KisConfigNotifier::instance()->notifyDropFramesModeChanged();
}
bool KisConfig::autoPinLayersToTimeline(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("autoPinLayers", true));
}
void KisConfig::setAutoPinLayersToTimeline(bool value)
{
m_cfg.writeEntry("autoPinLayers", value);
}
bool KisConfig::animationDropFrames(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("animationDropFrames", true));
}
int KisConfig::scrubbingUpdatesDelay(bool defaultValue) const
{
return (defaultValue ? 30 : m_cfg.readEntry("scrubbingUpdatesDelay", 30));
}
void KisConfig::setScrubbingUpdatesDelay(int value)
{
m_cfg.writeEntry("scrubbingUpdatesDelay", value);
}
int KisConfig::scrubbingAudioUpdatesDelay(bool defaultValue) const
{
return (defaultValue ? -1 : m_cfg.readEntry("scrubbingAudioUpdatesDelay", -1));
}
void KisConfig::setScrubbingAudioUpdatesDelay(int value)
{
m_cfg.writeEntry("scrubbingAudioUpdatesDelay", value);
}
int KisConfig::audioOffsetTolerance(bool defaultValue) const
{
return (defaultValue ? -1 : m_cfg.readEntry("audioOffsetTolerance", -1));
}
void KisConfig::setAudioOffsetTolerance(int value)
{
m_cfg.writeEntry("audioOffsetTolerance", value);
}
bool KisConfig::switchSelectionCtrlAlt(bool defaultValue) const
{
return defaultValue ? false : m_cfg.readEntry("switchSelectionCtrlAlt", false);
}
void KisConfig::setSwitchSelectionCtrlAlt(bool value)
{
m_cfg.writeEntry("switchSelectionCtrlAlt", value);
KisConfigNotifier::instance()->notifyConfigChanged();
}
bool KisConfig::convertToImageColorspaceOnImport(bool defaultValue) const
{
return defaultValue ? false : m_cfg.readEntry("ConvertToImageColorSpaceOnImport", false);
}
void KisConfig::setConvertToImageColorspaceOnImport(bool value)
{
m_cfg.writeEntry("ConvertToImageColorSpaceOnImport", value);
}
int KisConfig::stabilizerSampleSize(bool defaultValue) const
{
#ifdef Q_OS_WIN
const int defaultSampleSize = 50;
#else
const int defaultSampleSize = 15;
#endif
return defaultValue ?
defaultSampleSize : m_cfg.readEntry("stabilizerSampleSize", defaultSampleSize);
}
void KisConfig::setStabilizerSampleSize(int value)
{
m_cfg.writeEntry("stabilizerSampleSize", value);
}
bool KisConfig::stabilizerDelayedPaint(bool defaultValue) const
{
const bool defaultEnabled = true;
return defaultValue ?
defaultEnabled : m_cfg.readEntry("stabilizerDelayedPaint", defaultEnabled);
}
void KisConfig::setStabilizerDelayedPaint(bool value)
{
m_cfg.writeEntry("stabilizerDelayedPaint", value);
}
bool KisConfig::showBrushHud(bool defaultValue) const
{
return defaultValue ? false : m_cfg.readEntry("showBrushHud", false);
}
void KisConfig::setShowBrushHud(bool value)
{
m_cfg.writeEntry("showBrushHud", value);
}
QString KisConfig::brushHudSetting(bool defaultValue) const
{
QString defaultDoc = "<!DOCTYPE hud_properties>\n<hud_properties>\n <version value=\"1\" type=\"value\"/>\n <paintbrush>\n <properties_list type=\"array\">\n <item_0 value=\"size\" type=\"value\"/>\n <item_1 value=\"opacity\" type=\"value\"/>\n <item_2 value=\"angle\" type=\"value\"/>\n </properties_list>\n </paintbrush>\n <colorsmudge>\n <properties_list type=\"array\">\n <item_0 value=\"size\" type=\"value\"/>\n <item_1 value=\"opacity\" type=\"value\"/>\n <item_2 value=\"smudge_mode\" type=\"value\"/>\n <item_3 value=\"smudge_length\" type=\"value\"/>\n <item_4 value=\"smudge_color_rate\" type=\"value\"/>\n </properties_list>\n </colorsmudge>\n <sketchbrush>\n <properties_list type=\"array\">\n <item_0 value=\"opacity\" type=\"value\"/>\n <item_1 value=\"size\" type=\"value\"/>\n </properties_list>\n </sketchbrush>\n <hairybrush>\n <properties_list type=\"array\">\n <item_0 value=\"size\" type=\"value\"/>\n <item_1 value=\"opacity\" type=\"value\"/>\n </properties_list>\n </hairybrush>\n <experimentbrush>\n <properties_list type=\"array\">\n <item_0 value=\"opacity\" type=\"value\"/>\n <item_1 value=\"shape_windingfill\" type=\"value\"/>\n </properties_list>\n </experimentbrush>\n <spraybrush>\n <properties_list type=\"array\">\n <item_0 value=\"size\" type=\"value\"/>\n <item_1 value=\"opacity\" type=\"value\"/>\n <item_2 value=\"spray_particlecount\" type=\"value\"/>\n <item_3 value=\"spray_density\" type=\"value\"/>\n </properties_list>\n </spraybrush>\n <hatchingbrush>\n <properties_list type=\"array\">\n <item_0 value=\"size\" type=\"value\"/>\n <item_1 value=\"opacity\" type=\"value\"/>\n <item_2 value=\"hatching_angle\" type=\"value\"/>\n <item_3 value=\"hatching_thickness\" type=\"value\"/>\n <item_4 value=\"hatching_separation\" type=\"value\"/>\n </properties_list>\n </hatchingbrush>\n <gridbrush>\n <properties_list type=\"array\">\n <item_0 value=\"size\" type=\"value\"/>\n <item_1 value=\"opacity\" type=\"value\"/>\n <item_2 value=\"grid_divisionlevel\" type=\"value\"/>\n </properties_list>\n </gridbrush>\n <curvebrush>\n <properties_list type=\"array\">\n <item_0 value=\"opacity\" type=\"value\"/>\n <item_1 value=\"curve_historysize\" type=\"value\"/>\n <item_2 value=\"curve_linewidth\" type=\"value\"/>\n <item_3 value=\"curve_lineopacity\" type=\"value\"/>\n <item_4 value=\"curve_connectionline\" type=\"value\"/>\n </properties_list>\n </curvebrush>\n <dynabrush>\n <properties_list type=\"array\">\n <item_0 value=\"dyna_diameter\" type=\"value\"/>\n <item_1 value=\"opacity\" type=\"value\"/>\n <item_2 value=\"dyna_mass\" type=\"value\"/>\n <item_3 value=\"dyna_drag\" type=\"value\"/>\n </properties_list>\n </dynabrush>\n <particlebrush>\n <properties_list type=\"array\">\n <item_0 value=\"opacity\" type=\"value\"/>\n <item_1 value=\"particle_particles\" type=\"value\"/>\n <item_2 value=\"particle_opecityweight\" type=\"value\"/>\n <item_3 value=\"particle_iterations\" type=\"value\"/>\n </properties_list>\n </particlebrush>\n <duplicate>\n <properties_list type=\"array\">\n <item_0 value=\"size\" type=\"value\"/>\n <item_1 value=\"opacity\" type=\"value\"/>\n <item_2 value=\"clone_healing\" type=\"value\"/>\n <item_3 value=\"clone_movesource\" type=\"value\"/>\n </properties_list>\n </duplicate>\n <deformbrush>\n <properties_list type=\"array\">\n <item_0 value=\"size\" type=\"value\"/>\n <item_1 value=\"opacity\" type=\"value\"/>\n <item_2 value=\"deform_amount\" type=\"value\"/>\n <item_3 value=\"deform_mode\" type=\"value\"/>\n </properties_list>\n </deformbrush>\n <tangentnormal>\n <properties_list type=\"array\">\n <item_0 value=\"size\" type=\"value\"/>\n <item_1 value=\"opacity\" type=\"value\"/>\n </properties_list>\n </tangentnormal>\n <filter>\n <properties_list type=\"array\">\n <item_0 value=\"size\" type=\"value\"/>\n <item_1 value=\"opacity\" type=\"value\"/>\n </properties_list>\n </filter>\n <roundmarker>\n <properties_list type=\"array\">\n <item_0 value=\"opacity\" type=\"value\"/>\n <item_1 value=\"size\" type=\"value\"/>\n </properties_list>\n </roundmarker>\n</hud_properties>\n";
return defaultValue ? defaultDoc : m_cfg.readEntry("brushHudSettings", defaultDoc);
}
void KisConfig::setBrushHudSetting(const QString &value) const
{
m_cfg.writeEntry("brushHudSettings", value);
}
bool KisConfig::calculateAnimationCacheInBackground(bool defaultValue) const
{
return defaultValue ? true : m_cfg.readEntry("calculateAnimationCacheInBackground", true);
}
void KisConfig::setCalculateAnimationCacheInBackground(bool value)
{
m_cfg.writeEntry("calculateAnimationCacheInBackground", value);
}
QColor KisConfig::defaultAssistantsColor(bool defaultValue) const
{
static const QColor defaultColor = QColor(176, 176, 176, 255);
return defaultValue ? defaultColor : m_cfg.readEntry("defaultAssistantsColor", defaultColor);
}
void KisConfig::setDefaultAssistantsColor(const QColor &color) const
{
m_cfg.writeEntry("defaultAssistantsColor", color);
}
bool KisConfig::autoSmoothBezierCurves(bool defaultValue) const
{
return defaultValue ? false : m_cfg.readEntry("autoSmoothBezierCurves", false);
}
void KisConfig::setAutoSmoothBezierCurves(bool value)
{
m_cfg.writeEntry("autoSmoothBezierCurves", value);
}
bool KisConfig::activateTransformToolAfterPaste(bool defaultValue) const
{
return defaultValue ? false : m_cfg.readEntry("activateTransformToolAfterPaste", false);
}
void KisConfig::setActivateTransformToolAfterPaste(bool value)
{
m_cfg.writeEntry("activateTransformToolAfterPaste", value);
}
KisConfig::RootSurfaceFormat KisConfig::rootSurfaceFormat(bool defaultValue) const
{
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
return rootSurfaceFormat(&kritarc, defaultValue);
}
void KisConfig::setRootSurfaceFormat(KisConfig::RootSurfaceFormat value)
{
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
setRootSurfaceFormat(&kritarc, value);
}
KisConfig::RootSurfaceFormat KisConfig::rootSurfaceFormat(QSettings *displayrc, bool defaultValue)
{
QString textValue = "bt709-g22";
if (!defaultValue) {
textValue = displayrc->value("rootSurfaceFormat", textValue).toString();
}
return textValue == "bt709-g10" ? BT709_G10 :
textValue == "bt2020-pq" ? BT2020_PQ :
BT709_G22;
}
void KisConfig::setRootSurfaceFormat(QSettings *displayrc, KisConfig::RootSurfaceFormat value)
{
const QString textValue =
value == BT709_G10 ? "bt709-g10" :
value == BT2020_PQ ? "bt2020-pq" :
"bt709-g22";
displayrc->setValue("rootSurfaceFormat", textValue);
}
bool KisConfig::useZip64(bool defaultValue) const
{
return defaultValue ? false : m_cfg.readEntry("UseZip64", false);
}
void KisConfig::setUseZip64(bool value)
{
m_cfg.writeEntry("UseZip64", value);
}
bool KisConfig::convertLayerColorSpaceInProperties(bool defaultValue) const
{
return defaultValue ? true : m_cfg.readEntry("convertLayerColorSpaceInProperties", true);
}
void KisConfig::setConvertLayerColorSpaceInProperties(bool value)
{
m_cfg.writeEntry("convertLayerColorSpaceInProperties", value);
}
#include <QDomDocument>
#include <QDomElement>
void KisConfig::writeKoColor(const QString& name, const KoColor& color) const
{
QDomDocument doc = QDomDocument(name);
QDomElement el = doc.createElement(name);
doc.appendChild(el);
color.toXML(doc, el);
m_cfg.writeEntry(name, doc.toString());
}
//ported from kispropertiesconfig.
KoColor KisConfig::readKoColor(const QString& name, const KoColor& _color) const
{
QDomDocument doc;
KoColor color = _color;
if (!m_cfg.readEntry(name).isNull()) {
doc.setContent(m_cfg.readEntry(name));
QDomElement e = doc.documentElement().firstChild().toElement();
color = KoColor::fromXML(e, Integer16BitsColorDepthID.id());
}
else {
QString blackColor = "<!DOCTYPE Color>\n<Color>\n <RGB r=\"0\" space=\"sRGB-elle-V2-srgbtrc.icc\" b=\"0\" g=\"0\"/>\n</Color>\n";
doc.setContent(blackColor);
QDomElement e = doc.documentElement().firstChild().toElement();
color = KoColor::fromXML(e, Integer16BitsColorDepthID.id());
}
return color;
}
diff --git a/libs/ui/kis_config.h b/libs/ui/kis_config.h
index 9c1d3898aa..d62fb9173f 100644
--- a/libs/ui/kis_config.h
+++ b/libs/ui/kis_config.h
@@ -1,656 +1,659 @@
/*
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
*
* 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_CONFIG_H_
#define KIS_CONFIG_H_
#include <QString>
#include <QStringList>
#include <QList>
#include <QColor>
#include <QObject>
#include <ksharedconfig.h>
#include <kconfiggroup.h>
#include <kis_global.h>
#include <kis_properties_configuration.h>
#include "kritaui_export.h"
class KoColorProfile;
class KoColorSpace;
class KisSnapConfig;
class QSettings;
class KisOcioConfiguration;
class KRITAUI_EXPORT KisConfig
{
public:
/**
* @brief KisConfig create a kisconfig object
* @param readOnly if true, there will be no call to sync when the object is deleted.
* Any KisConfig object created in a thread must be read-only.
*/
KisConfig(bool readOnly);
~KisConfig();
public Q_SLOTS:
/// Log the most interesting settings to the usage log
void logImportantSettings() const;
public:
bool disableTouchOnCanvas(bool defaultValue = false) const;
void setDisableTouchOnCanvas(bool value) const;
bool disableTouchRotation(bool defaultValue = false) const;
void setDisableTouchRotation(bool value) const;
// XXX Unused?
bool useProjections(bool defaultValue = false) const;
void setUseProjections(bool useProj) const;
bool undoEnabled(bool defaultValue = false) const;
void setUndoEnabled(bool undo) const;
int undoStackLimit(bool defaultValue = false) const;
void setUndoStackLimit(int limit) const;
bool useCumulativeUndoRedo(bool defaultValue = false) const;
void setCumulativeUndoRedo(bool value);
double stackT1(bool defaultValue = false) const;
void setStackT1(int T1);
double stackT2(bool defaultValue = false) const;
void setStackT2(int T2);
int stackN(bool defaultValue = false) const;
void setStackN(int N);
qint32 defImageWidth(bool defaultValue = false) const;
void defImageWidth(qint32 width) const;
qint32 defImageHeight(bool defaultValue = false) const;
void defImageHeight(qint32 height) const;
qreal defImageResolution(bool defaultValue = false) const;
void defImageResolution(qreal res) const;
int preferredVectorImportResolutionPPI(bool defaultValue = false) const;
void setPreferredVectorImportResolutionPPI(int value) const;
/**
* @return the id of the default color model used for creating new images.
*/
QString defColorModel(bool defaultValue = false) const;
/**
* set the id of the default color model used for creating new images.
*/
void defColorModel(const QString & model) const;
/**
* @return the id of the default color depth used for creating new images.
*/
QString defaultColorDepth(bool defaultValue = false) const;
/**
* set the id of the default color depth used for creating new images.
*/
void setDefaultColorDepth(const QString & depth) const;
/**
* @return the id of the default color profile used for creating new images.
*/
QString defColorProfile(bool defaultValue = false) const;
/**
* set the id of the default color profile used for creating new images.
*/
void defColorProfile(const QString & depth) const;
CursorStyle newCursorStyle(bool defaultValue = false) const;
void setNewCursorStyle(CursorStyle style);
QColor getCursorMainColor(bool defaultValue = false) const;
void setCursorMainColor(const QColor& v) const;
OutlineStyle newOutlineStyle(bool defaultValue = false) const;
void setNewOutlineStyle(OutlineStyle style);
QRect colorPreviewRect() const;
void setColorPreviewRect(const QRect &rect);
/// get the profile the user has selected for the given screen
QString monitorProfile(int screen) const;
void setMonitorProfile(int screen, const QString & monitorProfile, bool override) const;
QString monitorForScreen(int screen, const QString &defaultMonitor, bool defaultValue = true) const;
void setMonitorForScreen(int screen, const QString& monitor);
/// Get the actual profile to be used for the given screen, which is
/// either the screen profile set by the color management system or
/// the custom monitor profile set by the user, depending on the configuration
const KoColorProfile *displayProfile(int screen) const;
QString workingColorSpace(bool defaultValue = false) const;
void setWorkingColorSpace(const QString & workingColorSpace) const;
QString importProfile(bool defaultValue = false) const;
void setImportProfile(const QString & importProfile) const;
QString printerColorSpace(bool defaultValue = false) const;
void setPrinterColorSpace(const QString & printerColorSpace) const;
QString printerProfile(bool defaultValue = false) const;
void setPrinterProfile(const QString & printerProfile) const;
bool useBlackPointCompensation(bool defaultValue = false) const;
void setUseBlackPointCompensation(bool useBlackPointCompensation) const;
bool allowLCMSOptimization(bool defaultValue = false) const;
void setAllowLCMSOptimization(bool allowLCMSOptimization);
bool forcePaletteColors(bool defaultValue = false) const;
void setForcePaletteColors(bool forcePaletteColors);
void writeKoColor(const QString& name, const KoColor& color) const;
KoColor readKoColor(const QString& name, const KoColor& color = KoColor()) const;
bool showRulers(bool defaultValue = false) const;
void setShowRulers(bool rulers) const;
bool forceShowSaveMessages(bool defaultValue = true) const;
void setForceShowSaveMessages(bool value) const;
bool forceShowAutosaveMessages(bool defaultValue = true) const;
void setForceShowAutosaveMessages(bool ShowAutosaveMessages) const;
bool rulersTrackMouse(bool defaultValue = false) const;
void setRulersTrackMouse(bool value) const;
qint32 pasteBehaviour(bool defaultValue = false) const;
void setPasteBehaviour(qint32 behaviour) const;
qint32 monitorRenderIntent(bool defaultValue = false) const;
void setRenderIntent(qint32 monitorRenderIntent) const;
bool useOpenGL(bool defaultValue = false) const;
void disableOpenGL() const;
int openGLFilteringMode(bool defaultValue = false) const;
void setOpenGLFilteringMode(int filteringMode);
+ void setWidgetStyle(QString name);
+ QString widgetStyle(bool defaultValue = false);
+
bool useOpenGLTextureBuffer(bool defaultValue = false) const;
void setUseOpenGLTextureBuffer(bool useBuffer);
// XXX Unused?
bool disableVSync(bool defaultValue = false) const;
void setDisableVSync(bool disableVSync);
bool showAdvancedOpenGLSettings(bool defaultValue = false) const;
bool forceOpenGLFenceWorkaround(bool defaultValue = false) const;
int numMipmapLevels(bool defaultValue = false) const;
int openGLTextureSize(bool defaultValue = false) const;
int textureOverlapBorder() const;
quint32 getGridMainStyle(bool defaultValue = false) const;
void setGridMainStyle(quint32 v) const;
quint32 getGridSubdivisionStyle(bool defaultValue = false) const;
void setGridSubdivisionStyle(quint32 v) const;
QColor getGridMainColor(bool defaultValue = false) const;
void setGridMainColor(const QColor & v) const;
QColor getGridSubdivisionColor(bool defaultValue = false) const;
void setGridSubdivisionColor(const QColor & v) const;
QColor getPixelGridColor(bool defaultValue = false) const;
void setPixelGridColor(const QColor & v) const;
qreal getPixelGridDrawingThreshold(bool defaultValue = false) const;
void setPixelGridDrawingThreshold(qreal v) const;
bool pixelGridEnabled(bool defaultValue = false) const;
void enablePixelGrid(bool v) const;
quint32 guidesLineStyle(bool defaultValue = false) const;
void setGuidesLineStyle(quint32 v) const;
QColor guidesColor(bool defaultValue = false) const;
void setGuidesColor(const QColor & v) const;
void loadSnapConfig(KisSnapConfig *config, bool defaultValue = false) const;
void saveSnapConfig(const KisSnapConfig &config);
qint32 checkSize(bool defaultValue = false) const;
void setCheckSize(qint32 checkSize) const;
bool scrollCheckers(bool defaultValue = false) const;
void setScrollingCheckers(bool scollCheckers) const;
QColor checkersColor1(bool defaultValue = false) const;
void setCheckersColor1(const QColor & v) const;
QColor checkersColor2(bool defaultValue = false) const;
void setCheckersColor2(const QColor & v) const;
QColor canvasBorderColor(bool defaultValue = false) const;
void setCanvasBorderColor(const QColor &color) const;
bool hideScrollbars(bool defaultValue = false) const;
void setHideScrollbars(bool value) const;
bool antialiasCurves(bool defaultValue = false) const;
void setAntialiasCurves(bool v) const;
bool antialiasSelectionOutline(bool defaultValue = false) const;
void setAntialiasSelectionOutline(bool v) const;
bool showRootLayer(bool defaultValue = false) const;
void setShowRootLayer(bool showRootLayer) const;
bool showGlobalSelection(bool defaultValue = false) const;
void setShowGlobalSelection(bool showGlobalSelection) const;
bool showOutlineWhilePainting(bool defaultValue = false) const;
void setShowOutlineWhilePainting(bool showOutlineWhilePainting) const;
bool forceAlwaysFullSizedOutline(bool defaultValue = false) const;
void setForceAlwaysFullSizedOutline(bool value) const;
enum SessionOnStartup {
SOS_BlankSession,
SOS_PreviousSession,
SOS_ShowSessionManager
};
SessionOnStartup sessionOnStartup(bool defaultValue = false) const;
void setSessionOnStartup(SessionOnStartup value);
bool saveSessionOnQuit(bool defaultValue) const;
void setSaveSessionOnQuit(bool value);
qreal outlineSizeMinimum(bool defaultValue = false) const;
void setOutlineSizeMinimum(qreal outlineSizeMinimum) const;
qreal selectionViewSizeMinimum(bool defaultValue = false) const;
void setSelectionViewSizeMinimum(qreal outlineSizeMinimum) const;
int autoSaveInterval(bool defaultValue = false) const;
void setAutoSaveInterval(int seconds) const;
bool backupFile(bool defaultValue = false) const;
void setBackupFile(bool backupFile) const;
bool showFilterGallery(bool defaultValue = false) const;
void setShowFilterGallery(bool showFilterGallery) const;
bool showFilterGalleryLayerMaskDialog(bool defaultValue = false) const;
void setShowFilterGalleryLayerMaskDialog(bool showFilterGallery) const;
// OPENGL_SUCCESS, TRY_OPENGL, OPENGL_NOT_TRIED, OPENGL_FAILED
QString canvasState(bool defaultValue = false) const;
void setCanvasState(const QString& state) const;
bool toolOptionsPopupDetached(bool defaultValue = false) const;
void setToolOptionsPopupDetached(bool detached) const;
bool paintopPopupDetached(bool defaultValue = false) const;
void setPaintopPopupDetached(bool detached) const;
QString pressureTabletCurve(bool defaultValue = false) const;
void setPressureTabletCurve(const QString& curveString) const;
bool useWin8PointerInput(bool defaultValue = false) const;
void setUseWin8PointerInput(bool value);
static bool useWin8PointerInputNoApp(QSettings *settings, bool defaultValue = false);
static void setUseWin8PointerInputNoApp(QSettings *settings, bool value);
bool useRightMiddleTabletButtonWorkaround(bool defaultValue = false) const;
void setUseRightMiddleTabletButtonWorkaround(bool value);
qreal vastScrolling(bool defaultValue = false) const;
void setVastScrolling(const qreal factor) const;
int presetChooserViewMode(bool defaultValue = false) const;
void setPresetChooserViewMode(const int mode) const;
int presetIconSize(bool defaultValue = false) const;
void setPresetIconSize(const int value) const;
bool firstRun(bool defaultValue = false) const;
void setFirstRun(const bool firstRun) const;
bool clicklessSpacePan(bool defaultValue = false) const;
void setClicklessSpacePan(const bool toggle) const;
int horizontalSplitLines(bool defaultValue = false) const;
void setHorizontalSplitLines(const int numberLines) const;
int verticalSplitLines(bool defaultValue = false) const;
void setVerticalSplitLines(const int numberLines) const;
bool hideDockersFullscreen(bool defaultValue = false) const;
void setHideDockersFullscreen(const bool value) const;
bool showDockers(bool defaultValue = false) const;
void setShowDockers(const bool value) const;
bool showStatusBar(bool defaultValue = false) const;
void setShowStatusBar(const bool value) const;
bool hideMenuFullscreen(bool defaultValue = false) const;
void setHideMenuFullscreen(const bool value) const;
bool hideScrollbarsFullscreen(bool defaultValue = false) const;
void setHideScrollbarsFullscreen(const bool value) const;
bool hideStatusbarFullscreen(bool defaultValue = false) const;
void setHideStatusbarFullscreen(const bool value) const;
bool hideTitlebarFullscreen(bool defaultValue = false) const;
void setHideTitlebarFullscreen(const bool value) const;
bool hideToolbarFullscreen(bool defaultValue = false) const;
void setHideToolbarFullscreen(const bool value) const;
bool fullscreenMode(bool defaultValue = false) const;
void setFullscreenMode(const bool value) const;
QStringList favoriteCompositeOps(bool defaultValue = false) const;
void setFavoriteCompositeOps(const QStringList& compositeOps) const;
QString exportConfigurationXML(const QString &filterId, bool defaultValue = false) const;
KisPropertiesConfigurationSP exportConfiguration(const QString &filterId, bool defaultValue = false) const;
void setExportConfiguration(const QString &filterId, KisPropertiesConfigurationSP properties) const;
QString importConfiguration(const QString &filterId, bool defaultValue = false) const;
void setImportConfiguration(const QString &filterId, KisPropertiesConfigurationSP properties) const;
bool useOcio(bool defaultValue = false) const;
void setUseOcio(bool useOCIO) const;
int favoritePresets(bool defaultValue = false) const;
void setFavoritePresets(const int value);
bool levelOfDetailEnabled(bool defaultValue = false) const;
void setLevelOfDetailEnabled(bool value);
KisOcioConfiguration ocioConfiguration(bool defaultValue = false) const;
void setOcioConfiguration(const KisOcioConfiguration &cfg);
enum OcioColorManagementMode {
INTERNAL = 0,
OCIO_CONFIG,
OCIO_ENVIRONMENT
};
OcioColorManagementMode ocioColorManagementMode(bool defaultValue = false) const;
void setOcioColorManagementMode(OcioColorManagementMode mode) const;
int ocioLutEdgeSize(bool defaultValue = false) const;
void setOcioLutEdgeSize(int value);
bool ocioLockColorVisualRepresentation(bool defaultValue = false) const;
void setOcioLockColorVisualRepresentation(bool value);
bool useSystemMonitorProfile(bool defaultValue = false) const;
void setUseSystemMonitorProfile(bool _useSystemMonitorProfile) const;
QString defaultPalette(bool defaultValue = false) const;
void setDefaultPalette(const QString& name) const;
QString toolbarSlider(int sliderNumber, bool defaultValue = false) const;
void setToolbarSlider(int sliderNumber, const QString &slider);
int layerThumbnailSize(bool defaultValue = false) const;
void setLayerThumbnailSize(int size);
bool sliderLabels(bool defaultValue = false) const;
void setSliderLabels(bool enabled);
QString currentInputProfile(bool defaultValue = false) const;
void setCurrentInputProfile(const QString& name);
bool presetStripVisible(bool defaultValue = false) const;
void setPresetStripVisible(bool visible);
bool scratchpadVisible(bool defaultValue = false) const;
void setScratchpadVisible(bool visible);
bool showSingleChannelAsColor(bool defaultValue = false) const;
void setShowSingleChannelAsColor(bool asColor);
bool hidePopups(bool defaultValue = false) const;
void setHidePopups(bool hidepopups);
int numDefaultLayers(bool defaultValue = false) const;
void setNumDefaultLayers(int num);
quint8 defaultBackgroundOpacity(bool defaultValue = false) const;
void setDefaultBackgroundOpacity(quint8 value);
QColor defaultBackgroundColor(bool defaultValue = false) const;
void setDefaultBackgroundColor(const QColor &value);
enum BackgroundStyle {
RASTER_LAYER = 0,
CANVAS_COLOR = 1,
FILL_LAYER = 2
};
BackgroundStyle defaultBackgroundStyle(bool defaultValue = false) const;
void setDefaultBackgroundStyle(BackgroundStyle value);
int lineSmoothingType(bool defaultValue = false) const;
void setLineSmoothingType(int value);
qreal lineSmoothingDistance(bool defaultValue = false) const;
void setLineSmoothingDistance(qreal value);
qreal lineSmoothingTailAggressiveness(bool defaultValue = false) const;
void setLineSmoothingTailAggressiveness(qreal value);
bool lineSmoothingSmoothPressure(bool defaultValue = false) const;
void setLineSmoothingSmoothPressure(bool value);
bool lineSmoothingScalableDistance(bool defaultValue = false) const;
void setLineSmoothingScalableDistance(bool value);
qreal lineSmoothingDelayDistance(bool defaultValue = false) const;
void setLineSmoothingDelayDistance(qreal value);
bool lineSmoothingUseDelayDistance(bool defaultValue = false) const;
void setLineSmoothingUseDelayDistance(bool value);
bool lineSmoothingFinishStabilizedCurve(bool defaultValue = false) const;
void setLineSmoothingFinishStabilizedCurve(bool value);
bool lineSmoothingStabilizeSensors(bool defaultValue = false) const;
void setLineSmoothingStabilizeSensors(bool value);
int tabletEventsDelay(bool defaultValue = false) const;
void setTabletEventsDelay(int value);
bool trackTabletEventLatency(bool defaultValue = false) const;
void setTrackTabletEventLatency(bool value);
bool testingAcceptCompressedTabletEvents(bool defaultValue = false) const;
void setTestingAcceptCompressedTabletEvents(bool value);
bool shouldEatDriverShortcuts(bool defaultValue = false) const;
bool testingCompressBrushEvents(bool defaultValue = false) const;
void setTestingCompressBrushEvents(bool value);
const KoColorSpace* customColorSelectorColorSpace(bool defaultValue = false) const;
void setCustomColorSelectorColorSpace(const KoColorSpace *cs);
bool useDirtyPresets(bool defaultValue = false) const;
void setUseDirtyPresets(bool value);
bool useEraserBrushSize(bool defaultValue = false) const;
void setUseEraserBrushSize(bool value);
bool useEraserBrushOpacity(bool defaultValue = false) const;
void setUseEraserBrushOpacity(bool value);
QString getMDIBackgroundColor(bool defaultValue = false) const;
void setMDIBackgroundColor(const QString & v) const;
QString getMDIBackgroundImage(bool defaultValue = false) const;
void setMDIBackgroundImage(const QString & fileName) const;
int workaroundX11SmoothPressureSteps(bool defaultValue = false) const;
bool showCanvasMessages(bool defaultValue = false) const;
void setShowCanvasMessages(bool show);
bool compressKra(bool defaultValue = false) const;
void setCompressKra(bool compress);
bool trimKra(bool defaultValue = false) const;
void setTrimKra(bool trim);
bool toolOptionsInDocker(bool defaultValue = false) const;
void setToolOptionsInDocker(bool inDocker);
bool kineticScrollingEnabled(bool defaultValue = false) const;
void setKineticScrollingEnabled(bool enabled);
int kineticScrollingGesture(bool defaultValue = false) const;
void setKineticScrollingGesture(int kineticScroll);
int kineticScrollingSensitivity(bool defaultValue = false) const;
void setKineticScrollingSensitivity(int sensitivity);
bool kineticScrollingHiddenScrollbars(bool defaultValue = false) const;
void setKineticScrollingHideScrollbars(bool scrollbar);
void setEnableOpenGLFramerateLogging(bool value) const;
bool enableOpenGLFramerateLogging(bool defaultValue = false) const;
void setEnableBrushSpeedLogging(bool value) const;
bool enableBrushSpeedLogging(bool defaultValue = false) const;
void setEnableAmdVectorizationWorkaround(bool value);
bool enableAmdVectorizationWorkaround(bool defaultValue = false) const;
void setDisableAVXOptimizations(bool value);
bool disableAVXOptimizations(bool defaultValue = false) const;
bool animationDropFrames(bool defaultValue = false) const;
void setAnimationDropFrames(bool value);
bool autoPinLayersToTimeline(bool defaultValue = false) const;
void setAutoPinLayersToTimeline(bool value);
int scrubbingUpdatesDelay(bool defaultValue = false) const;
void setScrubbingUpdatesDelay(int value);
int scrubbingAudioUpdatesDelay(bool defaultValue = false) const;
void setScrubbingAudioUpdatesDelay(int value);
int audioOffsetTolerance(bool defaultValue = false) const;
void setAudioOffsetTolerance(int value);
bool switchSelectionCtrlAlt(bool defaultValue = false) const;
void setSwitchSelectionCtrlAlt(bool value);
bool convertToImageColorspaceOnImport(bool defaultValue = false) const;
void setConvertToImageColorspaceOnImport(bool value);
int stabilizerSampleSize(bool defaultValue = false) const;
void setStabilizerSampleSize(int value);
bool stabilizerDelayedPaint(bool defaultValue = false) const;
void setStabilizerDelayedPaint(bool value);
bool showBrushHud(bool defaultValue = false) const;
void setShowBrushHud(bool value);
QString brushHudSetting(bool defaultValue = false) const;
void setBrushHudSetting(const QString &value) const;
bool calculateAnimationCacheInBackground(bool defaultValue = false) const;
void setCalculateAnimationCacheInBackground(bool value);
QColor defaultAssistantsColor(bool defaultValue = false) const;
void setDefaultAssistantsColor(const QColor &color) const;
bool autoSmoothBezierCurves(bool defaultValue = false) const;
void setAutoSmoothBezierCurves(bool value);
bool activateTransformToolAfterPaste(bool defaultValue = false) const;
void setActivateTransformToolAfterPaste(bool value);
enum RootSurfaceFormat {
BT709_G22 = 0,
BT709_G10,
BT2020_PQ
};
RootSurfaceFormat rootSurfaceFormat(bool defaultValue = false) const;
void setRootSurfaceFormat(RootSurfaceFormat value);
static RootSurfaceFormat rootSurfaceFormat(QSettings *displayrc, bool defaultValue = false);
static void setRootSurfaceFormat(QSettings *displayrc, RootSurfaceFormat value);
bool useZip64(bool defaultValue = false) const;
void setUseZip64(bool value);
bool convertLayerColorSpaceInProperties(bool defaultValue = false) const;
void setConvertLayerColorSpaceInProperties(bool value);
template<class T>
void writeEntry(const QString& name, const T& value) {
m_cfg.writeEntry(name, value);
}
template<class T>
void writeList(const QString& name, const QList<T>& value) {
m_cfg.writeEntry(name, value);
}
template<class T>
T readEntry(const QString& name, const T& defaultValue=T()) {
return m_cfg.readEntry(name, defaultValue);
}
template<class T>
QList<T> readList(const QString& name, const QList<T>& defaultValue=QList<T>()) {
return m_cfg.readEntry(name, defaultValue);
}
/// get the profile the color management system has stored for the given screen
static const KoColorProfile* getScreenProfile(int screen);
private:
KisConfig(const KisConfig&);
KisConfig& operator=(const KisConfig&) const;
private:
mutable KConfigGroup m_cfg;
bool m_readOnly;
};
#endif // KIS_CONFIG_H_
diff --git a/libs/ui/kis_node_model.cpp b/libs/ui/kis_node_model.cpp
index b6fe3bed6e..cc627f952e 100644
--- a/libs/ui/kis_node_model.cpp
+++ b/libs/ui/kis_node_model.cpp
@@ -1,753 +1,745 @@
/*
* Copyright (c) 2007 Boudewijn Rempt <boud@valdyas.org>
* Copyright (c) 2008 Cyrille Berger <cberger@cberger.net>
*
* 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_node_model.h"
#include <iostream>
#include <QMimeData>
#include <QBuffer>
#include <QPointer>
#include <KoColorSpaceConstants.h>
#include <klocalizedstring.h>
#include "kis_mimedata.h"
#include <kis_debug.h>
#include <kis_node.h>
#include <kis_node_progress_proxy.h>
#include <kis_image.h>
#include <kis_selection.h>
#include <kis_selection_mask.h>
#include <kis_undo_adapter.h>
#include <commands/kis_node_property_list_command.h>
#include <kis_paint_layer.h>
#include <kis_group_layer.h>
#include <kis_projection_leaf.h>
#include <kis_shape_controller.h>
#include "kis_dummies_facade_base.h"
#include "kis_node_dummies_graph.h"
#include "kis_model_index_converter.h"
#include "kis_model_index_converter_show_all.h"
#include "kis_node_selection_adapter.h"
#include "kis_node_insertion_adapter.h"
#include "kis_node_manager.h"
#include <KisSelectionActionsAdapter.h>
#include <KisNodeDisplayModeAdapter.h>
#include "kis_config.h"
#include "kis_config_notifier.h"
#include "kis_signal_auto_connection.h"
#include "kis_signal_compressor.h"
struct KisNodeModel::Private
{
Private() : updateCompressor(100, KisSignalCompressor::FIRST_ACTIVE) {}
KisImageWSP image;
KisShapeController *shapeController = 0;
KisNodeSelectionAdapter *nodeSelectionAdapter = 0;
KisNodeInsertionAdapter *nodeInsertionAdapter = 0;
KisSelectionActionsAdapter *selectionActionsAdapter = 0;
KisNodeDisplayModeAdapter *nodeDisplayModeAdapter = 0;
KisNodeManager *nodeManager = 0;
KisSignalAutoConnectionsStore nodeDisplayModeAdapterConnections;
QList<KisNodeDummy*> updateQueue;
KisSignalCompressor updateCompressor;
KisModelIndexConverterBase *indexConverter = 0;
QPointer<KisDummiesFacadeBase> dummiesFacade = 0;
bool needFinishRemoveRows = false;
bool needFinishInsertRows = false;
bool showRootLayer = false;
bool showGlobalSelection = false;
QPersistentModelIndex activeNodeIndex;
QPointer<KisNodeDummy> parentOfRemovedNode = 0;
QSet<quintptr> dropEnabled;
};
KisNodeModel::KisNodeModel(QObject * parent)
: QAbstractItemModel(parent)
, m_d(new Private)
{
connect(&m_d->updateCompressor, SIGNAL(timeout()), SLOT(processUpdateQueue()));
}
KisNodeModel::~KisNodeModel()
{
delete m_d->indexConverter;
delete m_d;
}
KisNodeSP KisNodeModel::nodeFromIndex(const QModelIndex &index) const
{
Q_ASSERT(index.isValid());
KisNodeDummy *dummy = m_d->indexConverter->dummyFromIndex(index);
if (dummy) {
return dummy->node();
}
return 0;
}
QModelIndex KisNodeModel::indexFromNode(KisNodeSP node) const
{
KisNodeDummy *dummy = m_d->dummiesFacade->dummyForNode(node);
if(dummy)
return m_d->indexConverter->indexFromDummy(dummy);
return QModelIndex();
}
bool KisNodeModel::belongsToIsolatedGroup(KisImageSP image, KisNodeSP node, KisDummiesFacadeBase *dummiesFacade)
{
KisNodeSP isolatedRoot = image->isolatedModeRoot();
if (!isolatedRoot) return true;
KisNodeDummy *isolatedRootDummy =
dummiesFacade->dummyForNode(isolatedRoot);
KisNodeDummy *dummy =
dummiesFacade->dummyForNode(node);
while (dummy) {
if (dummy == isolatedRootDummy) {
return true;
}
dummy = dummy->parent();
}
return false;
}
bool KisNodeModel::belongsToIsolatedGroup(KisNodeSP node) const
{
return belongsToIsolatedGroup(m_d->image, node, m_d->dummiesFacade);
}
void KisNodeModel::resetIndexConverter()
{
delete m_d->indexConverter;
m_d->indexConverter = 0;
if(m_d->dummiesFacade) {
m_d->indexConverter = createIndexConverter();
}
}
KisModelIndexConverterBase *KisNodeModel::createIndexConverter()
{
if(m_d->showRootLayer) {
return new KisModelIndexConverterShowAll(m_d->dummiesFacade, this);
} else {
return new KisModelIndexConverter(m_d->dummiesFacade, this, m_d->showGlobalSelection);
}
}
void KisNodeModel::regenerateItems(KisNodeDummy *dummy)
{
const QModelIndex &index = m_d->indexConverter->indexFromDummy(dummy);
emit dataChanged(index, index);
dummy = dummy->firstChild();
while (dummy) {
regenerateItems(dummy);
dummy = dummy->nextSibling();
}
}
void KisNodeModel::slotIsolatedModeChanged()
{
regenerateItems(m_d->dummiesFacade->rootDummy());
}
bool KisNodeModel::showGlobalSelection() const
{
return m_d->nodeDisplayModeAdapter ?
m_d->nodeDisplayModeAdapter->showGlobalSelectionMask() :
false;
}
void KisNodeModel::setShowGlobalSelection(bool value)
{
if (m_d->nodeDisplayModeAdapter) {
m_d->nodeDisplayModeAdapter->setShowGlobalSelectionMask(value);
}
}
void KisNodeModel::slotNodeDisplayModeChanged(bool showRootNode, bool showGlobalSelectionMask)
{
const bool oldShowRootLayer = m_d->showRootLayer;
const bool oldShowGlobalSelection = m_d->showGlobalSelection;
m_d->showRootLayer = showRootNode;
m_d->showGlobalSelection = showGlobalSelectionMask;
if (m_d->showRootLayer != oldShowRootLayer || m_d->showGlobalSelection != oldShowGlobalSelection) {
resetIndexConverter();
beginResetModel();
endResetModel();
}
}
void KisNodeModel::progressPercentageChanged(int, const KisNodeSP node)
{
if(!m_d->dummiesFacade) return;
// Need to check here as the node might already be removed, but there might
// still be some signals arriving from another thread
if (m_d->dummiesFacade->hasDummyForNode(node)) {
QModelIndex index = indexFromNode(node);
emit dataChanged(index, index);
}
}
KisModelIndexConverterBase * KisNodeModel::indexConverter() const
{
return m_d->indexConverter;
}
KisDummiesFacadeBase *KisNodeModel::dummiesFacade() const
{
return m_d->dummiesFacade;
}
void KisNodeModel::connectDummy(KisNodeDummy *dummy, bool needConnect)
{
KisNodeSP node = dummy->node();
if (!node) {
qWarning() << "Dummy node has no node!" << dummy << dummy->node();
return;
}
KisNodeProgressProxy *progressProxy = node->nodeProgressProxy();
if(progressProxy) {
if(needConnect) {
connect(progressProxy, SIGNAL(percentageChanged(int,KisNodeSP)),
SLOT(progressPercentageChanged(int,KisNodeSP)));
} else {
progressProxy->disconnect(this);
}
}
}
void KisNodeModel::connectDummies(KisNodeDummy *dummy, bool needConnect)
{
connectDummy(dummy, needConnect);
dummy = dummy->firstChild();
while(dummy) {
connectDummies(dummy, needConnect);
dummy = dummy->nextSibling();
}
}
void KisNodeModel::setDummiesFacade(KisDummiesFacadeBase *dummiesFacade,
KisImageWSP image,
KisShapeController *shapeController,
KisSelectionActionsAdapter *selectionActionsAdapter,
KisNodeManager *nodeManager)
{
QPointer<KisDummiesFacadeBase> oldDummiesFacade(m_d->dummiesFacade);
KisShapeController *oldShapeController = m_d->shapeController;
m_d->shapeController = shapeController;
m_d->nodeManager = nodeManager;
m_d->nodeSelectionAdapter = nodeManager ? nodeManager->nodeSelectionAdapter() : nullptr;
m_d->nodeInsertionAdapter = nodeManager ? nodeManager->nodeInsertionAdapter() : nullptr;
m_d->selectionActionsAdapter = selectionActionsAdapter;
m_d->nodeDisplayModeAdapterConnections.clear();
m_d->nodeDisplayModeAdapter = nodeManager ? nodeManager->nodeDisplayModeAdapter() : nullptr;
if (m_d->nodeDisplayModeAdapter) {
m_d->nodeDisplayModeAdapterConnections.addConnection(
m_d->nodeDisplayModeAdapter, SIGNAL(sigNodeDisplayModeChanged(bool,bool)),
this, SLOT(slotNodeDisplayModeChanged(bool,bool)));
// cold initialization
m_d->showGlobalSelection = m_d->nodeDisplayModeAdapter->showGlobalSelectionMask();
m_d->showRootLayer = false;
}
if (oldDummiesFacade && m_d->image) {
m_d->image->disconnect(this);
oldDummiesFacade->disconnect(this);
connectDummies(m_d->dummiesFacade->rootDummy(), false);
}
m_d->image = image;
m_d->dummiesFacade = dummiesFacade;
m_d->parentOfRemovedNode = 0;
resetIndexConverter();
if (m_d->dummiesFacade) {
KisNodeDummy *rootDummy = m_d->dummiesFacade->rootDummy();
if (rootDummy) {
connectDummies(rootDummy, true);
}
connect(m_d->dummiesFacade, SIGNAL(sigBeginInsertDummy(KisNodeDummy*,int,QString)),
SLOT(slotBeginInsertDummy(KisNodeDummy*,int,QString)));
connect(m_d->dummiesFacade, SIGNAL(sigEndInsertDummy(KisNodeDummy*)),
SLOT(slotEndInsertDummy(KisNodeDummy*)));
connect(m_d->dummiesFacade, SIGNAL(sigBeginRemoveDummy(KisNodeDummy*)),
SLOT(slotBeginRemoveDummy(KisNodeDummy*)));
connect(m_d->dummiesFacade, SIGNAL(sigEndRemoveDummy()),
SLOT(slotEndRemoveDummy()));
connect(m_d->dummiesFacade, SIGNAL(sigDummyChanged(KisNodeDummy*)),
SLOT(slotDummyChanged(KisNodeDummy*)));
if (m_d->image.isValid()) {
connect(m_d->image, SIGNAL(sigIsolatedModeChanged()), SLOT(slotIsolatedModeChanged()));
}
}
if (m_d->dummiesFacade != oldDummiesFacade || m_d->shapeController != oldShapeController) {
beginResetModel();
endResetModel();
}
}
void KisNodeModel::slotBeginInsertDummy(KisNodeDummy *parent, int index, const QString &metaObjectType)
{
int row = 0;
QModelIndex parentIndex;
bool willAdd =
m_d->indexConverter->indexFromAddedDummy(parent, index,
metaObjectType,
parentIndex, row);
if(willAdd) {
beginInsertRows(parentIndex, row, row);
m_d->needFinishInsertRows = true;
}
}
void KisNodeModel::slotEndInsertDummy(KisNodeDummy *dummy)
{
if(m_d->needFinishInsertRows) {
connectDummy(dummy, true);
endInsertRows();
m_d->needFinishInsertRows = false;
}
}
void KisNodeModel::slotBeginRemoveDummy(KisNodeDummy *dummy)
{
if (!dummy) return;
// FIXME: is it really what we want?
m_d->updateCompressor.stop();
m_d->updateQueue.clear();
m_d->parentOfRemovedNode = dummy->parent();
QModelIndex parentIndex;
if (m_d->parentOfRemovedNode) {
parentIndex = m_d->indexConverter->indexFromDummy(m_d->parentOfRemovedNode);
}
QModelIndex itemIndex = m_d->indexConverter->indexFromDummy(dummy);
if (itemIndex.isValid()) {
connectDummy(dummy, false);
beginRemoveRows(parentIndex, itemIndex.row(), itemIndex.row());
m_d->needFinishRemoveRows = true;
}
}
void KisNodeModel::slotEndRemoveDummy()
{
if(m_d->needFinishRemoveRows) {
endRemoveRows();
m_d->needFinishRemoveRows = false;
}
}
void KisNodeModel::slotDummyChanged(KisNodeDummy *dummy)
{
if (!m_d->updateQueue.contains(dummy)) {
m_d->updateQueue.append(dummy);
}
m_d->updateCompressor.start();
}
void addChangedIndex(const QModelIndex &idx, QSet<QModelIndex> *indexes)
{
if (!idx.isValid() || indexes->contains(idx)) return;
indexes->insert(idx);
const int rowCount = idx.model()->rowCount(idx);
for (int i = 0; i < rowCount; i++) {
addChangedIndex(idx.model()->index(i, 0, idx), indexes);
}
}
void KisNodeModel::processUpdateQueue()
{
QSet<QModelIndex> indexes;
Q_FOREACH (KisNodeDummy *dummy, m_d->updateQueue) {
QModelIndex index = m_d->indexConverter->indexFromDummy(dummy);
addChangedIndex(index, &indexes);
}
Q_FOREACH (const QModelIndex &index, indexes) {
emit dataChanged(index, index);
}
m_d->updateQueue.clear();
}
QModelIndex KisNodeModel::index(int row, int col, const QModelIndex &parent) const
{
if(!m_d->dummiesFacade || !hasIndex(row, col, parent)) return QModelIndex();
QModelIndex itemIndex;
KisNodeDummy *dummy = m_d->indexConverter->dummyFromRow(row, parent);
if(dummy) {
itemIndex = m_d->indexConverter->indexFromDummy(dummy);
}
return itemIndex;
}
int KisNodeModel::rowCount(const QModelIndex &parent) const
{
if(!m_d->dummiesFacade) return 0;
return m_d->indexConverter->rowCount(parent);
}
int KisNodeModel::columnCount(const QModelIndex&) const
{
return 1;
}
QModelIndex KisNodeModel::parent(const QModelIndex &index) const
{
if(!m_d->dummiesFacade || !index.isValid()) return QModelIndex();
KisNodeDummy *dummy = m_d->indexConverter->dummyFromIndex(index);
KisNodeDummy *parentDummy = dummy->parent();
QModelIndex parentIndex;
if(parentDummy) {
parentIndex = m_d->indexConverter->indexFromDummy(parentDummy);
}
return parentIndex;
}
QVariant KisNodeModel::data(const QModelIndex &index, int role) const
{
if (!m_d->dummiesFacade || !index.isValid() || !m_d->image.isValid()) return QVariant();
KisNodeSP node = nodeFromIndex(index);
switch (role) {
case Qt::DisplayRole: return node->name();
case Qt::DecorationRole: return node->icon();
case Qt::EditRole: return node->name();
case Qt::SizeHintRole: return m_d->image->size(); // FIXME
case Qt::TextColorRole:
return belongsToIsolatedGroup(node) &&
!node->projectionLeaf()->isDroppedNode() ? QVariant() : QVariant(QColor(Qt::gray));
case Qt::FontRole: {
QFont baseFont;
if (node->projectionLeaf()->isDroppedNode()) {
baseFont.setStrikeOut(true);
}
if (m_d->activeNodeIndex == index) {
baseFont.setBold(true);
}
return baseFont;
}
case KisNodeModel::PropertiesRole: return QVariant::fromValue(node->sectionModelProperties());
case KisNodeModel::AspectRatioRole: return double(m_d->image->width()) / m_d->image->height();
case KisNodeModel::ProgressRole: {
KisNodeProgressProxy *proxy = node->nodeProgressProxy();
return proxy ? proxy->percentage() : -1;
}
case KisNodeModel::ActiveRole: {
return m_d->activeNodeIndex == index;
}
case KisNodeModel::ShouldGrayOutRole: {
return !node->visible(true);
}
case KisNodeModel::ColorLabelIndexRole: {
return node->colorLabelIndex();
}
case KisNodeModel::DropReasonRole: {
QString result;
KisProjectionLeaf::NodeDropReason reason = node->projectionLeaf()->dropReason();
if (reason == KisProjectionLeaf::DropPassThroughMask) {
result = i18nc("@info:tooltip", "Disabled: masks on pass-through groups are not supported!");
} else if (reason == KisProjectionLeaf::DropPassThroughClone) {
result = i18nc("@info:tooltip", "Disabled: cloning pass-through groups is not supported!");
}
return result;
}
default:
if (role >= int(KisNodeModel::BeginThumbnailRole) && belongsToIsolatedGroup(node)) {
const int maxSize = role - int(KisNodeModel::BeginThumbnailRole);
-
- QSize size = node->extent().size();
- size.scale(maxSize, maxSize, Qt::KeepAspectRatio);
- if (size.width() == 0 || size.height() == 0) {
- // No thumbnail can be shown if there isn't width or height...
- return QVariant();
- }
-
- return node->createThumbnail(size.width(), size.height());
+ return node->createThumbnail(maxSize, maxSize, Qt::KeepAspectRatio);
} else {
return QVariant();
}
}
return QVariant();
}
Qt::ItemFlags KisNodeModel::flags(const QModelIndex &index) const
{
if(!m_d->dummiesFacade || !index.isValid()) return Qt::ItemIsDropEnabled;
Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEditable;
if (m_d->dropEnabled.contains(index.internalId())) {
flags |= Qt::ItemIsDropEnabled;
}
return flags;
}
bool KisNodeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role == KisNodeModel::DropEnabled) {
const QMimeData *mimeData = static_cast<const QMimeData*>(value.value<void*>());
setDropEnabled(mimeData);
return true;
}
if (role == KisNodeModel::ActiveRole || role == KisNodeModel::AlternateActiveRole) {
QModelIndex parentIndex;
if (!index.isValid() && m_d->parentOfRemovedNode && m_d->dummiesFacade && m_d->indexConverter) {
parentIndex = m_d->indexConverter->indexFromDummy(m_d->parentOfRemovedNode);
m_d->parentOfRemovedNode = 0;
}
KisNodeSP activatedNode;
if (index.isValid() && value.toBool()) {
activatedNode = nodeFromIndex(index);
}
else if (parentIndex.isValid() && value.toBool()) {
activatedNode = nodeFromIndex(parentIndex);
}
else {
activatedNode = 0;
}
QModelIndex newActiveNode = activatedNode ? indexFromNode(activatedNode) : QModelIndex();
if (role == KisNodeModel::ActiveRole && value.toBool() &&
m_d->activeNodeIndex == newActiveNode) {
return true;
}
m_d->activeNodeIndex = newActiveNode;
if (m_d->nodeSelectionAdapter) {
m_d->nodeSelectionAdapter->setActiveNode(activatedNode);
}
if (role == KisNodeModel::AlternateActiveRole) {
emit toggleIsolateActiveNode();
}
emit dataChanged(index, index);
return true;
}
if(!m_d->dummiesFacade || !index.isValid()) return false;
bool result = true;
bool shouldUpdate = true;
bool shouldUpdateRecursively = false;
KisNodeSP node = nodeFromIndex(index);
switch (role) {
case Qt::DisplayRole:
case Qt::EditRole:
m_d->nodeManager->setNodeName(node, value.toString());
break;
case KisNodeModel::PropertiesRole:
{
// don't record undo/redo for visibility, locked or alpha locked changes
KisBaseNode::PropertyList proplist = value.value<KisBaseNode::PropertyList>();
m_d->nodeManager->trySetNodeProperties(node, m_d->image, proplist);
shouldUpdateRecursively = true;
break;
}
case KisNodeModel::SelectOpaqueRole:
if (node && m_d->selectionActionsAdapter) {
SelectionAction action = SelectionAction(value.toInt());
m_d->selectionActionsAdapter->selectOpaqueOnNode(node, action);
}
shouldUpdate = false;
break;
default:
result = false;
}
if (result && shouldUpdate) {
if (shouldUpdateRecursively) {
QSet<QModelIndex> indexes;
addChangedIndex(index, &indexes);
Q_FOREACH (const QModelIndex &index, indexes) {
emit dataChanged(index, index);
}
} else {
emit dataChanged(index, index);
}
}
return result;
}
Qt::DropActions KisNodeModel::supportedDragActions() const
{
return Qt::CopyAction | Qt::MoveAction;
}
Qt::DropActions KisNodeModel::supportedDropActions() const
{
return Qt::MoveAction | Qt::CopyAction;
}
bool KisNodeModel::hasDummiesFacade()
{
return m_d->dummiesFacade != 0;
}
QStringList KisNodeModel::mimeTypes() const
{
QStringList types;
types << QLatin1String("application/x-krita-node");
types << QLatin1String("application/x-qt-image");
return types;
}
QMimeData * KisNodeModel::mimeData(const QModelIndexList &indexes) const
{
KisNodeList nodes;
Q_FOREACH (const QModelIndex &idx, indexes) {
nodes << nodeFromIndex(idx);
}
return KisMimeData::mimeForLayers(nodes, m_d->image);
}
bool KisNodeModel::dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent)
{
Q_UNUSED(column);
bool copyNode = (action == Qt::CopyAction);
KisNodeDummy *parentDummy = 0;
KisNodeDummy *aboveThisDummy = 0;
parentDummy = parent.isValid() ?
m_d->indexConverter->dummyFromIndex(parent) :
m_d->dummiesFacade->rootDummy();
if (row == -1) {
aboveThisDummy = parent.isValid() ? parentDummy->lastChild() : 0;
}
else {
aboveThisDummy = row < m_d->indexConverter->rowCount(parent) ? m_d->indexConverter->dummyFromRow(row, parent) : 0;
}
return KisMimeData::insertMimeLayers(data,
m_d->image,
m_d->shapeController,
parentDummy,
aboveThisDummy,
copyNode,
m_d->nodeInsertionAdapter);
}
bool KisNodeModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const {
if (parent.isValid()) {
// drop occurred on an item. always return true as returning false will mess up
// QT5's drag handling (see KisNodeModel::setDropEnabled).
return true;
} else {
return QAbstractItemModel::canDropMimeData(data, action, row, column, parent);
}
}
void KisNodeModel::setDropEnabled(const QMimeData *data) {
// what happens here should really happen in KisNodeModel::canDropMimeData(), but QT5
// will mess up if an item's Qt::ItemIsDropEnabled does not match what is returned by
// canDropMimeData; specifically, if we set the flag, but decide in canDropMimeData()
// later on that an "onto" drag is not allowed, QT will display an drop indicator for
// insertion, but not perform any drop when the mouse is released.
// the only robust implementation seems to set all flags correctly, which is done here.
bool copyNode = false;
KisNodeList nodes = KisMimeData::loadNodesFast(data, m_d->image, m_d->shapeController, copyNode);
m_d->dropEnabled.clear();
updateDropEnabled(nodes);
}
void KisNodeModel::updateDropEnabled(const QList<KisNodeSP> &nodes, QModelIndex parent) {
for (int r = 0; r < rowCount(parent); r++) {
QModelIndex idx = index(r, 0, parent);
KisNodeSP target = nodeFromIndex(idx);
bool dropEnabled = true;
Q_FOREACH (const KisNodeSP &node, nodes) {
if (!target->allowAsChild(node)) {
dropEnabled = false;
break;
}
}
if (dropEnabled) {
m_d->dropEnabled.insert(idx.internalId());
}
emit dataChanged(idx, idx); // indicate to QT that flags() have changed
if (hasChildren(idx)) {
updateDropEnabled(nodes, idx);
}
}
}
diff --git a/libs/ui/kis_selection_decoration.cc b/libs/ui/kis_selection_decoration.cc
index c6253a2b03..c7589f36d3 100644
--- a/libs/ui/kis_selection_decoration.cc
+++ b/libs/ui/kis_selection_decoration.cc
@@ -1,226 +1,226 @@
/*
* Copyright (c) 2008 Sven Langkamp <sven.langkamp@gmail.com>
*
* 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; 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 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 "kis_selection_decoration.h"
#include <QPainter>
#include <QVarLengthArray>
#include <kis_debug.h>
#include <klocalizedstring.h>
#include "kis_types.h"
#include "KisViewManager.h"
#include "kis_selection.h"
#include "kis_image.h"
#include "flake/kis_shape_selection.h"
#include "kis_pixel_selection.h"
#include "kis_update_outline_job.h"
#include "kis_selection_manager.h"
#include "canvas/kis_canvas2.h"
#include "kis_canvas_resource_provider.h"
#include "kis_coordinates_converter.h"
#include "kis_config.h"
#include "kis_config_notifier.h"
#include "kis_image_config.h"
#include "KisImageConfigNotifier.h"
#include "kis_painting_tweaks.h"
#include "KisView.h"
#include "kis_selection_mask.h"
#include <KisPart.h>
static const unsigned int ANT_LENGTH = 4;
static const unsigned int ANT_SPACE = 4;
static const unsigned int ANT_ADVANCE_WIDTH = ANT_LENGTH + ANT_SPACE;
KisSelectionDecoration::KisSelectionDecoration(QPointer<KisView>view)
: KisCanvasDecoration("selection", view),
m_signalCompressor(40 /*ms*/, KisSignalCompressor::FIRST_ACTIVE),
m_offset(0),
m_mode(Ants)
{
KisPaintingTweaks::initAntsPen(&m_antsPen, &m_outlinePen,
ANT_LENGTH, ANT_SPACE);
connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged()));
connect(KisImageConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged()));
slotConfigChanged();
m_antsTimer = new QTimer(this);
m_antsTimer->setInterval(150);
m_antsTimer->setSingleShot(false);
connect(m_antsTimer, SIGNAL(timeout()), SLOT(antsAttackEvent()));
connect(&m_signalCompressor, SIGNAL(timeout()), SLOT(slotStartUpdateSelection()));
// selections should be at the top of the stack
setPriority(100);
}
KisSelectionDecoration::~KisSelectionDecoration()
{
}
KisSelectionDecoration::Mode KisSelectionDecoration::mode() const
{
return m_mode;
}
void KisSelectionDecoration::setMode(Mode mode)
{
m_mode = mode;
selectionChanged();
}
bool KisSelectionDecoration::selectionIsActive()
{
KisSelectionSP selection = view()->selection();
return visible() && selection &&
- (selection->hasPixelSelection() || selection->hasShapeSelection()) &&
+ (selection->hasNonEmptyPixelSelection() || selection->hasNonEmptyShapeSelection()) &&
selection->isVisible();
}
void KisSelectionDecoration::selectionChanged()
{
KisSelectionMaskSP mask = qobject_cast<KisSelectionMask*>(view()->currentNode().data());
if (!mask || !mask->active() || !mask->visible(true)) {
mask = 0;
}
if (!view()->isCurrent() ||
view()->viewManager()->mainWindow() == KisPart::instance()->currentMainwindow()) {
view()->image()->setOverlaySelectionMask(mask);
}
KisSelectionSP selection = view()->selection();
if (!mask && selection && selectionIsActive()) {
if ((m_mode == Ants && selection->outlineCacheValid()) ||
(m_mode == Mask && selection->thumbnailImageValid())) {
m_signalCompressor.stop();
if (m_mode == Ants) {
m_outlinePath = selection->outlineCache();
m_antsTimer->start();
} else {
m_thumbnailImage = selection->thumbnailImage();
m_thumbnailImageTransform = selection->thumbnailImageTransform();
}
if (view() && view()->canvasBase()) {
view()->canvasBase()->updateCanvas();
}
} else {
m_signalCompressor.start();
}
} else {
m_signalCompressor.stop();
m_outlinePath = QPainterPath();
m_thumbnailImage = QImage();
m_thumbnailImageTransform = QTransform();
view()->canvasBase()->updateCanvas();
m_antsTimer->stop();
}
}
void KisSelectionDecoration::slotStartUpdateSelection()
{
KisSelectionSP selection = view()->selection();
if (!selection) return;
view()->image()->addSpontaneousJob(new KisUpdateOutlineJob(selection, m_mode == Mask, m_maskColor));
}
void KisSelectionDecoration::slotConfigChanged()
{
KisImageConfig imageConfig(true);
KisConfig cfg(true);
m_maskColor = imageConfig.selectionOverlayMaskColor();
m_antialiasSelectionOutline = cfg.antialiasSelectionOutline();
}
void KisSelectionDecoration::antsAttackEvent()
{
KisSelectionSP selection = view()->selection();
if (!selection) return;
if (selectionIsActive()) {
m_offset = (m_offset + 1) % ANT_ADVANCE_WIDTH;
m_antsPen.setDashOffset(m_offset);
view()->canvasBase()->updateCanvas();
}
}
void KisSelectionDecoration::drawDecoration(QPainter& gc, const QRectF& updateRect, const KisCoordinatesConverter *converter, KisCanvas2 *canvas)
{
Q_UNUSED(updateRect);
Q_UNUSED(canvas);
if (!selectionIsActive()) return;
if ((m_mode == Ants && m_outlinePath.isEmpty()) ||
(m_mode == Mask && m_thumbnailImage.isNull())) return;
QTransform transform = converter->imageToWidgetTransform();
gc.save();
gc.setTransform(transform, false);
if (m_mode == Mask) {
gc.setRenderHints(QPainter::SmoothPixmapTransform |
QPainter::HighQualityAntialiasing, false);
gc.setTransform(m_thumbnailImageTransform, true);
gc.drawImage(QPoint(), m_thumbnailImage);
QRect r1 = m_thumbnailImageTransform.inverted().mapRect(view()->image()->bounds());
QRect r2 = m_thumbnailImage.rect();
QPainterPath p1;
p1.addRect(r1);
QPainterPath p2;
p2.addRect(r2);
gc.setBrush(m_maskColor);
gc.setPen(Qt::NoPen);
gc.drawPath(p1 - p2);
} else /* if (m_mode == Ants) */ {
gc.setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing, m_antialiasSelectionOutline);
// render selection outline in white
gc.setPen(m_outlinePen);
gc.drawPath(m_outlinePath);
// render marching ants in black (above the white outline)
gc.setPen(m_antsPen);
gc.drawPath(m_outlinePath);
}
gc.restore();
}
void KisSelectionDecoration::setVisible(bool v)
{
KisCanvasDecoration::setVisible(v);
selectionChanged();
}
diff --git a/libs/ui/kis_selection_manager.cc b/libs/ui/kis_selection_manager.cc
index b469249eb5..c719835b53 100644
--- a/libs/ui/kis_selection_manager.cc
+++ b/libs/ui/kis_selection_manager.cc
@@ -1,740 +1,740 @@
/*
* Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
* Copyright (c) 2007 Sven Langkamp <sven.langkamp@gmail.com>
*
* The outline algorithm uses the limn algorithm of fontutils by
* Karl Berry <karl@cs.umb.edu> and Kathryn Hargreaves <letters@cs.umb.edu>
*
* 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_manager.h"
#include <QApplication>
#include <QClipboard>
#include <QColor>
#include <QTimer>
#include <QMimeData>
#include <QAction>
#include <ktoggleaction.h>
#include <klocalizedstring.h>
#include <kstandardaction.h>
#include <kactioncollection.h>
#include "KoCanvasController.h"
#include "KoChannelInfo.h"
#include "KoIntegerMaths.h"
#include <KisDocument.h>
#include <KisMainWindow.h>
#include <KoSelection.h>
#include <KoShapeManager.h>
#include <KoSelectedShapesProxy.h>
#include <KoShapeStroke.h>
#include <KoColorSpace.h>
#include <KoCompositeOp.h>
#include <KoToolProxy.h>
#include <KoSvgPaste.h>
#include <kis_icon.h>
#include "kis_adjustment_layer.h"
#include "kis_node_manager.h"
#include "canvas/kis_canvas2.h"
#include "kis_config.h"
#include "kis_convolution_painter.h"
#include "kis_convolution_kernel.h"
#include "kis_debug.h"
#include "kis_fill_painter.h"
#include "kis_group_layer.h"
#include "kis_layer.h"
#include "kis_statusbar.h"
#include "kis_paint_device.h"
#include "kis_paint_layer.h"
#include "kis_painter.h"
#include "kis_transaction.h"
#include "kis_selection.h"
#include "kis_types.h"
#include "kis_canvas_resource_provider.h"
#include "kis_undo_adapter.h"
#include "kis_pixel_selection.h"
#include "flake/kis_shape_selection.h"
#include "commands/kis_selection_commands.h"
#include "kis_selection_mask.h"
#include "flake/kis_shape_layer.h"
#include "kis_selection_decoration.h"
#include "canvas/kis_canvas_decoration.h"
#include "kis_node_commands_adapter.h"
#include "kis_iterator_ng.h"
#include "kis_clipboard.h"
#include "KisViewManager.h"
#include "kis_selection_filters.h"
#include "kis_figure_painting_tool_helper.h"
#include "KisView.h"
#include "dialogs/kis_dlg_stroke_selection_properties.h"
#include "actions/kis_selection_action_factories.h"
#include "actions/KisPasteActionFactories.h"
#include "kis_action.h"
#include "kis_action_manager.h"
#include "operations/kis_operation_configuration.h"
//new
#include "kis_node_query_path.h"
#include "kis_tool_shape.h"
KisSelectionManager::KisSelectionManager(KisViewManager * view)
: m_view(view)
, m_adapter(new KisNodeCommandsAdapter(view))
{
m_clipboard = KisClipboard::instance();
}
KisSelectionManager::~KisSelectionManager()
{
}
void KisSelectionManager::setup(KisActionManager* actionManager)
{
m_cut = actionManager->createStandardAction(KStandardAction::Cut, this, SLOT(cut()));
m_copy = actionManager->createStandardAction(KStandardAction::Copy, this, SLOT(copy()));
m_paste = actionManager->createStandardAction(KStandardAction::Paste, this, SLOT(paste()));
KisAction *action = actionManager->createAction("copy_sharp");
connect(action, SIGNAL(triggered()), this, SLOT(copySharp()));
action = actionManager->createAction("cut_sharp");
connect(action, SIGNAL(triggered()), this, SLOT(cutSharp()));
m_pasteNew = actionManager->createAction("paste_new");
connect(m_pasteNew, SIGNAL(triggered()), this, SLOT(pasteNew()));
m_pasteAt = actionManager->createAction("paste_at");
connect(m_pasteAt, SIGNAL(triggered()), this, SLOT(pasteAt()));
m_pasteAsReference = actionManager->createAction("paste_as_reference");
connect(m_pasteAsReference, SIGNAL(triggered()), this, SLOT(pasteAsReference()));
m_copyMerged = actionManager->createAction("copy_merged");
connect(m_copyMerged, SIGNAL(triggered()), this, SLOT(copyMerged()));
m_selectAll = actionManager->createAction("select_all");
connect(m_selectAll, SIGNAL(triggered()), this, SLOT(selectAll()));
m_deselect = actionManager->createAction("deselect");
connect(m_deselect, SIGNAL(triggered()), this, SLOT(deselect()));
m_clear = actionManager->createAction("clear");
connect(m_clear, SIGNAL(triggered()), SLOT(clear()));
m_reselect = actionManager->createAction("reselect");
connect(m_reselect, SIGNAL(triggered()), this, SLOT(reselect()));
m_invert = actionManager->createAction("invert_selection");
m_invert->setOperationID("invertselection");
actionManager->registerOperation(new KisInvertSelectionOperation);
m_copyToNewLayer = actionManager->createAction("copy_selection_to_new_layer");
connect(m_copyToNewLayer, SIGNAL(triggered()), this, SLOT(copySelectionToNewLayer()));
m_cutToNewLayer = actionManager->createAction("cut_selection_to_new_layer");
connect(m_cutToNewLayer, SIGNAL(triggered()), this, SLOT(cutToNewLayer()));
m_fillForegroundColor = actionManager->createAction("fill_selection_foreground_color");
connect(m_fillForegroundColor, SIGNAL(triggered()), this, SLOT(fillForegroundColor()));
m_fillBackgroundColor = actionManager->createAction("fill_selection_background_color");
connect(m_fillBackgroundColor, SIGNAL(triggered()), this, SLOT(fillBackgroundColor()));
m_fillPattern = actionManager->createAction("fill_selection_pattern");
connect(m_fillPattern, SIGNAL(triggered()), this, SLOT(fillPattern()));
m_fillForegroundColorOpacity = actionManager->createAction("fill_selection_foreground_color_opacity");
connect(m_fillForegroundColorOpacity, SIGNAL(triggered()), this, SLOT(fillForegroundColorOpacity()));
m_fillBackgroundColorOpacity = actionManager->createAction("fill_selection_background_color_opacity");
connect(m_fillBackgroundColorOpacity, SIGNAL(triggered()), this, SLOT(fillBackgroundColorOpacity()));
m_fillPatternOpacity = actionManager->createAction("fill_selection_pattern_opacity");
connect(m_fillPatternOpacity, SIGNAL(triggered()), this, SLOT(fillPatternOpacity()));
m_strokeShapes = actionManager->createAction("stroke_shapes");
connect(m_strokeShapes, SIGNAL(triggered()), this, SLOT(paintSelectedShapes()));
m_toggleDisplaySelection = actionManager->createAction("toggle_display_selection");
connect(m_toggleDisplaySelection, SIGNAL(triggered()), this, SLOT(toggleDisplaySelection()));
m_toggleDisplaySelection->setChecked(true);
m_imageResizeToSelection = actionManager->createAction("resizeimagetoselection");
connect(m_imageResizeToSelection, SIGNAL(triggered()), this, SLOT(imageResizeToSelection()));
action = actionManager->createAction("edit_selection");
connect(action, SIGNAL(triggered()), SLOT(editSelection()));
action = actionManager->createAction("convert_to_vector_selection");
connect(action, SIGNAL(triggered()), SLOT(convertToVectorSelection()));
action = actionManager->createAction("convert_to_raster_selection");
connect(action, SIGNAL(triggered()), SLOT(convertToRasterSelection()));
action = actionManager->createAction("convert_shapes_to_vector_selection");
connect(action, SIGNAL(triggered()), SLOT(convertShapesToVectorSelection()));
action = actionManager->createAction("convert_selection_to_shape");
connect(action, SIGNAL(triggered()), SLOT(convertToShape()));
m_toggleSelectionOverlayMode = actionManager->createAction("toggle-selection-overlay-mode");
connect(m_toggleSelectionOverlayMode, SIGNAL(triggered()), SLOT(slotToggleSelectionDecoration()));
m_strokeSelected = actionManager->createAction("stroke_selection");
connect(m_strokeSelected, SIGNAL(triggered()), SLOT(slotStrokeSelection()));
QClipboard *cb = QApplication::clipboard();
connect(cb, SIGNAL(dataChanged()), SLOT(clipboardDataChanged()));
}
void KisSelectionManager::setView(QPointer<KisView>imageView)
{
if (m_imageView && m_imageView->canvasBase()) {
disconnect(m_imageView->canvasBase()->toolProxy(), SIGNAL(toolChanged(QString)), this, SLOT(clipboardDataChanged()));
KoSelection *selection = m_imageView->canvasBase()->globalShapeManager()->selection();
selection->disconnect(this, SLOT(shapeSelectionChanged()));
KisSelectionDecoration *decoration = qobject_cast<KisSelectionDecoration*>(m_imageView->canvasBase()->decoration("selection").data());
if (decoration) {
disconnect(SIGNAL(currentSelectionChanged()), decoration);
}
m_imageView->image()->undoAdapter()->disconnect(this);
m_selectionDecoration = 0;
}
m_imageView = imageView;
if (m_imageView) {
connect(m_imageView->canvasBase()->selectedShapesProxy(), SIGNAL(selectionChanged()), this, SLOT(shapeSelectionChanged()), Qt::UniqueConnection);
KisSelectionDecoration* decoration = qobject_cast<KisSelectionDecoration*>(m_imageView->canvasBase()->decoration("selection").data());
if (!decoration) {
decoration = new KisSelectionDecoration(m_imageView);
decoration->setVisible(true);
m_imageView->canvasBase()->addDecoration(decoration);
}
m_selectionDecoration = decoration;
connect(this, SIGNAL(currentSelectionChanged()), decoration, SLOT(selectionChanged()));
connect(m_imageView->image()->undoAdapter(), SIGNAL(selectionChanged()), SLOT(selectionChanged()));
connect(m_imageView->canvasBase()->toolProxy(), SIGNAL(toolChanged(QString)), SLOT(clipboardDataChanged()));
}
}
void KisSelectionManager::clipboardDataChanged()
{
m_view->updateGUI();
}
bool KisSelectionManager::havePixelsSelected()
{
KisSelectionSP activeSelection = m_view->selection();
return activeSelection && !activeSelection->selectedRect().isEmpty();
}
bool KisSelectionManager::havePixelsInClipboard()
{
return m_clipboard->hasClip();
}
bool KisSelectionManager::haveShapesSelected()
{
if (m_view && m_view->canvasBase()) {
return m_view->canvasBase()->selectedShapesProxy()->selection()->count() > 0;
}
return false;
}
bool KisSelectionManager::haveShapesInClipboard()
{
KoSvgPaste paste;
return paste.hasShapes();
}
bool KisSelectionManager::haveAnySelectionWithPixels()
{
KisSelectionSP selection = m_view->selection();
- return selection && selection->hasPixelSelection();
+ return selection && selection->hasNonEmptyPixelSelection();
}
bool KisSelectionManager::haveShapeSelectionWithShapes()
{
KisSelectionSP selection = m_view->selection();
- return selection && selection->hasShapeSelection();
+ return selection && selection->hasNonEmptyShapeSelection();
}
bool KisSelectionManager::haveRasterSelectionWithPixels()
{
KisSelectionSP selection = m_view->selection();
- return selection && selection->hasPixelSelection() && !selection->hasShapeSelection();
+ return selection && selection->hasNonEmptyPixelSelection() && !selection->hasNonEmptyShapeSelection();
}
void KisSelectionManager::updateGUI()
{
Q_ASSERT(m_view);
Q_ASSERT(m_clipboard);
if (!m_view || !m_clipboard) return;
bool havePixelsSelected = this->havePixelsSelected();
bool havePixelsInClipboard = this->havePixelsInClipboard();
bool haveShapesSelected = this->haveShapesSelected();
bool haveShapesInClipboard = this->haveShapesInClipboard();
bool haveDevice = m_view->activeDevice();
KisLayerSP activeLayer = m_view->activeLayer();
KisImageWSP image = activeLayer ? activeLayer->image() : 0;
bool canReselect = image && image->canReselectGlobalSelection();
bool canDeselect = image && image->globalSelection();
m_clear->setEnabled(haveDevice || havePixelsSelected || haveShapesSelected);
m_cut->setEnabled(havePixelsSelected || haveShapesSelected);
m_copy->setEnabled(havePixelsSelected || haveShapesSelected);
m_paste->setEnabled(havePixelsInClipboard || haveShapesInClipboard);
m_pasteAt->setEnabled(havePixelsInClipboard || haveShapesInClipboard);
// FIXME: how about pasting shapes?
m_pasteNew->setEnabled(havePixelsInClipboard);
m_pasteAsReference->setEnabled(haveDevice);
m_selectAll->setEnabled(true);
m_deselect->setEnabled(canDeselect);
m_reselect->setEnabled(canReselect);
// m_load->setEnabled(true);
// m_save->setEnabled(havePixelsSelected);
updateStatusBar();
emit signalUpdateGUI();
}
void KisSelectionManager::updateStatusBar()
{
if (m_view && m_view->statusBar()) {
m_view->statusBar()->setSelection(m_view->image());
}
}
void KisSelectionManager::selectionChanged()
{
m_view->updateGUI();
emit currentSelectionChanged();
}
void KisSelectionManager::cut()
{
KisCutCopyActionFactory factory;
factory.run(true, false, m_view);
}
void KisSelectionManager::copy()
{
KisCutCopyActionFactory factory;
factory.run(false, false, m_view);
}
void KisSelectionManager::cutSharp()
{
KisCutCopyActionFactory factory;
factory.run(true, true, m_view);
}
void KisSelectionManager::copySharp()
{
KisCutCopyActionFactory factory;
factory.run(false, true, m_view);
}
void KisSelectionManager::copyMerged()
{
KisCopyMergedActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::paste()
{
KisPasteActionFactory factory;
factory.run(false, m_view);
}
void KisSelectionManager::pasteAt()
{
KisPasteActionFactory factory;
factory.run(true, m_view);
}
void KisSelectionManager::pasteAsReference()
{
KisPasteReferenceActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::pasteNew()
{
KisPasteNewActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::selectAll()
{
KisSelectAllActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::deselect()
{
KisDeselectActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::invert()
{
if(m_invert)
m_invert->trigger();
}
void KisSelectionManager::reselect()
{
KisReselectActionFactory factory;
factory.run(m_view);
}
#include <KoToolManager.h>
#include <KoInteractionTool.h>
void KisSelectionManager::editSelection()
{
KisSelectionSP selection = m_view->selection();
if (!selection) return;
KisAction *action = m_view->actionManager()->actionByName("show-global-selection-mask");
KIS_SAFE_ASSERT_RECOVER_RETURN(action);
if (!action->isChecked()) {
action->setChecked(true);
emit action->toggled(true);
emit action->triggered(true);
}
KisNodeSP node = selection->parentNode();
KIS_SAFE_ASSERT_RECOVER_RETURN(node);
m_view->nodeManager()->slotNonUiActivatedNode(node);
if (selection->hasShapeSelection()) {
KisShapeSelection *shapeSelection = dynamic_cast<KisShapeSelection*>(selection->shapeSelection());
KIS_SAFE_ASSERT_RECOVER_RETURN(shapeSelection);
KoToolManager::instance()->switchToolRequested(KoInteractionTool_ID);
QList<KoShape*> shapes = shapeSelection->shapes();
if (shapes.isEmpty()) {
KIS_SAFE_ASSERT_RECOVER_NOOP(0 && "no shapes");
return;
}
Q_FOREACH (KoShape *shape, shapes) {
m_view->canvasBase()->selectedShapesProxy()->selection()->select(shape);
}
} else {
KoToolManager::instance()->switchToolRequested("KisToolTransform");
}
}
void KisSelectionManager::convertToVectorSelection()
{
KisSelectionToVectorActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::convertToRasterSelection()
{
KisSelectionToRasterActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::convertShapesToVectorSelection()
{
KisShapesToVectorSelectionActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::convertToShape()
{
KisSelectionToShapeActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::clear()
{
KisClearActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::fillForegroundColor()
{
KisFillActionFactory factory;
factory.run("fg", m_view);
}
void KisSelectionManager::fillBackgroundColor()
{
KisFillActionFactory factory;
factory.run("bg", m_view);
}
void KisSelectionManager::fillPattern()
{
KisFillActionFactory factory;
factory.run("pattern", m_view);
}
void KisSelectionManager::fillForegroundColorOpacity()
{
KisFillActionFactory factory;
factory.run("fg_opacity", m_view);
}
void KisSelectionManager::fillBackgroundColorOpacity()
{
KisFillActionFactory factory;
factory.run("bg_opacity", m_view);
}
void KisSelectionManager::fillPatternOpacity()
{
KisFillActionFactory factory;
factory.run("pattern_opacity", m_view);
}
void KisSelectionManager::copySelectionToNewLayer()
{
copy();
paste();
}
void KisSelectionManager::cutToNewLayer()
{
cut();
paste();
}
void KisSelectionManager::toggleDisplaySelection()
{
KIS_ASSERT_RECOVER_RETURN(m_selectionDecoration);
m_selectionDecoration->toggleVisibility();
m_toggleDisplaySelection->blockSignals(true);
m_toggleDisplaySelection->setChecked(m_selectionDecoration->visible());
m_toggleDisplaySelection->blockSignals(false);
emit displaySelectionChanged();
}
bool KisSelectionManager::displaySelection()
{
return m_toggleDisplaySelection->isChecked();
}
void KisSelectionManager::shapeSelectionChanged()
{
KoShapeManager* shapeManager = m_view->canvasBase()->globalShapeManager();
KoSelection * selection = shapeManager->selection();
QList<KoShape*> selectedShapes = selection->selectedShapes();
KoShapeStrokeSP border(new KoShapeStroke(0, Qt::lightGray));
Q_FOREACH (KoShape* shape, shapeManager->shapes()) {
if (dynamic_cast<KisShapeSelection*>(shape->parent())) {
if (selectedShapes.contains(shape))
shape->setStroke(border);
else
shape->setStroke(KoShapeStrokeSP());
}
}
m_view->updateGUI();
}
void KisSelectionManager::imageResizeToSelection()
{
KisImageResizeToSelectionActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::paintSelectedShapes()
{
KisImageWSP image = m_view->image();
if (!image) return;
KisLayerSP layer = m_view->activeLayer();
if (!layer) return;
QList<KoShape*> shapes = m_view->canvasBase()->shapeManager()->selection()->selectedShapes();
KisPaintLayerSP paintLayer = new KisPaintLayer(image, i18n("Stroked Shapes"), OPACITY_OPAQUE_U8);
KUndo2MagicString actionName = kundo2_i18n("Stroke Shapes");
m_adapter->beginMacro(actionName);
m_adapter->addNode(paintLayer.data(), layer->parent().data(), layer.data());
KisFigurePaintingToolHelper helper(actionName,
image,
paintLayer.data(),
m_view->canvasResourceProvider()->resourceManager(),
KisToolShapeUtils::StrokeStyleForeground,
KisToolShapeUtils::FillStyleNone);
Q_FOREACH (KoShape* shape, shapes) {
QTransform matrix = shape->absoluteTransformation() * QTransform::fromScale(image->xRes(), image->yRes());
QPainterPath mapedOutline = matrix.map(shape->outline());
helper.paintPainterPath(mapedOutline);
}
m_adapter->endMacro();
}
void KisSelectionManager::slotToggleSelectionDecoration()
{
KIS_ASSERT_RECOVER_RETURN(m_selectionDecoration);
KisSelectionDecoration::Mode mode =
m_selectionDecoration->mode() ?
KisSelectionDecoration::Ants : KisSelectionDecoration::Mask;
m_selectionDecoration->setMode(mode);
emit displaySelectionChanged();
}
bool KisSelectionManager::showSelectionAsMask() const
{
if (m_selectionDecoration) {
return m_selectionDecoration->mode() == KisSelectionDecoration::Mask;
}
return false;
}
void KisSelectionManager::slotStrokeSelection()
{
KisImageWSP image = m_view->image();
if (!image ) {
return;
}
KisNodeSP currentNode = m_view->canvasResourceProvider()->resourceManager()->resource(KisCanvasResourceProvider::CurrentKritaNode).value<KisNodeWSP>();
bool isVectorLayer = false;
if (currentNode->inherits("KisShapeLayer")) {
isVectorLayer = true;
}
QPointer<KisDlgStrokeSelection> dlg = new KisDlgStrokeSelection(image, m_view, isVectorLayer);
if (dlg->exec() == QDialog::Accepted) {
StrokeSelectionOptions params = dlg->getParams();
if (params.brushSelected){
KisStrokeBrushSelectionActionFactory factory;
factory.run(m_view, params);
}
else {
KisStrokeSelectionActionFactory factory;
factory.run(m_view, params);
}
}
delete dlg;
}
#include "kis_image_barrier_locker.h"
#include "kis_selection_tool_helper.h"
void KisSelectionManager::selectOpaqueOnNode(KisNodeSP node, SelectionAction action)
{
KisImageSP image = m_view->image();
if (!m_view->blockUntilOperationsFinished(image)) {
return;
}
KUndo2MagicString actionName;
KisPixelSelectionSP tmpSel = KisPixelSelectionSP(new KisPixelSelection());
KisCanvas2 *canvas = m_view->canvasBase();
{
KisImageBarrierLocker locker(image);
KisPaintDeviceSP device = node->projection();
if (!device) device = node->paintDevice();
if (!device) device = node->original();
if (!device) return;
QRect rc = device->exactBounds();
if (rc.isEmpty()) return;
KIS_ASSERT_RECOVER_RETURN(canvas);
/**
* If there is nothing selected, just create a new selection
*/
if (!canvas->imageView()->selection()) {
action = SELECTION_REPLACE;
}
switch (action) {
case SELECTION_ADD:
actionName = kundo2_i18n("Select Opaque (Add)");
break;
case SELECTION_SUBTRACT:
actionName = kundo2_i18n("Select Opaque (Subtract)");
break;
case SELECTION_INTERSECT:
actionName = kundo2_i18n("Select Opaque (Intersect)");
break;
case SELECTION_SYMMETRICDIFFERENCE:
actionName = kundo2_i18n("Select Opaque (Symmetric Difference)");
break;
default:
actionName = kundo2_i18n("Select Opaque");
break;
}
qint32 x, y, w, h;
rc.getRect(&x, &y, &w, &h);
const KoColorSpace * cs = device->colorSpace();
KisHLineConstIteratorSP deviter = device->createHLineConstIteratorNG(x, y, w);
KisHLineIteratorSP selIter = tmpSel ->createHLineIteratorNG(x, y, w);
for (int row = y; row < h + y; ++row) {
do {
*selIter->rawData() = cs->opacityU8(deviter->oldRawData());
} while (deviter->nextPixel() && selIter->nextPixel());
deviter->nextRow();
selIter->nextRow();
}
}
KisSelectionToolHelper helper(canvas, actionName);
tmpSel->invalidateOutlineCache();
helper.selectPixelSelection(tmpSel, action);
}
diff --git a/libs/ui/layerstyles/wdglayerstyles.ui b/libs/ui/layerstyles/wdglayerstyles.ui
index 4812a41b93..a5f6ff3f8f 100644
--- a/libs/ui/layerstyles/wdglayerstyles.ui
+++ b/libs/ui/layerstyles/wdglayerstyles.ui
@@ -1,209 +1,209 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>WdgStylesDialog</class>
<widget class="QWidget" name="WdgStylesDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1607</width>
<height>924</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="chkMasterFxSwitch">
<property name="text">
<string>Enable Effects</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="lstStyleSelector">
<item>
<property name="text">
<string>Styles</string>
</property>
</item>
<item>
<property name="text">
<string>Blending Options</string>
</property>
</item>
<item>
<property name="text">
<string>Drop Shadow</string>
</property>
<property name="checkState">
<enum>Unchecked</enum>
</property>
</item>
<item>
<property name="text">
<string>Inner Shadow</string>
</property>
<property name="checkState">
<enum>Unchecked</enum>
</property>
</item>
<item>
<property name="text">
<string>Outer Glow</string>
</property>
<property name="checkState">
<enum>Unchecked</enum>
</property>
</item>
<item>
<property name="text">
<string>Inner Glow</string>
</property>
<property name="checkState">
<enum>Unchecked</enum>
</property>
</item>
<item>
<property name="text">
<string>Bevel and Emboss</string>
</property>
<property name="checkState">
<enum>Unchecked</enum>
</property>
</item>
<item>
<property name="text">
<string>Contour</string>
</property>
<property name="checkState">
<enum>Unchecked</enum>
</property>
<property name="flags">
<set>ItemIsSelectable|ItemIsDragEnabled|ItemIsUserCheckable</set>
</property>
</item>
<item>
<property name="text">
<string>Texture</string>
</property>
<property name="checkState">
<enum>Unchecked</enum>
</property>
<property name="flags">
<set>ItemIsSelectable|ItemIsDragEnabled|ItemIsUserCheckable</set>
</property>
</item>
<item>
<property name="text">
<string>Satin</string>
</property>
<property name="checkState">
<enum>Unchecked</enum>
</property>
</item>
<item>
<property name="text">
<string>Color Overlay</string>
</property>
<property name="checkState">
<enum>Unchecked</enum>
</property>
</item>
<item>
<property name="text">
<string>Gradient Overlay</string>
</property>
<property name="checkState">
<enum>Unchecked</enum>
</property>
</item>
<item>
<property name="text">
<string>Pattern Overlay</string>
</property>
<property name="checkState">
<enum>Unchecked</enum>
</property>
</item>
<item>
<property name="text">
<string>Stroke</string>
</property>
<property name="checkState">
<enum>Unchecked</enum>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QStackedWidget" name="stylesStack"/>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="btnNewStyle">
<property name="text">
- <string>Ne&amp;w...</string>
+ <string comment="New layer style">&amp;New...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnLoadStyle">
<property name="text">
<string>&amp;Import...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSaveStyle">
<property name="text">
<string>&amp;Export...</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="chkPreview">
<property name="text">
<string>Pre&amp;view</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblPreview">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
diff --git a/libs/ui/opengl/KisOpenGLModeProber.cpp b/libs/ui/opengl/KisOpenGLModeProber.cpp
index 6589e67034..c47b106346 100644
--- a/libs/ui/opengl/KisOpenGLModeProber.cpp
+++ b/libs/ui/opengl/KisOpenGLModeProber.cpp
@@ -1,333 +1,334 @@
/*
* Copyright (c) 2017 Alvin Wong <alvinhochun@gmail.com>
* Copyright (c) 2019 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "KisOpenGLModeProber.h"
#include <config-hdr.h>
#include <QApplication>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QWindow>
#include <QGlobalStatic>
Q_GLOBAL_STATIC(KisOpenGLModeProber, s_instance)
KisOpenGLModeProber::KisOpenGLModeProber()
{
}
KisOpenGLModeProber::~KisOpenGLModeProber()
{
}
KisOpenGLModeProber *KisOpenGLModeProber::instance()
{
return s_instance;
}
bool KisOpenGLModeProber::useHDRMode() const
{
return isFormatHDR(QSurfaceFormat::defaultFormat());
}
QSurfaceFormat KisOpenGLModeProber::surfaceformatInUse() const
{
// TODO: use information provided by KisOpenGL instead
QOpenGLContext *sharedContext = QOpenGLContext::globalShareContext();
QSurfaceFormat format = sharedContext ? sharedContext->format() : QSurfaceFormat::defaultFormat();
return format;
}
const KoColorProfile *KisOpenGLModeProber::rootSurfaceColorProfile() const
{
const KoColorProfile *profile = KoColorSpaceRegistry::instance()->p709SRGBProfile();
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
const KisSurfaceColorSpace surfaceColorSpace = surfaceformatInUse().colorSpace();
if (surfaceColorSpace == KisSurfaceColorSpace::sRGBColorSpace) {
// use the default one!
#ifdef HAVE_HDR
} else if (surfaceColorSpace == KisSurfaceColorSpace::scRGBColorSpace) {
profile = KoColorSpaceRegistry::instance()->p709G10Profile();
} else if (surfaceColorSpace == KisSurfaceColorSpace::bt2020PQColorSpace) {
profile = KoColorSpaceRegistry::instance()->p2020PQProfile();
#endif
}
#endif
return profile;
}
namespace {
struct AppAttributeSetter
{
AppAttributeSetter(Qt::ApplicationAttribute attribute, bool useOpenGLES)
: m_attribute(attribute),
m_oldValue(QCoreApplication::testAttribute(attribute))
{
QCoreApplication::setAttribute(attribute, useOpenGLES);
}
~AppAttributeSetter() {
QCoreApplication::setAttribute(m_attribute, m_oldValue);
}
private:
Qt::ApplicationAttribute m_attribute;
bool m_oldValue = false;
};
struct SurfaceFormatSetter
{
SurfaceFormatSetter(const QSurfaceFormat &format)
: m_oldFormat(QSurfaceFormat::defaultFormat())
{
QSurfaceFormat::setDefaultFormat(format);
}
~SurfaceFormatSetter() {
QSurfaceFormat::setDefaultFormat(m_oldFormat);
}
private:
QSurfaceFormat m_oldFormat;
};
#if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0))
QString qEnvironmentVariable(const char *varName) {
return qgetenv(varName);
}
#endif
struct EnvironmentSetter
{
EnvironmentSetter(const QLatin1String &env, const QString &value)
: m_env(env)
{
if (qEnvironmentVariableIsEmpty(m_env.latin1())) {
m_oldValue = qgetenv(env.latin1());
}
if (!value.isEmpty()) {
qputenv(env.latin1(), value.toLatin1());
} else {
qunsetenv(env.latin1());
}
}
~EnvironmentSetter() {
if (m_oldValue) {
qputenv(m_env.latin1(), (*m_oldValue).toLatin1());
} else {
qunsetenv(m_env.latin1());
}
}
private:
const QLatin1String m_env;
boost::optional<QString> m_oldValue;
};
}
boost::optional<KisOpenGLModeProber::Result>
KisOpenGLModeProber::probeFormat(const KisOpenGL::RendererConfig &rendererConfig,
bool adjustGlobalState)
{
const QSurfaceFormat &format = rendererConfig.format;
QScopedPointer<AppAttributeSetter> sharedContextSetter;
QScopedPointer<AppAttributeSetter> glSetter;
QScopedPointer<AppAttributeSetter> glesSetter;
QScopedPointer<SurfaceFormatSetter> formatSetter;
QScopedPointer<EnvironmentSetter> rendererSetter;
QScopedPointer<QGuiApplication> application;
int argc = 1;
QByteArray probeAppName("krita");
char *argv = probeAppName.data();
if (adjustGlobalState) {
sharedContextSetter.reset(new AppAttributeSetter(Qt::AA_ShareOpenGLContexts, false));
if (format.renderableType() != QSurfaceFormat::DefaultRenderableType) {
glSetter.reset(new AppAttributeSetter(Qt::AA_UseDesktopOpenGL, format.renderableType() != QSurfaceFormat::OpenGLES));
glesSetter.reset(new AppAttributeSetter(Qt::AA_UseOpenGLES, format.renderableType() == QSurfaceFormat::OpenGLES));
}
rendererSetter.reset(new EnvironmentSetter(QLatin1String("QT_ANGLE_PLATFORM"), angleRendererToString(rendererConfig.angleRenderer)));
formatSetter.reset(new SurfaceFormatSetter(format));
QGuiApplication::setDesktopSettingsAware(false);
application.reset(new QGuiApplication(argc, &argv));
QGuiApplication::setDesktopSettingsAware(true);
}
QWindow surface;
surface.setFormat(format);
surface.setSurfaceType(QSurface::OpenGLSurface);
surface.create();
QOpenGLContext context;
context.setFormat(format);
if (!context.create()) {
dbgOpenGL << "OpenGL context cannot be created";
return boost::none;
}
if (!context.isValid()) {
dbgOpenGL << "OpenGL context is not valid while checking Qt's OpenGL status";
return boost::none;
}
if (!context.makeCurrent(&surface)) {
dbgOpenGL << "OpenGL context cannot be made current";
return boost::none;
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
if (!fuzzyCompareColorSpaces(context.format().colorSpace(), format.colorSpace())) {
dbgOpenGL << "Failed to create an OpenGL context with requested color space. Requested:" << format.colorSpace() << "Actual:" << context.format().colorSpace();
return boost::none;
}
#endif
return Result(context);
}
bool KisOpenGLModeProber::fuzzyCompareColorSpaces(const KisSurfaceColorSpace &lhs, const KisSurfaceColorSpace &rhs)
{
return lhs == rhs ||
((lhs == KisSurfaceColorSpace::DefaultColorSpace ||
lhs == KisSurfaceColorSpace::sRGBColorSpace) &&
(rhs == KisSurfaceColorSpace::DefaultColorSpace ||
rhs == KisSurfaceColorSpace::sRGBColorSpace));
}
void KisOpenGLModeProber::initSurfaceFormatFromConfig(KisConfig::RootSurfaceFormat config,
QSurfaceFormat *format)
{
#ifdef HAVE_HDR
if (config == KisConfig::BT2020_PQ) {
format->setRedBufferSize(10);
format->setGreenBufferSize(10);
format->setBlueBufferSize(10);
format->setAlphaBufferSize(2);
format->setColorSpace(KisSurfaceColorSpace::bt2020PQColorSpace);
} else if (config == KisConfig::BT709_G10) {
format->setRedBufferSize(16);
format->setGreenBufferSize(16);
format->setBlueBufferSize(16);
format->setAlphaBufferSize(16);
format->setColorSpace(KisSurfaceColorSpace::scRGBColorSpace);
} else
#else
if (config == KisConfig::BT2020_PQ) {
qWarning() << "WARNING: Bt.2020 PQ surface type is not supported by this build of Krita";
} else if (config == KisConfig::BT709_G10) {
qWarning() << "WARNING: scRGB surface type is not supported by this build of Krita";
}
#endif
{
format->setRedBufferSize(8);
format->setGreenBufferSize(8);
format->setBlueBufferSize(8);
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
format->setAlphaBufferSize(8);
#else
format->setAlphaBufferSize(0);
#endif
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
// TODO: check if we can use real sRGB space here
format->setColorSpace(KisSurfaceColorSpace::DefaultColorSpace);
#endif
}
}
bool KisOpenGLModeProber::isFormatHDR(const QSurfaceFormat &format)
{
#ifdef HAVE_HDR
bool isBt2020PQ =
format.colorSpace() == KisSurfaceColorSpace::bt2020PQColorSpace &&
format.redBufferSize() == 10 &&
format.greenBufferSize() == 10 &&
format.blueBufferSize() == 10 &&
format.alphaBufferSize() == 2;
bool isBt709G10 =
format.colorSpace() == KisSurfaceColorSpace::scRGBColorSpace &&
format.redBufferSize() == 16 &&
format.greenBufferSize() == 16 &&
format.blueBufferSize() == 16 &&
format.alphaBufferSize() == 16;
return isBt2020PQ || isBt709G10;
#else
Q_UNUSED(format);
return false;
#endif
}
QString KisOpenGLModeProber::angleRendererToString(KisOpenGL::AngleRenderer renderer)
{
QString value;
switch (renderer) {
case KisOpenGL::AngleRendererDefault:
break;
case KisOpenGL::AngleRendererD3d9:
value = "d3d9";
break;
case KisOpenGL::AngleRendererD3d11:
value = "d3d11";
break;
case KisOpenGL::AngleRendererD3d11Warp:
value = "warp";
break;
};
return value;
}
KisOpenGLModeProber::Result::Result(QOpenGLContext &context) {
if (!context.isValid()) {
return;
}
QOpenGLFunctions *funcs = context.functions(); // funcs is ready to be used
m_rendererString = QString(reinterpret_cast<const char *>(funcs->glGetString(GL_RENDERER)));
m_driverVersionString = QString(reinterpret_cast<const char *>(funcs->glGetString(GL_VERSION)));
m_vendorString = QString(reinterpret_cast<const char *>(funcs->glGetString(GL_VENDOR)));
m_shadingLanguageString = QString(reinterpret_cast<const char *>(funcs->glGetString(GL_SHADING_LANGUAGE_VERSION)));
m_glMajorVersion = context.format().majorVersion();
m_glMinorVersion = context.format().minorVersion();
m_supportsDeprecatedFunctions = (context.format().options() & QSurfaceFormat::DeprecatedFunctions);
m_isOpenGLES = context.isOpenGLES();
m_format = context.format();
+ m_supportsFBO = context.functions()->hasOpenGLFeature(QOpenGLFunctions::Framebuffers);
}
diff --git a/libs/ui/opengl/KisOpenGLModeProber.h b/libs/ui/opengl/KisOpenGLModeProber.h
index d1aa59b30a..409aff25c9 100644
--- a/libs/ui/opengl/KisOpenGLModeProber.h
+++ b/libs/ui/opengl/KisOpenGLModeProber.h
@@ -1,148 +1,153 @@
/*
* Copyright (c) 2017 Alvin Wong <alvinhochun@gmail.com>
* Copyright (c) 2019 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KISOPENGLMODEPROBER_H
#define KISOPENGLMODEPROBER_H
#include "kritaui_export.h"
#include "kis_config.h"
#include <QSurfaceFormat>
#include "KisSurfaceColorSpace.h"
#include <boost/optional.hpp>
#include "kis_opengl.h"
class KoColorProfile;
class KRITAUI_EXPORT KisOpenGLModeProber
{
public:
class Result;
public:
KisOpenGLModeProber();
~KisOpenGLModeProber();
static KisOpenGLModeProber* instance();
bool useHDRMode() const;
QSurfaceFormat surfaceformatInUse() const;
const KoColorProfile *rootSurfaceColorProfile() const;
boost::optional<Result> probeFormat(const KisOpenGL::RendererConfig &rendererConfig,
bool adjustGlobalState = true);
static bool fuzzyCompareColorSpaces(const KisSurfaceColorSpace &lhs,
const KisSurfaceColorSpace &rhs);
static QString angleRendererToString(KisOpenGL::AngleRenderer renderer);
public:
static void initSurfaceFormatFromConfig(KisConfig::RootSurfaceFormat config,
QSurfaceFormat *format);
static bool isFormatHDR(const QSurfaceFormat &format);
};
class KisOpenGLModeProber::Result {
public:
Result(QOpenGLContext &context);
int glMajorVersion() const {
return m_glMajorVersion;
}
int glMinorVersion() const {
return m_glMinorVersion;
}
bool supportsDeprecatedFunctions() const {
return m_supportsDeprecatedFunctions;
}
bool isOpenGLES() const {
return m_isOpenGLES;
}
QString rendererString() const {
return m_rendererString;
}
QString driverVersionString() const {
return m_driverVersionString;
}
bool isSupportedVersion() const {
return
#ifdef Q_OS_MACOS
((m_glMajorVersion * 100 + m_glMinorVersion) >= 302)
#else
(m_glMajorVersion >= 3 && (m_supportsDeprecatedFunctions || m_isOpenGLES)) ||
((m_glMajorVersion * 100 + m_glMinorVersion) == 201)
#endif
;
}
bool supportsLoD() const {
return (m_glMajorVersion * 100 + m_glMinorVersion) >= 300;
}
bool hasOpenGL3() const {
return (m_glMajorVersion * 100 + m_glMinorVersion) >= 302;
}
bool supportsFenceSync() const {
return m_glMajorVersion >= 3;
}
+ bool supportsFBO() const {
+ return m_supportsFBO;
+ }
+
#ifdef Q_OS_WIN
// This is only for detecting whether ANGLE is being used.
// For detecting generic OpenGL ES please check isOpenGLES
bool isUsingAngle() const {
return m_rendererString.startsWith("ANGLE", Qt::CaseInsensitive);
}
#endif
QString shadingLanguageString() const
{
return m_shadingLanguageString;
}
QString vendorString() const
{
return m_vendorString;
}
QSurfaceFormat format() const
{
return m_format;
}
private:
int m_glMajorVersion = 0;
int m_glMinorVersion = 0;
bool m_supportsDeprecatedFunctions = false;
bool m_isOpenGLES = false;
+ bool m_supportsFBO = false;
QString m_rendererString;
QString m_driverVersionString;
QString m_vendorString;
QString m_shadingLanguageString;
QSurfaceFormat m_format;
};
#endif // KISOPENGLMODEPROBER_H
diff --git a/libs/ui/opengl/kis_opengl.cpp b/libs/ui/opengl/kis_opengl.cpp
index de2c4a0918..48211adb27 100644
--- a/libs/ui/opengl/kis_opengl.cpp
+++ b/libs/ui/opengl/kis_opengl.cpp
@@ -1,915 +1,921 @@
/*
* Copyright (c) 2007 Adrian Page <adrian@pagenet.plus.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <config-hdr.h>
#include "opengl/kis_opengl.h"
#include "opengl/kis_opengl_p.h"
#include <QOpenGLContext>
#include <QOpenGLDebugLogger>
#include <QOpenGLFunctions>
#include <QApplication>
#include <QDesktopWidget>
#include <QPixmapCache>
#include <QDir>
#include <QFile>
#include <QStandardPaths>
#include <QVector>
#include <QWindow>
#include <klocalizedstring.h>
#include <kis_debug.h>
#include <kis_config.h>
#include "KisOpenGLModeProber.h"
#include <KisUsageLogger.h>
#include <boost/optional.hpp>
#include "kis_assert.h"
#include <QRegularExpression>
#include <QSettings>
#include <QScreen>
#ifndef GL_RENDERER
# define GL_RENDERER 0x1F01
#endif
using namespace KisOpenGLPrivate;
namespace
{
// config option, set manually by main()
bool g_isDebugSynchronous = false;
bool g_sanityDefaultFormatIsSet = false;
boost::optional<KisOpenGLModeProber::Result> openGLCheckResult;
bool g_needsFenceWorkaround = false;
bool g_needsPixmapCacheWorkaround = false;
QString g_surfaceFormatDetectionLog;
QString g_debugText("OpenGL Info\n **OpenGL not initialized**");
QVector<KLocalizedString> g_openglWarningStrings;
KisOpenGL::OpenGLRenderers g_supportedRenderers;
KisOpenGL::OpenGLRenderer g_rendererPreferredByQt;
void overrideSupportedRenderers(KisOpenGL::OpenGLRenderers supportedRenderers, KisOpenGL::OpenGLRenderer preferredByQt) {
g_supportedRenderers = supportedRenderers;
g_rendererPreferredByQt = preferredByQt;
}
void openglOnMessageLogged(const QOpenGLDebugMessage& debugMessage) {
qDebug() << "OpenGL:" << debugMessage;
}
KisOpenGL::OpenGLRenderer getRendererFromProbeResult(KisOpenGLModeProber::Result info) {
KisOpenGL::OpenGLRenderer result = KisOpenGL::RendererDesktopGL;
if (info.isOpenGLES()) {
const QString rendererString = info.rendererString().toLower();
if (rendererString.contains("basic render driver") ||
rendererString.contains("software")) {
result = KisOpenGL::RendererSoftware;
} else {
result = KisOpenGL::RendererOpenGLES;
}
}
return result;
}
}
KisOpenGLPrivate::OpenGLCheckResult::OpenGLCheckResult(QOpenGLContext &context) {
if (!context.isValid()) {
return;
}
QOpenGLFunctions *funcs = context.functions(); // funcs is ready to be used
m_rendererString = QString(reinterpret_cast<const char *>(funcs->glGetString(GL_RENDERER)));
m_driverVersionString = QString(reinterpret_cast<const char *>(funcs->glGetString(GL_VERSION)));
m_glMajorVersion = context.format().majorVersion();
m_glMinorVersion = context.format().minorVersion();
m_supportsDeprecatedFunctions = (context.format().options() & QSurfaceFormat::DeprecatedFunctions);
m_isOpenGLES = context.isOpenGLES();
}
void KisOpenGLPrivate::appendOpenGLWarningString(KLocalizedString warning)
{
g_openglWarningStrings << warning;
}
void KisOpenGLPrivate::overrideOpenGLWarningString(QVector<KLocalizedString> warnings)
{
g_openglWarningStrings = warnings;
}
void KisOpenGL::initialize()
{
if (openGLCheckResult) return;
KIS_SAFE_ASSERT_RECOVER_NOOP(g_sanityDefaultFormatIsSet);
KisOpenGL::RendererConfig config;
config.format = QSurfaceFormat::defaultFormat();
openGLCheckResult =
KisOpenGLModeProber::instance()->probeFormat(config, false);
g_debugText.clear();
QDebug debugOut(&g_debugText);
debugOut << "OpenGL Info\n";
if (openGLCheckResult) {
debugOut << "\n Vendor: " << openGLCheckResult->vendorString();
debugOut << "\n Renderer: " << openGLCheckResult->rendererString();
debugOut << "\n Version: " << openGLCheckResult->driverVersionString();
debugOut << "\n Shading language: " << openGLCheckResult->shadingLanguageString();
debugOut << "\n Requested format: " << QSurfaceFormat::defaultFormat();
debugOut << "\n Current format: " << openGLCheckResult->format();
debugOut.nospace();
debugOut << "\n Version: " << openGLCheckResult->glMajorVersion() << "." << openGLCheckResult->glMinorVersion();
debugOut.resetFormat();
debugOut << "\n Supports deprecated functions" << openGLCheckResult->supportsDeprecatedFunctions();
debugOut << "\n is OpenGL ES:" << openGLCheckResult->isOpenGLES();
}
debugOut << "\n\nQPA OpenGL Detection Info";
debugOut << "\n supportsDesktopGL:" << bool(g_supportedRenderers & RendererDesktopGL);
#ifdef Q_OS_WIN
debugOut << "\n supportsAngleD3D11:" << bool(g_supportedRenderers & RendererOpenGLES);
debugOut << "\n isQtPreferAngle:" << bool(g_rendererPreferredByQt == RendererOpenGLES);
#else
debugOut << "\n supportsOpenGLES:" << bool(g_supportedRenderers & RendererOpenGLES);
debugOut << "\n isQtPreferOpenGLES:" << bool(g_rendererPreferredByQt == RendererOpenGLES);
#endif
// debugOut << "\n== log ==\n";
// debugOut.noquote();
// debugOut << g_surfaceFormatDetectionLog;
// debugOut.resetFormat();
// debugOut << "\n== end log ==";
dbgOpenGL.noquote().nospace() << g_debugText;
KisUsageLogger::writeSysInfo(g_debugText);
if (!openGLCheckResult) {
return;
}
// Check if we have a bugged driver that needs fence workaround
bool isOnX11 = false;
#ifdef HAVE_X11
isOnX11 = true;
#endif
KisConfig cfg(true);
if ((isOnX11 && openGLCheckResult->rendererString().startsWith("AMD")) || cfg.forceOpenGLFenceWorkaround()) {
g_needsFenceWorkaround = true;
}
/**
* NVidia + Qt's openGL don't play well together and one cannot
* draw a pixmap on a widget more than once in one rendering cycle.
*
* It can be workarounded by drawing strictly via QPixmapCache and
* only when the pixmap size in bigger than doubled size of the
* display framebuffer. That is for 8-bit HD display, you should have
* a cache bigger than 16 MiB. Don't ask me why. (DK)
*
* See bug: https://bugs.kde.org/show_bug.cgi?id=361709
*
* TODO: check if this workaround is still needed after merging
* Qt5+openGL3 branch.
*/
if (openGLCheckResult->vendorString().toUpper().contains("NVIDIA")) {
g_needsPixmapCacheWorkaround = true;
const QRect screenSize = QGuiApplication::primaryScreen()->availableGeometry();
const int minCacheSize = 20 * 1024;
const int cacheSize = 2048 + 2 * 4 * screenSize.width() * screenSize.height() / 1024; //KiB
QPixmapCache::setCacheLimit(qMax(minCacheSize, cacheSize));
}
}
void KisOpenGL::initializeContext(QOpenGLContext *ctx)
{
KisConfig cfg(true);
initialize();
const bool isDebugEnabled = ctx->format().testOption(QSurfaceFormat::DebugContext);
dbgUI << "OpenGL: Opening new context";
if (isDebugEnabled) {
// Passing ctx for ownership management only, not specifying context.
// QOpenGLDebugLogger only function on the current active context.
// FIXME: Do we need to make sure ctx is the active context?
QOpenGLDebugLogger* openglLogger = new QOpenGLDebugLogger(ctx);
if (openglLogger->initialize()) {
qDebug() << "QOpenGLDebugLogger is initialized. Check whether you get a message below.";
QObject::connect(openglLogger, &QOpenGLDebugLogger::messageLogged, &openglOnMessageLogged);
openglLogger->startLogging(g_isDebugSynchronous ? QOpenGLDebugLogger::SynchronousLogging : QOpenGLDebugLogger::AsynchronousLogging);
openglLogger->logMessage(QOpenGLDebugMessage::createApplicationMessage(QStringLiteral("QOpenGLDebugLogger is logging.")));
} else {
qDebug() << "QOpenGLDebugLogger cannot be initialized.";
delete openglLogger;
}
}
// Double check we were given the version we requested
QSurfaceFormat format = ctx->format();
QOpenGLFunctions *f = ctx->functions();
f->initializeOpenGLFunctions();
QFile log(QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/krita-opengl.txt");
log.open(QFile::WriteOnly);
QString vendor((const char*)f->glGetString(GL_VENDOR));
log.write(vendor.toLatin1());
log.write(", ");
log.write(openGLCheckResult->rendererString().toLatin1());
log.write(", ");
QString version((const char*)f->glGetString(GL_VERSION));
log.write(version.toLatin1());
log.close();
}
const QString &KisOpenGL::getDebugText()
{
initialize();
return g_debugText;
}
QStringList KisOpenGL::getOpenGLWarnings() {
QStringList strings;
Q_FOREACH (const KLocalizedString &item, g_openglWarningStrings) {
strings << item.toString();
}
return strings;
}
// XXX Temporary function to allow LoD on OpenGL3 without triggering
// all of the other 3.2 functionality, can be removed once we move to Qt5.7
bool KisOpenGL::supportsLoD()
{
initialize();
return openGLCheckResult && openGLCheckResult->supportsLoD();
}
bool KisOpenGL::hasOpenGL3()
{
initialize();
return openGLCheckResult && openGLCheckResult->hasOpenGL3();
}
bool KisOpenGL::hasOpenGLES()
{
initialize();
return openGLCheckResult && openGLCheckResult->isOpenGLES();
}
bool KisOpenGL::supportsFenceSync()
{
initialize();
return openGLCheckResult && openGLCheckResult->supportsFenceSync();
}
+bool KisOpenGL::supportsRenderToFBO()
+{
+ initialize();
+ return openGLCheckResult && openGLCheckResult->supportsFBO();
+}
+
bool KisOpenGL::needsFenceWorkaround()
{
initialize();
return g_needsFenceWorkaround;
}
bool KisOpenGL::needsPixmapCacheWorkaround()
{
initialize();
return g_needsPixmapCacheWorkaround;
}
void KisOpenGL::testingInitializeDefaultSurfaceFormat()
{
setDefaultSurfaceConfig(selectSurfaceConfig(KisOpenGL::RendererAuto, KisConfig::BT709_G22, false));
}
void KisOpenGL::setDebugSynchronous(bool value)
{
g_isDebugSynchronous = value;
}
KisOpenGL::OpenGLRenderer KisOpenGL::getCurrentOpenGLRenderer()
{
if (!openGLCheckResult) return RendererAuto;
return getRendererFromProbeResult(*openGLCheckResult);
}
KisOpenGL::OpenGLRenderer KisOpenGL::getQtPreferredOpenGLRenderer()
{
return g_rendererPreferredByQt;
}
KisOpenGL::OpenGLRenderers KisOpenGL::getSupportedOpenGLRenderers()
{
return g_supportedRenderers;
}
KisOpenGL::OpenGLRenderer KisOpenGL::getUserPreferredOpenGLRendererConfig()
{
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
return convertConfigToOpenGLRenderer(kritarc.value("OpenGLRenderer", "auto").toString());
}
void KisOpenGL::setUserPreferredOpenGLRendererConfig(KisOpenGL::OpenGLRenderer renderer)
{
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
kritarc.setValue("OpenGLRenderer", KisOpenGL::convertOpenGLRendererToConfig(renderer));
}
QString KisOpenGL::convertOpenGLRendererToConfig(KisOpenGL::OpenGLRenderer renderer)
{
switch (renderer) {
case RendererNone:
return QStringLiteral("none");
case RendererSoftware:
return QStringLiteral("software");
case RendererDesktopGL:
return QStringLiteral("desktop");
case RendererOpenGLES:
return QStringLiteral("angle");
default:
return QStringLiteral("auto");
}
}
KisOpenGL::OpenGLRenderer KisOpenGL::convertConfigToOpenGLRenderer(QString renderer)
{
if (renderer == "desktop") {
return RendererDesktopGL;
} else if (renderer == "angle") {
return RendererOpenGLES;
} else if (renderer == "software") {
return RendererSoftware;
} else if (renderer == "none") {
return RendererNone;
} else {
return RendererAuto;
}
}
KisOpenGL::OpenGLRenderer KisOpenGL::RendererConfig::rendererId() const
{
KisOpenGL::OpenGLRenderer result = RendererAuto;
if (format.renderableType() == QSurfaceFormat::OpenGLES &&
angleRenderer == AngleRendererD3d11Warp) {
result = RendererSoftware;
} else if (format.renderableType() == QSurfaceFormat::OpenGLES &&
angleRenderer == AngleRendererD3d11) {
result = RendererOpenGLES;
} else if (format.renderableType() == QSurfaceFormat::OpenGL) {
result = RendererDesktopGL;
} else if (format.renderableType() == QSurfaceFormat::DefaultRenderableType &&
angleRenderer == AngleRendererD3d11) {
// noop
} else {
qWarning() << "WARNING: unsupported combination of OpenGL renderer" << ppVar(format.renderableType()) << ppVar(angleRenderer);
}
return result;
}
namespace {
typedef std::pair<QSurfaceFormat::RenderableType, KisOpenGL::AngleRenderer> RendererInfo;
RendererInfo getRendererInfo(KisOpenGL::OpenGLRenderer renderer)
{
RendererInfo info = {QSurfaceFormat::DefaultRenderableType,
KisOpenGL::AngleRendererD3d11};
switch (renderer) {
case KisOpenGL::RendererNone:
info = {QSurfaceFormat::DefaultRenderableType, KisOpenGL::AngleRendererDefault};
break;
case KisOpenGL::RendererAuto:
break;
case KisOpenGL::RendererDesktopGL:
info = {QSurfaceFormat::OpenGL, KisOpenGL::AngleRendererD3d11};
break;
case KisOpenGL::RendererOpenGLES:
info = {QSurfaceFormat::OpenGLES, KisOpenGL::AngleRendererD3d11};
break;
case KisOpenGL::RendererSoftware:
info = {QSurfaceFormat::OpenGLES, KisOpenGL::AngleRendererD3d11Warp};
break;
}
return info;
}
KisOpenGL::RendererConfig generateSurfaceConfig(KisOpenGL::OpenGLRenderer renderer,
KisConfig::RootSurfaceFormat rootSurfaceFormat,
bool debugContext)
{
RendererInfo info = getRendererInfo(renderer);
KisOpenGL::RendererConfig config;
config.angleRenderer = info.second;
QSurfaceFormat &format = config.format;
#ifdef Q_OS_MACOS
format.setVersion(3, 2);
format.setProfile(QSurfaceFormat::CoreProfile);
#elif !defined(Q_OS_ANDROID)
// XXX This can be removed once we move to Qt5.7
format.setVersion(3, 0);
format.setProfile(QSurfaceFormat::CompatibilityProfile);
format.setOptions(QSurfaceFormat::DeprecatedFunctions);
#endif
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
KisOpenGLModeProber::initSurfaceFormatFromConfig(rootSurfaceFormat, &format);
format.setRenderableType(info.first);
format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
format.setSwapInterval(0); // Disable vertical refresh syncing
if (debugContext) {
format.setOption(QSurfaceFormat::DebugContext, true);
}
return config;
}
bool isOpenGLRendererBlacklisted(const QString &rendererString,
const QString &driverVersionString,
QVector<KLocalizedString> *warningMessage)
{
bool isBlacklisted = false;
#ifndef Q_OS_WIN
Q_UNUSED(rendererString);
Q_UNUSED(driverVersionString);
Q_UNUSED(warningMessage);
#else
// Special blacklisting of OpenGL/ANGLE is tracked on:
// https://phabricator.kde.org/T7411
// HACK: Specifically detect for Intel driver build number
// See https://www.intel.com/content/www/us/en/support/articles/000005654/graphics-drivers.html
if (rendererString.startsWith("Intel")) {
KLocalizedString knownBadIntelWarning = ki18n("The Intel graphics driver in use is known to have issues with OpenGL.");
KLocalizedString grossIntelWarning = ki18n(
"Intel graphics drivers tend to have issues with OpenGL so ANGLE will be used by default. "
"You may manually switch to OpenGL but it is not guaranteed to work properly."
);
QRegularExpression regex("\\b\\d{1,2}\\.\\d{2}\\.\\d{1,3}\\.(\\d{4})\\b");
QRegularExpressionMatch match = regex.match(driverVersionString);
if (match.hasMatch()) {
int driverBuild = match.captured(1).toInt();
if (driverBuild > 4636 && driverBuild < 4729) {
// Make ANGLE the preferred renderer for Intel driver versions
// between build 4636 and 4729 (exclusive) due to an UI offset bug.
// See https://communities.intel.com/thread/116003
// (Build 4636 is known to work from some test results)
qDebug() << "Detected Intel driver build between 4636 and 4729, making ANGLE the preferred renderer";
isBlacklisted = true;
*warningMessage << knownBadIntelWarning;
} else if (driverBuild == 4358) {
// There are several reports on a bug where the canvas is not being
// updated properly which has debug info pointing to this build.
qDebug() << "Detected Intel driver build 4358, making ANGLE the preferred renderer";
isBlacklisted = true;
*warningMessage << knownBadIntelWarning;
} else {
// Intel tends to randomly break OpenGL in some of their new driver
// builds, therefore we just shouldn't use OpenGL by default to
// reduce bug report noises.
qDebug() << "Detected Intel driver, making ANGLE the preferred renderer";
isBlacklisted = true;
*warningMessage << grossIntelWarning;
}
} else {
// In case Intel changed the driver version format to something that
// we don't understand, we still select ANGLE.
qDebug() << "Detected Intel driver with unknown version format, making ANGLE the preferred renderer";
isBlacklisted = true;
*warningMessage << grossIntelWarning;
}
}
#endif
return isBlacklisted;
}
boost::optional<bool> orderPreference(bool lhs, bool rhs)
{
if (lhs == rhs) return boost::none;
if (lhs && !rhs) return true;
if (!lhs && rhs) return false;
return false;
}
#define ORDER_BY(lhs, rhs) if (auto res = orderPreference((lhs), (rhs))) { return *res; }
class FormatPositionLess
{
public:
FormatPositionLess()
{
}
bool operator()(const KisOpenGL::RendererConfig &lhs, const KisOpenGL::RendererConfig &rhs) const {
KIS_SAFE_ASSERT_RECOVER_NOOP(m_preferredColorSpace != KisSurfaceColorSpace::DefaultColorSpace);
if (m_preferredRendererByUser != KisOpenGL::RendererSoftware) {
ORDER_BY(!isFallbackOnly(lhs.rendererId()), !isFallbackOnly(rhs.rendererId()));
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
ORDER_BY(isPreferredColorSpace(lhs.format.colorSpace()),
isPreferredColorSpace(rhs.format.colorSpace()));
#endif
if (doPreferHDR()) {
ORDER_BY(isHDRFormat(lhs.format), isHDRFormat(rhs.format));
} else {
ORDER_BY(!isHDRFormat(lhs.format), !isHDRFormat(rhs.format));
}
if (m_preferredRendererByUser != KisOpenGL::RendererAuto) {
ORDER_BY(lhs.rendererId() == m_preferredRendererByUser,
rhs.rendererId() == m_preferredRendererByUser);
}
ORDER_BY(!isBlacklisted(lhs.rendererId()), !isBlacklisted(rhs.rendererId()));
if (doPreferHDR() &&
m_preferredRendererByHDR != KisOpenGL::RendererAuto) {
ORDER_BY(lhs.rendererId() == m_preferredRendererByHDR,
rhs.rendererId() == m_preferredRendererByHDR);
}
KIS_SAFE_ASSERT_RECOVER_NOOP(m_preferredRendererByQt != KisOpenGL::RendererAuto);
ORDER_BY(lhs.rendererId() == m_preferredRendererByQt,
rhs.rendererId() == m_preferredRendererByQt);
return false;
}
public:
void setPreferredColorSpace(const KisSurfaceColorSpace &preferredColorSpace) {
m_preferredColorSpace = preferredColorSpace;
}
void setPreferredRendererByQt(const KisOpenGL::OpenGLRenderer &preferredRendererByQt) {
m_preferredRendererByQt = preferredRendererByQt;
}
void setPreferredRendererByUser(const KisOpenGL::OpenGLRenderer &preferredRendererByUser) {
m_preferredRendererByUser = preferredRendererByUser;
}
void setPreferredRendererByHDR(const KisOpenGL::OpenGLRenderer &preferredRendererByHDR) {
m_preferredRendererByHDR = preferredRendererByHDR;
}
void setOpenGLBlacklisted(bool openGLBlacklisted) {
m_openGLBlacklisted = openGLBlacklisted;
}
void setOpenGLESBlacklisted(bool openGLESBlacklisted) {
m_openGLESBlacklisted = openGLESBlacklisted;
}
bool isOpenGLBlacklisted() const {
return m_openGLBlacklisted;
}
bool isOpenGLESBlacklisted() const {
return m_openGLESBlacklisted;
}
KisSurfaceColorSpace preferredColorSpace() const {
return m_preferredColorSpace;
}
KisOpenGL::OpenGLRenderer preferredRendererByUser() const {
return m_preferredRendererByUser;
}
private:
bool isHDRFormat(const QSurfaceFormat &f) const {
#ifdef HAVE_HDR
return f.colorSpace() == KisSurfaceColorSpace::bt2020PQColorSpace ||
f.colorSpace() == KisSurfaceColorSpace::scRGBColorSpace;
#else
Q_UNUSED(f);
return false;
#endif
}
bool isFallbackOnly(KisOpenGL::OpenGLRenderer r) const {
return r == KisOpenGL::RendererSoftware;
}
bool isBlacklisted(KisOpenGL::OpenGLRenderer r) const {
KIS_SAFE_ASSERT_RECOVER_NOOP(r == KisOpenGL::RendererAuto ||
r == KisOpenGL::RendererDesktopGL ||
r == KisOpenGL::RendererOpenGLES ||
r == KisOpenGL::RendererSoftware ||
r == KisOpenGL::RendererNone);
return (r == KisOpenGL::RendererDesktopGL && m_openGLBlacklisted) ||
(r == KisOpenGL::RendererOpenGLES && m_openGLESBlacklisted) ||
(r == KisOpenGL::RendererSoftware && m_openGLESBlacklisted);
}
bool doPreferHDR() const {
#ifdef HAVE_HDR
return m_preferredColorSpace == KisSurfaceColorSpace::bt2020PQColorSpace ||
m_preferredColorSpace == KisSurfaceColorSpace::scRGBColorSpace;
#else
return false;
#endif
}
bool isPreferredColorSpace(const KisSurfaceColorSpace cs) const {
return KisOpenGLModeProber::fuzzyCompareColorSpaces(m_preferredColorSpace, cs);
return false;
}
private:
KisSurfaceColorSpace m_preferredColorSpace = KisSurfaceColorSpace::DefaultColorSpace;
KisOpenGL::OpenGLRenderer m_preferredRendererByQt = KisOpenGL::RendererDesktopGL;
KisOpenGL::OpenGLRenderer m_preferredRendererByUser = KisOpenGL::RendererAuto;
KisOpenGL::OpenGLRenderer m_preferredRendererByHDR = KisOpenGL::RendererAuto;
bool m_openGLBlacklisted = false;
bool m_openGLESBlacklisted = false;
};
struct DetectionDebug : public QDebug
{
DetectionDebug(QString *string)
: QDebug(string),
m_string(string),
m_originalSize(string->size())
{}
~DetectionDebug() { dbgOpenGL << m_string->right(m_string->size() - m_originalSize); *this << endl; }
QString *m_string;
int m_originalSize;
};
}
#define dbgDetection() DetectionDebug(&g_surfaceFormatDetectionLog)
KisOpenGL::RendererConfig KisOpenGL::selectSurfaceConfig(KisOpenGL::OpenGLRenderer preferredRenderer,
KisConfig::RootSurfaceFormat preferredRootSurfaceFormat,
bool enableDebug)
{
QVector<KLocalizedString> warningMessages;
using Info = boost::optional<KisOpenGLModeProber::Result>;
QHash<OpenGLRenderer, Info> renderersToTest;
#ifndef Q_OS_ANDROID
renderersToTest.insert(RendererDesktopGL, Info());
#endif
renderersToTest.insert(RendererOpenGLES, Info());
#ifdef Q_OS_WIN
renderersToTest.insert(RendererSoftware, Info());
#endif
#ifdef HAVE_HDR
QVector<KisConfig::RootSurfaceFormat> formatSymbols({KisConfig::BT709_G22, KisConfig::BT709_G10, KisConfig::BT2020_PQ});
#else
QVector<KisConfig::RootSurfaceFormat> formatSymbols({KisConfig::BT709_G22});
#endif
KisOpenGL::RendererConfig defaultConfig = generateSurfaceConfig(KisOpenGL::RendererAuto,
KisConfig::BT709_G22, false);
Info info = KisOpenGLModeProber::instance()->probeFormat(defaultConfig);
#ifdef Q_OS_WIN
if (!info) {
// try software rasterizer (WARP)
defaultConfig = generateSurfaceConfig(KisOpenGL::RendererSoftware,
KisConfig::BT709_G22, false);
info = KisOpenGLModeProber::instance()->probeFormat(defaultConfig);
if (!info) {
renderersToTest.remove(RendererSoftware);
}
}
#endif
if (!info) return KisOpenGL::RendererConfig();
const OpenGLRenderer defaultRenderer = getRendererFromProbeResult(*info);
OpenGLRenderers supportedRenderers = RendererNone;
FormatPositionLess compareOp;
compareOp.setPreferredRendererByQt(defaultRenderer);
#ifdef HAVE_HDR
compareOp.setPreferredColorSpace(
preferredRootSurfaceFormat == KisConfig::BT709_G22 ? KisSurfaceColorSpace::sRGBColorSpace :
preferredRootSurfaceFormat == KisConfig::BT709_G10 ? KisSurfaceColorSpace::scRGBColorSpace :
KisSurfaceColorSpace::bt2020PQColorSpace);
#else
Q_UNUSED(preferredRootSurfaceFormat);
compareOp.setPreferredColorSpace(KisSurfaceColorSpace::sRGBColorSpace);
#endif
#ifdef Q_OS_WIN
compareOp.setPreferredRendererByHDR(KisOpenGL::RendererOpenGLES);
#endif
compareOp.setPreferredRendererByUser(preferredRenderer);
compareOp.setOpenGLESBlacklisted(false); // We cannot blacklist ES drivers atm
renderersToTest[defaultRenderer] = info;
for (auto it = renderersToTest.begin(); it != renderersToTest.end(); ++it) {
Info info = it.value();
if (!info) {
info = KisOpenGLModeProber::instance()->
probeFormat(generateSurfaceConfig(it.key(),
KisConfig::BT709_G22, false));
*it = info;
}
compareOp.setOpenGLBlacklisted(
!info ||
isOpenGLRendererBlacklisted(info->rendererString(),
info->driverVersionString(),
&warningMessages));
if (info && info->isSupportedVersion()) {
supportedRenderers |= it.key();
}
}
OpenGLRenderer preferredByQt = defaultRenderer;
if (preferredByQt == RendererDesktopGL &&
supportedRenderers & RendererDesktopGL &&
compareOp.isOpenGLBlacklisted()) {
preferredByQt = RendererOpenGLES;
} else if (preferredByQt == RendererOpenGLES &&
supportedRenderers & RendererOpenGLES &&
compareOp.isOpenGLESBlacklisted()) {
preferredByQt = RendererDesktopGL;
}
QVector<RendererConfig> preferredConfigs;
for (auto it = renderersToTest.begin(); it != renderersToTest.end(); ++it) {
// if default mode of the renderer doesn't work, then custom won't either
if (!it.value()) continue;
Q_FOREACH (const KisConfig::RootSurfaceFormat formatSymbol, formatSymbols) {
preferredConfigs << generateSurfaceConfig(it.key(), formatSymbol, enableDebug);
}
}
std::stable_sort(preferredConfigs.begin(), preferredConfigs.end(), compareOp);
dbgDetection() << "Supported renderers:" << supportedRenderers;
dbgDetection() << "Surface format preference list:";
Q_FOREACH (const KisOpenGL::RendererConfig &config, preferredConfigs) {
dbgDetection() << "*" << config.format;
dbgDetection() << " " << config.rendererId();
}
KisOpenGL::RendererConfig resultConfig = defaultConfig;
if (preferredRenderer != RendererNone) {
Q_FOREACH (const KisOpenGL::RendererConfig &config, preferredConfigs) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
dbgDetection() <<"Probing format..." << config.format.colorSpace() << config.rendererId();
#else
dbgDetection() <<"Probing format..." << config.rendererId();
#endif
Info info = KisOpenGLModeProber::instance()->probeFormat(config);
if (info && info->isSupportedVersion()) {
#ifdef Q_OS_WIN
// HACK: Block ANGLE with Direct3D9
// Direct3D9 does not give OpenGL ES 3.0
// Some versions of ANGLE returns OpenGL version 3.0 incorrectly
if (info->isUsingAngle() &&
info->rendererString().contains("Direct3D9", Qt::CaseInsensitive)) {
dbgDetection() << "Skipping Direct3D 9 Angle implementation, it shouldn't have happened.";
continue;
}
#endif
dbgDetection() << "Found format:" << config.format;
dbgDetection() << " " << config.rendererId();
resultConfig = config;
break;
}
}
{
const bool colorSpaceIsCorrect =
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
KisOpenGLModeProber::fuzzyCompareColorSpaces(compareOp.preferredColorSpace(),
resultConfig.format.colorSpace());
#else
true;
#endif
const bool rendererIsCorrect =
compareOp.preferredRendererByUser() == KisOpenGL::RendererAuto ||
compareOp.preferredRendererByUser() == resultConfig.rendererId();
if (!rendererIsCorrect && colorSpaceIsCorrect) {
warningMessages << ki18n("Preferred renderer doesn't support requested surface format. Another renderer has been selected.");
} else if (!colorSpaceIsCorrect) {
warningMessages << ki18n("Preferred output format is not supported by available renderers");
}
}
} else {
resultConfig.format = QSurfaceFormat();
resultConfig.angleRenderer = AngleRendererDefault;
}
overrideSupportedRenderers(supportedRenderers, preferredByQt);
overrideOpenGLWarningString(warningMessages);
return resultConfig;
}
void KisOpenGL::setDefaultSurfaceConfig(const KisOpenGL::RendererConfig &config)
{
KIS_SAFE_ASSERT_RECOVER_NOOP(!g_sanityDefaultFormatIsSet);
g_sanityDefaultFormatIsSet = true;
QSurfaceFormat::setDefaultFormat(config.format);
#ifdef Q_OS_WIN
// Force ANGLE to use Direct3D11. D3D9 doesn't support OpenGL ES 3 and WARP
// might get weird crashes atm.
qputenv("QT_ANGLE_PLATFORM", KisOpenGLModeProber::angleRendererToString(config.angleRenderer).toLatin1());
#endif
if (config.format.renderableType() == QSurfaceFormat::OpenGLES) {
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES, true);
} else if (config.format.renderableType() == QSurfaceFormat::OpenGL) {
QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL, true);
}
}
bool KisOpenGL::hasOpenGL()
{
return openGLCheckResult->isSupportedVersion();
}
diff --git a/libs/ui/opengl/kis_opengl.h b/libs/ui/opengl/kis_opengl.h
index 365003a93b..4300de3696 100644
--- a/libs/ui/opengl/kis_opengl.h
+++ b/libs/ui/opengl/kis_opengl.h
@@ -1,137 +1,146 @@
/*
* Copyright (c) 2007 Adrian Page <adrian@pagenet.plus.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KIS_OPENGL_H_
#define KIS_OPENGL_H_
/** @file */
#include <QtGlobal>
#include <QFlags>
#include <QSurfaceFormat>
#include "kis_config.h"
#include "kritaui_export.h"
class QOpenGLContext;
class QString;
class QStringList;
class QSurfaceFormat;
/**
* This class manages a shared OpenGL context and provides utility
* functions for checking capabilities and error reporting.
*/
class KRITAUI_EXPORT KisOpenGL
{
public:
enum FilterMode {
NearestFilterMode, // nearest
BilinearFilterMode, // linear, no mipmap
TrilinearFilterMode, // LINEAR_MIPMAP_LINEAR
HighQualityFiltering // Mipmaps + custom shader
};
enum OpenGLRenderer {
RendererNone = 0x00,
RendererAuto = 0x01,
RendererDesktopGL = 0x02,
RendererOpenGLES = 0x04,
RendererSoftware = 0x08
};
Q_DECLARE_FLAGS(OpenGLRenderers, OpenGLRenderer)
enum AngleRenderer {
AngleRendererDefault = 0x0000,
AngleRendererD3d11 = 0x0002,
AngleRendererD3d9 = 0x0004,
AngleRendererD3d11Warp = 0x0008, // "Windows Advanced Rasterization Platform"
};
struct RendererConfig {
QSurfaceFormat format;
AngleRenderer angleRenderer = AngleRendererDefault;
OpenGLRenderer rendererId() const;
};
public:
static RendererConfig selectSurfaceConfig(KisOpenGL::OpenGLRenderer preferredRenderer,
KisConfig::RootSurfaceFormat preferredRootSurfaceFormat,
bool enableDebug);
static void setDefaultSurfaceConfig(const RendererConfig &config);
static OpenGLRenderer getCurrentOpenGLRenderer();
static OpenGLRenderer getQtPreferredOpenGLRenderer();
static OpenGLRenderers getSupportedOpenGLRenderers();
static OpenGLRenderer getUserPreferredOpenGLRendererConfig();
static void setUserPreferredOpenGLRendererConfig(OpenGLRenderer renderer);
static QString convertOpenGLRendererToConfig(OpenGLRenderer renderer);
static OpenGLRenderer convertConfigToOpenGLRenderer(QString renderer);
/// Request OpenGL version 3.2
static void initialize();
/// Initialize shared OpenGL context
static void initializeContext(QOpenGLContext *ctx);
static const QString &getDebugText();
static QStringList getOpenGLWarnings();
static bool supportsLoD();
static bool hasOpenGL3();
static bool hasOpenGLES();
/// Check for OpenGL
static bool hasOpenGL();
/**
* @brief supportsFilter
* @return True if OpenGL provides fence sync methods.
*/
static bool supportsFenceSync();
+ /**
+ * @brief supportsRenderToFBO
+ * @return True if OpenGL can render to FBO, used
+ * currently for rendering cursor with image overlay
+ * fx.
+ */
+ static bool supportsRenderToFBO();
+
+
/**
* Returns true if we have a driver that has bugged support to sync objects (a fence)
* and false otherwise.
*/
static bool needsFenceWorkaround();
/**
* @see a comment in initializeContext()
*/
static bool needsPixmapCacheWorkaround();
static void testingInitializeDefaultSurfaceFormat();
static void setDebugSynchronous(bool value);
private:
static void fakeInitWindowsOpenGL(KisOpenGL::OpenGLRenderers supportedRenderers, KisOpenGL::OpenGLRenderer preferredByQt);
KisOpenGL();
};
#ifdef Q_OS_WIN
Q_DECLARE_OPERATORS_FOR_FLAGS(KisOpenGL::OpenGLRenderers);
#endif
#endif // KIS_OPENGL_H_
diff --git a/libs/ui/opengl/kis_opengl_canvas2.cpp b/libs/ui/opengl/kis_opengl_canvas2.cpp
index 59f2181f07..dce0f530b5 100644
--- a/libs/ui/opengl/kis_opengl_canvas2.cpp
+++ b/libs/ui/opengl/kis_opengl_canvas2.cpp
@@ -1,1062 +1,1119 @@
/* This file is part of the KDE project
* Copyright (C) Boudewijn Rempt <boud@valdyas.org>, (C) 2006-2013
* Copyright (C) 2015 Michael Abrahams <miabraha@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define GL_GLEXT_PROTOTYPES
#include "opengl/kis_opengl_canvas2.h"
#include "opengl/kis_opengl_canvas2_p.h"
+#include "kis_algebra_2d.h"
#include "opengl/kis_opengl_shader_loader.h"
#include "opengl/kis_opengl_canvas_debugger.h"
#include "canvas/kis_canvas2.h"
#include "canvas/kis_coordinates_converter.h"
#include "canvas/kis_display_filter.h"
#include "canvas/kis_display_color_converter.h"
#include "kis_config.h"
#include "kis_config_notifier.h"
#include "kis_debug.h"
#include <QPainter>
#include <QPainterPath>
#include <QPointF>
+#include <QPointer>
#include <QMatrix>
#include <QTransform>
#include <QThread>
#include <QFile>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLBuffer>
+#include <QOpenGLFramebufferObject>
#include <QMessageBox>
#include "KisOpenGLModeProber.h"
#include <KoColorModelStandardIds.h>
#if !defined(Q_OS_MACOS) && !defined(HAS_ONLY_OPENGL_ES)
#include <QOpenGLFunctions_2_1>
#endif
#define NEAR_VAL -1000.0
#define FAR_VAL 1000.0
#ifndef GL_CLAMP_TO_EDGE
#define GL_CLAMP_TO_EDGE 0x812F
#endif
#define PROGRAM_VERTEX_ATTRIBUTE 0
#define PROGRAM_TEXCOORD_ATTRIBUTE 1
static bool OPENGL_SUCCESS = false;
struct KisOpenGLCanvas2::Private
{
public:
~Private() {
delete displayShader;
delete checkerShader;
delete solidColorShader;
+ delete overlayInvertedShader;
Sync::deleteSync(glSyncObject);
}
bool canvasInitialized{false};
KisOpenGLImageTexturesSP openGLImageTextures;
KisOpenGLShaderLoader shaderLoader;
KisShaderProgram *displayShader{0};
KisShaderProgram *checkerShader{0};
KisShaderProgram *solidColorShader{0};
+ KisShaderProgram *overlayInvertedShader{0};
+
+ QScopedPointer<QOpenGLFramebufferObject> canvasFBO;
+
bool displayShaderCompiledWithDisplayFilterSupport{false};
GLfloat checkSizeScale;
bool scrollCheckers;
QSharedPointer<KisDisplayFilter> displayFilter;
KisOpenGL::FilterMode filterMode;
bool proofingConfigIsUpdated=false;
GLsync glSyncObject{0};
bool wrapAroundMode{false};
// Stores a quad for drawing the canvas
QOpenGLVertexArrayObject quadVAO;
QOpenGLBuffer quadBuffers[2];
// Stores data for drawing tool outlines
QOpenGLVertexArrayObject outlineVAO;
- QOpenGLBuffer lineBuffer;
+ QOpenGLBuffer lineVertexBuffer;
+ QOpenGLBuffer lineTexCoordBuffer;
QVector3D vertices[6];
QVector2D texCoords[6];
#if !defined(Q_OS_MACOS) && !defined(HAS_ONLY_OPENGL_ES)
QOpenGLFunctions_2_1 *glFn201;
#endif
qreal pixelGridDrawingThreshold;
bool pixelGridEnabled;
QColor gridColor;
QColor cursorColor;
bool lodSwitchInProgress = false;
int xToColWithWrapCompensation(int x, const QRect &imageRect) {
int firstImageColumn = openGLImageTextures->xToCol(imageRect.left());
int lastImageColumn = openGLImageTextures->xToCol(imageRect.right());
int colsPerImage = lastImageColumn - firstImageColumn + 1;
int numWraps = floor(qreal(x) / imageRect.width());
int remainder = x - imageRect.width() * numWraps;
return colsPerImage * numWraps + openGLImageTextures->xToCol(remainder);
}
int yToRowWithWrapCompensation(int y, const QRect &imageRect) {
int firstImageRow = openGLImageTextures->yToRow(imageRect.top());
int lastImageRow = openGLImageTextures->yToRow(imageRect.bottom());
int rowsPerImage = lastImageRow - firstImageRow + 1;
int numWraps = floor(qreal(y) / imageRect.height());
int remainder = y - imageRect.height() * numWraps;
return rowsPerImage * numWraps + openGLImageTextures->yToRow(remainder);
}
};
KisOpenGLCanvas2::KisOpenGLCanvas2(KisCanvas2 *canvas,
KisCoordinatesConverter *coordinatesConverter,
QWidget *parent,
KisImageWSP image,
KisDisplayColorConverter *colorConverter)
: QOpenGLWidget(parent)
, KisCanvasWidgetBase(canvas, coordinatesConverter)
, d(new Private())
{
KisConfig cfg(false);
cfg.setCanvasState("OPENGL_STARTED");
d->openGLImageTextures =
KisOpenGLImageTextures::getImageTextures(image,
colorConverter->openGLCanvasSurfaceProfile(),
colorConverter->renderingIntent(),
colorConverter->conversionFlags());
connect(d->openGLImageTextures.data(),
SIGNAL(sigShowFloatingMessage(QString, int, bool)),
SLOT(slotShowFloatingMessage(QString, int, bool)));
setAcceptDrops(true);
setAutoFillBackground(false);
setFocusPolicy(Qt::StrongFocus);
setAttribute(Qt::WA_NoSystemBackground, true);
#ifdef Q_OS_MACOS
setAttribute(Qt::WA_AcceptTouchEvents, false);
#else
setAttribute(Qt::WA_AcceptTouchEvents, true);
#endif
setAttribute(Qt::WA_InputMethodEnabled, false);
setAttribute(Qt::WA_DontCreateNativeAncestors, true);
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
// we should make sure the texture doesn't have alpha channel,
// otherwise blending will not work correctly.
if (KisOpenGLModeProber::instance()->useHDRMode()) {
setTextureFormat(GL_RGBA16F);
} else {
/**
* When in pure OpenGL mode, the canvas surface will have alpha
* channel. Therefore, if our canvas blending algorithm produces
* semi-transparent pixels (and it does), then Krita window itself
* will become transparent. Which is not good.
*
* In Angle mode, GL_RGB8 is not available (and the transparence effect
* doesn't exist at all).
*/
if (!KisOpenGL::hasOpenGLES()) {
setTextureFormat(GL_RGB8);
}
}
#endif
setDisplayFilterImpl(colorConverter->displayFilter(), true);
connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged()));
connect(KisConfigNotifier::instance(), SIGNAL(pixelGridModeChanged()), SLOT(slotPixelGridModeChanged()));
slotConfigChanged();
slotPixelGridModeChanged();
cfg.writeEntry("canvasState", "OPENGL_SUCCESS");
}
KisOpenGLCanvas2::~KisOpenGLCanvas2()
{
delete d;
}
void KisOpenGLCanvas2::setDisplayFilter(QSharedPointer<KisDisplayFilter> displayFilter)
{
setDisplayFilterImpl(displayFilter, false);
}
void KisOpenGLCanvas2::setDisplayFilterImpl(QSharedPointer<KisDisplayFilter> displayFilter, bool initializing)
{
bool needsInternalColorManagement =
!displayFilter || displayFilter->useInternalColorManagement();
bool needsFullRefresh = d->openGLImageTextures->setInternalColorManagementActive(needsInternalColorManagement);
d->displayFilter = displayFilter;
if (!initializing && needsFullRefresh) {
canvas()->startUpdateInPatches(canvas()->image()->bounds());
}
else if (!initializing) {
canvas()->updateCanvas();
}
}
void KisOpenGLCanvas2::notifyImageColorSpaceChanged(const KoColorSpace *cs)
{
// FIXME: on color space change the data is refetched multiple
// times by different actors!
if (d->openGLImageTextures->setImageColorSpace(cs)) {
canvas()->startUpdateInPatches(canvas()->image()->bounds());
}
}
void KisOpenGLCanvas2::setWrapAroundViewingMode(bool value)
{
d->wrapAroundMode = value;
update();
}
inline void rectToVertices(QVector3D* vertices, const QRectF &rc)
{
vertices[0] = QVector3D(rc.left(), rc.bottom(), 0.f);
vertices[1] = QVector3D(rc.left(), rc.top(), 0.f);
vertices[2] = QVector3D(rc.right(), rc.bottom(), 0.f);
vertices[3] = QVector3D(rc.left(), rc.top(), 0.f);
vertices[4] = QVector3D(rc.right(), rc.top(), 0.f);
vertices[5] = QVector3D(rc.right(), rc.bottom(), 0.f);
}
inline void rectToTexCoords(QVector2D* texCoords, const QRectF &rc)
{
texCoords[0] = QVector2D(rc.left(), rc.bottom());
texCoords[1] = QVector2D(rc.left(), rc.top());
texCoords[2] = QVector2D(rc.right(), rc.bottom());
texCoords[3] = QVector2D(rc.left(), rc.top());
texCoords[4] = QVector2D(rc.right(), rc.top());
texCoords[5] = QVector2D(rc.right(), rc.bottom());
}
void KisOpenGLCanvas2::initializeGL()
{
KisOpenGL::initializeContext(context());
initializeOpenGLFunctions();
#if !defined(Q_OS_MACOS) && !defined(HAS_ONLY_OPENGL_ES)
if (!KisOpenGL::hasOpenGLES()) {
d->glFn201 = context()->versionFunctions<QOpenGLFunctions_2_1>();
if (!d->glFn201) {
warnUI << "Cannot obtain QOpenGLFunctions_2_1, glLogicOp cannot be used";
}
} else {
d->glFn201 = nullptr;
}
#endif
KisConfig cfg(true);
d->openGLImageTextures->setProofingConfig(canvas()->proofingConfiguration());
d->openGLImageTextures->initGL(context()->functions());
d->openGLImageTextures->generateCheckerTexture(createCheckersImage(cfg.checkSize()));
initializeShaders();
// If we support OpenGL 3.2, then prepare our VAOs and VBOs for drawing
if (KisOpenGL::hasOpenGL3()) {
d->quadVAO.create();
d->quadVAO.bind();
glEnableVertexAttribArray(PROGRAM_VERTEX_ATTRIBUTE);
glEnableVertexAttribArray(PROGRAM_TEXCOORD_ATTRIBUTE);
// Create the vertex buffer object, it has 6 vertices with 3 components
d->quadBuffers[0].create();
d->quadBuffers[0].setUsagePattern(QOpenGLBuffer::StaticDraw);
d->quadBuffers[0].bind();
d->quadBuffers[0].allocate(d->vertices, 6 * 3 * sizeof(float));
glVertexAttribPointer(PROGRAM_VERTEX_ATTRIBUTE, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Create the texture buffer object, it has 6 texture coordinates with 2 components
d->quadBuffers[1].create();
d->quadBuffers[1].setUsagePattern(QOpenGLBuffer::StaticDraw);
d->quadBuffers[1].bind();
d->quadBuffers[1].allocate(d->texCoords, 6 * 2 * sizeof(float));
glVertexAttribPointer(PROGRAM_TEXCOORD_ATTRIBUTE, 2, GL_FLOAT, GL_FALSE, 0, 0);
// Create the outline buffer, this buffer will store the outlines of
// tools and will frequently change data
d->outlineVAO.create();
d->outlineVAO.bind();
glEnableVertexAttribArray(PROGRAM_VERTEX_ATTRIBUTE);
+ glEnableVertexAttribArray(PROGRAM_TEXCOORD_ATTRIBUTE);
// The outline buffer has a StreamDraw usage pattern, because it changes constantly
- d->lineBuffer.create();
- d->lineBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw);
- d->lineBuffer.bind();
+ d->lineVertexBuffer.create();
+ d->lineVertexBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw);
+ d->lineVertexBuffer.bind();
glVertexAttribPointer(PROGRAM_VERTEX_ATTRIBUTE, 3, GL_FLOAT, GL_FALSE, 0, 0);
+
+ d->lineTexCoordBuffer.create();
+ d->lineTexCoordBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw);
+ d->lineTexCoordBuffer.bind();
+ glVertexAttribPointer(PROGRAM_TEXCOORD_ATTRIBUTE, 2, GL_FLOAT, GL_FALSE, 0 ,0);
}
Sync::init(context());
d->canvasInitialized = true;
}
/**
* Loads all shaders and reports compilation problems
*/
void KisOpenGLCanvas2::initializeShaders()
{
KIS_SAFE_ASSERT_RECOVER_RETURN(!d->canvasInitialized);
delete d->checkerShader;
delete d->solidColorShader;
+ delete d->overlayInvertedShader;
d->checkerShader = 0;
d->solidColorShader = 0;
+ d->overlayInvertedShader = 0;
try {
d->checkerShader = d->shaderLoader.loadCheckerShader();
d->solidColorShader = d->shaderLoader.loadSolidColorShader();
+ d->overlayInvertedShader = d->shaderLoader.loadOverlayInvertedShader();
} catch (const ShaderLoaderException &e) {
reportFailedShaderCompilation(e.what());
}
initializeDisplayShader();
}
void KisOpenGLCanvas2::initializeDisplayShader()
{
KIS_SAFE_ASSERT_RECOVER_RETURN(!d->canvasInitialized);
bool useHiQualityFiltering = d->filterMode == KisOpenGL::HighQualityFiltering;
delete d->displayShader;
d->displayShader = 0;
try {
d->displayShader = d->shaderLoader.loadDisplayShader(d->displayFilter, useHiQualityFiltering);
d->displayShaderCompiledWithDisplayFilterSupport = d->displayFilter;
} catch (const ShaderLoaderException &e) {
reportFailedShaderCompilation(e.what());
}
}
/**
* Displays a message box telling the user that
* shader compilation failed and turns off OpenGL.
*/
void KisOpenGLCanvas2::reportFailedShaderCompilation(const QString &context)
{
KisConfig cfg(false);
qDebug() << "Shader Compilation Failure: " << context;
QMessageBox::critical(this, i18nc("@title:window", "Krita"),
i18n("Krita could not initialize the OpenGL canvas:\n\n%1\n\n Krita will disable OpenGL and close now.", context),
QMessageBox::Close);
cfg.disableOpenGL();
cfg.setCanvasState("OPENGL_FAILED");
}
-void KisOpenGLCanvas2::resizeGL(int /*width*/, int /*height*/)
+void KisOpenGLCanvas2::resizeGL(int width, int height)
{
// The given size is the widget size but here we actually want to give
// KisCoordinatesConverter the viewport size aligned to device pixels.
+ if (KisOpenGL::supportsRenderToFBO()) {
+ d->canvasFBO.reset(new QOpenGLFramebufferObject(QSize(width, height)));
+ }
coordinatesConverter()->setCanvasWidgetSize(widgetSizeAlignedToDevicePixel());
paintGL();
}
void KisOpenGLCanvas2::paintGL()
{
if (!OPENGL_SUCCESS) {
KisConfig cfg(false);
cfg.writeEntry("canvasState", "OPENGL_PAINT_STARTED");
}
KisOpenglCanvasDebugger::instance()->nofityPaintRequested();
+ if (d->canvasFBO) {
+ d->canvasFBO->bind();
+ }
+
renderCanvasGL();
+ if (d->canvasFBO) {
+ d->canvasFBO->release();
+ QOpenGLFramebufferObject::blitFramebuffer(nullptr, d->canvasFBO.data(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ QOpenGLFramebufferObject::bindDefault();
+ }
+
if (d->glSyncObject) {
Sync::deleteSync(d->glSyncObject);
}
d->glSyncObject = Sync::getSync();
QPainter gc(this);
renderDecorations(&gc);
gc.end();
if (!OPENGL_SUCCESS) {
KisConfig cfg(false);
cfg.writeEntry("canvasState", "OPENGL_SUCCESS");
OPENGL_SUCCESS = true;
}
}
void KisOpenGLCanvas2::paintToolOutline(const QPainterPath &path)
{
- if (!d->solidColorShader->bind()) {
+ if (!d->overlayInvertedShader->bind()) {
return;
}
QSizeF widgetSize = widgetSizeAlignedToDevicePixel();
// setup the mvp transformation
QMatrix4x4 projectionMatrix;
projectionMatrix.setToIdentity();
// FIXME: It may be better to have the projection in device pixel, but
// this requires introducing a new coordinate system.
projectionMatrix.ortho(0, widgetSize.width(), widgetSize.height(), 0, NEAR_VAL, FAR_VAL);
- // Set view/projection matrices
+ // Set view/projection & texture matrices
QMatrix4x4 modelMatrix(coordinatesConverter()->flakeToWidgetTransform());
modelMatrix.optimize();
modelMatrix = projectionMatrix * modelMatrix;
- d->solidColorShader->setUniformValue(d->solidColorShader->location(Uniform::ModelViewProjection), modelMatrix);
+ d->overlayInvertedShader->setUniformValue(d->overlayInvertedShader->location(Uniform::ModelViewProjection), modelMatrix);
- if (!KisOpenGL::hasOpenGLES()) {
-#ifndef HAS_ONLY_OPENGL_ES
- glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
+ d->overlayInvertedShader->setUniformValue(
+ d->overlayInvertedShader->location(Uniform::FragmentColor),
+ QVector4D(d->cursorColor.redF(), d->cursorColor.greenF(), d->cursorColor.blueF(), 1.0f));
+
+ // NOTE: Texture matrix transforms flake space -> widget space -> OpenGL UV texcoord space..
+ const QMatrix4x4 widgetToFBOTexCoordTransform = KisAlgebra2D::mapToRectInverse(QRect(QPoint(0, this->height()),
+ QSize(this->width(), -1 * this->height())));
+ const QMatrix4x4 textureMatrix = widgetToFBOTexCoordTransform *
+ QMatrix4x4(coordinatesConverter()->flakeToWidgetTransform());
+ d->overlayInvertedShader->setUniformValue(d->overlayInvertedShader->location(Uniform::TextureMatrix), textureMatrix);
+
+ // For the legacy shader, we should use old fixed function
+ // blending operations if available.
+ if (!KisOpenGL::hasOpenGL3() && !KisOpenGL::hasOpenGLES()) {
+ #ifndef HAS_ONLY_OPENGL_ES
+ glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glEnable(GL_COLOR_LOGIC_OP);
-#ifndef Q_OS_MACOS
+
+ #ifndef Q_OS_MACOS
if (d->glFn201) {
d->glFn201->glLogicOp(GL_XOR);
}
-#else
+ #else // Q_OS_MACOS
glLogicOp(GL_XOR);
-#endif // Q_OS_OSX
+ #endif // Q_OS_MACOS
-#else // HAS_ONLY_OPENGL_ES
+ #else // HAS_ONLY_OPENGL_ES
KIS_ASSERT_X(false, "KisOpenGLCanvas2::paintToolOutline",
- "Unexpected KisOpenGL::hasOpenGLES returned false");
-#endif // HAS_ONLY_OPENGL_ES
- } else {
- glEnable(GL_BLEND);
- glBlendFuncSeparate(GL_ONE_MINUS_DST_COLOR, GL_ZERO, GL_ONE, GL_ONE);
+ "Unexpected KisOpenGL::hasOpenGLES returned false");
+ #endif // HAS_ONLY_OPENGL_ES
}
- d->solidColorShader->setUniformValue(
- d->solidColorShader->location(Uniform::FragmentColor),
- QVector4D(d->cursorColor.redF(), d->cursorColor.greenF(), d->cursorColor.blueF(), 1.0f));
-
// Paint the tool outline
if (KisOpenGL::hasOpenGL3()) {
d->outlineVAO.bind();
- d->lineBuffer.bind();
+ d->lineVertexBuffer.bind();
}
// Convert every disjointed subpath to a polygon and draw that polygon
QList<QPolygonF> subPathPolygons = path.toSubpathPolygons();
- for (int i = 0; i < subPathPolygons.size(); i++) {
- const QPolygonF& polygon = subPathPolygons.at(i);
+ for (int polyIndex = 0; polyIndex < subPathPolygons.size(); polyIndex++) {
+ const QPolygonF& polygon = subPathPolygons.at(polyIndex);
QVector<QVector3D> vertices;
+ QVector<QVector2D> texCoords;
vertices.resize(polygon.count());
-
- for (int j = 0; j < polygon.count(); j++) {
- QPointF p = polygon.at(j);
- vertices[j].setX(p.x());
- vertices[j].setY(p.y());
+ texCoords.resize(polygon.count());
+
+ for (int vertIndex = 0; vertIndex < polygon.count(); vertIndex++) {
+ QPointF point = polygon.at(vertIndex);
+ vertices[vertIndex].setX(point.x());
+ vertices[vertIndex].setY(point.y());
+ texCoords[vertIndex].setX(point.x());
+ texCoords[vertIndex].setY(point.y());
}
if (KisOpenGL::hasOpenGL3()) {
- d->lineBuffer.allocate(vertices.constData(), 3 * vertices.size() * sizeof(float));
+ d->lineVertexBuffer.bind();
+ d->lineVertexBuffer.allocate(vertices.constData(), 3 * vertices.size() * sizeof(float));
+ d->lineTexCoordBuffer.bind();
+ d->lineTexCoordBuffer.allocate(texCoords.constData(), 2 * texCoords.size() * sizeof(float));
}
else {
- d->solidColorShader->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
- d->solidColorShader->setAttributeArray(PROGRAM_VERTEX_ATTRIBUTE, vertices.constData());
+ d->overlayInvertedShader->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
+ d->overlayInvertedShader->setAttributeArray(PROGRAM_VERTEX_ATTRIBUTE, vertices.constData());
+ d->overlayInvertedShader->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
+ d->overlayInvertedShader->setAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE, texCoords.constData());
}
- glDrawArrays(GL_LINE_STRIP, 0, vertices.size());
+ const bool usingLegacyShader = !((KisOpenGL::hasOpenGL3() || KisOpenGL::hasOpenGLES()) && KisOpenGL::supportsRenderToFBO());
+ if (usingLegacyShader){
+ glDrawArrays(GL_LINE_STRIP, 0, vertices.size());
+ } else {
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, d->canvasFBO->texture());
+
+ glDrawArrays(GL_LINE_STRIP, 0, vertices.size());
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
}
if (KisOpenGL::hasOpenGL3()) {
- d->lineBuffer.release();
+ d->lineVertexBuffer.release();
d->outlineVAO.release();
}
if (!KisOpenGL::hasOpenGLES()) {
#ifndef HAS_ONLY_OPENGL_ES
glDisable(GL_COLOR_LOGIC_OP);
#else
KIS_ASSERT_X(false, "KisOpenGLCanvas2::paintToolOutline",
"Unexpected KisOpenGL::hasOpenGLES returned false");
#endif
} else {
glDisable(GL_BLEND);
}
- d->solidColorShader->release();
+ d->overlayInvertedShader->release();
}
bool KisOpenGLCanvas2::isBusy() const
{
const bool isBusyStatus = Sync::syncStatus(d->glSyncObject) == Sync::Unsignaled;
KisOpenglCanvasDebugger::instance()->nofitySyncStatus(isBusyStatus);
return isBusyStatus;
}
void KisOpenGLCanvas2::setLodResetInProgress(bool value)
{
d->lodSwitchInProgress = value;
}
void KisOpenGLCanvas2::drawCheckers()
{
if (!d->checkerShader) {
return;
}
KisCoordinatesConverter *converter = coordinatesConverter();
QTransform textureTransform;
QTransform modelTransform;
QRectF textureRect;
QRectF modelRect;
QSizeF widgetSize = widgetSizeAlignedToDevicePixel();
QRectF viewportRect = !d->wrapAroundMode ?
converter->imageRectInViewportPixels() :
converter->widgetToViewport(QRectF(0, 0, widgetSize.width(), widgetSize.height()));
if (!canvas()->renderingLimit().isEmpty()) {
const QRect vrect = converter->imageToViewport(canvas()->renderingLimit()).toAlignedRect();
viewportRect &= vrect;
}
converter->getOpenGLCheckersInfo(viewportRect,
&textureTransform, &modelTransform, &textureRect, &modelRect, d->scrollCheckers);
textureTransform *= QTransform::fromScale(d->checkSizeScale / KisOpenGLImageTextures::BACKGROUND_TEXTURE_SIZE,
d->checkSizeScale / KisOpenGLImageTextures::BACKGROUND_TEXTURE_SIZE);
if (!d->checkerShader->bind()) {
qWarning() << "Could not bind checker shader";
return;
}
QMatrix4x4 projectionMatrix;
projectionMatrix.setToIdentity();
// FIXME: It may be better to have the projection in device pixel, but
// this requires introducing a new coordinate system.
projectionMatrix.ortho(0, widgetSize.width(), widgetSize.height(), 0, NEAR_VAL, FAR_VAL);
// Set view/projection matrices
QMatrix4x4 modelMatrix(modelTransform);
modelMatrix.optimize();
modelMatrix = projectionMatrix * modelMatrix;
d->checkerShader->setUniformValue(d->checkerShader->location(Uniform::ModelViewProjection), modelMatrix);
QMatrix4x4 textureMatrix(textureTransform);
d->checkerShader->setUniformValue(d->checkerShader->location(Uniform::TextureMatrix), textureMatrix);
//Setup the geometry for rendering
if (KisOpenGL::hasOpenGL3()) {
rectToVertices(d->vertices, modelRect);
d->quadBuffers[0].bind();
d->quadBuffers[0].write(0, d->vertices, 3 * 6 * sizeof(float));
rectToTexCoords(d->texCoords, textureRect);
d->quadBuffers[1].bind();
d->quadBuffers[1].write(0, d->texCoords, 2 * 6 * sizeof(float));
}
else {
rectToVertices(d->vertices, modelRect);
d->checkerShader->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
d->checkerShader->setAttributeArray(PROGRAM_VERTEX_ATTRIBUTE, d->vertices);
rectToTexCoords(d->texCoords, textureRect);
d->checkerShader->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
d->checkerShader->setAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE, d->texCoords);
}
// render checkers
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, d->openGLImageTextures->checkerTexture());
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindTexture(GL_TEXTURE_2D, 0);
d->checkerShader->release();
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void KisOpenGLCanvas2::drawGrid()
{
if (!d->solidColorShader->bind()) {
return;
}
QSizeF widgetSize = widgetSizeAlignedToDevicePixel();
QMatrix4x4 projectionMatrix;
projectionMatrix.setToIdentity();
// FIXME: It may be better to have the projection in device pixel, but
// this requires introducing a new coordinate system.
projectionMatrix.ortho(0, widgetSize.width(), widgetSize.height(), 0, NEAR_VAL, FAR_VAL);
// Set view/projection matrices
QMatrix4x4 modelMatrix(coordinatesConverter()->imageToWidgetTransform());
modelMatrix.optimize();
modelMatrix = projectionMatrix * modelMatrix;
d->solidColorShader->setUniformValue(d->solidColorShader->location(Uniform::ModelViewProjection), modelMatrix);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
d->solidColorShader->setUniformValue(
d->solidColorShader->location(Uniform::FragmentColor),
QVector4D(d->gridColor.redF(), d->gridColor.greenF(), d->gridColor.blueF(), 0.5f));
if (KisOpenGL::hasOpenGL3()) {
d->outlineVAO.bind();
- d->lineBuffer.bind();
+ d->lineVertexBuffer.bind();
}
QRectF widgetRect(0,0, widgetSize.width(), widgetSize.height());
QRectF widgetRectInImagePixels = coordinatesConverter()->documentToImage(coordinatesConverter()->widgetToDocument(widgetRect));
QRect wr = widgetRectInImagePixels.toAlignedRect();
if (!d->wrapAroundMode) {
wr &= d->openGLImageTextures->storedImageBounds();
}
QPoint topLeftCorner = wr.topLeft();
QPoint bottomRightCorner = wr.bottomRight() + QPoint(1, 1);
QVector<QVector3D> grid;
for (int i = topLeftCorner.x(); i <= bottomRightCorner.x(); ++i) {
grid.append(QVector3D(i, topLeftCorner.y(), 0));
grid.append(QVector3D(i, bottomRightCorner.y(), 0));
}
for (int i = topLeftCorner.y(); i <= bottomRightCorner.y(); ++i) {
grid.append(QVector3D(topLeftCorner.x(), i, 0));
grid.append(QVector3D(bottomRightCorner.x(), i, 0));
}
if (KisOpenGL::hasOpenGL3()) {
- d->lineBuffer.allocate(grid.constData(), 3 * grid.size() * sizeof(float));
+ d->lineVertexBuffer.allocate(grid.constData(), 3 * grid.size() * sizeof(float));
}
else {
d->solidColorShader->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
d->solidColorShader->setAttributeArray(PROGRAM_VERTEX_ATTRIBUTE, grid.constData());
}
glDrawArrays(GL_LINES, 0, grid.size());
if (KisOpenGL::hasOpenGL3()) {
- d->lineBuffer.release();
+ d->lineVertexBuffer.release();
d->outlineVAO.release();
}
d->solidColorShader->release();
glDisable(GL_BLEND);
}
void KisOpenGLCanvas2::drawImage()
{
if (!d->displayShader) {
return;
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
KisCoordinatesConverter *converter = coordinatesConverter();
d->displayShader->bind();
QSizeF widgetSize = widgetSizeAlignedToDevicePixel();
QMatrix4x4 projectionMatrix;
projectionMatrix.setToIdentity();
// FIXME: It may be better to have the projection in device pixel, but
// this requires introducing a new coordinate system.
projectionMatrix.ortho(0, widgetSize.width(), widgetSize.height(), 0, NEAR_VAL, FAR_VAL);
// Set view/projection matrices
QMatrix4x4 modelMatrix(converter->imageToWidgetTransform());
modelMatrix.optimize();
modelMatrix = projectionMatrix * modelMatrix;
d->displayShader->setUniformValue(d->displayShader->location(Uniform::ModelViewProjection), modelMatrix);
QMatrix4x4 textureMatrix;
textureMatrix.setToIdentity();
d->displayShader->setUniformValue(d->displayShader->location(Uniform::TextureMatrix), textureMatrix);
QRectF widgetRect(0,0, widgetSize.width(), widgetSize.height());
QRectF widgetRectInImagePixels = converter->documentToImage(converter->widgetToDocument(widgetRect));
const QRect renderingLimit = canvas()->renderingLimit();
if (!renderingLimit.isEmpty()) {
widgetRectInImagePixels &= renderingLimit;
}
qreal scaleX, scaleY;
converter->imagePhysicalScale(&scaleX, &scaleY);
d->displayShader->setUniformValue(d->displayShader->location(Uniform::ViewportScale), (GLfloat) scaleX);
d->displayShader->setUniformValue(d->displayShader->location(Uniform::TexelSize), (GLfloat) d->openGLImageTextures->texelSize());
QRect ir = d->openGLImageTextures->storedImageBounds();
QRect wr = widgetRectInImagePixels.toAlignedRect();
if (!d->wrapAroundMode) {
// if we don't want to paint wrapping images, just limit the
// processing area, and the code will handle all the rest
wr &= ir;
}
int firstColumn = d->xToColWithWrapCompensation(wr.left(), ir);
int lastColumn = d->xToColWithWrapCompensation(wr.right(), ir);
int firstRow = d->yToRowWithWrapCompensation(wr.top(), ir);
int lastRow = d->yToRowWithWrapCompensation(wr.bottom(), ir);
int minColumn = d->openGLImageTextures->xToCol(ir.left());
int maxColumn = d->openGLImageTextures->xToCol(ir.right());
int minRow = d->openGLImageTextures->yToRow(ir.top());
int maxRow = d->openGLImageTextures->yToRow(ir.bottom());
int imageColumns = maxColumn - minColumn + 1;
int imageRows = maxRow - minRow + 1;
for (int col = firstColumn; col <= lastColumn; col++) {
for (int row = firstRow; row <= lastRow; row++) {
int effectiveCol = col;
int effectiveRow = row;
QPointF tileWrappingTranslation;
if (effectiveCol > maxColumn || effectiveCol < minColumn) {
int translationStep = floor(qreal(col) / imageColumns);
int originCol = translationStep * imageColumns;
effectiveCol = col - originCol;
tileWrappingTranslation.rx() = translationStep * ir.width();
}
if (effectiveRow > maxRow || effectiveRow < minRow) {
int translationStep = floor(qreal(row) / imageRows);
int originRow = translationStep * imageRows;
effectiveRow = row - originRow;
tileWrappingTranslation.ry() = translationStep * ir.height();
}
KisTextureTile *tile =
d->openGLImageTextures->getTextureTileCR(effectiveCol, effectiveRow);
if (!tile) {
warnUI << "OpenGL: Trying to paint texture tile but it has not been created yet.";
continue;
}
/*
* We create a float rect here to workaround Qt's
* "history reasons" in calculation of right()
* and bottom() coordinates of integer rects.
*/
QRectF textureRect;
QRectF modelRect;
if (renderingLimit.isEmpty()) {
textureRect = tile->tileRectInTexturePixels();
modelRect = tile->tileRectInImagePixels().translated(tileWrappingTranslation.x(), tileWrappingTranslation.y());
} else {
const QRect limitedTileRect = tile->tileRectInImagePixels() & renderingLimit;
textureRect = tile->imageRectInTexturePixels(limitedTileRect);
modelRect = limitedTileRect.translated(tileWrappingTranslation.x(), tileWrappingTranslation.y());
}
//Setup the geometry for rendering
if (KisOpenGL::hasOpenGL3()) {
rectToVertices(d->vertices, modelRect);
d->quadBuffers[0].bind();
d->quadBuffers[0].write(0, d->vertices, 3 * 6 * sizeof(float));
rectToTexCoords(d->texCoords, textureRect);
d->quadBuffers[1].bind();
d->quadBuffers[1].write(0, d->texCoords, 2 * 6 * sizeof(float));
}
else {
rectToVertices(d->vertices, modelRect);
d->displayShader->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
d->displayShader->setAttributeArray(PROGRAM_VERTEX_ATTRIBUTE, d->vertices);
rectToTexCoords(d->texCoords, textureRect);
d->displayShader->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
d->displayShader->setAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE, d->texCoords);
}
if (d->displayFilter) {
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, d->displayFilter->lutTexture());
d->displayShader->setUniformValue(d->displayShader->location(Uniform::Texture1), 1);
}
glActiveTexture(GL_TEXTURE0);
const int currentLodPlane = tile->bindToActiveTexture(d->lodSwitchInProgress);
if (d->displayShader->location(Uniform::FixedLodLevel) >= 0) {
d->displayShader->setUniformValue(d->displayShader->location(Uniform::FixedLodLevel),
(GLfloat) currentLodPlane);
}
if (currentLodPlane > 0) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
} else if (SCALE_MORE_OR_EQUAL_TO(scaleX, scaleY, 2.0)) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
switch(d->filterMode) {
case KisOpenGL::NearestFilterMode:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
break;
case KisOpenGL::BilinearFilterMode:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
break;
case KisOpenGL::TrilinearFilterMode:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
break;
case KisOpenGL::HighQualityFiltering:
if (SCALE_LESS_THAN(scaleX, scaleY, 0.5)) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
break;
}
}
glDrawArrays(GL_TRIANGLES, 0, 6);
}
}
glBindTexture(GL_TEXTURE_2D, 0);
d->displayShader->release();
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisable(GL_BLEND);
}
QSize KisOpenGLCanvas2::viewportDevicePixelSize() const
{
// This is how QOpenGLCanvas sets the FBO and the viewport size. If
// devicePixelRatioF() is non-integral, the result is truncated.
int viewportWidth = static_cast<int>(width() * devicePixelRatioF());
int viewportHeight = static_cast<int>(height() * devicePixelRatioF());
return QSize(viewportWidth, viewportHeight);
}
QSizeF KisOpenGLCanvas2::widgetSizeAlignedToDevicePixel() const
{
QSize viewportSize = viewportDevicePixelSize();
qreal scaledWidth = viewportSize.width() / devicePixelRatioF();
qreal scaledHeight = viewportSize.height() / devicePixelRatioF();
return QSizeF(scaledWidth, scaledHeight);
}
void KisOpenGLCanvas2::slotConfigChanged()
{
KisConfig cfg(true);
d->checkSizeScale = KisOpenGLImageTextures::BACKGROUND_TEXTURE_CHECK_SIZE / static_cast<GLfloat>(cfg.checkSize());
d->scrollCheckers = cfg.scrollCheckers();
d->openGLImageTextures->generateCheckerTexture(createCheckersImage(cfg.checkSize()));
d->openGLImageTextures->updateConfig(cfg.useOpenGLTextureBuffer(), cfg.numMipmapLevels());
d->filterMode = (KisOpenGL::FilterMode) cfg.openGLFilteringMode();
d->cursorColor = cfg.getCursorMainColor();
notifyConfigChanged();
}
void KisOpenGLCanvas2::slotPixelGridModeChanged()
{
KisConfig cfg(true);
d->pixelGridDrawingThreshold = cfg.getPixelGridDrawingThreshold();
d->pixelGridEnabled = cfg.pixelGridEnabled();
d->gridColor = cfg.getPixelGridColor();
update();
}
void KisOpenGLCanvas2::slotShowFloatingMessage(const QString &message, int timeout, bool priority)
{
canvas()->imageView()->showFloatingMessage(message, QIcon(), timeout, priority ? KisFloatingMessage::High : KisFloatingMessage::Medium);
}
QVariant KisOpenGLCanvas2::inputMethodQuery(Qt::InputMethodQuery query) const
{
return processInputMethodQuery(query);
}
void KisOpenGLCanvas2::inputMethodEvent(QInputMethodEvent *event)
{
processInputMethodEvent(event);
}
void KisOpenGLCanvas2::renderCanvasGL()
{
{
// Draw the border (that is, clear the whole widget to the border color)
QColor widgetBackgroundColor = borderColor();
const KoColorSpace *finalColorSpace =
KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(),
d->openGLImageTextures->updateInfoBuilder().destinationColorSpace()->colorDepthId().id(),
d->openGLImageTextures->monitorProfile());
KoColor convertedBackgroudColor = KoColor(widgetBackgroundColor, KoColorSpaceRegistry::instance()->rgb8());
convertedBackgroudColor.convertTo(finalColorSpace);
QVector<float> channels = QVector<float>(4);
convertedBackgroudColor.colorSpace()->normalisedChannelsValue(convertedBackgroudColor.data(), channels);
// Data returned by KoRgbU8ColorSpace comes in the order: blue, green, red.
glClearColor(channels[2], channels[1], channels[0], 1.0);
}
glClear(GL_COLOR_BUFFER_BIT);
if ((d->displayFilter && d->displayFilter->updateShader()) ||
(bool(d->displayFilter) != d->displayShaderCompiledWithDisplayFilterSupport)) {
KIS_SAFE_ASSERT_RECOVER_NOOP(d->canvasInitialized);
d->canvasInitialized = false; // TODO: check if actually needed?
initializeDisplayShader();
d->canvasInitialized = true;
}
if (KisOpenGL::hasOpenGL3()) {
d->quadVAO.bind();
}
drawCheckers();
drawImage();
if ((coordinatesConverter()->effectiveZoom() > d->pixelGridDrawingThreshold - 0.00001) && d->pixelGridEnabled) {
drawGrid();
}
if (KisOpenGL::hasOpenGL3()) {
d->quadVAO.release();
}
}
void KisOpenGLCanvas2::renderDecorations(QPainter *painter)
{
QRect boundingRect = coordinatesConverter()->imageRectInWidgetPixels().toAlignedRect();
drawDecorations(*painter, boundingRect);
}
void KisOpenGLCanvas2::setDisplayColorConverter(KisDisplayColorConverter *colorConverter)
{
d->openGLImageTextures->setMonitorProfile(colorConverter->openGLCanvasSurfaceProfile(),
colorConverter->renderingIntent(),
colorConverter->conversionFlags());
}
void KisOpenGLCanvas2::channelSelectionChanged(const QBitArray &channelFlags)
{
d->openGLImageTextures->setChannelFlags(channelFlags);
}
void KisOpenGLCanvas2::finishResizingImage(qint32 w, qint32 h)
{
if (d->canvasInitialized) {
d->openGLImageTextures->slotImageSizeChanged(w, h);
}
}
KisUpdateInfoSP KisOpenGLCanvas2::startUpdateCanvasProjection(const QRect & rc, const QBitArray &channelFlags)
{
d->openGLImageTextures->setChannelFlags(channelFlags);
if (canvas()->proofingConfigUpdated()) {
d->openGLImageTextures->setProofingConfig(canvas()->proofingConfiguration());
canvas()->setProofingConfigUpdated(false);
}
return d->openGLImageTextures->updateCache(rc, d->openGLImageTextures->image());
}
QRect KisOpenGLCanvas2::updateCanvasProjection(KisUpdateInfoSP info)
{
// See KisQPainterCanvas::updateCanvasProjection for more info
bool isOpenGLUpdateInfo = dynamic_cast<KisOpenGLUpdateInfo*>(info.data());
if (isOpenGLUpdateInfo) {
d->openGLImageTextures->recalculateCache(info, d->lodSwitchInProgress);
}
return QRect(); // FIXME: Implement dirty rect for OpenGL
}
QVector<QRect> KisOpenGLCanvas2::updateCanvasProjection(const QVector<KisUpdateInfoSP> &infoObjects)
{
#ifdef Q_OS_MACOS
/**
* On OSX openGL different (shared) contexts have different execution queues.
* It means that the textures uploading and their painting can be easily reordered.
* To overcome the issue, we should ensure that the textures are uploaded in the
* same openGL context as the painting is done.
*/
QOpenGLContext *oldContext = QOpenGLContext::currentContext();
QSurface *oldSurface = oldContext ? oldContext->surface() : 0;
this->makeCurrent();
#endif
QVector<QRect> result = KisCanvasWidgetBase::updateCanvasProjection(infoObjects);
#ifdef Q_OS_MACOS
if (oldContext) {
oldContext->makeCurrent(oldSurface);
} else {
this->doneCurrent();
}
#endif
return result;
}
bool KisOpenGLCanvas2::callFocusNextPrevChild(bool next)
{
return focusNextPrevChild(next);
}
KisOpenGLImageTexturesSP KisOpenGLCanvas2::openGLImageTextures() const
{
return d->openGLImageTextures;
}
diff --git a/libs/ui/opengl/kis_opengl_canvas2.h b/libs/ui/opengl/kis_opengl_canvas2.h
index fc08867b5f..de46a89ce0 100644
--- a/libs/ui/opengl/kis_opengl_canvas2.h
+++ b/libs/ui/opengl/kis_opengl_canvas2.h
@@ -1,135 +1,136 @@
/*
* Copyright (C) Boudewijn Rempt <boud@valdyas.org>, (C) 2006
* Copyright (C) Michael Abrahams <miabraha@gmail.com>, (C) 2015
*
* 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_OPENGL_CANVAS_2_H
#define KIS_OPENGL_CANVAS_2_H
#include <QOpenGLWidget>
#ifndef Q_OS_MACOS
#include <QOpenGLFunctions>
#else
#include <QOpenGLFunctions_3_2_Core>
#endif
#include "canvas/kis_canvas_widget_base.h"
#include "opengl/kis_opengl_image_textures.h"
#include "kritaui_export.h"
#include "kis_ui_types.h"
class KisCanvas2;
class KisDisplayColorConverter;
class QOpenGLShaderProgram;
class QPainterPath;
#ifndef Q_MOC_RUN
#ifndef Q_OS_MACOS
#define GLFunctions QOpenGLFunctions
#else
#define GLFunctions QOpenGLFunctions_3_2_Core
#endif
#endif
/**
* KisOpenGLCanvas is the widget that shows the actual image using OpenGL
*
* NOTE: if you change something in the event handling here, also change it
* in the qpainter canvas.
*
*/
class KRITAUI_EXPORT KisOpenGLCanvas2
: public QOpenGLWidget
#ifndef Q_MOC_RUN
, protected GLFunctions
#endif
, public KisCanvasWidgetBase
{
Q_OBJECT
public:
KisOpenGLCanvas2(KisCanvas2 *canvas, KisCoordinatesConverter *coordinatesConverter, QWidget *parent, KisImageWSP image, KisDisplayColorConverter *colorConverter);
~KisOpenGLCanvas2() override;
public: // QOpenGLWidget
void resizeGL(int width, int height) override;
void initializeGL() override;
void paintGL() override;
QVariant inputMethodQuery(Qt::InputMethodQuery query) const override;
void inputMethodEvent(QInputMethodEvent *event) override;
public:
void renderCanvasGL();
void renderDecorations(QPainter *painter);
void paintToolOutline(const QPainterPath &path);
+
public: // Implement kis_abstract_canvas_widget interface
void setDisplayFilter(QSharedPointer<KisDisplayFilter> displayFilter) override;
void notifyImageColorSpaceChanged(const KoColorSpace *cs) override;
void setWrapAroundViewingMode(bool value) override;
void channelSelectionChanged(const QBitArray &channelFlags) override;
void setDisplayColorConverter(KisDisplayColorConverter *colorConverter) override;
void finishResizingImage(qint32 w, qint32 h) override;
KisUpdateInfoSP startUpdateCanvasProjection(const QRect & rc, const QBitArray &channelFlags) override;
QRect updateCanvasProjection(KisUpdateInfoSP info) override;
QVector<QRect> updateCanvasProjection(const QVector<KisUpdateInfoSP> &infoObjects) override;
QWidget *widget() override {
return this;
}
bool isBusy() const override;
void setLodResetInProgress(bool value) override;
void setDisplayFilterImpl(QSharedPointer<KisDisplayFilter> displayFilter, bool initializing);
KisOpenGLImageTexturesSP openGLImageTextures() const;
public Q_SLOTS:
void slotConfigChanged();
void slotPixelGridModeChanged();
private Q_SLOTS:
void slotShowFloatingMessage(const QString &message, int timeout, bool priority);
protected: // KisCanvasWidgetBase
bool callFocusNextPrevChild(bool next) override;
private:
void initializeShaders();
void initializeDisplayShader();
void reportFailedShaderCompilation(const QString &context);
void drawImage();
void drawCheckers();
void drawGrid();
QSize viewportDevicePixelSize() const;
QSizeF widgetSizeAlignedToDevicePixel() const;
private:
struct Private;
Private * const d;
};
#endif // KIS_OPENGL_CANVAS_2_H
diff --git a/libs/ui/opengl/kis_opengl_shader_loader.cpp b/libs/ui/opengl/kis_opengl_shader_loader.cpp
index 306e3a56c0..574c0626b3 100644
--- a/libs/ui/opengl/kis_opengl_shader_loader.cpp
+++ b/libs/ui/opengl/kis_opengl_shader_loader.cpp
@@ -1,211 +1,229 @@
/* This file is part of the KDE project
* Copyright (C) Julian Thijssen <julianthijssen@gmail.com>, (C) 2016
*
* 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_opengl_shader_loader.h"
#include "opengl/kis_opengl.h"
#include "kis_config.h"
#include <QFile>
#include <QMessageBox>
#include <KLocalizedString>
#define PROGRAM_VERTEX_ATTRIBUTE 0
#define PROGRAM_TEXCOORD_ATTRIBUTE 1
// Mapping of uniforms to uniform names
std::map<Uniform, const char *> KisShaderProgram::names = {
{ModelViewProjection, "modelViewProjection"},
{TextureMatrix, "textureMatrix"},
{ViewportScale, "viewportScale"},
{TexelSize, "texelSize"},
{Texture0, "texture0"},
{Texture1, "texture1"},
{FixedLodLevel, "fixedLodLevel"},
{FragmentColor, "fragColor"}
};
/**
* Generic shader loading function that will compile a shader program given
* a vertex shader and fragment shader resource path. Extra code can be prepended
* to each shader respectively using the header parameters.
*
* @param vertPath Resource path to a vertex shader
* @param fragPath Resource path to a fragment shader
* @param vertHeader Extra code which will be prepended to the vertex shader
* @param fragHeader Extra code which will be prepended to the fragment shader
*/
KisShaderProgram *KisOpenGLShaderLoader::loadShader(QString vertPath, QString fragPath,
QByteArray vertHeader, QByteArray fragHeader)
{
bool result;
KisShaderProgram *shader = new KisShaderProgram();
// Load vertex shader
QByteArray vertSource;
// XXX Check can be removed and set to the MAC version after we move to Qt5.7
#ifdef Q_OS_MACOS
vertSource.append(KisOpenGL::hasOpenGL3() ? "#version 150 core\n" : "#version 120\n");
// OpenColorIO doesn't support the new GLSL version yet.
vertSource.append("#define texture2D texture\n");
vertSource.append("#define texture3D texture\n");
#else
if (KisOpenGL::hasOpenGLES()) {
vertSource.append("#version 300 es\n");
} else {
vertSource.append(KisOpenGL::supportsLoD() ? "#version 130\n" : "#version 120\n");
}
#endif
vertSource.append(vertHeader);
QFile vertexShaderFile(":/" + vertPath);
vertexShaderFile.open(QIODevice::ReadOnly);
vertSource.append(vertexShaderFile.readAll());
result = shader->addShaderFromSourceCode(QOpenGLShader::Vertex, vertSource);
if (!result)
throw ShaderLoaderException(QString("%1: %2 - Cause: %3").arg("Failed to add vertex shader source from file", vertPath, shader->log()));
// Load fragment shader
QByteArray fragSource;
// XXX Check can be removed and set to the MAC version after we move to Qt5.7
#ifdef Q_OS_MACOS
fragSource.append(KisOpenGL::hasOpenGL3() ? "#version 150 core\n" : "#version 120\n");
// OpenColorIO doesn't support the new GLSL version yet.
fragSource.append("#define texture2D texture\n");
fragSource.append("#define texture3D texture\n");
#else
if (KisOpenGL::hasOpenGLES()) {
fragSource.append(
"#version 300 es\n"
"precision mediump float;\n"
"precision mediump sampler3D;\n");
// OpenColorIO doesn't support the new GLSL version yet.
fragSource.append("#define texture2D texture\n");
fragSource.append("#define texture3D texture\n");
} else {
fragSource.append(KisOpenGL::supportsLoD() ? "#version 130\n" : "#version 120\n");
}
#endif
fragSource.append(fragHeader);
QFile fragmentShaderFile(":/" + fragPath);
fragmentShaderFile.open(QIODevice::ReadOnly);
fragSource.append(fragmentShaderFile.readAll());
result = shader->addShaderFromSourceCode(QOpenGLShader::Fragment, fragSource);
if (!result)
throw ShaderLoaderException(QString("%1: %2 - Cause: %3").arg("Failed to add fragment shader source from file", fragPath, shader->log()));
// Bind attributes
shader->bindAttributeLocation("a_vertexPosition", PROGRAM_VERTEX_ATTRIBUTE);
shader->bindAttributeLocation("a_textureCoordinate", PROGRAM_TEXCOORD_ATTRIBUTE);
// Link
result = shader->link();
if (!result)
throw ShaderLoaderException(QString("Failed to link shader: ").append(vertPath));
Q_ASSERT(shader->isLinked());
return shader;
}
/**
* Specific display shader loading function. It adds the appropriate extra code
* to the fragment shader depending on what is available on the target machine.
* Additionally, it picks the appropriate shader files depending on the availability
* of OpenGL3.
*/
KisShaderProgram *KisOpenGLShaderLoader::loadDisplayShader(QSharedPointer<KisDisplayFilter> displayFilter, bool useHiQualityFiltering)
{
QByteArray fragHeader;
if (KisOpenGL::supportsLoD()) {
fragHeader.append("#define DIRECT_LOD_FETCH\n");
if (useHiQualityFiltering) {
fragHeader.append("#define HIGHQ_SCALING\n");
}
}
// If we have an OCIO display filter and it contains a function we add
// it to our shader header which will sit on top of the fragment code.
bool haveDisplayFilter = displayFilter && !displayFilter->program().isEmpty();
if (haveDisplayFilter) {
fragHeader.append("#define USE_OCIO\n");
fragHeader.append(displayFilter->program().toLatin1());
}
QString vertPath, fragPath;
// Select appropriate shader files
if (KisOpenGL::supportsLoD()) {
vertPath = "matrix_transform.vert";
fragPath = "highq_downscale.frag";
} else {
vertPath = "matrix_transform_legacy.vert";
fragPath = "simple_texture_legacy.frag";
}
KisShaderProgram *shader = loadShader(vertPath, fragPath, QByteArray(), fragHeader);
return shader;
}
/**
* Specific checker shader loading function. It picks the appropriate shader
* files depending on the availability of OpenGL3 on the target machine.
*/
KisShaderProgram *KisOpenGLShaderLoader::loadCheckerShader()
{
QString vertPath, fragPath;
// Select appropriate shader files
if (KisOpenGL::supportsLoD()) {
vertPath = "matrix_transform.vert";
fragPath = "simple_texture.frag";
} else {
vertPath = "matrix_transform_legacy.vert";
fragPath = "simple_texture_legacy.frag";
}
KisShaderProgram *shader = loadShader(vertPath, fragPath, QByteArray(), QByteArray());
return shader;
}
/**
* Specific uniform shader loading function. It picks the appropriate shader
* files depending on the availability of OpenGL3 on the target machine.
*/
KisShaderProgram *KisOpenGLShaderLoader::loadSolidColorShader()
{
QString vertPath, fragPath;
// Select appropriate shader files
if (KisOpenGL::supportsLoD()) {
vertPath = "matrix_transform.vert";
fragPath = "solid_color.frag";
} else {
vertPath = "matrix_transform_legacy.vert";
fragPath = "solid_color_legacy.frag";
}
KisShaderProgram *shader = loadShader(vertPath, fragPath, QByteArray(), QByteArray());
return shader;
}
+
+KisShaderProgram *KisOpenGLShaderLoader::loadOverlayInvertedShader()
+{
+ QString vertPath, fragPath;
+
+ // Select appropriate shader files
+ if ((KisOpenGL::hasOpenGL3() || KisOpenGL::hasOpenGLES()) && KisOpenGL::supportsRenderToFBO()) {
+ vertPath = "matrix_transform.vert";
+ fragPath = "overlay_inverted.frag";
+ } else {
+ vertPath = "matrix_transform_legacy.vert";
+ fragPath = "solid_color_legacy.frag";
+ }
+
+ KisShaderProgram *shader = loadShader(vertPath, fragPath, QByteArray(), QByteArray());
+
+ return shader;
+}
diff --git a/libs/ui/opengl/kis_opengl_shader_loader.h b/libs/ui/opengl/kis_opengl_shader_loader.h
index 0ab064032d..801bc05dca 100644
--- a/libs/ui/opengl/kis_opengl_shader_loader.h
+++ b/libs/ui/opengl/kis_opengl_shader_loader.h
@@ -1,91 +1,92 @@
/*
* Copyright (C) Julian Thijssen <julianthijssen@gmail.com>, (C) 2016
*
* 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 "canvas/kis_display_filter.h"
#include <QOpenGLShaderProgram>
#include <QByteArray>
#include <QString>
#include <unordered_map>
#include <string>
#include <stdexcept>
#include <map>
/**
* An enum for storing all uniform names used in shaders
*/
enum Uniform { ModelViewProjection, TextureMatrix, ViewportScale,
TexelSize, Texture0, Texture1, FixedLodLevel, FragmentColor };
/**
* A wrapper class over Qt's QOpenGLShaderProgram to
* provide access to uniform locations without
* having to store them as constants next to the shader.
*/
class KisShaderProgram : public QOpenGLShaderProgram {
public:
/**
* Stores the mapping of uniform enums to actual shader uniform names.
* The actual shader names are necessary for calls to uniformLocation.
*/
static std::map<Uniform, const char *> names;
/**
* Stores uniform location in cache if it is called for the first time
* and retrieves the location from the map on subsequent calls.
*/
int location(Uniform uniform) {
std::map<Uniform, int>::const_iterator it = locationMap.find(uniform);
if (it != locationMap.end()) {
return it->second;
} else {
int location = uniformLocation(names[uniform]);
locationMap[uniform] = location;
return location;
}
}
private:
std::map<Uniform, int> locationMap;
};
/**
* A wrapper class over C++ Runtime Error, specifically to record
* failures in shader compilation. Only thrown in KisOpenGLShaderLoader.
*/
class ShaderLoaderException : public std::runtime_error {
public:
ShaderLoaderException(QString error) : std::runtime_error(error.toStdString()) { }
};
/**
* A utility class for loading various shaders we use in Krita. It provides
* specific methods for shaders that pick the correct vertex and fragment files
* depending on the availability of OpenGL3. Additionally, it provides a generic
* shader loading method to prevent duplication.
*/
class KisOpenGLShaderLoader {
public:
KisShaderProgram *loadDisplayShader(QSharedPointer<KisDisplayFilter> displayFilter, bool useHiQualityFiltering);
KisShaderProgram *loadCheckerShader();
KisShaderProgram *loadSolidColorShader();
+ KisShaderProgram *loadOverlayInvertedShader();
private:
KisShaderProgram *loadShader(QString vertPath, QString fragPath, QByteArray vertHeader, QByteArray fragHeader);
};
diff --git a/libs/ui/tests/kis_shape_selection_test.cpp b/libs/ui/tests/kis_shape_selection_test.cpp
index d49cffac52..9e45c2dd93 100644
--- a/libs/ui/tests/kis_shape_selection_test.cpp
+++ b/libs/ui/tests/kis_shape_selection_test.cpp
@@ -1,192 +1,341 @@
/*
* Copyright (c) 2008 Sven Langkamp <sven.langkamp@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_shape_selection_test.h"
#include <QTest>
#include <kis_debug.h>
#include <QRect>
#include <KoColorSpace.h>
#include <KoColorSpaceRegistry.h>
#include <KoPathShape.h>
#include "kis_selection.h"
#include "kis_pixel_selection.h"
#include "flake/kis_shape_selection.h"
#include "kis_image.h"
#include "testutil.h"
#include "kistest.h"
#include <KisPart.h>
#include <KisDocument.h>
#include "kis_transaction.h"
void KisShapeSelectionTest::testAddChild()
{
const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument());
QColor qc(Qt::white);
qc.setAlpha(0);
KoColor bgColor(qc, cs);
doc->newImage("test", 300, 300, cs, bgColor, KisConfig::CANVAS_COLOR, 1, "test", 100);
KisImageSP image = doc->image();
KisSelectionSP selection = new KisSelection();
- QVERIFY(selection->hasPixelSelection() == false);
- QVERIFY(selection->hasShapeSelection() == false);
+ QVERIFY(!selection->hasNonEmptyPixelSelection());
+ QVERIFY(!selection->hasNonEmptyShapeSelection());
KisPixelSelectionSP pixelSelection = selection->pixelSelection();
pixelSelection->select(QRect(0, 0, 100, 100));
QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 25, 25), MAX_SELECTED);
QCOMPARE(selection->selectedExactRect(), QRect(0, 0, 100, 100));
QRectF rect(50, 50, 100, 100);
QTransform matrix;
matrix.scale(1 / image->xRes(), 1 / image->yRes());
rect = matrix.mapRect(rect);
KoPathShape* shape = new KoPathShape();
shape->setShapeId(KoPathShapeId);
shape->moveTo(rect.topLeft());
shape->lineTo(rect.topRight());
shape->lineTo(rect.bottomRight());
shape->lineTo(rect.bottomLeft());
shape->close();
KisShapeSelection * shapeSelection = new KisShapeSelection(doc->shapeController(), image, selection);
- selection->setShapeSelection(shapeSelection);
+ selection->convertToVectorSelectionNoUndo(shapeSelection);
shapeSelection->addShape(shape);
- QVERIFY(selection->hasShapeSelection());
+ QVERIFY(selection->hasNonEmptyShapeSelection());
selection->updateProjection();
image->waitForDone();
QCOMPARE(selection->selectedExactRect(), QRect(50, 50, 100, 100));
}
KoPathShape *createRectangularShape(const QRectF &rect)
{
KoPathShape* shape = new KoPathShape();
shape->setShapeId(KoPathShapeId);
shape->moveTo(rect.topLeft());
shape->lineTo(rect.topRight());
shape->lineTo(rect.bottomRight());
shape->lineTo(rect.bottomLeft());
shape->close();
return shape;
}
void KisShapeSelectionTest::testUndoFlattening()
{
const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument());
KoColor bgColor(QColor(255, 255, 255, 0), cs);
doc->newImage("test", 300, 300, cs, bgColor, KisConfig::CANVAS_COLOR, 1, "test", 100);
KisImageSP image = doc->image();
QCOMPARE(image->locked(), false);
KisSelectionSP selection = new KisSelection();
- QCOMPARE(selection->hasPixelSelection(), false);
- QCOMPARE(selection->hasShapeSelection(), false);
+ QCOMPARE(selection->hasNonEmptyPixelSelection(), false);
+ QCOMPARE(selection->hasNonEmptyShapeSelection(), false);
selection->setParentNode(image->root());
KisPixelSelectionSP pixelSelection = selection->pixelSelection();
pixelSelection->select(QRect(0, 0, 100, 100));
QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 25, 25), MAX_SELECTED);
QCOMPARE(selection->selectedExactRect(), QRect(0, 0, 100, 100));
QTransform matrix;
matrix.scale(1 / image->xRes(), 1 / image->yRes());
const QRectF srcRect1(50, 50, 100, 100);
const QRectF rect1 = matrix.mapRect(srcRect1);
- KisShapeSelection * shapeSelection = new KisShapeSelection(doc->shapeController(), image, selection);
- selection->setShapeSelection(shapeSelection);
+ KisShapeSelection * shapeSelection1 = new KisShapeSelection(doc->shapeController(), image, selection);
+ selection->convertToVectorSelectionNoUndo(shapeSelection1);
KoPathShape *shape1 = createRectangularShape(rect1);
- shapeSelection->addShape(shape1);
+ shapeSelection1->addShape(shape1);
- QVERIFY(selection->hasShapeSelection());
+ QVERIFY(selection->hasNonEmptyShapeSelection());
selection->pixelSelection()->clear();
QCOMPARE(selection->selectedExactRect(), QRect());
selection->updateProjection();
image->waitForDone();
QCOMPARE(selection->selectedExactRect(), srcRect1.toRect());
QCOMPARE(selection->outlineCacheValid(), true);
QCOMPARE(selection->outlineCache().boundingRect(), srcRect1);
- QCOMPARE(selection->hasShapeSelection(), true);
+ QCOMPARE(selection->hasNonEmptyShapeSelection(), true);
- KisTransaction t1(selection->pixelSelection());
+ KisSelectionTransaction t1(selection->pixelSelection());
selection->pixelSelection()->clear();
KUndo2Command *cmd1 = t1.endAndTake();
+ cmd1->redo(); // first redo
QTest::qWait(400);
image->waitForDone();
QCOMPARE(selection->selectedExactRect(), QRect());
QCOMPARE(selection->outlineCacheValid(), true);
QCOMPARE(selection->outlineCache().boundingRect(), QRectF());
- QCOMPARE(selection->hasShapeSelection(), false);
+ QCOMPARE(selection->hasNonEmptyShapeSelection(), false);
const QRectF srcRect2(10, 10, 20, 20);
const QRectF rect2 = matrix.mapRect(srcRect2);
KoPathShape *shape2 = createRectangularShape(rect2);
- shapeSelection->addShape(shape2);
+
+ KisShapeSelection * shapeSelection2 = new KisShapeSelection(doc->shapeController(), image, selection);
+ KUndo2Command *cmd2 = selection->convertToVectorSelection(shapeSelection2);
+ cmd2->redo(); // first redo
+
+ shapeSelection2->addShape(shape2);
QTest::qWait(400);
image->waitForDone();
QCOMPARE(selection->selectedExactRect(), srcRect2.toRect());
QCOMPARE(selection->outlineCacheValid(), true);
QCOMPARE(selection->outlineCache().boundingRect(), srcRect2);
- QCOMPARE(selection->hasShapeSelection(), true);
+ QCOMPARE(selection->hasNonEmptyShapeSelection(), true);
- shapeSelection->removeShape(shape2);
+ shapeSelection1->removeShape(shape2);
QTest::qWait(400);
image->waitForDone();
QCOMPARE(selection->selectedExactRect(), QRect());
QCOMPARE(selection->outlineCacheValid(), true);
QCOMPARE(selection->outlineCache().boundingRect(), QRectF());
- QCOMPARE(selection->hasShapeSelection(), false);
+ QCOMPARE(selection->hasNonEmptyShapeSelection(), false);
+ cmd2->undo();
cmd1->undo();
QTest::qWait(400);
image->waitForDone();
QCOMPARE(selection->selectedExactRect(), srcRect1.toRect());
QCOMPARE(selection->outlineCacheValid(), true);
QCOMPARE(selection->outlineCache().boundingRect(), srcRect1);
- QCOMPARE(selection->hasShapeSelection(), true);
+ QCOMPARE(selection->hasNonEmptyShapeSelection(), true);
+
+ delete cmd2;
+ delete cmd1;
+ QTest::qWait(400);
+
+}
+
+#include "kis_paint_device_debug_utils.h"
+
+void KisShapeSelectionTest::testHistoryOnFlattening()
+{
+ const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
+ QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument());
+ KoColor bgColor(QColor(255, 255, 255, 0), cs);
+ doc->newImage("test", 300, 300, cs, bgColor, KisConfig::CANVAS_COLOR, 1, "test", 100);
+ KisImageSP image = doc->image();
+
+ QCOMPARE(image->locked(), false);
+
+ KisSelectionSP selection = new KisSelection();
+ QCOMPARE(selection->hasNonEmptyPixelSelection(), false);
+ QCOMPARE(selection->hasNonEmptyShapeSelection(), false);
+
+ selection->setParentNode(image->root());
+
+ KisPixelSelectionSP pixelSelection = selection->pixelSelection();
+
+ KisSelectionTransaction t0(pixelSelection);
+ pixelSelection->select(QRect(70, 70, 180, 20));
+ QScopedPointer<KUndo2Command> cmd0(t0.endAndTake());
+ cmd0->redo(); // first redo
+
+ KisSelectionTransaction t1(pixelSelection);
+ pixelSelection->clear();
+ pixelSelection->select(QRect(0, 0, 100, 100));
+ QScopedPointer<KUndo2Command> cmd1(t1.endAndTake());
+ cmd1->redo(); // first redo
+
+ // KIS_DUMP_DEVICE_2(pixelSelection, QRect(0,0,300,300), "00_0pixel", "dd");
+ QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 25, 25), MAX_SELECTED);
+ QCOMPARE(selection->selectedExactRect(), QRect(0, 0, 100, 100));
+
+ QTransform matrix;
+ matrix.scale(1 / image->xRes(), 1 / image->yRes());
+ const QRectF srcRect1(50, 50, 100, 100);
+ const QRectF rect1 = matrix.mapRect(srcRect1);
+
+ KisShapeSelection * shapeSelection = new KisShapeSelection(doc->shapeController(), image, selection);
+
+ QScopedPointer<KUndo2Command> cmd2(selection->convertToVectorSelection(shapeSelection));
+ cmd2->redo();
+
+ QVERIFY(!selection->hasNonEmptyShapeSelection());
+ QTest::qWait(200);
+ image->waitForDone();
+
+ // KIS_DUMP_DEVICE_2(pixelSelection, QRect(0,0,300,300), "00_1converted", "dd");
+ QCOMPARE(selection->selectedExactRect(), QRect());
+
+ KoPathShape *shape1 = createRectangularShape(rect1);
+ shapeSelection->addShape(shape1);
+
+ QVERIFY(selection->hasNonEmptyShapeSelection());
+ QTest::qWait(200);
+ image->waitForDone();
+
+ // KIS_DUMP_DEVICE_2(pixelSelection, QRect(0,0,300,300), "01_vector", "dd");
+ QCOMPARE(selection->selectedExactRect(), QRect(50, 50, 100, 100));
+
+ KisSelectionTransaction flatteningTransaction(pixelSelection);
+ pixelSelection->select(QRect(80, 80, 100, 83));
+
+ QScopedPointer<KUndo2Command> cmd3(flatteningTransaction.endAndTake());
+ cmd3->redo(); // first redo!
+
+ // KIS_DUMP_DEVICE_2(pixelSelection, QRect(0,0,300,300), "02_flattened", "dd");
+ QCOMPARE(selection->selectedExactRect(), QRect(50, 50, 130, 113));
+ QVERIFY(!selection->hasNonEmptyShapeSelection());
+
+ cmd3->undo();
+ QTest::qWait(200);
+ image->waitForDone();
+
+ // KIS_DUMP_DEVICE_2(pixelSelection, QRect(0,0,300,300), "03_undo_flattening", "dd");
+ QCOMPARE(selection->selectedExactRect(), QRect(50, 50, 100, 100));
+ QVERIFY(selection->hasNonEmptyShapeSelection());
+
+ cmd3->redo();
+ QTest::qWait(200);
+ image->waitForDone();
+
+ // KIS_DUMP_DEVICE_2(pixelSelection, QRect(0,0,300,300), "04_redo_flattening", "dd");
+ QCOMPARE(selection->selectedExactRect(), QRect(50, 50, 130, 113));
+ QVERIFY(!selection->hasNonEmptyShapeSelection());
+
+ cmd3->undo();
+ QTest::qWait(200);
+ image->waitForDone();
+
+ // KIS_DUMP_DEVICE_2(pixelSelection, QRect(0,0,300,300), "05_2ndundo_flattening", "dd");
+ QCOMPARE(selection->selectedExactRect(), QRect(50, 50, 100, 100));
+ QVERIFY(selection->hasNonEmptyShapeSelection());
+
+ shapeSelection->removeShape(shape1);
+
+ QTest::qWait(200);
+ image->waitForDone();
+
+ // KIS_DUMP_DEVICE_2(pixelSelection, QRect(0,0,300,300), "06_undo_add_shape", "dd");
+ QVERIFY(selection->shapeSelection());
+ QVERIFY(!selection->hasNonEmptyShapeSelection());
+ QCOMPARE(selection->selectedExactRect(), QRect());
+
+ cmd2->undo();
+
+ QTest::qWait(200);
+ image->waitForDone();
+
+ // KIS_DUMP_DEVICE_2(pixelSelection, QRect(0,0,300,300), "07_undo_conversion", "dd");
+ QVERIFY(!selection->shapeSelection());
+ QVERIFY(!selection->hasNonEmptyShapeSelection());
+ QCOMPARE(selection->selectedExactRect(), QRect(0, 0, 100, 100));
+
+ cmd1->undo();
+
+ QTest::qWait(200);
+ image->waitForDone();
+
+ // KIS_DUMP_DEVICE_2(pixelSelection, QRect(0,0,300,300), "08_undo_initial_paint", "dd");
+ QVERIFY(!selection->shapeSelection());
+ QVERIFY(!selection->hasNonEmptyShapeSelection());
+ QCOMPARE(selection->selectedExactRect(), QRect(70, 70, 180, 20));
+
+ cmd0->undo();
+
+ QTest::qWait(200);
+ image->waitForDone();
+
+ // KIS_DUMP_DEVICE_2(pixelSelection, QRect(0,0,300,300), "09_undo_zero_paint", "dd");
+ QVERIFY(!selection->shapeSelection());
+ QVERIFY(!selection->hasNonEmptyShapeSelection());
+ QCOMPARE(selection->selectedExactRect(), QRect());
}
KISTEST_MAIN(KisShapeSelectionTest)
diff --git a/libs/ui/tests/kis_shape_selection_test.h b/libs/ui/tests/kis_shape_selection_test.h
index d7340b9692..57f0d5294b 100644
--- a/libs/ui/tests/kis_shape_selection_test.h
+++ b/libs/ui/tests/kis_shape_selection_test.h
@@ -1,36 +1,38 @@
/*
* Copyright (c) 2008 Sven Langkamp <sven.langkamp@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KIS_SHAPE_SELETION_TEST_H
#define KIS_SHAPE_SELETION_TEST_H
#include <QtTest>
class KisShapeSelectionTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void testAddChild();
void testUndoFlattening();
+
+ void testHistoryOnFlattening();
};
#endif
diff --git a/libs/ui/tests/util.h b/libs/ui/tests/util.h
index f7e8a5b64b..7d01674acd 100644
--- a/libs/ui/tests/util.h
+++ b/libs/ui/tests/util.h
@@ -1,230 +1,230 @@
/*
* Copyright (c) 2008 Boudewijn Rempt boud@valdyas.org
*
* 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 _UTIL_H_
#define _UTIL_H_
#include <QTest>
#include <QBitArray>
#include <KisDocument.h>
#include <KoDocumentInfo.h>
#include <KoColorSpaceRegistry.h>
#include <KoShapeContainer.h>
#include <KoColorSpace.h>
#include <KoPathShape.h>
#include <kis_count_visitor.h>
#include "kis_types.h"
#include "filter/kis_filter_registry.h"
#include "filter/kis_filter_configuration.h"
#include "filter/kis_filter.h"
#include "KisPart.h"
#include "kis_image.h"
#include "kis_pixel_selection.h"
#include "kis_group_layer.h"
#include "kis_paint_layer.h"
#include "kis_clone_layer.h"
#include "kis_adjustment_layer.h"
#include "kis_shape_layer.h"
#include "kis_filter_mask.h"
#include "kis_transparency_mask.h"
#include "kis_selection_mask.h"
#include "kis_selection.h"
#include "kis_fill_painter.h"
#include "kis_shape_selection.h"
#include "kis_default_bounds.h"
#include "kis_transform_mask_params_interface.h"
#include "kis_shape_controller.h"
#include <KisGlobalResourcesInterface.h>
KisSelectionSP createPixelSelection(KisPaintDeviceSP paintDevice)
{
KisSelectionSP pixelSelection = new KisSelection(new KisSelectionDefaultBounds(paintDevice));
KisFillPainter gc(pixelSelection->pixelSelection());
gc.fillRect(10, 10, 200, 200, KoColor(gc.device()->colorSpace()));
gc.fillRect(150, 150, 200, 200, KoColor(QColor(100, 100, 100, 100), gc.device()->colorSpace()));
gc.end();
return pixelSelection;
}
KisSelectionSP createVectorSelection(KisPaintDeviceSP paintDevice, KisImageWSP image, KoShapeControllerBase *shapeController)
{
KisSelectionSP vectorSelection = new KisSelection(new KisSelectionDefaultBounds(paintDevice));
KoPathShape* path = new KoPathShape();
path->setShapeId(KoPathShapeId);
path->moveTo(QPointF(10, 10));
path->lineTo(QPointF(10, 10) + QPointF(100, 0));
path->lineTo(QPointF(100, 100));
path->lineTo(QPointF(10, 10) + QPointF(0, 100));
path->close();
path->normalize();
KisShapeSelection* shapeSelection = new KisShapeSelection(shapeController, image, vectorSelection);
shapeSelection->addShape(path);
- vectorSelection->setShapeSelection(shapeSelection);
+ vectorSelection->convertToVectorSelectionNoUndo(shapeSelection);
return vectorSelection;
}
QTransform createTestingTransform() {
return QTransform(1,2,3,4,5,6,7,8,9);
}
KisDocument* createCompleteDocument(bool shouldMaskToShapeLayer = false)
{
KisImageWSP image = new KisImage(0, 1024, 1024, KoColorSpaceRegistry::instance()->rgb8(), "test for roundtrip");
KisDocument *doc = qobject_cast<KisDocument*>(KisPart::instance()->createDocument());
doc->setCurrentImage(image);
doc->documentInfo()->setAboutInfo("title", image->objectName());
KisGroupLayerSP group1 = new KisGroupLayer(image, "group1", 50);
KisGroupLayerSP group2 = new KisGroupLayer(image, "group2", 100);
KisPaintLayerSP paintLayer1 = new KisPaintLayer(image, "paintlayer1", OPACITY_OPAQUE_U8);
paintLayer1->setUserLocked(true);
QBitArray channelFlags(4);
channelFlags[0] = true;
channelFlags[2] = true;
paintLayer1->setChannelFlags(channelFlags);
{
KisFillPainter gc(paintLayer1->paintDevice());
gc.fillRect(10, 10, 200, 200, KoColor(Qt::red, paintLayer1->paintDevice()->colorSpace()));
gc.end();
}
KisPaintLayerSP paintLayer2 = new KisPaintLayer(image, "paintlayer2", OPACITY_TRANSPARENT_U8, KoColorSpaceRegistry::instance()->lab16());
paintLayer2->setVisible(false);
{
KisFillPainter gc(paintLayer2->paintDevice());
gc.fillRect(0, 0, 900, 1024, KoColor(QColor(10, 20, 30), paintLayer2->paintDevice()->colorSpace()));
gc.end();
}
KisCloneLayerSP cloneLayer1 = new KisCloneLayer(group1, image, "clonelayer1", 150);
cloneLayer1->setX(100);
cloneLayer1->setY(100);
KisSelectionSP pixelSelection = createPixelSelection(paintLayer1->paintDevice());
KisFilterConfigurationSP kfc = KisFilterRegistry::instance()->get("pixelize")->defaultConfiguration(KisGlobalResourcesInterface::instance());
Q_ASSERT(kfc);
KisAdjustmentLayerSP adjustmentLayer1 = new KisAdjustmentLayer(image, "adjustmentLayer1", kfc->cloneWithResourcesSnapshot(), pixelSelection);
KisSelectionSP vectorSelection = createVectorSelection(paintLayer2->paintDevice(), image, doc->shapeController());
KisAdjustmentLayerSP adjustmentLayer2 = new KisAdjustmentLayer(image, "adjustmentLayer2", kfc->cloneWithResourcesSnapshot(), vectorSelection);
image->addNode(paintLayer1);
image->addNode(group1);
image->addNode(paintLayer2, group1);
image->addNode(group2);
image->addNode(cloneLayer1, group2);
image->addNode(adjustmentLayer1, group2);
// KoShapeContainer * parentContainer =
// dynamic_cast<KoShapeContainer*>(doc->shapeForNode(group1));
KoPathShape* path = new KoPathShape();
path->setShapeId(KoPathShapeId);
path->moveTo(QPointF(10, 10));
path->lineTo(QPointF(10, 10) + QPointF(100, 0));
path->lineTo(QPointF(100, 100));
path->lineTo(QPointF(10, 10) + QPointF(0, 100));
path->close();
path->normalize();
KisShapeLayerSP shapeLayer = new KisShapeLayer(doc->shapeController(), image, "shapeLayer1", 75);
shapeLayer->addShape(path);
image->addNode(shapeLayer, group1);
image->addNode(adjustmentLayer2, group1);
KisFilterMaskSP filterMask1 = new KisFilterMask();
filterMask1->setName("filterMask1");
kfc = KisFilterRegistry::instance()->get("pixelize")->defaultConfiguration(KisGlobalResourcesInterface::instance());
filterMask1->setFilter(kfc->cloneWithResourcesSnapshot());
kfc = 0; // kfc cannot be shared!
filterMask1->setSelection(createPixelSelection(paintLayer1->paintDevice()));
image->addNode(filterMask1, paintLayer1);
KisFilterMaskSP filterMask2 = new KisFilterMask();
filterMask2->setName("filterMask2");
kfc = KisFilterRegistry::instance()->get("pixelize")->defaultConfiguration(KisGlobalResourcesInterface::instance());
filterMask2->setFilter(kfc->cloneWithResourcesSnapshot());
kfc = 0; // kfc cannot be shared!
filterMask2->setSelection(createVectorSelection(paintLayer2->paintDevice(), image, doc->shapeController()));
image->addNode(filterMask2, paintLayer2);
KisTransparencyMaskSP transparencyMask1 = new KisTransparencyMask();
transparencyMask1->setName("transparencyMask1");
transparencyMask1->setSelection(createPixelSelection(paintLayer1->paintDevice()));
image->addNode(transparencyMask1, group1);
KisTransparencyMaskSP transparencyMask2 = new KisTransparencyMask();
transparencyMask2->setName("transparencyMask2");
transparencyMask2->setSelection(createPixelSelection(paintLayer1->paintDevice()));
image->addNode(transparencyMask2, group2);
KisSelectionMaskSP selectionMask1 = new KisSelectionMask(image);
image->addNode(selectionMask1, paintLayer1);
selectionMask1->setName("selectionMask1");
selectionMask1->setSelection(createPixelSelection(paintLayer1->paintDevice()));
KisSelectionMaskSP selectionMask2 = new KisSelectionMask(image);
selectionMask2->setName("selectionMask2");
selectionMask2->setSelection(createPixelSelection(paintLayer2->paintDevice()));
image->addNode(selectionMask2, paintLayer2);
KisTransformMaskSP transformMask = new KisTransformMask();
transformMask->setName("testTransformMask");
transformMask->setTransformParams(KisTransformMaskParamsInterfaceSP(
new KisDumbTransformMaskParams(createTestingTransform())));
image->addNode(transformMask, paintLayer2);
if (shouldMaskToShapeLayer) {
// add all-visible transparency mask to crash a shape layer
KisTransparencyMaskSP transparencyMask3 = new KisTransparencyMask();
transparencyMask3->setName("crashy-transparency-mask");
transparencyMask3->initSelection(shapeLayer);
image->addNode(transparencyMask3, shapeLayer);
}
return doc;
}
KisDocument *createEmptyDocument()
{
KisImageWSP image = new KisImage(0, 1024, 1024, KoColorSpaceRegistry::instance()->rgb8(), "test for roundtrip");
KisDocument *doc = qobject_cast<KisDocument*>(KisPart::instance()->createDocument());
doc->setCurrentImage(image);
doc->documentInfo()->setAboutInfo("title", image->objectName());
return doc;
}
#endif
diff --git a/libs/ui/tool/strokes/KisNodeSelectionRecipe.cpp b/libs/ui/tool/strokes/KisNodeSelectionRecipe.cpp
new file mode 100644
index 0000000000..1eb2045e81
--- /dev/null
+++ b/libs/ui/tool/strokes/KisNodeSelectionRecipe.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2020 Dmitry Kazakov <dimula73@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "KisNodeSelectionRecipe.h"
+
+#include "kis_layer_utils.h"
+#include "kis_tool_utils.h"
+#include "kis_lod_transform.h"
+#include "kis_node.h"
+
+KisNodeSelectionRecipe::KisNodeSelectionRecipe(KisNodeList _selectedNodes)
+ : selectedNodes(_selectedNodes),
+ mode(SelectedLayer)
+{
+}
+
+KisNodeSelectionRecipe::KisNodeSelectionRecipe(KisNodeList _selectedNodes, KisNodeSelectionRecipe::SelectionMode _mode, QPoint _pickPoint)
+ : selectedNodes(_selectedNodes),
+ mode(_mode),
+ pickPoint(_pickPoint)
+{
+}
+
+KisNodeSelectionRecipe::KisNodeSelectionRecipe(const KisNodeSelectionRecipe &rhs, int levelOfDetail)
+ : KisNodeSelectionRecipe(rhs)
+{
+ KisLodTransform t(levelOfDetail);
+ pickPoint = t.map(rhs.pickPoint);
+}
+
+KisNodeList KisNodeSelectionRecipe::selectNodesToProcess() const
+{
+ if (selectedNodes.isEmpty() || mode == SelectedLayer) {
+ return selectedNodes;
+ }
+
+ KisNodeList result;
+
+ const bool wholeGroup = mode == Group;
+ KisNodeSP node = KisToolUtils::findNode(KisLayerUtils::findRoot(selectedNodes.first()), pickPoint, wholeGroup);
+ if (node) {
+ result = {node};
+ }
+
+ return result;
+}
diff --git a/libs/ui/tool/strokes/KisNodeSelectionRecipe.h b/libs/ui/tool/strokes/KisNodeSelectionRecipe.h
new file mode 100644
index 0000000000..ee52352bc9
--- /dev/null
+++ b/libs/ui/tool/strokes/KisNodeSelectionRecipe.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2020 Dmitry Kazakov <dimula73@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KISNODESELECTIONRECIPE_H
+#define KISNODESELECTIONRECIPE_H
+
+#include "kis_types.h"
+#include "kritaui_export.h"
+
+
+class KRITAUI_EXPORT KisNodeSelectionRecipe
+{
+public:
+ enum SelectionMode {
+ SelectedLayer,
+ FirstLayer,
+ Group
+ };
+
+ KisNodeSelectionRecipe(KisNodeList _selectedNodes);
+ KisNodeSelectionRecipe(KisNodeList _selectedNodes, SelectionMode _mode, QPoint _pickPoint);
+ KisNodeSelectionRecipe(const KisNodeSelectionRecipe &rhs) = default;
+ KisNodeSelectionRecipe(const KisNodeSelectionRecipe &rhs, int levelOfDetail);
+
+ KisNodeList selectNodesToProcess() const;
+
+ KisNodeList selectedNodes;
+ SelectionMode mode;
+ QPoint pickPoint;
+};
+
+#endif // KISNODESELECTIONRECIPE_H
diff --git a/libs/ui/tool/strokes/move_stroke_strategy.cpp b/libs/ui/tool/strokes/move_stroke_strategy.cpp
index 376e88ded8..0f296fe13d 100644
--- a/libs/ui/tool/strokes/move_stroke_strategy.cpp
+++ b/libs/ui/tool/strokes/move_stroke_strategy.cpp
@@ -1,302 +1,359 @@
/*
* Copyright (c) 2011 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "move_stroke_strategy.h"
#include <klocalizedstring.h>
#include "kis_image_interfaces.h"
#include "kis_node.h"
#include "commands_new/kis_update_command.h"
#include "commands_new/kis_node_move_command2.h"
#include "kis_layer_utils.h"
#include "krita_utils.h"
#include "KisRunnableStrokeJobData.h"
#include "KisRunnableStrokeJobUtils.h"
#include "KisRunnableStrokeJobsInterface.h"
-MoveStrokeStrategy::MoveStrokeStrategy(KisNodeList nodes,
+MoveStrokeStrategy::MoveStrokeStrategy(KisNodeSelectionRecipe nodeSelection,
KisUpdatesFacade *updatesFacade,
KisStrokeUndoFacade *undoFacade)
: KisStrokeStrategyUndoCommandBased(kundo2_i18n("Move"), false, undoFacade),
- m_nodes(),
+ m_requestedNodeSelection(nodeSelection),
m_updatesFacade(updatesFacade),
m_updatesEnabled(true)
{
- m_nodes = KisLayerUtils::sortAndFilterMergableInternalNodes(nodes, true);
-
- KritaUtils::filterContainer<KisNodeList>(m_nodes,
- [this](KisNodeSP node) {
- return
- !KisLayerUtils::checkIsCloneOf(node, m_nodes) &&
- node->isEditable(false);
- });
-
- Q_FOREACH(KisNodeSP subtree, m_nodes) {
- KisLayerUtils::recursiveApplyNodes(
- subtree,
- [this](KisNodeSP node) {
- if (KisLayerUtils::checkIsCloneOf(node, m_nodes) ||
- !node->isEditable(false)) {
-
- m_blacklistedNodes.insert(node);
- }
- });
- }
-
setSupportsWrapAroundMode(true);
enableJob(KisSimpleStrokeStrategy::JOB_INIT, true, KisStrokeJobData::BARRIER);
}
-MoveStrokeStrategy::MoveStrokeStrategy(const MoveStrokeStrategy &rhs)
+MoveStrokeStrategy::MoveStrokeStrategy(KisNodeList nodes, KisUpdatesFacade *updatesFacade, KisStrokeUndoFacade *undoFacade)
+ : MoveStrokeStrategy(KisNodeSelectionRecipe(nodes), updatesFacade, undoFacade)
+{
+}
+
+MoveStrokeStrategy::MoveStrokeStrategy(const MoveStrokeStrategy &rhs, int lod)
: QObject(),
KisStrokeStrategyUndoCommandBased(rhs),
+ m_requestedNodeSelection(rhs.m_requestedNodeSelection, lod),
m_nodes(rhs.m_nodes),
m_blacklistedNodes(rhs.m_blacklistedNodes),
m_updatesFacade(rhs.m_updatesFacade),
m_finalOffset(rhs.m_finalOffset),
m_dirtyRect(rhs.m_dirtyRect),
m_dirtyRects(rhs.m_dirtyRects),
m_updatesEnabled(rhs.m_updatesEnabled)
{
}
-
void MoveStrokeStrategy::saveInitialNodeOffsets(KisNodeSP node)
{
if (!m_blacklistedNodes.contains(node)) {
m_initialNodeOffsets.insert(node, QPoint(node->x(), node->y()));
}
KisNodeSP child = node->firstChild();
while(child) {
saveInitialNodeOffsets(child);
child = child->nextSibling();
}
}
void MoveStrokeStrategy::initStrokeCallback()
{
+ /**
+ * Our LodN moght have already prepared the list of nodes for us,
+ * so we should reuse it to avoid different nodes to be moved in
+ * LodN and Lod0 modes.
+ */
+ if (m_updatesEnabled) {
+ m_nodes = m_requestedNodeSelection.selectNodesToProcess();
+
+ if (!m_nodes.isEmpty()) {
+ m_nodes = KisLayerUtils::sortAndFilterMergableInternalNodes(m_nodes, true);
+ }
+
+ KritaUtils::filterContainer<KisNodeList>(m_nodes,
+ [this](KisNodeSP node) {
+ // TODO: check isolation
+ return
+ !KisLayerUtils::checkIsCloneOf(node, m_nodes) &&
+ node->isEditable(true);
+ });
+ Q_FOREACH(KisNodeSP subtree, m_nodes) {
+ KisLayerUtils::recursiveApplyNodes(
+ subtree,
+ [this](KisNodeSP node) {
+ if (KisLayerUtils::checkIsCloneOf(node, m_nodes) ||
+ !node->isEditable(false)) {
+
+ m_blacklistedNodes.insert(node);
+ }
+ });
+ }
+
+ if (m_sharedNodes) {
+ *m_sharedNodes = m_nodes;
+ }
+ } else {
+ KIS_SAFE_ASSERT_RECOVER_RETURN(m_sharedNodes);
+ m_nodes = *m_sharedNodes;
+ }
+
+ if (m_nodes.isEmpty()) {
+ emit sigStrokeStartedEmpty();
+ return;
+ }
+
QVector<KisRunnableStrokeJobData*> jobs;
KritaUtils::addJobBarrier(jobs, [this]() {
Q_FOREACH(KisNodeSP node, m_nodes) {
KisLayerUtils::forceAllHiddenOriginalsUpdate(node);
}
});
KritaUtils::addJobBarrier(jobs, [this]() {
Q_FOREACH(KisNodeSP node, m_nodes) {
KisLayerUtils::forceAllDelayedNodesUpdate(node);
}
});
KritaUtils::addJobBarrier(jobs, [this]() {
QRect handlesRect;
Q_FOREACH(KisNodeSP node, m_nodes) {
saveInitialNodeOffsets(node);
handlesRect |= KisLayerUtils::recursiveTightNodeVisibleBounds(node);
}
KisStrokeStrategyUndoCommandBased::initStrokeCallback();
- emit this->sigHandlesRectCalculated(handlesRect);
+ if (m_updatesEnabled) {
+ KisLodTransform t(m_nodes.first()->projection());
+ handlesRect = t.mapInverted(handlesRect);
+
+ emit this->sigHandlesRectCalculated(handlesRect);
+ }
+
m_updateTimer.start();
});
runnableJobsInterface()->addRunnableJobs(jobs);
}
void MoveStrokeStrategy::finishStrokeCallback()
{
Q_FOREACH (KisNodeSP node, m_nodes) {
KUndo2Command *updateCommand =
new KisUpdateCommand(node, m_dirtyRects[node], m_updatesFacade, true);
addMoveCommands(node, updateCommand);
notifyCommandDone(KUndo2CommandSP(updateCommand),
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::EXCLUSIVE);
}
if (!m_updatesEnabled) {
Q_FOREACH (KisNodeSP node, m_nodes) {
m_updatesFacade->refreshGraphAsync(node, m_dirtyRects[node]);
}
}
KisStrokeStrategyUndoCommandBased::finishStrokeCallback();
}
void MoveStrokeStrategy::cancelStrokeCallback()
{
if (!m_nodes.isEmpty()) {
m_finalOffset = QPoint();
m_hasPostponedJob = true;
tryPostUpdateJob(true);
}
KisStrokeStrategyUndoCommandBased::cancelStrokeCallback();
}
void MoveStrokeStrategy::tryPostUpdateJob(bool forceUpdate)
{
if (!m_hasPostponedJob) return;
if (forceUpdate ||
(m_updateTimer.elapsed() > m_updateInterval &&
!m_updatesFacade->hasUpdatesRunning())) {
addMutatedJob(new BarrierUpdateData(forceUpdate));
}
}
void MoveStrokeStrategy::doStrokeCallback(KisStrokeJobData *data)
{
+ if (PickLayerData *pickData = dynamic_cast<PickLayerData*>(data)) {
+ KisNodeSelectionRecipe clone = m_requestedNodeSelection;
+ clone.pickPoint = pickData->pos;
+ emit sigLayersPicked(clone.selectNodesToProcess());
+ return;
+ }
+
Data *d = dynamic_cast<Data*>(data);
if (!m_nodes.isEmpty() && d) {
/**
* NOTE: we do not care about threading here, because
* all our jobs are declared sequential
*/
m_finalOffset = d->offset;
m_hasPostponedJob = true;
tryPostUpdateJob(false);
} else if (BarrierUpdateData *barrierData =
dynamic_cast<BarrierUpdateData*>(data)) {
doCanvasUpdate(barrierData->forceUpdate);
} else if (KisAsyncronousStrokeUpdateHelper::UpdateData *updateData =
dynamic_cast<KisAsyncronousStrokeUpdateHelper::UpdateData*>(data)) {
tryPostUpdateJob(updateData->forceUpdate);
} else {
KisStrokeStrategyUndoCommandBased::doStrokeCallback(data);
}
}
#include "kis_selection_mask.h"
#include "kis_selection.h"
void MoveStrokeStrategy::doCanvasUpdate(bool forceUpdate)
{
if (!forceUpdate &&
(m_updateTimer.elapsed() < m_updateInterval ||
m_updatesFacade->hasUpdatesRunning())) {
return;
}
if (!m_hasPostponedJob) return;
Q_FOREACH (KisNodeSP node, m_nodes) {
QRect dirtyRect = moveNode(node, m_finalOffset);
m_dirtyRects[node] |= dirtyRect;
if (m_updatesEnabled) {
m_updatesFacade->refreshGraphAsync(node, dirtyRect);
}
if (KisSelectionMask *mask = dynamic_cast<KisSelectionMask*>(node.data())) {
Q_UNUSED(mask);
//mask->selection()->notifySelectionChanged();
}
}
m_hasPostponedJob = false;
m_updateTimer.restart();
}
QRect MoveStrokeStrategy::moveNode(KisNodeSP node, QPoint offset)
{
QRect dirtyRect;
if (!m_blacklistedNodes.contains(node)) {
dirtyRect = node->extent();
QPoint newOffset = m_initialNodeOffsets[node] + offset;
/**
* Some layers, e.g. clones need an update to change extent(), so
* calculate the dirty rect manually
*/
QPoint currentOffset(node->x(), node->y());
dirtyRect |= dirtyRect.translated(newOffset - currentOffset);
node->setX(newOffset.x());
node->setY(newOffset.y());
KisNodeMoveCommand2::tryNotifySelection(node);
}
KisNodeSP child = node->firstChild();
while(child) {
dirtyRect |= moveNode(child, offset);
child = child->nextSibling();
}
return dirtyRect;
}
void MoveStrokeStrategy::addMoveCommands(KisNodeSP node, KUndo2Command *parent)
{
if (!m_blacklistedNodes.contains(node)) {
QPoint nodeOffset(node->x(), node->y());
new KisNodeMoveCommand2(node, nodeOffset - m_finalOffset, nodeOffset, parent);
}
KisNodeSP child = node->firstChild();
while(child) {
addMoveCommands(child, parent);
child = child->nextSibling();
}
}
void MoveStrokeStrategy::setUpdatesEnabled(bool value)
{
m_updatesEnabled = value;
}
bool checkSupportsLodMoves(KisNodeSP subtree)
{
return
!KisLayerUtils::recursiveFindNode(
subtree,
[](KisNodeSP node) -> bool {
return !node->supportsLodMoves();
});
}
KisStrokeStrategy* MoveStrokeStrategy::createLodClone(int levelOfDetail)
{
- Q_UNUSED(levelOfDetail);
+ KisNodeList nodesToCheck;
- Q_FOREACH (KisNodeSP node, m_nodes) {
+ if (m_requestedNodeSelection.mode == KisNodeSelectionRecipe::SelectedLayer) {
+ nodesToCheck = m_requestedNodeSelection.selectedNodes;
+ } else if (!m_requestedNodeSelection.selectedNodes.isEmpty()){
+ /**
+ * Since this function is executed in the GUI thread, we cannot properly
+ * pick the layers. Therefore we should use pessimistic approach and
+ * check if there are non-lodn-capable nodes in the entire image.
+ */
+ nodesToCheck.append(KisLayerUtils::findRoot(m_requestedNodeSelection.selectedNodes.first()));
+ }
+
+ Q_FOREACH (KisNodeSP node, nodesToCheck) {
if (!checkSupportsLodMoves(node)) return 0;
}
- MoveStrokeStrategy *clone = new MoveStrokeStrategy(*this);
+ MoveStrokeStrategy *clone = new MoveStrokeStrategy(*this, levelOfDetail);
+ connect(clone, SIGNAL(sigHandlesRectCalculated(QRect)), this, SIGNAL(sigHandlesRectCalculated(QRect)));
+ connect(clone, SIGNAL(sigStrokeStartedEmpty()), this, SIGNAL(sigStrokeStartedEmpty()));
+ connect(clone, SIGNAL(sigLayersPicked(const KisNodeList&)), this, SIGNAL(sigLayersPicked(const KisNodeList&)));
this->setUpdatesEnabled(false);
+ m_sharedNodes.reset(new KisNodeList());
+ clone->m_sharedNodes = m_sharedNodes;
return clone;
}
diff --git a/libs/ui/tool/strokes/move_stroke_strategy.h b/libs/ui/tool/strokes/move_stroke_strategy.h
index 8a82aa0432..4d89c30c0c 100644
--- a/libs/ui/tool/strokes/move_stroke_strategy.h
+++ b/libs/ui/tool/strokes/move_stroke_strategy.h
@@ -1,111 +1,144 @@
/*
* Copyright (c) 2011 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MOVE_STROKE_STRATEGY_H
#define __MOVE_STROKE_STRATEGY_H
#include <QHash>
#include <QObject>
#include "kritaui_export.h"
#include "kis_stroke_strategy_undo_command_based.h"
#include "kis_types.h"
#include "kis_lod_transform.h"
#include <QElapsedTimer>
#include "KisAsyncronousStrokeUpdateHelper.h"
-
+#include "KisNodeSelectionRecipe.h"
class KisUpdatesFacade;
class KisPostExecutionUndoAdapter;
class KRITAUI_EXPORT MoveStrokeStrategy : public QObject, public KisStrokeStrategyUndoCommandBased
{
Q_OBJECT
public:
class Data : public KisStrokeJobData {
public:
Data(QPoint _offset)
: KisStrokeJobData(SEQUENTIAL, NORMAL),
offset(_offset)
{
}
KisStrokeJobData* createLodClone(int levelOfDetail) override {
return new Data(*this, levelOfDetail);
}
QPoint offset;
private:
Data(const Data &rhs, int levelOfDetail)
: KisStrokeJobData(rhs)
{
KisLodTransform t(levelOfDetail);
offset = t.map(rhs.offset);
}
};
+ class PickLayerData : public KisStrokeJobData {
+ public:
+ PickLayerData(QPoint _pos)
+ : KisStrokeJobData(SEQUENTIAL, NORMAL),
+ pos(_pos)
+ {
+ }
+
+ KisStrokeJobData* createLodClone(int levelOfDetail) override {
+ return new PickLayerData(*this, levelOfDetail);
+ }
+
+ QPoint pos;
+
+ private:
+ PickLayerData(const PickLayerData &rhs, int levelOfDetail)
+ : KisStrokeJobData(rhs)
+ {
+ KisLodTransform t(levelOfDetail);
+ pos = t.map(rhs.pos);
+ }
+ };
+
+
struct BarrierUpdateData : public KisAsyncronousStrokeUpdateHelper::UpdateData
{
BarrierUpdateData(bool forceUpdate)
: KisAsyncronousStrokeUpdateHelper::UpdateData(forceUpdate, BARRIER, EXCLUSIVE)
{}
};
public:
- MoveStrokeStrategy(KisNodeList nodes, KisUpdatesFacade *updatesFacade,
+ MoveStrokeStrategy(KisNodeSelectionRecipe nodeSelection,
+ KisUpdatesFacade *updatesFacade,
+ KisStrokeUndoFacade *undoFacade);
+
+ MoveStrokeStrategy(KisNodeList nodes,
+ KisUpdatesFacade *updatesFacade,
KisStrokeUndoFacade *undoFacade);
void initStrokeCallback() override;
void finishStrokeCallback() override;
void cancelStrokeCallback() override;
void doStrokeCallback(KisStrokeJobData *data) override;
KisStrokeStrategy* createLodClone(int levelOfDetail) override;
Q_SIGNALS:
void sigHandlesRectCalculated(const QRect &handlesRect);
+ void sigStrokeStartedEmpty();
+ void sigLayersPicked(const KisNodeList &nodes);
private:
- MoveStrokeStrategy(const MoveStrokeStrategy &rhs);
+ MoveStrokeStrategy(const MoveStrokeStrategy &rhs, int lod);
void setUndoEnabled(bool value);
void setUpdatesEnabled(bool value);
private:
QRect moveNode(KisNodeSP node, QPoint offset);
void addMoveCommands(KisNodeSP node, KUndo2Command *parent);
void saveInitialNodeOffsets(KisNodeSP node);
void doCanvasUpdate(bool forceUpdate = false);
void tryPostUpdateJob(bool forceUpdate);
private:
+ KisNodeSelectionRecipe m_requestedNodeSelection;
KisNodeList m_nodes;
+ QSharedPointer<KisNodeList> m_sharedNodes;
QSet<KisNodeSP> m_blacklistedNodes;
KisUpdatesFacade *m_updatesFacade;
QPoint m_finalOffset;
QRect m_dirtyRect;
QHash<KisNodeSP, QRect> m_dirtyRects;
bool m_updatesEnabled;
QHash<KisNodeSP, QPoint> m_initialNodeOffsets;
QElapsedTimer m_updateTimer;
bool m_hasPostponedJob = false;
const int m_updateInterval = 30;
};
#endif /* __MOVE_STROKE_STRATEGY_H */
diff --git a/libs/ui/widgets/kis_scratch_pad.cpp b/libs/ui/widgets/kis_scratch_pad.cpp
index 7d4f622733..d6258e008b 100644
--- a/libs/ui/widgets/kis_scratch_pad.cpp
+++ b/libs/ui/widgets/kis_scratch_pad.cpp
@@ -1,536 +1,644 @@
/* This file is part of the KDE project
* Copyright 2010 (C) Boudewijn Rempt <boud@valdyas.org>
* Copyright 2011 (C) Dmitry Kazakov <dimula73@gmail.com>
*
* 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 "kis_scratch_pad.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QMutex>
#include <KoColorSpace.h>
#include <KoColorProfile.h>
#include <KoColorSpaceRegistry.h>
#include <KoPointerEvent.h>
#include <resources/KoAbstractGradient.h>
#include <kis_cursor.h>
#include <kis_tool_utils.h>
#include <kis_paint_layer.h>
#include <kis_paint_device.h>
#include <kis_gradient_painter.h>
#include <kis_default_bounds.h>
#include <kis_canvas_resource_provider.h>
#include "kis_config.h"
#include "kis_image.h"
#include "kis_undo_stores.h"
#include "kis_update_scheduler.h"
#include "kis_post_execution_undo_adapter.h"
#include "kis_scratch_pad_event_filter.h"
#include "kis_painting_information_builder.h"
#include "kis_tool_freehand_helper.h"
#include "kis_image_patch.h"
#include "kis_canvas_widget_base.h"
#include "kis_layer_projection_plane.h"
#include "kis_node_graph_listener.h"
#include "kis_transaction.h"
class KisScratchPadNodeListener : public KisNodeGraphListener
{
public:
KisScratchPadNodeListener(KisScratchPad *scratchPad)
: m_scratchPad(scratchPad)
{
}
void requestProjectionUpdate(KisNode *node, const QVector<QRect> &rects, bool resetAnimationCache) override {
KisNodeGraphListener::requestProjectionUpdate(node, rects, resetAnimationCache);
QMutexLocker locker(&m_lock);
Q_FOREACH (const QRect &rc, rects) {
m_scratchPad->imageUpdated(rc);
}
}
private:
KisScratchPad *m_scratchPad;
QMutex m_lock;
};
class KisScratchPadDefaultBounds : public KisDefaultBounds
{
public:
KisScratchPadDefaultBounds(KisScratchPad *scratchPad)
: m_scratchPad(scratchPad)
{
}
~KisScratchPadDefaultBounds() override {}
QRect bounds() const override {
return m_scratchPad->imageBounds();
}
void * sourceCookie() const override {
return m_scratchPad;
}
private:
Q_DISABLE_COPY(KisScratchPadDefaultBounds)
KisScratchPad *m_scratchPad;
};
KisScratchPad::KisScratchPad(QWidget *parent)
: QWidget(parent)
, m_toolMode(HOVERING)
, m_paintLayer(0)
, m_displayProfile(0)
, m_resourceProvider(0)
{
setAutoFillBackground(false);
setMouseTracking(true);
m_cursor = KisCursor::load("tool_freehand_cursor.png", 5, 5);
+ m_colorPickerCursor = KisCursor::load("tool_color_picker_cursor.png", 5, 5);
setCursor(m_cursor);
+
KisConfig cfg(true);
QImage checkImage = KisCanvasWidgetBase::createCheckersImage(cfg.checkSize());
m_checkBrush = QBrush(checkImage);
// We are not supposed to use updates here,
// so just set the listener to null
m_updateScheduler = new KisUpdateScheduler(0);
m_undoStore = new KisSurrogateUndoStore();
m_undoAdapter = new KisPostExecutionUndoAdapter(m_undoStore, m_updateScheduler);
m_nodeListener = new KisScratchPadNodeListener(this);
connect(this, SIGNAL(sigUpdateCanvas(QRect)), SLOT(slotUpdateCanvas(QRect)), Qt::QueuedConnection);
// filter will be deleted by the QObject hierarchy
m_eventFilter = new KisScratchPadEventFilter(this);
m_infoBuilder = new KisPaintingInformationBuilder();
m_scaleBorderWidth = 1;
}
KisScratchPad::~KisScratchPad()
{
delete m_infoBuilder;
delete m_undoAdapter;
delete m_undoStore;
delete m_updateScheduler;
delete m_nodeListener;
}
KisScratchPad::Mode KisScratchPad::modeFromButton(Qt::MouseButton button) const
{
return
button == Qt::NoButton ? HOVERING :
button == Qt::MidButton ? PANNING :
button == Qt::RightButton ? PICKING :
PAINTING;
}
void KisScratchPad::pointerPress(KoPointerEvent *event)
{
- if (m_toolMode != HOVERING) return;
+ if (isModeManuallySet == false) {
- m_toolMode = modeFromButton(event->button());
+ if (m_toolMode != HOVERING) return;
+
+ m_toolMode = modeFromButton(event->button());
- if (m_toolMode == PAINTING) {
- beginStroke(event);
- event->accept();
}
- else if (m_toolMode == PANNING) {
- beginPan(event);
- event->accept();
+
+ // see if we are pressing down with a button
+ if (event->button() == Qt::LeftButton ||
+ event->button() == Qt::MidButton ||
+ event->button() == Qt::RightButton) {
+ isMouseDown = true;
+ } else {
+ isMouseDown = false;
}
- else if (m_toolMode == PICKING) {
- pick(event);
- event->accept();
+
+ // if mouse is down, we are doing one of three things
+ if(isMouseDown) {
+ if (m_toolMode == PAINTING) {
+ beginStroke(event);
+ event->accept();
+ }
+ else if (m_toolMode == PANNING) {
+ beginPan(event);
+ event->accept();
+ }
+ else if (m_toolMode == PICKING) {
+ pick(event);
+ event->accept();
+ }
}
+
}
void KisScratchPad::pointerRelease(KoPointerEvent *event)
{
- if (modeFromButton(event->button()) != m_toolMode) return;
+ isMouseDown = false;
+
+ if (isModeManuallySet == false) {
+ if (modeFromButton(event->button()) != m_toolMode) return;
+
+ if (m_toolMode == PAINTING) {
+ endStroke(event);
+ m_toolMode = HOVERING;
+ event->accept();
+ }
+ else if (m_toolMode == PANNING) {
+ endPan(event);
+ m_toolMode = HOVERING;
+ event->accept();
+ }
+ else if (m_toolMode == PICKING) {
+ event->accept();
+ m_toolMode = HOVERING;
+ }
+
+ } else {
+ if (m_toolMode == PAINTING) {
+ endStroke(event);
+ }
+ else if (m_toolMode == PANNING) {
+ endPan(event);
+ }
- if (m_toolMode == PAINTING) {
- endStroke(event);
- m_toolMode = HOVERING;
- event->accept();
- }
- else if (m_toolMode == PANNING) {
- endPan(event);
- m_toolMode = HOVERING;
- event->accept();
- }
- else if (m_toolMode == PICKING) {
event->accept();
- m_toolMode = HOVERING;
}
+
+
}
void KisScratchPad::pointerMove(KoPointerEvent *event)
{
- m_helper->cursorMoved(documentToWidget().map(event->point));
- if (m_toolMode == PAINTING) {
- doStroke(event);
- event->accept();
- }
- else if (m_toolMode == PANNING) {
- doPan(event);
- event->accept();
+ if(event && event->point.isNull() == false) {
+ m_helper->cursorMoved(documentToWidget().map(event->point));
}
- else if (m_toolMode == PICKING) {
- pick(event);
- event->accept();
+
+
+ if (isMouseDown) {
+ if (m_toolMode == PAINTING) {
+ doStroke(event);
+ event->accept();
+ }
+ else if (m_toolMode == PANNING) {
+ doPan(event);
+ event->accept();
+ }
+ else if (m_toolMode == PICKING) {
+ pick(event);
+ event->accept();
+ }
}
}
void KisScratchPad::beginStroke(KoPointerEvent *event)
{
+
m_helper->initPaint(event,
documentToWidget().map(event->point),
0,
0,
m_updateScheduler,
m_paintLayer,
m_paintLayer->paintDevice()->defaultBounds());
+
+
}
void KisScratchPad::doStroke(KoPointerEvent *event)
{
m_helper->paintEvent(event);
}
void KisScratchPad::endStroke(KoPointerEvent *event)
{
Q_UNUSED(event);
m_helper->endPaint();
}
void KisScratchPad::beginPan(KoPointerEvent *event)
{
setCursor(QCursor(Qt::ClosedHandCursor));
m_panDocPoint = event->point;
}
void KisScratchPad::doPan(KoPointerEvent *event)
{
QPointF docOffset = event->point - m_panDocPoint;
m_translateTransform.translate(-docOffset.x(), -docOffset.y());
updateTransformations();
update();
}
void KisScratchPad::endPan(KoPointerEvent *event)
{
Q_UNUSED(event);
- setCursor(m_cursor);
+
+ // the normal brush editor scratchpad reverts back to paint mode when done
+ if(isModeManuallySet) {
+ setCursor(QCursor(Qt::OpenHandCursor));
+ } else {
+ setCursor(m_cursor);
+ }
+
}
void KisScratchPad::pick(KoPointerEvent *event)
{
KoColor color;
if (KisToolUtils::pickColor(color, m_paintLayer->projection(), event->point.toPoint())) {
emit colorSelected(color);
}
}
void KisScratchPad::setOnScreenResolution(qreal scaleX, qreal scaleY)
{
m_scaleBorderWidth = BORDER_SIZE(qMax(scaleX, scaleY));
m_scaleTransform = QTransform::fromScale(scaleX, scaleY);
updateTransformations();
update();
}
QTransform KisScratchPad::documentToWidget() const
{
return m_translateTransform.inverted() * m_scaleTransform;
}
QTransform KisScratchPad::widgetToDocument() const
{
return m_scaleTransform.inverted() * m_translateTransform;
}
void KisScratchPad::updateTransformations()
{
m_eventFilter->setWidgetToDocumentTransform(widgetToDocument());
}
QRect KisScratchPad::imageBounds() const
{
return widgetToDocument().mapRect(rect());
}
void KisScratchPad::imageUpdated(const QRect &rect)
{
emit sigUpdateCanvas(documentToWidget().mapRect(QRectF(rect)).toAlignedRect());
}
void KisScratchPad::slotUpdateCanvas(const QRect &rect)
{
update(rect);
}
void KisScratchPad::paintEvent ( QPaintEvent * event ) {
if(!m_paintLayer) return;
QRectF imageRect = widgetToDocument().mapRect(QRectF(event->rect()));
QRect alignedImageRect =
imageRect.adjusted(-m_scaleBorderWidth, -m_scaleBorderWidth,
m_scaleBorderWidth, m_scaleBorderWidth).toAlignedRect();
QPointF offset = alignedImageRect.topLeft();
m_paintLayer->projectionPlane()->recalculate(alignedImageRect, m_paintLayer);
KisPaintDeviceSP projection = m_paintLayer->projection();
QImage image = projection->convertToQImage(m_displayProfile,
alignedImageRect.x(),
alignedImageRect.y(),
alignedImageRect.width(),
alignedImageRect.height(),
KoColorConversionTransformation::internalRenderingIntent(),
KoColorConversionTransformation::internalConversionFlags());
QPainter gc(this);
gc.fillRect(event->rect(), m_checkBrush);
gc.setRenderHints(QPainter::SmoothPixmapTransform);
gc.drawImage(QRectF(event->rect()), image, imageRect.translated(-offset));
QBrush brush(Qt::lightGray);
QPen pen(brush, 1, Qt::DotLine);
gc.setPen(pen);
if (m_cutoutOverlay.isValid()) {
gc.drawRect(m_cutoutOverlay);
}
if(!isEnabled()) {
QColor color(Qt::lightGray);
color.setAlphaF(0.5);
QBrush disabledBrush(color);
gc.fillRect(event->rect(), disabledBrush);
}
gc.end();
}
void KisScratchPad::setupScratchPad(KisCanvasResourceProvider* resourceProvider,
const QColor &defaultColor)
{
m_resourceProvider = resourceProvider;
KisConfig cfg(true);
setDisplayProfile(cfg.displayProfile(QApplication::desktop()->screenNumber(this)));
connect(m_resourceProvider, SIGNAL(sigDisplayProfileChanged(const KoColorProfile*)),
SLOT(setDisplayProfile(const KoColorProfile*)));
connect(m_resourceProvider, SIGNAL(sigOnScreenResolutionChanged(qreal,qreal)),
SLOT(setOnScreenResolution(qreal,qreal)));
connect(this, SIGNAL(colorSelected(KoColor)),
m_resourceProvider, SLOT(slotSetFGColor(KoColor)));
m_helper.reset(new KisToolFreehandHelper(m_infoBuilder, m_resourceProvider->resourceManager()));
- m_defaultColor = KoColor(defaultColor, KoColorSpaceRegistry::instance()->rgb8());
+ setFillColor(defaultColor);
KisPaintDeviceSP paintDevice =
new KisPaintDevice(m_defaultColor.colorSpace(), "scratchpad");
m_paintLayer = new KisPaintLayer(0, "ScratchPad", OPACITY_OPAQUE_U8, paintDevice);
m_paintLayer->setGraphListener(m_nodeListener);
m_paintLayer->paintDevice()->setDefaultBounds(new KisScratchPadDefaultBounds(this));
fillDefault();
}
void KisScratchPad::setCutoutOverlayRect(const QRect& rc)
{
m_cutoutOverlay = rc;
}
+void KisScratchPad::setModeManually(bool value)
+{
+ isModeManuallySet = value;
+}
+
+void KisScratchPad::setModeType(QString mode)
+{
+ if (mode.toLower() == "painting") {
+ m_toolMode = PAINTING;
+ setCursor(m_cursor);
+ }
+ else if (mode.toLower() == "panning") {
+ m_toolMode = PANNING;
+ setCursor(Qt::OpenHandCursor);
+ }
+ else if (mode.toLower() == "colorpicking") {
+ m_toolMode = PICKING;
+ setCursor(m_colorPickerCursor);
+ }
+}
+
QImage KisScratchPad::cutoutOverlay() const
{
if(!m_paintLayer) return QImage();
KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice();
QRect rc = widgetToDocument().mapRect(m_cutoutOverlay);
QImage rawImage = paintDevice->convertToQImage(0, rc.x(), rc.y(), rc.width(), rc.height(), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags());
QImage scaledImage = rawImage.scaled(m_cutoutOverlay.size(),
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation);
return scaledImage;
}
void KisScratchPad::setPresetImage(const QImage& image)
{
m_presetImage = image;
}
void KisScratchPad::paintCustomImage(const QImage& loadedImage)
{
// this is 99% copied from the normal paintPresetImage()
// we don't want to save over the preset image, so we don't
// want to store it in the m_presetImage
if(!m_paintLayer) return;
KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice();
QRect overlayRect = widgetToDocument().mapRect(m_cutoutOverlay);
QRect imageRect(QPoint(), overlayRect.size());
QImage scaledImage = loadedImage.scaled(overlayRect.size(),
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation);
KisPaintDeviceSP device = new KisPaintDevice(paintDevice->colorSpace());
device->convertFromQImage(scaledImage, 0);
KisPainter painter(paintDevice);
painter.beginTransaction();
painter.bitBlt(overlayRect.topLeft(), device, imageRect);
painter.deleteTransaction();
update();
}
+void KisScratchPad::loadScratchpadImage(QImage image)
+{
+ if(!m_paintLayer) return;
+
+ m_translateTransform.reset(); // image will be loaded at 0,0, so reset panning location
+ updateTransformations();
+
+ fillDefault(); // wipes out whatever was there before
+
+ QRect imageSize = image.rect();
+ KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice();
+
+ KisPaintDeviceSP device = new KisPaintDevice(paintDevice->colorSpace());
+ device->convertFromQImage(image, 0);
+
+ KisPainter painter(paintDevice);
+ painter.beginTransaction();
+ painter.bitBlt(imageSize.topLeft(), device, imageSize);
+ painter.deleteTransaction();
+ update();
+}
+
+QImage KisScratchPad::copyScratchpadImageData()
+{
+ const QRect paintingBounds = m_paintLayer.data()->exactBounds();
+ QImage imageData = m_paintLayer->paintDevice()->convertToQImage(0, paintingBounds.x(), paintingBounds.y(), paintingBounds.width(), paintingBounds.height(),
+ KoColorConversionTransformation::internalRenderingIntent(),
+ KoColorConversionTransformation::internalConversionFlags());
+ return imageData;
+}
+
void KisScratchPad::paintPresetImage()
{
if(!m_paintLayer) return;
KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice();
QRect overlayRect = widgetToDocument().mapRect(m_cutoutOverlay);
QRect imageRect(QPoint(), overlayRect.size());
QImage scaledImage = m_presetImage.scaled(overlayRect.size(),
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation);
KisPaintDeviceSP device = new KisPaintDevice(paintDevice->colorSpace());
device->convertFromQImage(scaledImage, 0);
KisPainter painter(paintDevice);
painter.beginTransaction();
painter.bitBlt(overlayRect.topLeft(), device, imageRect);
painter.deleteTransaction();
update();
}
void KisScratchPad::setDisplayProfile(const KoColorProfile *colorProfile)
{
if (colorProfile) {
m_displayProfile = colorProfile;
QWidget::update();
}
}
void KisScratchPad::fillDefault()
{
if(!m_paintLayer) return;
KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice();
KisTransaction t(paintDevice);
paintDevice->setDefaultPixel(m_defaultColor);
paintDevice->clear();
t.end();
update();
}
void KisScratchPad::fillTransparent() {
if(!m_paintLayer) return;
KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice();
QColor transQColor(0,0,0,0);
KoColor transparentColor(transQColor, KoColorSpaceRegistry::instance()->rgb8());
transparentColor.setOpacity(0.0);
KisTransaction t(paintDevice);
paintDevice->setDefaultPixel(transparentColor);
paintDevice->clear();
t.end();
update();
}
+void KisScratchPad::setFillColor(QColor newColor)
+{
+ m_defaultColor = KoColor(newColor, KoColorSpaceRegistry::instance()->rgb8());
+}
+
void KisScratchPad::fillGradient()
{
if(!m_paintLayer) return;
KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice();
KoAbstractGradientSP gradient = m_resourceProvider->currentGradient();
QRect gradientRect = widgetToDocument().mapRect(rect());
KisTransaction t(paintDevice);
paintDevice->clear();
KisGradientPainter painter(paintDevice);
painter.setGradient(gradient);
painter.setGradientShape(KisGradientPainter::GradientShapeLinear);
painter.paintGradient(gradientRect.topLeft(),
gradientRect.bottomRight(),
KisGradientPainter::GradientRepeatNone,
0.2, false,
gradientRect.left(), gradientRect.top(),
gradientRect.width(), gradientRect.height());
t.end();
update();
}
void KisScratchPad::fillBackground()
{
if(!m_paintLayer) return;
KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice();
KisTransaction t(paintDevice);
paintDevice->setDefaultPixel(m_resourceProvider->bgColor());
paintDevice->clear();
t.end();
update();
}
void KisScratchPad::fillLayer()
{
if(!m_paintLayer) return;
KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice();
QRect sourceRect(0, 0, paintDevice->exactBounds().width(), paintDevice->exactBounds().height());
KisPainter painter(paintDevice);
painter.beginTransaction();
painter.bitBlt(QPoint(0, 0), m_resourceProvider->currentImage()->projection(), sourceRect);
painter.deleteTransaction();
update();
}
diff --git a/libs/ui/widgets/kis_scratch_pad.h b/libs/ui/widgets/kis_scratch_pad.h
index d920ec2327..34c1168919 100644
--- a/libs/ui/widgets/kis_scratch_pad.h
+++ b/libs/ui/widgets/kis_scratch_pad.h
@@ -1,181 +1,204 @@
/* This file is part of the KDE project
* Copyright 2010 (C) Boudewijn Rempt <boud@valdyas.org>
* Copyright 2011 (C) Dmitry Kazakov <dimula73@gmail.com>
*
* 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 KIS_SCRATCH_PAD_H
#define KIS_SCRATCH_PAD_H
#include <QImage>
#include <QWidget>
#include <QRect>
#include <KoColor.h>
#include <brushengine/kis_paintop_preset.h>
#include <kis_types.h>
#include <kritaui_export.h>
class QColor;
class KoColorProfile;
class KoPointerEvent;
class KisCanvasResourceProvider;
class KisUpdateScheduler;
class KisUndoStore;
class KisPostExecutionUndoAdapter;
class KisScratchPadEventFilter;
class KisPaintingInformationBuilder;
class KisToolFreehandHelper;
class KisNodeGraphListener;
/**
* A scratchpad is a painting canvas with only one zoomlevel and based on
* a paint layer, not on a KisImage. It can have a blank, tiled background or
* a gradient background.
*/
class KRITAUI_EXPORT KisScratchPad : public QWidget
{
Q_OBJECT
public:
void setupScratchPad(KisCanvasResourceProvider* resourceProvider,
const QColor &defaultColor);
KisScratchPad(QWidget *parent = 0);
~KisScratchPad() override;
/// set the specified rect as the area taken for @see cutoutOverlay
void setCutoutOverlayRect(const QRect&rc);
+ /**
+ * keep track of if our scratchpad is in paint, pan, or color pick mode
+ * Set to true if there is a GUI controlling current mode
+ * If this is false, the modes are only changed with various mouse click shortcuts
+ */
+ void setModeManually(bool value);
+
+ /**
+ * @brief change the mode explicitly to paint, mix, or pan
+ * @param what mode to change it to
+ */
+ void setModeType(QString modeName);
+
/// return the contents of the area under the cutoutOverlay rect
QImage cutoutOverlay() const;
// A callback for our own node graph listener
void imageUpdated(const QRect &rect);
// A callback for scratch pad default bounds
QRect imageBounds() const;
// Called by the event filter
void pointerPress(KoPointerEvent *event);
void pointerRelease(KoPointerEvent *event);
void pointerMove(KoPointerEvent *event);
public Q_SLOTS:
void fillDefault();
void fillGradient();
void fillBackground();
void fillTransparent();
+ void setFillColor(QColor newColor);
+
/// Fill the area with what is on your current canvas
void fillLayer();
/**
* Set the icon of the current preset
*/
void setPresetImage(const QImage& image);
/**
* Paint the icon of the current preset inside the
* cutout overlay
*
* \see setPresetImage
*/
void paintPresetImage();
/**
* Paint the icon of a custom image that is being loaded
*
*/
- void paintCustomImage(const QImage& loadedImage);
+ void paintCustomImage(const QImage & loadedImage);
+
+
+ void loadScratchpadImage(QImage image);
+
+ QImage copyScratchpadImageData();
private Q_SLOTS:
void setOnScreenResolution(qreal scaleX, qreal scaleY);
void setDisplayProfile(const KoColorProfile* colorProfile);
void slotUpdateCanvas(const QRect &rect);
Q_SIGNALS:
void colorSelected(const KoColor& color);
void sigUpdateCanvas(const QRect &rect);
protected:
void paintEvent ( QPaintEvent * event ) override;
private:
void beginStroke(KoPointerEvent *event);
void doStroke(KoPointerEvent *event);
void endStroke(KoPointerEvent *event);
void beginPan(KoPointerEvent *event);
void doPan(KoPointerEvent *event);
void endPan(KoPointerEvent *event);
void pick(KoPointerEvent *event);
void updateTransformations();
QTransform documentToWidget() const;
QTransform widgetToDocument() const;
private:
enum Mode {
PAINTING,
HOVERING,
PANNING,
PICKING
};
Mode modeFromButton(Qt::MouseButton button) const;
private:
KoColor m_defaultColor;
Mode m_toolMode;
+ bool isModeManuallySet = false;
+ bool isMouseDown = false;
KisPaintLayerSP m_paintLayer;
const KoColorProfile* m_displayProfile;
QCursor m_cursor;
+ QCursor m_colorPickerCursor;
QRect m_cutoutOverlay;
QBrush m_checkBrush;
KisCanvasResourceProvider* m_resourceProvider;
KisUpdateScheduler *m_updateScheduler;
KisUndoStore *m_undoStore;
KisPostExecutionUndoAdapter *m_undoAdapter;
KisNodeGraphListener *m_nodeListener;
KisScratchPadEventFilter *m_eventFilter;
QScopedPointer<KisToolFreehandHelper> m_helper;
KisPaintingInformationBuilder *m_infoBuilder;
QTransform m_scaleTransform;
QTransform m_translateTransform;
QPointF m_panDocPoint;
int m_scaleBorderWidth;
QImage m_presetImage;
};
#endif // KIS_SCRATCH_PAD_H
diff --git a/libs/widgets/CMakeLists.txt b/libs/widgets/CMakeLists.txt
index 0f02994eeb..1bc8367495 100644
--- a/libs/widgets/CMakeLists.txt
+++ b/libs/widgets/CMakeLists.txt
@@ -1,119 +1,111 @@
add_subdirectory( tests )
include_directories(${CMAKE_CURRENT_BINARY_DIR})
set(kritawidgets_LIB_SRCS
KoVBox.cpp
KoDialog.cpp
KoZoomWidget.cpp
KoAspectButton.cpp
- KoPagePreviewWidget.cpp
KoSliderCombo.cpp
KoColorPopupButton.cpp
KoConfigAuthorPage.cpp
KoUnitDoubleSpinBox.cpp
KoZoomAction.cpp
KoZoomController.cpp
KoZoomInput.cpp
KoZoomHandler.cpp
KoZoomMode.cpp
KoDpi.cpp
KoColorPatch.cpp
KoColorPopupAction.cpp
KoColorSetWidget.cpp
KoColorSlider.cpp
KoTriangleColorSelector.cpp
KoResourcePopupAction.cpp
KoRuler.cpp
KoResourceServerProvider.cpp
KoLineStyleSelector.cpp
KoLineStyleItemDelegate.cpp
KoLineStyleModel.cpp
KoTitledTabWidget.cpp
KoToolBoxButton.cpp
KoToolBox.cpp
KoToolBoxDocker.cpp
KoToolBoxFactory.cpp
KoToolDocker.cpp
- KoPageLayoutWidget.cpp
- KoPageLayoutDialog.cpp
KoShadowConfigWidget.cpp
KoMarkerSelector.cpp
KoMarkerModel.cpp
KoMarkerItemDelegate.cpp
- KoDocumentInfoDlg.cpp
-
WidgetsDebug.cpp
kis_file_name_requester.cpp
KisColorSelectorInterface.cpp
KoAnchorSelectionWidget.cpp
KisGradientSlider.cpp
KisGradientSliderWidget.cpp
kis_color_input.cpp
# classes used by internal color selector
kis_spinbox_color_selector.cpp
KisSpinboxHSXSelector.cpp
KisVisualColorSelector.cpp
KisVisualColorSelectorShape.cpp
KisVisualEllipticalSelectorShape.cpp
KisVisualRectangleSelectorShape.cpp
KisVisualTriangleSelectorShape.cpp
KisScreenColorPickerBase.cpp
KisDlgInternalColorSelector.cpp
KisPaletteModel.cpp
KisPaletteDelegate.cpp
kis_palette_view.cpp
KisPaletteChooser.cpp
KisPaletteComboBox.cpp
kis_color_button.cpp
)
ki18n_wrap_ui( kritawidgets_LIB_SRCS
KoConfigAuthorPage.ui
- koDocumentInfoAboutWidget.ui
- koDocumentInfoAuthorWidget.ui
wdg_file_name_requester.ui
- KoPageLayoutWidget.ui
KoShadowConfigWidget.ui
WdgDlgInternalColorSelector.ui
WdgPaletteListWidget.ui
)
add_library(kritawidgets SHARED ${kritawidgets_LIB_SRCS})
generate_export_header(kritawidgets BASE_NAME kritawidgets)
target_link_libraries(kritawidgets
- kritaodf
+
kritaglobal
kritaflake
kritapigment
kritawidgetutils
kritaresources
kritaresourcewidgets
Qt5::PrintSupport
KF5::CoreAddons
KF5::ConfigGui
KF5::GuiAddons
KF5::WidgetsAddons
KF5::ConfigCore
KF5::Completion
)
if(X11_FOUND)
target_link_libraries(kritawidgets Qt5::X11Extras ${X11_LIBRARIES})
endif()
set_target_properties(kritawidgets PROPERTIES
VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION}
)
install(TARGETS kritawidgets ${INSTALL_TARGETS_DEFAULT_ARGS})
diff --git a/libs/widgets/KoPageLayoutDialog.cpp b/libs/widgets/KoPageLayoutDialog.cpp
deleted file mode 100644
index 26f2c8b625..0000000000
--- a/libs/widgets/KoPageLayoutDialog.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007,2010 Thomas Zander <zander@kde.org>
- *
- * 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 "KoPageLayoutDialog.h"
-
-#include "KoPageLayoutWidget.h"
-#include "KoPagePreviewWidget.h"
-
-#include <klocalizedstring.h>
-#include <WidgetsDebug.h>
-
-#include <QCheckBox>
-#include <QDialogButtonBox>
-#include <QHBoxLayout>
-#include <QTimer>
-
-class Q_DECL_HIDDEN KoPageLayoutDialog::Private
-{
-public:
- Private() : pageLayoutWidget(0), documentCheckBox(0) {}
- KoPageLayoutWidget *pageLayoutWidget;
- QCheckBox *documentCheckBox;
-};
-
-
-KoPageLayoutDialog::KoPageLayoutDialog(QWidget *parent, const KoPageLayout &layout)
- : KPageDialog(parent)
- , d(new Private)
-{
- setWindowTitle(i18n("Page Layout"));
- setFaceType(KPageDialog::Tabbed);
-
- QWidget *widget = new QWidget(this);
- addPage(widget, i18n("Page"));
-
- QHBoxLayout *lay = new QHBoxLayout(widget);
-
- d->pageLayoutWidget = new KoPageLayoutWidget(widget, layout);
- d->pageLayoutWidget->showUnitchooser(false);
- lay->addWidget(d->pageLayoutWidget,1);
-
- KoPagePreviewWidget *prev = new KoPagePreviewWidget(widget);
- // use not original layout, but "fixed" one (e.g. with 0 values) as now hold by pageLayoutWidget
- prev->setPageLayout(d->pageLayoutWidget->pageLayout());
- lay->addWidget(prev, 1);
-
- connect (d->pageLayoutWidget, SIGNAL(layoutChanged(KoPageLayout)),
- prev, SLOT(setPageLayout(KoPageLayout)));
- connect (d->pageLayoutWidget, SIGNAL(layoutChanged(KoPageLayout)),
- this, SLOT(setPageLayout(KoPageLayout)));
- connect (d->pageLayoutWidget, SIGNAL(unitChanged(KoUnit)),
- this, SIGNAL(unitChanged(KoUnit)));
-}
-
-KoPageLayoutDialog::~KoPageLayoutDialog()
-{
- delete d;
-}
-
-KoPageLayout KoPageLayoutDialog::pageLayout() const
-{
- return d->pageLayoutWidget->pageLayout();
-}
-
-void KoPageLayoutDialog::setPageLayout(const KoPageLayout &layout)
-{
- d->pageLayoutWidget->setPageLayout(layout);
-}
-
-void KoPageLayoutDialog::accept()
-{
- KPageDialog::accept();
- deleteLater();
-}
-
-void KoPageLayoutDialog::reject()
-{
- KPageDialog::reject();
- deleteLater();
-}
-
-bool KoPageLayoutDialog::applyToDocument() const
-{
- return d->documentCheckBox && d->documentCheckBox->isChecked();
-}
-
-void KoPageLayoutDialog::showApplyToDocument(bool on)
-{
- if (on && d->documentCheckBox == 0) {
- for (int i = 0; i < children().count(); ++i) {
- if (QDialogButtonBox *buttonBox = qobject_cast<QDialogButtonBox*>(children()[i])) {
- d->documentCheckBox = new QCheckBox(i18n("Apply to document"), buttonBox);
- d->documentCheckBox->setChecked(true);
- buttonBox->addButton(d->documentCheckBox, QDialogButtonBox::ResetRole);
- break;
- }
- }
-
- Q_ASSERT(d->pageLayoutWidget);
- connect (d->documentCheckBox, SIGNAL(toggled(bool)),
- d->pageLayoutWidget, SLOT(setApplyToDocument(bool)));
- } else if (d->documentCheckBox) {
- d->documentCheckBox->setVisible(on);
- }
-}
-
-void KoPageLayoutDialog::showTextDirection(bool on)
-{
- d->pageLayoutWidget->showTextDirection(on);
-}
-
-void KoPageLayoutDialog::showPageSpread(bool on)
-{
- d->pageLayoutWidget->showPageSpread(on);
-}
-
-void KoPageLayoutDialog::setPageSpread(bool pageSpread)
-{
- d->pageLayoutWidget->setPageSpread(pageSpread);
-}
-
-void KoPageLayoutDialog::showUnitchooser(bool on)
-{
- d->pageLayoutWidget->showUnitchooser(on);
-}
-
-void KoPageLayoutDialog::setUnit(const KoUnit &unit)
-{
- d->pageLayoutWidget->setUnit(unit);
-}
-
diff --git a/libs/widgets/KoPageLayoutDialog.h b/libs/widgets/KoPageLayoutDialog.h
deleted file mode 100644
index 7276f6a941..0000000000
--- a/libs/widgets/KoPageLayoutDialog.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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_PAGE_LAYOUT_DIALOG
-#define KO_PAGE_LAYOUT_DIALOG
-
-#include "kritawidgets_export.h"
-
-#include <kpagedialog.h>
-#include <KoUnit.h>
-
-struct KoPageLayout;
-
-/// A dialog to show the settings for one page and apply them afterwards.
-class KRITAWIDGETS_EXPORT KoPageLayoutDialog : public KPageDialog
-{
- Q_OBJECT
-public:
- explicit KoPageLayoutDialog(QWidget *parent, const KoPageLayout &layout);
- ~KoPageLayoutDialog() override;
-
- void showTextDirection(bool on);
- void showPageSpread(bool on);
- void setPageSpread(bool pageSpread);
- KoPageLayout pageLayout() const;
- bool applyToDocument() const;
- void showApplyToDocument(bool on);
-
- void showUnitchooser(bool on);
- void setUnit(const KoUnit &unit);
-
-Q_SIGNALS:
- void unitChanged(const KoUnit &unit);
-
-public Q_SLOTS:
- void setPageLayout(const KoPageLayout &layout);
-
-protected Q_SLOTS:
- void accept() override;
- void reject() override;
-
-private:
- class Private;
- Private * const d;
-};
-
-#endif
diff --git a/libs/widgets/KoPageLayoutWidget.cpp b/libs/widgets/KoPageLayoutWidget.cpp
deleted file mode 100644
index 7fb2d7261f..0000000000
--- a/libs/widgets/KoPageLayoutWidget.cpp
+++ /dev/null
@@ -1,320 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007, 2010 Thomas Zander <zander@kde.org>
- *
- * 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 "KoPageLayoutWidget.h"
-
-#include <ui_KoPageLayoutWidget.h>
-
-#include <KoUnit.h>
-
-#include <QButtonGroup>
-
-class Q_DECL_HIDDEN KoPageLayoutWidget::Private
-{
-public:
- Ui::KoPageLayoutWidget widget;
- KoPageLayout pageLayout;
- KoUnit unit;
-
- QButtonGroup *orientationGroup;
- bool marginsEnabled;
- bool allowSignals;
-};
-
-
-KoPageLayoutWidget::KoPageLayoutWidget(QWidget *parent, const KoPageLayout &layout)
- : QWidget(parent)
- , d(new Private)
-{
- d->widget.setupUi(this);
-
- d->pageLayout = layout;
- d->marginsEnabled = true;
- d->allowSignals = true;
- d->orientationGroup = new QButtonGroup(this);
- d->orientationGroup->addButton(d->widget.portrait, KoPageFormat::Portrait);
- d->orientationGroup->addButton(d->widget.landscape, KoPageFormat::Landscape);
-
- QButtonGroup *group2 = new QButtonGroup(this);
- group2->addButton(d->widget.singleSided);
- group2->addButton(d->widget.facingPages);
- // the two sets of labels we use might have different lengths; make sure this does not create a 'jumping' ui
- d->widget.facingPages->setChecked(true);
- facingPagesChanged();
- int width = qMax(d->widget.leftLabel->width(), d->widget.rightLabel->width());
- d->widget.singleSided->setChecked(true);
- facingPagesChanged();
- width = qMax(width, qMax(d->widget.leftLabel->width(), d->widget.rightLabel->width()));
- d->widget.leftLabel->setMinimumSize(QSize(width, 5));
-
- d->widget.units->addItems(KoUnit::listOfUnitNameForUi(KoUnit::HidePixel));
- d->widget.sizes->addItems(KoPageFormat::localizedPageFormatNames());
- setPageSpread(false);
-
- connect(d->widget.sizes, SIGNAL(currentIndexChanged(int)), this, SLOT(sizeChanged(int)));
- connect(d->widget.units, SIGNAL(currentIndexChanged(int)), this, SLOT(unitChanged(int)));
- connect(group2, SIGNAL(buttonClicked(int)), this, SLOT(facingPagesChanged()));
- connect(d->orientationGroup, SIGNAL(buttonClicked(int)), this, SLOT(orientationChanged()));
- connect(d->widget.width, SIGNAL(valueChangedPt(qreal)), this, SLOT(optionsChanged()));
- connect(d->widget.height, SIGNAL(valueChangedPt(qreal)), this, SLOT(optionsChanged()));
- connect(d->widget.topMargin, SIGNAL(valueChangedPt(qreal)), this, SLOT(marginsChanged()));
- connect(d->widget.bottomMargin, SIGNAL(valueChangedPt(qreal)), this, SLOT(marginsChanged()));
- connect(d->widget.bindingEdgeMargin, SIGNAL(valueChangedPt(qreal)), this, SLOT(marginsChanged()));
- connect(d->widget.pageEdgeMargin, SIGNAL(valueChangedPt(qreal)), this, SLOT(marginsChanged()));
- connect(d->widget.width, SIGNAL(valueChangedPt(qreal)), this, SLOT(optionsChanged()));
- connect(d->widget.height, SIGNAL(valueChangedPt(qreal)), this, SLOT(optionsChanged()));
-
- setUnit(KoUnit(KoUnit::Millimeter));
- setPageLayout(layout);
- if (layout.format == 0) // make sure we always call this during startup, even if the A3 (index=0) was chosen
- sizeChanged(layout.format);
-
- showTextDirection(false);
- /* disable advanced page layout features by default */
- d->widget.facingPageLabel->setVisible(false);
- d->widget.facingPages->setVisible(false);
- d->widget.singleSided->setVisible(false);
- d->widget.stylesLabel->setVisible(false);
- d->widget.pageStyle->setVisible(false);
-}
-
-KoPageLayoutWidget::~KoPageLayoutWidget()
-{
- delete d;
-}
-
-KoPageLayout KoPageLayoutWidget::pageLayout() const
-{
- return d->pageLayout;
-}
-
-void KoPageLayoutWidget::sizeChanged(int row)
-{
- if (row < 0) return;
- if (! d->allowSignals) return;
- d->allowSignals = false;
- d->pageLayout.format = static_cast<KoPageFormat::Format> (row);
- bool custom = d->pageLayout.format == KoPageFormat::CustomSize;
- d->widget.width->setEnabled( custom );
- d->widget.height->setEnabled( custom );
-
- if ( !custom ) {
- d->pageLayout.width = MM_TO_POINT( KoPageFormat::width( d->pageLayout.format, d->pageLayout.orientation ) );
- d->pageLayout.height = MM_TO_POINT( KoPageFormat::height( d->pageLayout.format, d->pageLayout.orientation ) );
- if (d->widget.facingPages->isChecked()) // is pagespread
- d->pageLayout.width *= 2;
- }
-
- d->widget.width->changeValue( d->pageLayout.width );
- d->widget.height->changeValue( d->pageLayout.height );
-
- emit layoutChanged(d->pageLayout);
- d->allowSignals = true;
-}
-
-void KoPageLayoutWidget::unitChanged(int row)
-{
- setUnit(KoUnit::fromListForUi(row, KoUnit::HidePixel));
-}
-
-void KoPageLayoutWidget::setUnit(const KoUnit &unit)
-{
- if (d->unit == unit)
- return;
- d->unit = unit;
-
- d->widget.width->setUnit(unit);
- d->widget.height->setUnit(unit);
- d->widget.topMargin->setUnit(unit);
- d->widget.bottomMargin->setUnit(unit);
- d->widget.bindingEdgeMargin->setUnit(unit);
- d->widget.pageEdgeMargin->setUnit(unit);
- d->widget.units->setCurrentIndex(unit.indexInListForUi(KoUnit::HidePixel));
-
- emit unitChanged(d->unit);
-}
-
-void KoPageLayoutWidget::setPageLayout(const KoPageLayout &layout)
-{
- if (! d->allowSignals) return;
- d->allowSignals = false;
- d->pageLayout = layout;
-
- Q_ASSERT(d->orientationGroup->button( layout.orientation ));
- d->orientationGroup->button( layout.orientation )->setChecked( true );
- if (layout.bindingSide >= 0 && layout.pageEdge >= 0) {
- d->widget.facingPages->setChecked(true);
- d->widget.bindingEdgeMargin->changeValue(layout.bindingSide);
- d->widget.pageEdgeMargin->changeValue(layout.pageEdge);
- d->pageLayout.leftMargin = -1;
- d->pageLayout.rightMargin = -1;
- }
- else {
- d->widget.singleSided->setChecked(true);
- d->widget.bindingEdgeMargin->changeValue(layout.leftMargin);
- d->widget.pageEdgeMargin->changeValue(layout.rightMargin);
- d->pageLayout.pageEdge = -1;
- d->pageLayout.bindingSide = -1;
- }
- facingPagesChanged();
-
- d->widget.topMargin->changeValue(layout.topMargin);
- d->widget.bottomMargin->changeValue(layout.bottomMargin);
- d->allowSignals = true;
- d->widget.sizes->setCurrentIndex(layout.format); // calls sizeChanged()
-}
-
-void KoPageLayoutWidget::facingPagesChanged()
-{
- if (! d->allowSignals) return;
- d->allowSignals = false;
- if (d->widget.singleSided->isChecked()) {
- d->widget.leftLabel->setText(i18n("Left Edge:"));
- d->widget.rightLabel->setText(i18n("Right Edge:"));
- }
- else {
- d->widget.leftLabel->setText(i18n("Binding Edge:"));
- d->widget.rightLabel->setText(i18n("Page Edge:"));
- }
- d->allowSignals = true;
- marginsChanged();
- sizeChanged(d->widget.sizes->currentIndex());
-}
-
-void KoPageLayoutWidget::marginsChanged()
-{
- if (! d->allowSignals) return;
- d->allowSignals = false;
- d->pageLayout.leftMargin = -1;
- d->pageLayout.rightMargin = -1;
- d->pageLayout.bindingSide = -1;
- d->pageLayout.pageEdge = -1;
- d->pageLayout.topMargin = d->marginsEnabled?d->widget.topMargin->value():0;
- d->pageLayout.bottomMargin = d->marginsEnabled?d->widget.bottomMargin->value():0;
- qreal left = d->marginsEnabled?d->widget.bindingEdgeMargin->value():0;
- qreal right = d->marginsEnabled?d->widget.pageEdgeMargin->value():0;
- if (left + right > d->pageLayout.width - 10) {
- // make sure the actual text area is never smaller than 10 points.
- qreal diff = d->pageLayout.width - 10 - left - right;
- left = qMin(d->pageLayout.width - 10, qMax(qreal(0.0), left - diff / qreal(2.0)));
- right = qMax(qreal(0.0), right - d->pageLayout.width - 10 - left);
- }
-
- if (d->widget.singleSided->isChecked()) {
- d->pageLayout.leftMargin = left;
- d->pageLayout.rightMargin = right;
- }
- else {
- d->pageLayout.bindingSide = left;
- d->pageLayout.pageEdge = right;
- }
- // debugWidgets << " " << d->pageLayout.left <<"|"<< d->pageLayout.bindingSide << "," <<
- // d->pageLayout.right << "|"<< d->pageLayout.pageEdge;
- emit layoutChanged(d->pageLayout);
- d->allowSignals = true;
-}
-
-void KoPageLayoutWidget::setTextAreaAvailable(bool available)
-{
- d->marginsEnabled = available;
- d->widget.margins->setEnabled(available);
- marginsChanged();
-}
-
-void KoPageLayoutWidget::optionsChanged()
-{
- if (! d->allowSignals) return;
- if (d->widget.sizes->currentIndex() == KoPageFormat::CustomSize) {
- d->pageLayout.width = d->widget.width->value();
- d->pageLayout.height = d->widget.height->value();
- } else
- sizeChanged(d->widget.sizes->currentIndex());
-
- marginsChanged();
-}
-
-void KoPageLayoutWidget::orientationChanged()
-{
- if (! d->allowSignals) return;
- d->allowSignals = false;
- d->pageLayout.orientation = d->widget.landscape->isChecked() ? KoPageFormat::Landscape : KoPageFormat::Portrait;
-
- qreal x = d->widget.height->value();
- d->widget.height->changeValue( d->widget.width->value() );
- d->widget.width->changeValue( x );
-
- d->allowSignals = true;
- optionsChanged();
-}
-
-void KoPageLayoutWidget::showUnitchooser(bool on) {
- d->widget.units->setVisible(on);
- d->widget.unitsLabel->setVisible(on);
-}
-
-void KoPageLayoutWidget::showPageSpread(bool on)
-{
- d->widget.facingPageLabel->setVisible(on);
- d->widget.singleSided->setVisible(on);
- d->widget.facingPages->setVisible(on);
-}
-
-void KoPageLayoutWidget::setPageSpread(bool pageSpread)
-{
- if (pageSpread)
- d->widget.facingPages->setChecked(true);
- else
- d->widget.singleSided->setChecked(true);
-}
-
-void KoPageLayoutWidget::setApplyToDocument(bool apply)
-{
- if (apply) {
- d->widget.facingPageLabel->setText(i18n("Facing Pages:"));
- d->widget.facingPages->setText(i18n("Facing pages"));
- }
- else {
- d->widget.facingPageLabel->setText(i18n("Page Layout:"));
- d->widget.facingPages->setText(i18n("Page spread"));
- }
-}
-
-void KoPageLayoutWidget::showTextDirection(bool on)
-{
- d->widget.directionLabel->setVisible(on);
- d->widget.textDirection->setVisible(on);
-}
-
-
-void KoPageLayoutWidget::showPageStyles(bool on)
-{
- d->widget.stylesLabel->setVisible(on);
- d->widget.pageStyle->setVisible(on);
-}
-
-void KoPageLayoutWidget::setPageStyles(const QStringList &styles)
-{
- d->widget.pageStyle->clear();
- d->widget.pageStyle->addItems(styles);
-}
-
-QString KoPageLayoutWidget::currentPageStyle() const
-{
- return d->widget.pageStyle->currentText();
-}
diff --git a/libs/widgets/KoPageLayoutWidget.h b/libs/widgets/KoPageLayoutWidget.h
deleted file mode 100644
index 5362fa9dd7..0000000000
--- a/libs/widgets/KoPageLayoutWidget.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007, 2010 Thomas Zander <zander@kde.org>
- *
- * 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_PAGE_LAYOUT_WIDGET
-#define KO_PAGE_LAYOUT_WIDGET
-
-#include "kritawidgets_export.h"
-
-#include <KoPageLayout.h>
-#include <QWidget>
-
-class KoUnit;
-
-/// the widget that shows the size/margins and other page settings.
-class KRITAWIDGETS_EXPORT KoPageLayoutWidget : public QWidget
-{
- Q_OBJECT
-
-public:
- KoPageLayoutWidget(QWidget *parent, const KoPageLayout &layout);
- ~KoPageLayoutWidget() override;
-
- KoPageLayout pageLayout() const;
-
- void setUnit(const KoUnit &unit);
- void showUnitchooser(bool on);
- void showPageSpread(bool on);
- void showPageStyles(bool on);
- void setPageStyles(const QStringList &styles);
- QString currentPageStyle() const;
- void setPageSpread(bool pageSpread);
- void showTextDirection(bool on);
-
-Q_SIGNALS:
- void layoutChanged(const KoPageLayout &layout);
- void unitChanged(const KoUnit &unit);
-
-public Q_SLOTS:
- void setPageLayout(const KoPageLayout &layout);
- void setTextAreaAvailable(bool available);
-
-private Q_SLOTS:
- void sizeChanged(int row);
- void unitChanged(int row);
- void facingPagesChanged();
- void optionsChanged();
- void marginsChanged();
- void orientationChanged();
- void setApplyToDocument(bool apply);
-
-private:
- class Private;
- Private * const d;
-};
-
-#endif
diff --git a/libs/widgets/KoPageLayoutWidget.ui b/libs/widgets/KoPageLayoutWidget.ui
deleted file mode 100644
index ec0f1229bb..0000000000
--- a/libs/widgets/KoPageLayoutWidget.ui
+++ /dev/null
@@ -1,365 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>KoPageLayoutWidget</class>
- <widget class="QWidget" name="KoPageLayoutWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>341</width>
- <height>417</height>
- </rect>
- </property>
- <layout class="QVBoxLayout">
- <property name="leftMargin">
- <number>0</number>
- </property>
- <property name="topMargin">
- <number>0</number>
- </property>
- <property name="rightMargin">
- <number>0</number>
- </property>
- <property name="bottomMargin">
- <number>0</number>
- </property>
- <item>
- <layout class="QGridLayout" name="gridLayout" columnstretch="0,1,1">
- <property name="leftMargin">
- <number>0</number>
- </property>
- <property name="topMargin">
- <number>0</number>
- </property>
- <property name="rightMargin">
- <number>0</number>
- </property>
- <property name="bottomMargin">
- <number>0</number>
- </property>
- <item row="0" column="0">
- <widget class="QLabel" name="unitsLabel">
- <property name="text">
- <string>&amp;Unit:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>units</cstring>
- </property>
- </widget>
- </item>
- <item row="0" column="1" colspan="2">
- <widget class="QComboBox" name="units">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="stylesLabel">
- <property name="text">
- <string>&amp;Follow style:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>pageStyle</cstring>
- </property>
- </widget>
- </item>
- <item row="1" column="1" colspan="2">
- <widget class="QComboBox" name="pageStyle"/>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>S&amp;ize:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>sizes</cstring>
- </property>
- </widget>
- </item>
- <item row="2" column="1" colspan="2">
- <widget class="QComboBox" name="sizes"/>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="label_3">
- <property name="text">
- <string>Width:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>width</cstring>
- </property>
- </widget>
- </item>
- <item row="3" column="1" colspan="2">
- <layout class="QHBoxLayout">
- <property name="leftMargin">
- <number>0</number>
- </property>
- <property name="topMargin">
- <number>0</number>
- </property>
- <property name="rightMargin">
- <number>0</number>
- </property>
- <property name="bottomMargin">
- <number>0</number>
- </property>
- <item>
- <widget class="KisDoubleParseUnitSpinBox" name="width"/>
- </item>
- <item>
- <widget class="QLabel" name="heightLabel">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>&amp;Height:</string>
- </property>
- <property name="buddy">
- <cstring>height</cstring>
- </property>
- </widget>
- </item>
- <item>
- <widget class="KisDoubleParseUnitSpinBox" name="height"/>
- </item>
- </layout>
- </item>
- <item row="4" column="0">
- <widget class="QLabel" name="orientationLabel">
- <property name="text">
- <string>Orientation:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item row="4" column="1">
- <widget class="QRadioButton" name="portrait">
- <property name="text">
- <string>Po&amp;rtrait</string>
- </property>
- </widget>
- </item>
- <item row="4" column="2">
- <widget class="QRadioButton" name="landscape">
- <property name="text">
- <string>Landscape</string>
- </property>
- </widget>
- </item>
- <item row="5" column="0">
- <widget class="QLabel" name="facingPageLabel">
- <property name="text">
- <string>Facing pages:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item row="5" column="1">
- <widget class="QRadioButton" name="singleSided">
- <property name="text">
- <string>Single sided</string>
- </property>
- </widget>
- </item>
- <item row="5" column="2">
- <widget class="QRadioButton" name="facingPages">
- <property name="text">
- <string>Facing pages</string>
- </property>
- </widget>
- </item>
- <item row="6" column="0">
- <widget class="QLabel" name="directionLabel">
- <property name="text">
- <string>&amp;Text direction:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>textDirection</cstring>
- </property>
- </widget>
- </item>
- <item row="6" column="1" colspan="2">
- <widget class="QComboBox" name="textDirection">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <item>
- <property name="text">
- <string>Automatic</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Left to right</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Right to left</string>
- </property>
- </item>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QGroupBox" name="margins">
- <property name="title">
- <string>Margins</string>
- </property>
- <layout class="QFormLayout">
- <item row="0" column="0">
- <widget class="QLabel" name="label_13">
- <property name="text">
- <string>Top:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>topMargin</cstring>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="KisDoubleParseUnitSpinBox" name="topMargin">
- <property name="maximum">
- <double>999.990000000000009</double>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="leftLabel">
- <property name="text">
- <string>&amp;Binding edge:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>bindingEdgeMargin</cstring>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="KisDoubleParseUnitSpinBox" name="bindingEdgeMargin">
- <property name="maximum">
- <double>999.990000000000009</double>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="rightLabel">
- <property name="text">
- <string>Pa&amp;ge edge:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>pageEdgeMargin</cstring>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="KisDoubleParseUnitSpinBox" name="pageEdgeMargin">
- <property name="maximum">
- <double>999.990000000000009</double>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="label_12">
- <property name="text">
- <string>Botto&amp;m:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>bottomMargin</cstring>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="KisDoubleParseUnitSpinBox" name="bottomMargin">
- <property name="maximum">
- <double>999.990000000000009</double>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer>
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::MinimumExpanding</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>KisDoubleParseUnitSpinBox</class>
- <extends>QDoubleSpinBox</extends>
- <header>kis_double_parse_unit_spin_box.h</header>
- </customwidget>
- </customwidgets>
- <tabstops>
- <tabstop>units</tabstop>
- <tabstop>sizes</tabstop>
- <tabstop>width</tabstop>
- <tabstop>height</tabstop>
- <tabstop>portrait</tabstop>
- <tabstop>landscape</tabstop>
- <tabstop>singleSided</tabstop>
- <tabstop>facingPages</tabstop>
- <tabstop>textDirection</tabstop>
- <tabstop>topMargin</tabstop>
- <tabstop>bindingEdgeMargin</tabstop>
- <tabstop>pageEdgeMargin</tabstop>
- <tabstop>bottomMargin</tabstop>
- </tabstops>
- <resources/>
- <connections/>
-</ui>
diff --git a/libs/widgets/KoPagePreviewWidget.cpp b/libs/widgets/KoPagePreviewWidget.cpp
deleted file mode 100644
index 5d9d73b3f3..0000000000
--- a/libs/widgets/KoPagePreviewWidget.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2006 Gary Cramblitt <garycramblitt@comcast.net>
- *
- * 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 "KoPagePreviewWidget.h"
-
-#include <KoDpi.h>
-#include <KoUnit.h>
-#include <KoPageLayout.h>
-#include <KoColumns.h>
-
-#include <QPainter>
-#include <WidgetsDebug.h>
-
-class Q_DECL_HIDDEN KoPagePreviewWidget::Private
-{
-public:
- KoPageLayout pageLayout;
- KoColumns columns;
-};
-
-
-KoPagePreviewWidget::KoPagePreviewWidget(QWidget *parent)
- : QWidget(parent)
- , d(new Private)
-{
- setMinimumSize( 100, 100 );
-}
-
-KoPagePreviewWidget::~KoPagePreviewWidget()
-{
- delete d;
-}
-
-void KoPagePreviewWidget::paintEvent(QPaintEvent *event)
-{
- Q_UNUSED(event);
- // resolution[XY] is in pixel per pt
- qreal resolutionX = POINT_TO_INCH( static_cast<qreal>(KoDpi::dpiX()) );
- qreal resolutionY = POINT_TO_INCH( static_cast<qreal>(KoDpi::dpiY()) );
-
- qreal pageWidth = d->pageLayout.width * resolutionX;
- qreal pageHeight = d->pageLayout.height * resolutionY;
-
- const bool pageSpread = (d->pageLayout.bindingSide >= 0 && d->pageLayout.pageEdge >= 0);
- qreal sheetWidth = pageWidth / (pageSpread?2:1);
-
- qreal zoomH = (height() * 90.0 / 100.0) / pageHeight;
- qreal zoomW = (width() * 90.0 / 100.0) / pageWidth;
- qreal zoom = qMin( zoomW, zoomH );
-
- pageWidth *= zoom;
- sheetWidth *= zoom;
- pageHeight *= zoom;
- QPainter painter( this );
-
- QRect page = QRectF((width() - pageWidth) / 2.0,
- (height() - pageHeight) / 2.0, sheetWidth, pageHeight).toRect();
-
- painter.save();
- drawPage(painter, zoom, page, true);
- painter.restore();
- if(pageSpread) {
- page.moveLeft(page.left() + (int) (sheetWidth));
- painter.save();
- drawPage(painter, zoom, page, false);
- painter.restore();
- }
-
- painter.end();
-
- // paint scale
-}
-
-void KoPagePreviewWidget::drawPage(QPainter &painter, qreal zoom, const QRect &dimensions, bool left)
-{
- painter.fillRect(dimensions, QBrush(palette().base()));
- painter.setPen(QPen(palette().color(QPalette::Dark), 0));
- painter.drawRect(dimensions);
-
- // draw text areas
- QRect textArea = dimensions;
- if ((d->pageLayout.topMargin == 0 && d->pageLayout.bottomMargin == 0 &&
- d->pageLayout.leftMargin == 0 && d->pageLayout.rightMargin == 0) ||
- ( d->pageLayout.pageEdge == 0 && d->pageLayout.bindingSide == 0)) {
- // no margin
- return;
- }
- else {
- textArea.setTop(textArea.top() + qRound(zoom * d->pageLayout.topMargin));
- textArea.setBottom(textArea.bottom() - qRound(zoom * d->pageLayout.bottomMargin));
-
- qreal leftMargin, rightMargin;
- if(d->pageLayout.bindingSide < 0) { // normal margins.
- leftMargin = d->pageLayout.leftMargin;
- rightMargin = d->pageLayout.rightMargin;
- }
- else { // margins mirrored for left/right pages
- leftMargin = d->pageLayout.bindingSide;
- rightMargin = d->pageLayout.pageEdge;
- if(left)
- std::swap(leftMargin, rightMargin);
- }
- textArea.setLeft(textArea.left() + qRound(zoom * leftMargin));
- textArea.setRight(textArea.right() - qRound(zoom * rightMargin));
- }
- painter.setBrush( QBrush( palette().color(QPalette::ButtonText), Qt::HorPattern ) );
- painter.setPen(QPen(palette().color(QPalette::Dark), 0));
-
- // uniform columns?
- if (d->columns.columnData.isEmpty()) {
- qreal columnWidth = (textArea.width() + (d->columns.gapWidth * zoom)) / d->columns.count;
- int width = qRound(columnWidth - d->columns.gapWidth * zoom);
- for ( int i = 0; i < d->columns.count; ++i )
- painter.drawRect( qRound(textArea.x() + i * columnWidth), textArea.y(), width, textArea.height());
- } else {
- qreal totalRelativeWidth = 0.0;
- Q_FOREACH (const KoColumns::ColumnDatum &cd, d->columns.columnData) {
- totalRelativeWidth += cd.relativeWidth;
- }
- int relativeColumnXOffset = 0;
- for (int i = 0; i < d->columns.count; i++) {
- const KoColumns::ColumnDatum &columnDatum = d->columns.columnData.at(i);
- const qreal columnWidth = textArea.width() * columnDatum.relativeWidth / totalRelativeWidth;
- const qreal columnXOffset = textArea.width() * relativeColumnXOffset / totalRelativeWidth;
-
- painter.drawRect( qRound(textArea.x() + columnXOffset + columnDatum.leftMargin * zoom),
- qRound(textArea.y() + columnDatum.topMargin * zoom),
- qRound(columnWidth - (columnDatum.leftMargin + columnDatum.rightMargin) * zoom),
- qRound(textArea.height() - (columnDatum.topMargin + columnDatum.bottomMargin) * zoom));
-
- relativeColumnXOffset += columnDatum.relativeWidth;
- }
- }
-}
-
-void KoPagePreviewWidget::setPageLayout(const KoPageLayout &layout)
-{
- d->pageLayout = layout;
- update();
-}
-
-void KoPagePreviewWidget::setColumns(const KoColumns &columns)
-{
- d->columns = columns;
- update();
-}
-
diff --git a/libs/widgets/KoPagePreviewWidget.h b/libs/widgets/KoPagePreviewWidget.h
deleted file mode 100644
index 91cc3380ec..0000000000
--- a/libs/widgets/KoPagePreviewWidget.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2006 Gary Cramblitt <garycramblitt@comcast.net>
- *
- * 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_PAGE_PREVIEW_WIDGET
-#define KO_PAGE_PREVIEW_WIDGET
-
-#include "kritawidgets_export.h"
-
-#include <QWidget>
-
-// Needed for building on Windows (cannot use forward declarations)
-#include <KoPageLayout.h>
-#include <KoColumns.h>
-
-/// A widget to preview the KoPageLayout and KoColumns data structures.
-class KRITAWIDGETS_EXPORT KoPagePreviewWidget : public QWidget {
- Q_OBJECT
-public:
- explicit KoPagePreviewWidget(QWidget *parent = 0);
- ~KoPagePreviewWidget() override;
-
-protected:
- void paintEvent(QPaintEvent *event) override;
-
-public Q_SLOTS:
- void setPageLayout(const KoPageLayout &layout);
- void setColumns(const KoColumns &columns);
-
-private:
- void drawPage(QPainter &painter, qreal zoom, const QRect &dimensions, bool left);
-
-private:
- class Private;
- Private * const d;
-};
-
-#endif
diff --git a/libs/widgetutils/CMakeLists.txt b/libs/widgetutils/CMakeLists.txt
index 5ec2533a7d..48499f117e 100644
--- a/libs/widgetutils/CMakeLists.txt
+++ b/libs/widgetutils/CMakeLists.txt
@@ -1,143 +1,143 @@
add_subdirectory(tests)
configure_file(xmlgui/config-xmlgui.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-xmlgui.h )
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/config)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/xmlgui)
set(kritawidgetutils_LIB_SRCS
WidgetUtilsDebug.cpp
kis_icon_utils.cpp
kis_action_registry.cpp
KisActionsSnapshot.cpp
KoGroupButton.cpp
KoProgressProxy.cpp
KoFakeProgressProxy.cpp
KoProgressBar.cpp
KoProgressUpdater.cpp
KoUpdater.cpp
KoUpdaterPrivate_p.cpp
KoProperties.cpp
KoFileDialog.cpp
KisKineticScroller.cpp
KoCheckerBoardPainter.cpp
KoItemToolTip.cpp
KisSqueezedComboBox.cpp
KisDialogStateSaver.cpp
KisPopupButton.cpp
kis_cursor.cc
kis_cursor_cache.cpp
kis_double_parse_spin_box.cpp
kis_double_parse_unit_spin_box.cpp
kis_int_parse_spin_box.cpp
kis_num_parser.cpp
kis_slider_spin_box.cpp
kis_spin_box_unit_manager.cpp
config/kcolorscheme.cpp
config/kcolorschememanager.cpp
config/khelpclient.cpp
config/klanguagebutton.cpp
config/krecentfilesaction.cpp
config/kstandardaction.cpp
xmlgui/KisShortcutsEditorItem.cpp
xmlgui/KisShortcutEditWidget.cpp
xmlgui/KisShortcutsEditorDelegate.cpp
xmlgui/KisShortcutsDialog.cpp
xmlgui/KisShortcutsDialog_p.cpp
xmlgui/KisShortcutsEditor.cpp
xmlgui/KisShortcutsEditor_p.cpp
xmlgui/kshortcutschemeseditor.cpp
xmlgui/kshortcutschemeshelper.cpp
xmlgui/kaboutkdedialog_p.cpp
xmlgui/kactioncategory.cpp
xmlgui/kactioncollection.cpp
xmlgui/kbugreport.cpp
xmlgui/kcheckaccelerators.cpp
xmlgui/kedittoolbar.cpp
xmlgui/kgesture.cpp
xmlgui/kgesturemap.cpp
xmlgui/khelpmenu.cpp
xmlgui/kkeysequencewidget.cpp
xmlgui/kmainwindow.cpp
xmlgui/kmenumenuhandler_p.cpp
xmlgui/kshortcutwidget.cpp
xmlgui/kswitchlanguagedialog_p.cpp
xmlgui/ktoggletoolbaraction.cpp
xmlgui/ktoolbar.cpp
xmlgui/ktoolbarhandler.cpp
xmlgui/kundoactions.cpp
xmlgui/kxmlguibuilder.cpp
xmlgui/kxmlguiclient.cpp
xmlgui/kxmlguifactory.cpp
xmlgui/kxmlguifactory_p.cpp
xmlgui/kxmlguiversionhandler.cpp
xmlgui/kxmlguiwindow.cpp
)
if (HAVE_DBUS)
set(kritawidgetutils_LIB_SRCS ${kritawidgetutils_LIB_SRCS}
xmlgui/kmainwindowiface.cpp
)
endif()
ki18n_wrap_ui(kritawidgetutils_LIB_SRCS
xmlgui/KisShortcutsDialog.ui
xmlgui/kshortcutwidget.ui
)
qt5_add_resources(kritawidgetutils_LIB_SRCS xmlgui/kxmlgui.qrc)
add_library(kritawidgetutils SHARED ${kritawidgetutils_LIB_SRCS})
target_include_directories(kritawidgetutils
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/config>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/xmlgui>
)
generate_export_header(kritawidgetutils BASE_NAME kritawidgetutils)
if (HAVE_DBUS)
set (KRITA_WIDGET_UTILS_EXTRA_LIBS ${KRITA_WIDGET_UTILS_EXTRA_LIBS} Qt5::DBus)
endif ()
if (APPLE)
find_library(FOUNDATION_LIBRARY Foundation)
set(KRITA_WIDGET_UTILS_EXTRA_LIBS ${KRITA_WIDGET_UTILS_EXTRA_LIBS} ${FOUNDATION_LIBRARY})
endif ()
target_link_libraries(kritawidgetutils
PUBLIC
Qt5::Widgets
Qt5::Gui
Qt5::Xml
Qt5::Core
KF5::ItemViews
kritaglobal
kritaresources
PRIVATE
Qt5::PrintSupport
KF5::I18n
KF5::ConfigCore
KF5::CoreAddons
KF5::ConfigGui
KF5::GuiAddons
KF5::WidgetsAddons
KF5::WindowSystem
kritaplugin
- kritaodf
+
${KRITA_WIDGET_UTILS_EXTRA_LIBS}
)
set_target_properties(kritawidgetutils
PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION}
)
install(TARGETS kritawidgetutils ${INSTALL_TARGETS_DEFAULT_ARGS})
diff --git a/libs/widgetutils/xmlgui/kshortcutschemeseditor.cpp b/libs/widgetutils/xmlgui/kshortcutschemeseditor.cpp
index 363f36efbc..957d3c7eca 100644
--- a/libs/widgetutils/xmlgui/kshortcutschemeseditor.cpp
+++ b/libs/widgetutils/xmlgui/kshortcutschemeseditor.cpp
@@ -1,242 +1,242 @@
/* This file is part of the KDE libraries
Copyright (C) 2008 Alexander Dymo <adymo@kdevelop.org>
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 "kshortcutschemeseditor.h"
#include "KisShortcutsDialog_p.h"
#include <QLabel>
#include <QMenu>
#include <QFile>
#include <QPushButton>
#include <QTextStream>
#include <QDomDocument>
#include <QStandardPaths>
#include <QInputDialog>
#include <QComboBox>
#include <QHBoxLayout>
#include <QDebug>
#include <kconfiggroup.h>
#include <kmessagebox.h>
#include <ksharedconfig.h>
#include <KoFileDialog.h>
#include "KisShortcutsDialog.h"
#include "kshortcutschemeshelper_p.h"
#include "kactioncollection.h"
#include "kxmlguiclient.h"
#include "KoResourcePaths.h"
KShortcutSchemesEditor::KShortcutSchemesEditor(KisShortcutsDialog *parent)
: QHBoxLayout(parent)
, m_dialog(parent)
{
KConfigGroup group(KSharedConfig::openConfig(), "Shortcut Schemes");
QStringList schemes;
schemes << QStringLiteral("Default");
auto schemeFileLocations = KShortcutSchemesHelper::schemeFileLocations();
schemes << schemeFileLocations.keys();
const QString currentScheme = group.readEntry("Current Scheme", "Default");
setMargin(0);
QLabel *schemesLabel = new QLabel(i18n("Shortcut Schemes:"), m_dialog);
addWidget(schemesLabel);
m_schemesList = new QComboBox(m_dialog);
m_schemesList->setEditable(false);
m_schemesList->addItems(schemes);
m_schemesList->setCurrentIndex(m_schemesList->findText(currentScheme));
schemesLabel->setBuddy(m_schemesList);
addWidget(m_schemesList);
- m_newScheme = new QPushButton(i18n("New..."));
+ m_newScheme = new QPushButton(i18nc("New shortcut scheme", "New..."));
addWidget(m_newScheme);
m_deleteScheme = new QPushButton(i18n("Delete"));
addWidget(m_deleteScheme);
QPushButton *moreActions = new QPushButton(i18n("Save/Load"));
addWidget(moreActions);
QMenu *moreActionsMenu = new QMenu(m_dialog);
// moreActionsMenu->addAction(i18n("Save as Scheme Defaults"),
// this, SLOT(saveAsDefaultsForScheme()));
moreActionsMenu->addAction(i18n("Save Custom Shortcuts"),
this, SLOT(saveCustomShortcuts()));
moreActionsMenu->addAction(i18n("Load Custom Shortcuts"),
this, SLOT(loadCustomShortcuts()));
moreActionsMenu->addAction(i18n("Export Scheme..."),
this, SLOT(exportShortcutsScheme()));
moreActionsMenu->addAction(i18n("Import Scheme..."),
this, SLOT(importShortcutsScheme()));
moreActions->setMenu(moreActionsMenu);
addStretch(1);
connect(m_schemesList, SIGNAL(activated(QString)),
this, SIGNAL(shortcutsSchemeChanged(QString)));
connect(m_newScheme, SIGNAL(clicked()), this, SLOT(newScheme()));
connect(m_deleteScheme, SIGNAL(clicked()), this, SLOT(deleteScheme()));
updateDeleteButton();
}
void KShortcutSchemesEditor::newScheme()
{
bool ok;
const QString newName = QInputDialog::getText(m_dialog, i18n("Name for New Scheme"),
i18n("Name for new scheme:"), QLineEdit::Normal, i18n("New Scheme"), &ok);
if (!ok) {
return;
}
if (m_schemesList->findText(newName) != -1) {
KMessageBox::sorry(m_dialog, i18n("A scheme with this name already exists."));
return;
}
const QString newSchemeFileName = KShortcutSchemesHelper::shortcutSchemeFileName(newName) + ".shortcuts";
QFile schemeFile(newSchemeFileName);
if (!schemeFile.open(QFile::WriteOnly | QFile::Truncate)) {
qDebug() << "Could not open scheme file.";
return;
}
schemeFile.close();
m_dialog->exportConfiguration(newSchemeFileName);
m_schemesList->addItem(newName);
m_schemesList->setCurrentIndex(m_schemesList->findText(newName));
m_schemeFileLocations.insert(newName, newSchemeFileName);
updateDeleteButton();
emit shortcutsSchemeChanged(newName);
}
void KShortcutSchemesEditor::deleteScheme()
{
if (KMessageBox::questionYesNo(m_dialog,
i18n("Do you really want to delete the scheme %1?\n\
Note that this will not remove any system wide shortcut schemes.", currentScheme())) == KMessageBox::No) {
return;
}
//delete the scheme for the app itself
QFile::remove(KShortcutSchemesHelper::shortcutSchemeFileName(currentScheme()));
m_schemesList->removeItem(m_schemesList->findText(currentScheme()));
updateDeleteButton();
emit shortcutsSchemeChanged(currentScheme());
}
QString KShortcutSchemesEditor::currentScheme()
{
return m_schemesList->currentText();
}
void KShortcutSchemesEditor::exportShortcutsScheme()
{
KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs");
QString proposedPath = group.readEntry("ExportShortcuts", KoResourcePaths::saveLocation("kis_shortcuts"));
KoFileDialog dialog(m_dialog, KoFileDialog::SaveFile, "ExportShortcuts");
dialog.setCaption(i18n("Export Shortcuts"));
dialog.setDefaultDir(proposedPath);
dialog.setMimeTypeFilters(QStringList() << "application/x-krita-shortcuts", "application/x-krita-shortcuts");
QString path = dialog.filename();
if (!path.isEmpty()) {
m_dialog->exportConfiguration(path);
}
}
void KShortcutSchemesEditor::saveCustomShortcuts()
{
KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs");
QString proposedPath = group.readEntry("SaveCustomShortcuts", QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
KoFileDialog dialog(m_dialog, KoFileDialog::SaveFile, "SaveCustomShortcuts");
dialog.setCaption(i18n("Save Shortcuts"));
dialog.setDefaultDir(proposedPath);
dialog.setMimeTypeFilters(QStringList() << "application/x-krita-shortcuts", "application/x-krita-shortcuts");
QString path = dialog.filename();
if (!path.isEmpty()) {
m_dialog->saveCustomShortcuts(path);
}
}
void KShortcutSchemesEditor::loadCustomShortcuts()
{
KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs");
QString proposedPath = group.readEntry("ImportShortcuts", QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
KoFileDialog dialog(m_dialog, KoFileDialog::ImportFile, "ImportShortcuts");
dialog.setCaption(i18n("Import Shortcuts"));
dialog.setDefaultDir(proposedPath);
dialog.setMimeTypeFilters(QStringList() << "application/x-krita-shortcuts", "application/x-krita-shortcuts");
QString path = dialog.filename();
if (path.isEmpty()) {
return;
}
// auto ar = KisActionRegistry::instance();
// ar->loadCustomShortcuts(path);
m_dialog->loadCustomShortcuts(path);
}
void KShortcutSchemesEditor::importShortcutsScheme()
{
KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs");
QString proposedPath = group.readEntry("ImportShortcuts", QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
KoFileDialog dialog(m_dialog, KoFileDialog::ImportFile, "ImportShortcuts");
dialog.setCaption(i18n("Import Shortcuts"));
dialog.setDefaultDir(proposedPath);
dialog.setMimeTypeFilters(QStringList() << "application/x-krita-shortcuts", "application/x-krita-shortcuts");
QString path = dialog.filename();
if (path.isEmpty()) {
return;
}
m_dialog->importConfiguration(path);
}
#if 0
// XXX: Not implemented
void KShortcutSchemesEditor::saveAsDefaultsForScheme()
{
foreach (KActionCollection *collection, m_dialog->actionCollections()) {
KShortcutSchemesHelper::exportActionCollection(collection, currentScheme());
}
}
#endif
void KShortcutSchemesEditor::updateDeleteButton()
{
m_deleteScheme->setEnabled(m_schemesList->count() >= 1);
}
diff --git a/packaging/macos/osxbuild.sh b/packaging/macos/osxbuild.sh
index 51319d2af2..2cab60b771 100755
--- a/packaging/macos/osxbuild.sh
+++ b/packaging/macos/osxbuild.sh
@@ -1,682 +1,686 @@
#!/usr/bin/env bash
# osxbuild.sh automates building and installing of krita and krita dependencies
# for OSX, the script only needs you to set BUILDROOT environment to work
# properly.
#
# Run with no args for a short help about each command.
# builddeps: Attempts to build krita dependencies in the necessary order,
# intermediate steps for creating symlinks and fixing rpath of some
# packages midway is also managed. Order goes from top to bottom, to add
# new steps just place them in the proper place.
# rebuilddeps: This re-runs all make and make install of dependencies 3rdparty
# this was needed as deleting the entire install directory an rerunning build
# step for dependencies does not install if they are already built. This step
# forces installation. Have not tested it lately so it might not be needed anymore
# build: Runs cmake build and make step for krita sources. It always run cmake step, so
# it might take a bit longer than a pure <make> on the source tree. The script tries
# to set the make flag -jN to a proper N.
# install: Runs install step for krita sources.
# fixboost: Search for all libraries using boost and sets a proper @rpath for boost as by
# default it fails to set a proper @rpath
# buildinstall: Runs build, install and fixboost steps.#
if test -z $BUILDROOT; then
echo "ERROR: BUILDROOT env not set, exiting!"
echo "\t Must point to the root of the buildfiles as stated in 3rdparty Readme"
exit
fi
+
+BUILDROOT="${BUILDROOT%/}"
echo "BUILDROOT set to ${BUILDROOT}"
# Set some global variables.
OSXBUILD_TYPE="RelWithDebInfo"
OSXBUILD_TESTING="OFF"
# -- Parse input args
for arg in "${@}"; do
if [[ "${arg}" = --dirty ]]; then
OSXBUILD_CLEAN="keep dirty"
- fi
-
- if [[ "${arg}" = --debug ]]; then
+ elif [[ "${arg}" = --debug ]]; then
OSXBUILD_TYPE="Debug"
OSXBUILD_TESTING="ON"
+ else
+ parsed_args="${parsed_args} ${arg}"
fi
done
export KIS_SRC_DIR=${BUILDROOT}/krita
export KIS_TBUILD_DIR=${BUILDROOT}/depbuild
export KIS_TDEPINSTALL_DIR=${BUILDROOT}/depinstall
export KIS_DOWN_DIR=${BUILDROOT}/down
export KIS_BUILD_DIR=${BUILDROOT}/kisbuild
export KIS_INSTALL_DIR=${BUILDROOT}/i
# flags for OSX environment
# Qt only supports from 10.12 up, and https://doc.qt.io/qt-5/macos.html#target-platforms warns against setting it lower
export MACOSX_DEPLOYMENT_TARGET=10.12
export QMAKE_MACOSX_DEPLOYMENT_TARGET=10.12
export PATH=${KIS_INSTALL_DIR}/bin:$PATH
export PKG_CONFIG_PATH=${KIS_INSTALL_DIR}/share/pkgconfig:${KIS_INSTALL_DIR}/lib/pkgconfig
export CMAKE_PREFIX_PATH=${KIS_INSTALL_DIR}
export C_INCLUDE_PATH=${KIS_INSTALL_DIR}/include:/usr/include:${C_INCLUDE_PATH}
export CPLUS_INCLUDE_PATH=${KIS_INSTALL_DIR}/include:/usr/include:${CPLUS_INCLUDE_PATH}
export LIBRARY_PATH=${KIS_INSTALL_DIR}/lib:/usr/lib:${LIBRARY_PATH}
# export CPPFLAGS=-I${KIS_INSTALL_DIR}/include
# export LDFLAGS=-L${KIS_INSTALL_DIR}/lib
export FRAMEWORK_PATH=${KIS_INSTALL_DIR}/lib/
# export PYTHONHOME=${KIS_INSTALL_DIR}
# export PYTHONPATH=${KIS_INSTALL_DIR}/sip:${KIS_INSTALL_DIR}/lib/python3.8/site-packages:${KIS_INSTALL_DIR}/lib/python3.8
# This will make the debug output prettier
export KDE_COLOR_DEBUG=1
export QTEST_COLORED=1
export OUPUT_LOG="${BUILDROOT}/osxbuild.log"
printf "" > "${OUPUT_LOG}"
# Build time variables
if test -z $(which cmake); then
echo "ERROR: cmake not found, exiting!"
exit
fi
# configure max core for make compile
((MAKE_THREADS=1))
if test ${OSTYPE} == "darwin*"; then
((MAKE_THREADS = $(sysctl -n hw.logicalcpu)))
fi
# Prints stderr and stdout to log files
# >(tee) works but breaks sigint
log_cmd () {
"$@" 1>> ${OUPUT_LOG}
osxbuild_error="${?}"
}
# Log messages to logfile
log () {
printf "%s\n" "${@}" | tee -a ${OUPUT_LOG}
}
# if previous command gives error
# print msg
print_if_error() {
if [ "${osxbuild_error}" -ne 0 ]; then
printf "\nERROR: Printing last lines of log ouput\n\n"
tail ${OUPUT_LOG}
printf "\e[31m%s %s\e[0m\n" "Error:" "${1}"
fi
}
# print status messages
print_msg() {
printf "\e[32m%s\e[0m\n" "${1}"
printf "%s\n" "${1}" >> ${OUPUT_LOG}
}
check_dir_path () {
printf "%s" "Checking if ${1} exists and is dir... "
if test -d ${1}; then
echo -e "OK"
elif test -e ${1}; then
echo -e "\n\tERROR: file ${1} exists but is not a directory!" >&2
return 1
else
echo -e "Creating ${1}"
mkdir ${1}
fi
return 0
}
waiting_fixed() {
local message="${1}"
local waitTime=${2}
for i in $(seq ${waitTime}); do
sleep 1
printf -v dots '%*s' ${i}
printf -v spaces '%*s' $((${waitTime} - $i))
printf "\r%s [%s%s]" "${message}" "${dots// /.}" "${spaces}"
done
printf "\n"
}
dir_clean() {
if [[ -d "${1}" ]]; then
log "Default cleaning build dirs, use --dirty to keep them..."
waiting_fixed "Erase of ${1} in 5 sec" 5
rm -rf "${1}"
fi
}
# builds dependencies for the first time
cmake_3rdparty () {
cd ${KIS_TBUILD_DIR}
local build_pkgs=("${@}") # convert to array
local error="false"
if [[ ${2} = "1" ]]; then
local nofix="true"
local build_pkgs=(${build_pkgs[@]:0:1})
fi
for package in ${build_pkgs[@]} ; do
if [[ ${package:0:3} != "ext" ]]; then
continue
fi
print_msg "Building ${package}"
log_cmd cmake --build . --config RelWithDebInfo --target ${package}
print_if_error "Failed build ${package}"
if [[ ! ${osxbuild_error} -ne 0 ]]; then
print_msg "Build Success! ${package}"
else
log "${pkg} build fail, attempting known fixes..."
error="true"
fi
# fixes does not depend on failure
if [[ ! ${nofix} ]]; then
build_3rdparty_fixes ${package} ${error}
elif [[ "${error}" = "true" ]]; then
log "ERROR: ${pkg} failed a second time, time to check the logs"
log "stoping..."
fi
done
}
build_3rdparty_fixes(){
local pkg=${1}
local error=${2}
if [[ "${pkg}" = "ext_qt" && -e "${KIS_INSTALL_DIR}/bin/qmake" ]]; then
ln -sf qmake "${KIS_INSTALL_DIR}/bin/qmake-qt5"
# build macdeployqt
log_cmd cd "${BUILDROOT}/depbuild/ext_qt/ext_qt-prefix/src/ext_qt/qttools/src"
print_if_error "macdeployqt source dir was not found, it will be missing for deployment!"
if [[ ! ${osxbuild_error} -ne 0 && ! -e "${KIS_INSTALL_DIR}/bin/macdeployqt" ]]; then
make sub-macdeployqt-all
make sub-macdeployqt-install_subtargets
make install
fi
cd "${KIS_TBUILD_DIR}"
error="false"
elif [[ "${pkg}" = "ext_openexr" ]]; then
# open exr will fail the first time is called
# rpath needs to be fixed an build rerun
log "Fixing rpath on openexr file: b44ExpLogTable"
log "Fixing rpath on openexr file: dwaLookups"
log_cmd install_name_tool -add_rpath ${KIS_INSTALL_DIR}/lib $(find ${KIS_TBUILD_DIR}/ext_openexr/ext_openexr-prefix/src/ext_openexr-build -name b44ExpLogTable)
log_cmd install_name_tool -add_rpath ${KIS_INSTALL_DIR}/lib $(find ${KIS_TBUILD_DIR}/ext_openexr/ext_openexr-prefix/src/ext_openexr-build -name dwaLookups)
# we must rerun build!
cmake_3rdparty ext_openexr "1"
error="false"
elif [[ "${pkg}" = "ext_fontconfig" ]]; then
log "fixing rpath on fc-cache"
log_cmd install_name_tool -add_rpath ${KIS_INSTALL_DIR}/lib ${KIS_TBUILD_DIR}/ext_fontconfig/ext_fontconfig-prefix/src/ext_fontconfig-build/fc-cache/.libs/fc-cache
# rerun rebuild
cmake_3rdparty ext_fontconfig "1"
error="false"
elif [[ "${pkg}" = "ext_poppler" && "${error}" = "true" ]]; then
log "re-running poppler to avoid possible glitch"
cmake_3rdparty ext_poppler "1"
error="false"
fi
if [[ "${error}" = "true" ]]; then
log "Error building package ${pkg}, stopping..."
exit
fi
}
build_3rdparty () {
print_msg "building in ${KIS_TBUILD_DIR}"
log "$(check_dir_path ${KIS_TBUILD_DIR})"
log "$(check_dir_path ${KIS_DOWN_DIR})"
log "$(check_dir_path ${KIS_INSTALL_DIR})"
cd ${KIS_TBUILD_DIR}
log_cmd cmake ${KIS_SRC_DIR}/3rdparty/ \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.12 \
-DCMAKE_INSTALL_PREFIX=${KIS_INSTALL_DIR} \
-DCMAKE_PREFIX_PATH:PATH=${KIS_INSTALL_DIR} \
-DEXTERNALS_DOWNLOAD_DIR=${KIS_DOWN_DIR} \
-DINSTALL_ROOT=${KIS_INSTALL_DIR}
# -DCPPFLAGS=-I${KIS_INSTALL_DIR}/include \
# -DLDFLAGS=-L${KIS_INSTALL_DIR}/lib
print_msg "finished 3rdparty build setup"
if [[ -n ${1} ]]; then
cmake_3rdparty "${@}"
# log "Syncing install backup..."
# rsync -a --delete "${KIS_INSTALL_DIR}" "${KIS_INSTALL_DIR}.onlydeps"
exit
fi
# build 3rdparty tools
# The order must not be changed!
cmake_3rdparty \
ext_pkgconfig \
ext_gettext \
ext_openssl \
ext_qt \
ext_zlib \
ext_boost \
ext_eigen3 \
ext_exiv2 \
ext_fftw3 \
ext_ilmbase \
ext_jpeg \
ext_lcms2 \
ext_ocio \
ext_openexr \
ext_openjpeg
cmake_3rdparty \
ext_png \
ext_tiff \
ext_gsl \
ext_vc \
ext_libraw \
ext_giflib \
ext_freetype \
ext_fontconfig \
ext_poppler
# Stop if qmake link was not created
# this meant qt build fail and further builds will
# also fail.
log_cmd test -L "${KIS_INSTALL_DIR}/bin/qmake-qt5"
print_if_error "qmake link missing!"
if [[ ${osxbuild_error} -ne 0 ]]; then
printf "
link: ${KIS_INSTALL_DIR}/bin/qmake-qt5 missing!
It probably means ext_qt failed!!
check, fix and rerun!\n"
exit
fi
# for python
cmake_3rdparty \
ext_python \
ext_sip \
ext_pyqt
cmake_3rdparty ext_libheif
cmake_3rdparty \
ext_extra_cmake_modules \
ext_kconfig \
ext_kwidgetsaddons \
ext_kcompletion \
ext_kcoreaddons \
ext_kguiaddons \
ext_ki18n \
ext_kitemmodels \
ext_kitemviews \
ext_kimageformats \
ext_kwindowsystem \
ext_quazip
## All builds done, creating a new install onlydeps install dir
dir_clean "${KIS_INSTALL_DIR}.onlydeps"
log "Copying ${KIS_INSTALL_DIR} to ${KIS_INSTALL_DIR}.onlydeps"
cp -aP "${KIS_INSTALL_DIR}" "${KIS_INSTALL_DIR}.onlydeps"
print_msg "Build Finished!"
}
# Recall cmake for all 3rd party packages
# make is only on target first run
# subsequent runs only call make install
rebuild_3rdparty () {
print_msg "starting rebuild of 3rdparty packages"
build_install_ext() {
for pkg in ${@:1:${#@}}; do
{
cd ${KIS_TBUILD_DIR}/${pkg}/${pkg}-prefix/src/${pkg}-stamp
} || {
cd ${KIS_TBUILD_DIR}/ext_frameworks/${pkg}-prefix/src/${pkg}-stamp
} || {
cd ${KIS_TBUILD_DIR}/ext_heif/${pkg}-prefix/src/${pkg}-stamp
}
log "Installing ${pkg} files..."
rm ${pkg}-configure ${pkg}-build ${pkg}-install
cmake_3rdparty ${pkg}
cd ${KIS_TBUILD_DIR}
done
}
# Do not process complete list only pkgs given.
if ! test -z ${1}; then
build_install_ext ${@}
exit
fi
build_install_ext \
ext_pkgconfig \
ext_iconv \
ext_gettext \
ext_openssl \
ext_qt \
ext_zlib \
ext_boost \
ext_eigen3 \
ext_expat \
ext_exiv2 \
ext_fftw3 \
ext_ilmbase \
ext_jpeg \
ext_patch \
ext_lcms2 \
ext_ocio \
ext_ilmbase \
ext_openexr
#ext_openjpeg
build_install_ext \
ext_png \
ext_tiff \
ext_gsl \
ext_vc \
ext_libraw \
ext_giflib \
ext_fontconfig \
ext_freetype \
ext_poppler \
ext_python \
ext_sip \
ext_pyqt \
build_install_ext \
ext_nasm \
ext_libx265 \
ext_libde265 \
ext_libheif
# Build kde_frameworks
build_install_ext \
ext_extra_cmake_modules \
ext_kconfig \
ext_kwidgetsaddons \
ext_kcompletion \
ext_kcoreaddons \
ext_kguiaddons \
ext_ki18n \
ext_kitemmodels \
ext_kitemviews \
ext_kimageformats \
ext_kwindowsystem \
ext_quazip
}
#not tested
set_krita_dirs() {
if [[ -n ${1} ]]; then
KIS_BUILD_DIR=${BUILDROOT}/b_${1}
KIS_INSTALL_DIR=${BUILDROOT}/i_${1}
KIS_SRC_DIR=${BUILDROOT}/src_${1}
fi
}
# build_krita
# run cmake krita
build_krita () {
if [[ -z ${OSXBUILD_CLEAN} ]]; then
log "Deleting ${KIS_BUILD_DIR}"
dir_clean "${KIS_BUILD_DIR}"
else
if [[ -e "${KIS_INSTALL_DIR}.onlydeps" && -d "${KIS_INSTALL_DIR}.onlydeps" ]]; then
print_msg "Found ${KIS_INSTALL_DIR}.onlydeps"
log "==== manually copy onlydeps to ${KIS_INSTALL_DIR} if you need a fresh build"
fi
fi
export DYLD_FRAMEWORK_PATH=${FRAMEWORK_PATH}
echo ${KIS_BUILD_DIR}
echo ${KIS_INSTALL_DIR}
log_cmd check_dir_path ${KIS_BUILD_DIR}
cd ${KIS_BUILD_DIR}
cmake ${KIS_SRC_DIR} \
-DFOUNDATION_BUILD=ON \
-DBoost_INCLUDE_DIR=${KIS_INSTALL_DIR}/include \
-DCMAKE_INSTALL_PREFIX=${KIS_INSTALL_DIR} \
-DCMAKE_PREFIX_PATH=${KIS_INSTALL_DIR} \
-DDEFINE_NO_DEPRECATED=1 \
-DBUILD_TESTING=${OSXBUILD_TESTING} \
-DHIDE_SAFE_ASSERTS=ON \
-DKDE_INSTALL_BUNDLEDIR=${KIS_INSTALL_DIR}/bin \
-DPYQT_SIP_DIR_OVERRIDE=${KIS_INSTALL_DIR}/share/sip/ \
-DCMAKE_BUILD_TYPE=${OSXBUILD_TYPE} \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.12 \
-DPYTHON_INCLUDE_DIR=${KIS_INSTALL_DIR}/lib/Python.framework/Headers
# copiling phase
make -j${MAKE_THREADS}
# compile integrations
if test ${OSTYPE} == "darwin*"; then
cd ${KIS_BUILD_DIR}/krita/integration/kritaquicklook
make -j${MAKE_THREADS}
fi
}
build_krita_tarball () {
filename="$(basename ${1})"
KIS_CUSTOM_BUILD="${BUILDROOT}/releases/${filename%.tar.gz}"
print_msg "Tarball BUILDROOT is ${KIS_CUSTOM_BUILD}"
filename_dir=$(dirname "${1}")
cd "${filename_dir}"
file_abspath="$(pwd)/${1##*/}"
mkdir "${KIS_CUSTOM_BUILD}" 2> /dev/null
cd "${KIS_CUSTOM_BUILD}"
mkdir "src" "build" 2> /dev/null
log_cmd tar -xzf "${file_abspath}" --strip-components=1 --directory "src"
print_if_error "Failed untar of ${filename}"
if [[ ${osxbuild_error} -ne 0 ]]; then
exit
fi
KIS_BUILD_DIR="${KIS_CUSTOM_BUILD}/build"
KIS_SRC_DIR="${KIS_CUSTOM_BUILD}/src"
build_krita
print_msg "Build done!"
print_msg "to install run
osxbuild.sh install ${KIS_BUILD_DIR}"
}
install_krita () {
# custom install provided
if [[ -n "${1}" ]]; then
KIS_BUILD_DIR="${1}"
fi
# Delete any "krita" named file in install
# this helps avoid double versioned libraries
log "About to delete krita libs from ${KIS_INSTALL_DIR}"
waiting_fixed "Deleting files in 5 seconds" 5
find ${KIS_INSTALL_DIR} -type d -name "*krita*" | xargs -I FILE rm -rf FILE
find ${KIS_INSTALL_DIR} \( -type f -or -type l \) -name "*krita*" | xargs -P4 -I FILE rm FILE
print_msg "Install krita from ${KIS_BUILD_DIR}"
log_cmd check_dir_path ${KIS_BUILD_DIR}
cd "${KIS_BUILD_DIR}"
osxbuild_error=$?
print_if_error "could not cd to ${KIS_BUILD_DIR}"
if [[ ${osxbuild_error} -ne 0 ]]; then
exit
fi
make install
# compile integrations
if test ${OSTYPE} == "darwin*"; then
cd ${KIS_BUILD_DIR}/krita/integration/kritaquicklook
make install
fi
}
# Runs all fixes for path and packages.
# Historically only fixed boost @rpath
fix_boost_rpath () {
# helpers to define function only once
fixboost_find () {
for FILE in "${@}"; do
if [[ -n "$(otool -L $FILE | grep boost)" ]]; then
log "Fixing -- $FILE"
log_cmd install_name_tool -change libboost_system.dylib @rpath/libboost_system.dylib $FILE
fi
done
}
batch_fixboost() {
xargs -P4 -I FILE bash -c 'fixboost_find "FILE"'
}
export -f fixboost_find
export -f log
export -f log_cmd
print_msg "Fixing boost in... ${KIS_INSTALL_DIR}"
# install_name_tool -add_rpath ${KIS_INSTALL_DIR}/lib $BUILDROOT/$KRITA_INSTALL/bin/krita.app/Contents/MacOS/gmic_krita_qt
log_cmd install_name_tool -add_rpath ${KIS_INSTALL_DIR}/lib ${KIS_INSTALL_DIR}/bin/krita.app/Contents/MacOS/krita
# echo "Added rpath ${KIS_INSTALL_DIR}/lib to krita bin"
# install_name_tool -add_rpath ${BUILDROOT}/deps/lib ${KIS_INSTALL_DIR}/bin/krita.app/Contents/MacOS/krita
log_cmd install_name_tool -change libboost_system.dylib @rpath/libboost_system.dylib ${KIS_INSTALL_DIR}/bin/krita.app/Contents/MacOS/krita
find -L "${KIS_INSTALL_DIR}" -name '*so' -o -name '*dylib' | batch_fixboost
log "Fixing boost done!"
}
get_directory_fromargs() {
local OSXBUILD_DIR=""
for arg in "${@}"; do
if [[ -d "${arg}" ]]; then
OSXBUILD_DIR="${arg}"
continue
fi
done
echo "${OSXBUILD_DIR}"
}
print_usage () {
printf "USAGE: osxbuild.sh <buildstep> [pkg|file]\n"
printf "BUILDSTEPS:\t\t"
printf "\n builddeps \t\t Run cmake step for 3rd party dependencies, optionally takes a [pkg] arg"
printf "\n rebuilddeps \t\t Rerun make and make install step for 3rd party deps, optionally takes a [pkg] arg
\t\t\t useful for cleaning install directory and quickly reinstall all deps."
printf "\n fixboost \t\t Fixes broken boost \@rpath on OSX"
printf "\n build \t\t\t Builds krita"
printf "\n buildtarball \t\t Builds krita from provided [file] tarball"
printf "\n clean \t\t\t Removes build and install directories to start fresh"
printf "\n install \t\t Installs krita. Optionally accepts a [build dir] as argument
\t\t\t this will install krita from given directory"
printf "\n buildinstall \t\t Build and Installs krita, running fixboost after installing"
printf "\n"
printf "OPTIONS:\t\t"
printf "\n \t --dirty \t [build] (old default) Keep old build directories before build to start fresh"
printf "\n"
}
-if [[ ${#} -eq 0 ]]; then
- echo "ERROR: No option given!"
- print_usage
- exit 1
-fi
-
-if [[ ${1} = "builddeps" ]]; then
- if [[ -z ${OSXBUILD_CLEAN} ]]; then
- dir_clean "${KIS_INSTALL_DIR}"
- dir_clean "${KIS_TBUILD_DIR}"
+script_run() {
+ if [[ ${#} -eq 0 ]]; then
+ echo "ERROR: No option given!"
+ print_usage
+ exit 1
fi
- build_3rdparty "${@:2}"
- exit
-elif [[ ${1} = "rebuilddeps" ]]; then
- rebuild_3rdparty "${@:2}"
- exit
+ if [[ ${1} = "builddeps" ]]; then
+ if [[ -z ${OSXBUILD_CLEAN} ]]; then
+ dir_clean "${KIS_INSTALL_DIR}"
+ dir_clean "${KIS_TBUILD_DIR}"
+ fi
+ build_3rdparty "${@:2}"
+ exit
-elif [[ ${1} = "fixboost" ]]; then
- if [[ -d ${1} ]]; then
- KIS_BUILD_DIR="${1}"
- fi
- fix_boost_rpath
+ elif [[ ${1} = "rebuilddeps" ]]; then
+ rebuild_3rdparty "${@:2}"
+ exit
-elif [[ ${1} = "build" ]]; then
- OSXBUILD_DIR=$(get_directory_fromargs "${@}")
+ elif [[ ${1} = "fixboost" ]]; then
+ if [[ -d ${1} ]]; then
+ KIS_BUILD_DIR="${1}"
+ fi
+ fix_boost_rpath
- build_krita "${OSXBUILD_DIR}"
- exit
+ elif [[ ${1} = "build" ]]; then
+ OSXBUILD_DIR=$(get_directory_fromargs "${@}")
-elif [[ ${1} = "buildtarball" ]]; then
- # uncomment line to optionally change
- # install directory providing a third argument
- # This is not on by default as build success requires all
- # deps installed in the given dir beforehand.
- # KIS_INSTALL_DIR=${3}
- OSXBUILD_DIR=$(get_directory_fromargs "${@}")
-
- build_krita_tarball "${OSXBUILD_DIR}"
-
-elif [[ ${1} = "clean" ]]; then
- # remove all build and install directories to start
- # a fresh install. this no different than using rm directly
- dir_clean "${KIS_TBUILD_DIR}"
- dir_clean "${$KIS_BUILD_DIR}"
- dir_clean "${KIS_INSTALL_DIR}"
- exit
+ build_krita "${OSXBUILD_DIR}"
+ exit
-elif [[ ${1} = "install" ]]; then
- OSXBUILD_DIR=$(get_directory_fromargs "${@}")
+ elif [[ ${1} = "buildtarball" ]]; then
+ # uncomment line to optionally change
+ # install directory providing a third argument
+ # This is not on by default as build success requires all
+ # deps installed in the given dir beforehand.
+ # KIS_INSTALL_DIR=${3}
+ OSXBUILD_DIR=$(get_directory_fromargs "${@}")
- install_krita "${OSXBUILD_DIR}"
- fix_boost_rpath
+ build_krita_tarball "${OSXBUILD_DIR}"
-elif [[ ${1} = "buildinstall" ]]; then
- OSXBUILD_DIR=$(get_directory_fromargs "${@}")
+ elif [[ ${1} = "clean" ]]; then
+ # remove all build and install directories to start
+ # a fresh install. this no different than using rm directly
+ dir_clean "${KIS_TBUILD_DIR}"
+ dir_clean "${$KIS_BUILD_DIR}"
+ dir_clean "${KIS_INSTALL_DIR}"
+ exit
- build_krita "${OSXBUILD_DIR}"
- install_krita "${OSXBUILD_DIR}"
- fix_boost_rpath "${OSXBUILD_DIR}"
+ elif [[ ${1} = "install" ]]; then
+ OSXBUILD_DIR=$(get_directory_fromargs "${@}")
-elif [[ ${1} = "test" ]]; then
- ${KIS_INSTALL_DIR}/bin/krita.app/Contents/MacOS/krita
+ install_krita "${OSXBUILD_DIR}"
+ fix_boost_rpath
-else
- echo "Option ${1} not supported"
- print_usage
- exit 1
-fi
+ elif [[ ${1} = "buildinstall" ]]; then
+ OSXBUILD_DIR=$(get_directory_fromargs "${@}")
+
+ build_krita "${OSXBUILD_DIR}"
+ install_krita "${OSXBUILD_DIR}"
+ fix_boost_rpath "${OSXBUILD_DIR}"
+
+ elif [[ ${1} = "test" ]]; then
+ ${KIS_INSTALL_DIR}/bin/krita.app/Contents/MacOS/krita
+
+ else
+ echo "Option ${1} not supported"
+ print_usage
+ exit 1
+ fi
+}
-# after finishig sometimes it complains about missing matching quotes.
+script_run ${parsed_args}
diff --git a/packaging/macos/osxdeploy.sh b/packaging/macos/osxdeploy.sh
index 47fc7a9686..312f73fa8b 100755
--- a/packaging/macos/osxdeploy.sh
+++ b/packaging/macos/osxdeploy.sh
@@ -1,768 +1,770 @@
#!/usr/bin/env bash
# Krita tool to create dmg from installed source
# Copies all files to a folder to be converted into the final dmg
# osxdeploy.sh automates the creation of the release DMG.
# default background and style are used if none provided
# A short explanation of what it does:
# - Copies krita.app contents to kritadmg folder
# - Copies i/share to Contents/Resources excluding unnecessary files
# - Copies translations, qml and quicklook PlugIns
# - Copies i/plugins and i/lib/plugins to Contents/PlugIns
# - Runs macdeployqt: macdeployqt is not built by default in ext_qt
# build by:
# cd ${BUILDROOT}/depbuild/ext_qt/ext_qt-prefix/src/ext_qt/qttools/src
# make sub-macdeployqt-all
# make sub-macdeployqt-install_subtargets
# make install
# the script changes dir to installation/bin to run macdeployqt as it can be buggy
# if not run from the same folder as the binary is on.
# - Fix rpath from krita bin
# - Find missing libraries from plugins and copy to Frameworks or plugins.
# This uses oTool iterative to find all unique libraries, then it searches each
# library fond in <kritadmg> folder, and if not found attempts to copy contents
# to the appropriate folder, either Frameworks (if frameworks is in namefile, or
# library has plugin isnot in path), or plugin if otherwise.
# - Builds DMG
# Building DMG creates a new dmg with the contents of <kritadmg>
# mounts the dmg and sets the style for dmg.
# unmount
# Compress resulting dmg into krita_nightly-<gitsha>.dmg
# deletes temporary files.
if test -z ${BUILDROOT}; then
echo "ERROR: BUILDROOT env not set!"
echo "\t Must point to the root of the buildfiles as stated in 3rdparty Readme"
echo "exiting..."
exit
fi
+BUILDROOT="${BUILDROOT%/}"
+
# print status messages
print_msg() {
printf "\e[32m${1}\e[0m\n" "${@:2}"
# printf "%s\n" "${1}" >> ${OUPUT_LOG}
}
# print error
print_error() {
printf "\e[31m%s %s\e[0m\n" "Error:" "${1}"
}
get_script_dir() {
script_source="${BASH_SOURCE[0]}"
# go to target until finding root.
while [ -L "${script_source}" ]; do
script_target="$(readlink ${script_source})"
if [[ "${script_source}" = /* ]]; then
script_source="$script_target"
else
script_dir="$(dirname "${script_source}")"
script_source="${script_dir}/${script_target}"
fi
done
echo "$(dirname ${script_source})"
}
DMG_title="krita" #if changed krita.temp.dmg must be deleted manually
SCRIPT_SOURCE_DIR="$(get_script_dir)"
# There is some duplication between build and deploy scripts
# a config env file could would be a nice idea.
KIS_SRC_DIR=${BUILDROOT}/krita
KIS_INSTALL_DIR=${BUILDROOT}/i
KIS_BUILD_DIR=${BUILDROOT}/kisbuild # only used for getting git sha number
KRITA_DMG=${BUILDROOT}/kritadmg
KRITA_DMG_TEMPLATE=${BUILDROOT}/kritadmg-template
export PATH=${KIS_INSTALL_DIR}/bin:$PATH
# flags for OSX environment
# We only support from 10.11 up
export MACOSX_DEPLOYMENT_TARGET=10.11
export QMAKE_MACOSX_DEPLOYMENT_TARGET=10.11
print_usage () {
printf "USAGE:
osxdeploy.sh [-s=<identity>] [-notarize-ac=<apple-account>] [-style=<style.txt>] [-bg=<background-image>]
-s \t\t\t Code sign identity for codesign
-notarize-ac \t Apple account name for notarization purposes
\t\t\t script will attempt to get password from keychain, if fails provide one with
\t\t\t the -notarize-pass option: To add a password run
\t\t\t security add-generic-password -a \"AC_USERNAME\" -w <secret_password> -s \"AC_PASSWORD\"
-notarize-pass \t If given, the Apple account password. Otherwise an attempt will be macdeployqt_exists
\t\t\t to get the password from keychain using the account given in <notarize-ac> option.
-asc-provider \t some AppleIds might need this option pass the <shortname>
-style \t\t Style file defined from 'dmgstyle.sh' output
-bg \t\t Set a background image for dmg folder.
-name \t\t Set the DMG name output.
\t\t\t osxdeploy needs an input image to attach to the dmg background
\t\t\t image recommended size is at least 950x500
"
}
# Attempt to detach previous mouted DMG
if [[ -d "/Volumes/${DMG_title}" ]]; then
echo "WARNING: Another Krita DMG is mounted!"
echo "Attempting eject…"
hdiutil detach "/Volumes/${DMG_title}"
if [ $? -ne 0 ]; then
exit
fi
echo "Success!"
fi
# -- Parse input args
for arg in "${@}"; do
if [ "${arg}" = -bg=* -a -f "${arg#*=}" ]; then
DMG_validBG=0
bg_filename=${arg#*=}
echo "attempting to check background is valid jpg or png..."
BG_FORMAT=$(sips --getProperty format ${bg_filename} | awk '{printf $2}')
if [[ "png" = ${BG_FORMAT} || "jpeg" = ${BG_FORMAT} ]];then
echo "valid image file"
DMG_background=$(cd "$(dirname "${bg_filename}")"; pwd -P)/$(basename "${bg_filename}")
DMG_validBG=1
# check imageDPI
BG_DPI=$(sips --getProperty dpiWidth ${DMG_background} | grep dpi | awk '{print $2}')
if [[ $(echo "${BG_DPI} > 150" | bc -l) -eq 1 ]]; then
printf "WARNING: image dpi has an effect on apparent size!
Check dpi is adequate for screen display if image appears very small
Current dpi is: %s\n" ${BG_DPI}
fi
fi
fi
# If string starts with -sign
if [[ ${arg} = -s=* ]]; then
CODE_SIGNATURE="${arg#*=}"
fi
if [[ ${arg} = -name=* ]]; then
DMG_NAME="${arg#*=}"
fi
if [[ ${arg} = -notarize-ac=* ]]; then
NOTARIZE_ACC="${arg#*=}"
fi
if [[ ${arg} = -notarize-pass=* ]]; then
NOTARIZE_PASS="${arg#*=}"
fi
if [[ ${arg} = -style=* ]]; then
style_filename="${arg#*=}"
if [[ -f "${style_filename}" ]]; then
DMG_STYLE="${style_filename}"
fi
fi
if [[ ${arg} = -asc-provider=* ]]; then
ASC_PROVIDER="${arg#*=}"
fi
if [[ ${arg} = "-h" || ${arg} = "--help" ]]; then
print_usage
exit
fi
done
# -- Checks and messages
### PYTHONAttempt to find python_version
local_PY_MAYOR_VERSION=$(python -c "import sys; print(sys.version_info[0])")
local_PY_MINOR_VERSION=$(python -c "import sys; print(sys.version_info[1])")
PY_VERSION="${local_PY_MAYOR_VERSION}.${local_PY_MINOR_VERSION}"
print_msg "Detected Python %s" "${PY_VERSION}"
### Code Signature & NOTARIZATION
NOTARIZE="false"
if [[ -z "${CODE_SIGNATURE}" ]]; then
echo "WARNING: No code signature provided, Code will not be signed"
else
print_msg "Code will be signed with %s" "${CODE_SIGNATURE}"
### NOTARIZATION
if [[ -n "${NOTARIZE_ACC}" ]]; then
ASC_PROVIDER_OP=""
if [[ -n "${ASC_PROVIDER}" ]]; then
ASC_PROVIDER_OP="--asc-provider ${ASC_PROVIDER}"
fi
if [[ -z "${NOTARIZE_PASS}" ]]; then
NOTARIZE_PASS="@keychain:AC_PASSWORD"
fi
# check if we can perform notarization
xcrun altool --notarization-history 0 --username "${NOTARIZE_ACC}" --password "${NOTARIZE_PASS}" ${ASC_PROVIDER_OP} 1> /dev/null
if [[ ${?} -eq 0 ]]; then
NOTARIZE="true"
else
echo "No password given for notarization or AC_PASSWORD missig in keychain"
fi
fi
fi
if [[ ${NOTARIZE} = "true" ]]; then
print_msg "Notarization checks complete, This build will be notarized"
else
echo "WARNING: Account information missing, Notarization will not be performed"
fi
### STYLE for DMG
if [[ ! ${DMG_STYLE} ]]; then
DMG_STYLE="${SCRIPT_SOURCE_DIR}/default.style"
fi
print_msg "Using style from: %s" "${DMG_STYLE}"
### Background for DMG
if [[ ${DMG_validBG} -eq 0 ]]; then
echo "No jpg or png valid file detected!!"
echo "Using default style"
DMG_background="${SCRIPT_SOURCE_DIR}/krita_dmgBG.jpg"
fi
# Helper functions
countArgs () {
echo "${#}"
}
stringContains () {
echo "$(grep "${2}" <<< "${1}")"
}
waiting_fixed() {
local message="${1}"
local waitTime=${2}
for i in $(seq ${waitTime}); do
sleep 1
printf -v dots '%*s' ${i}
printf -v spaces '%*s' $((${waitTime} - $i))
printf "\r%s [%s%s]" "${message}" "${dots// /.}" "${spaces}"
done
printf "\n"
}
add_lib_to_list() {
local llist=${2}
if test -z "$(grep ${1##*/} <<< ${llist})" ; then
local llist="${llist} ${1##*/} "
fi
echo "${llist}"
}
# Find all @rpath and Absolute to buildroot path libs
# Add to libs_used
# converts absolute buildroot path to @rpath
find_needed_libs () {
# echo "Analyzing libraries with oTool..." >&2
local libs_used="" # input lib_lists founded
for libFile in ${@}; do
if test -z "$(file ${libFile} | grep 'Mach-O')" ; then
# echo "skipping ${libFile}" >&2
continue
fi
oToolResult=$(otool -L ${libFile} | awk '{print $1}')
resultArray=(${oToolResult}) # convert to array
for lib in ${resultArray[@]:1}; do
if test "${lib:0:1}" = "@"; then
local libs_used=$(add_lib_to_list "${lib}" "${libs_used}")
fi
if [[ "${lib:0:${#BUILDROOT}}" = "${BUILDROOT}" ]]; then
printf "Fixing %s: %s\n" "${libFile#${KRITA_DMG}/}" "${lib##*/}" >&2
if [[ "${lib##*/}" = "${libFile##*/}" ]]; then
install_name_tool -id ${lib##*/} "${libFile}"
else
install_name_tool -change ${lib} "@rpath/${lib##*/i/lib/}" "${libFile}"
local libs_used=$(add_lib_to_list "${lib}" "${libs_used}")
fi
fi
done
done
echo "${libs_used}" # return updated list
}
find_missing_libs (){
# echo "Searching for missing libs on deployment folders…" >&2
local libs_missing=""
for lib in ${@}; do
if test -z "$(find ${KRITA_DMG}/krita.app/Contents/ -name ${lib})"; then
# echo "Adding ${lib} to missing libraries." >&2
libs_missing="${libs_missing} ${lib}"
fi
done
echo "${libs_missing}"
}
copy_missing_libs () {
for lib in ${@}; do
result=$(find -L "${BUILDROOT}/i" -name "${lib}")
if test $(countArgs ${result}) -eq 1; then
if [ "$(stringContains "${result}" "plugin")" ]; then
cp -pv ${result} ${KRITA_DMG}/krita.app/Contents/PlugIns/
krita_findmissinglibs "${KRITA_DMG}/krita.app/Contents/PlugIns/${result##*/}"
else
cp -pv ${result} ${KRITA_DMG}/krita.app/Contents/Frameworks/
krita_findmissinglibs "${KRITA_DMG}/krita.app/Contents/Frameworks/${result##*/}"
fi
else
echo "${lib} might be a missing framework"
if [ "$(stringContains "${result}" "framework")" ]; then
echo "copying framework ${BUILDROOT}/i/lib/${lib}.framework to dmg"
# rsync only included ${lib} Resources Versions
rsync -priul ${BUILDROOT}/i/lib/${lib}.framework/${lib} ${KRITA_DMG}/krita.app/Contents/Frameworks/${lib}.framework/
rsync -priul ${BUILDROOT}/i/lib/${lib}.framework/Resources ${KRITA_DMG}/krita.app/Contents/Frameworks/${lib}.framework/
rsync -priul ${BUILDROOT}/i/lib/${lib}.framework/Versions ${KRITA_DMG}/krita.app/Contents/Frameworks/${lib}.framework/
krita_findmissinglibs "$(find "${KRITA_DMG}/krita.app/Contents/Frameworks/${lib}.framework/" -type f -perm 755)"
fi
fi
done
}
krita_findmissinglibs() {
neededLibs=$(find_needed_libs "${@}")
missingLibs=$(find_missing_libs ${neededLibs})
if test $(countArgs ${missingLibs}) -gt 0; then
printf "Found missing libs: %s\n" "${missingLibs}"
copy_missing_libs ${missingLibs}
fi
}
strip_python_dmginstall() {
# reduce size of framework python
# Removes tests, installers, pyenv, distutils
echo "Removing unnecessary files from Python.Framework to be packaged..."
PythonFrameworkBase="${KRITA_DMG}/krita.app/Contents/Frameworks/Python.framework"
cd "${PythonFrameworkBase}"
find . -name "test*" -type d | xargs rm -rf
find "${PythonFrameworkBase}/Versions/${PY_VERSION}/bin" -not -name "python*" \( -type f -or -type l \) | xargs rm -f
cd "${PythonFrameworkBase}/Versions/${PY_VERSION}/lib/python${PY_VERSION}"
rm -rf distutils tkinter ensurepip venv lib2to3 idlelib turtledemo
cd "${PythonFrameworkBase}/Versions/${PY_VERSION}/Resources"
rm -rf Python.app
}
-# Some libraries require r_path to be removed
-# we must not apply delete rpath globally
-delete_install_rpath() {
- xargs -P4 -I FILE install_name_tool -delete_rpath "${BUILDROOT}/i/lib" FILE 2> "${BUILDROOT}/deploy_error.log"
-}
-
# Remove any missing rpath poiting to BUILDROOT
libs_clean_rpath () {
for libFile in ${@}; do
- rpath=$(otool -l "${libFile}" | grep "${BUILDROOT}/i/lib" | awk '{$1=$1;print $2}')
+ rpath=$(otool -l "${libFile}" | grep "path ${BUILDROOT}" | awk '{$1=$1;print $2}')
if [[ -n "${rpath}" ]]; then
echo "removed rpath _${rpath}_ from ${libFile}"
install_name_tool -delete_rpath "${rpath}" "${libFile}"
fi
done
}
+# Multhread version
+# of libs_clean_rpath, but makes assumptions
+delete_install_rpath() {
+ xargs -P4 -I FILE install_name_tool -delete_rpath "${BUILDROOT}/i/lib" FILE 2> "${BUILDROOT}/deploy_error.log"
+}
+
fix_python_framework() {
# Fix python.framework rpath and slims down installation
PythonFrameworkBase="${KRITA_DMG}/krita.app/Contents/Frameworks/Python.framework"
# Fix permissions
find "${PythonFrameworkBase}" -name "*.so" | xargs -P4 -I FILE chmod a+x FILE 2> "${BUILDROOT}/deploy_error.log"
cd "${PythonFrameworkBase}/Versions/${PY_VERSION}/lib/python${PY_VERSION}"
chmod a+x pydoc.py
# Fix main library
pythonLib="${PythonFrameworkBase}/Python"
install_name_tool -id "${pythonLib##*/}" "${pythonLib}"
install_name_tool -add_rpath @loader_path/../../../ "${pythonLib}" 2> /dev/null
install_name_tool -change @loader_path/../../../../libintl.9.dylib @loader_path/../../../libintl.9.dylib "${pythonLib}"
# Fix all executables
install_name_tool -add_rpath @executable_path/../../../../../../../ "${PythonFrameworkBase}/Versions/Current/Resources/Python.app/Contents/MacOS/Python"
install_name_tool -change "${KIS_INSTALL_DIR}/lib/Python.framework/Versions/${PY_VERSION}/Python" @executable_path/../../../../../../Python "${PythonFrameworkBase}/Versions/Current/Resources/Python.app/Contents/MacOS/Python"
install_name_tool -add_rpath @executable_path/../../../../ "${PythonFrameworkBase}/Versions/Current/bin/python${PY_VERSION}"
install_name_tool -add_rpath @executable_path/../../../../ "${PythonFrameworkBase}/Versions/Current/bin/python${PY_VERSION}m"
# Fix rpaths from Python.Framework
find "${PythonFrameworkBase}" -type f -perm 755 | delete_install_rpath
find "${PythonFrameworkBase}/Versions/Current/site-packages/PyQt5" -type f -name "*.so" | delete_install_rpath
}
# Checks for macdeployqt
# If not present attempts to install
# If it fails shows an informatve message
# (For now, macdeployqt is fundamental to deploy)
macdeployqt_exists() {
printf "Checking for macdeployqt... "
if [[ ! -e "${KIS_INSTALL_DIR}/bin/macdeployqt" ]]; then
printf "Not Found!\n"
printf "Attempting to install macdeployqt\n"
- cd ${BUILDROOT}/depbuild/ext_qt/ext_qt-prefix/src/ext_qt/qttools/src
+ cd "${BUILDROOT}/depbuild/ext_qt/ext_qt-prefix/src/ext_qt/qttools/src"
make sub-macdeployqt-all
make sub-macdeployqt-install_subtargets
make install
if [[ ! -e "${KIS_INSTALL_DIR}/bin/macdeployqt" ]]; then
printf "
ERROR: Failed to install macdeployqt!
Compile and install from qt source directory
Source code to build could be located in qttools/src in qt source dir:
${BUILDROOT}/depbuild/ext_qt/ext_qt-prefix/src/ext_qt/qttools/src
From the source dir, build and install:
make sub-macdeployqt-all
make sub-macdeployqt-install_subtargets
make install
"
printf "\nexiting...\n"
exit
else
echo "Done!"
fi
else
echo "Found!"
fi
}
krita_deploy () {
# check for macdeployqt
macdeployqt_exists
cd ${BUILDROOT}
# Update files in krita.app
echo "Deleting previous kritadmg run..."
rm -rf ./krita.dmg ${KRITA_DMG}
# Copy new builtFiles
echo "Preparing ${KRITA_DMG} for deployment..."
echo "Copying krita.app..."
mkdir "${KRITA_DMG}"
rsync -prul ${KIS_INSTALL_DIR}/bin/krita.app ${KRITA_DMG}
mkdir -p ${KRITA_DMG}/krita.app/Contents/PlugIns
mkdir -p ${KRITA_DMG}/krita.app/Contents/Frameworks
echo "Copying share..."
# Deletes old copies of translation and qml to be recreated
cd ${KIS_INSTALL_DIR}/share/
rsync -prul --delete ./ \
--exclude krita_SRCS.icns \
--exclude aclocal \
--exclude doc \
--exclude ECM \
--exclude eigen3 \
--exclude emacs \
--exclude gettext \
--exclude gettext-0.19.8 \
--exclude info \
--exclude kf5 \
--exclude kservices5 \
--exclude man \
--exclude ocio \
--exclude pkgconfig \
--exclude mime \
--exclude translations \
--exclude qml \
${KRITA_DMG}/krita.app/Contents/Resources
cd ${BUILDROOT}
echo "Copying translations..."
rsync -prul ${KIS_INSTALL_DIR}/translations/ \
${KRITA_DMG}/krita.app/Contents/Resources/translations
echo "Copying kritaquicklook..."
mkdir -p ${KRITA_DMG}/krita.app/Contents/Library/QuickLook
rsync -prul ${KIS_INSTALL_DIR}/plugins/kritaquicklook.qlgenerator ${KRITA_DMG}/krita.app/Contents/Library/QuickLook
cd ${KRITA_DMG}/krita.app/Contents
ln -shF Resources share
echo "Copying qml..."
rsync -prul ${KIS_INSTALL_DIR}/qml Resources/qml
echo "Copying plugins..."
# exclude kritaquicklook.qlgenerator/
cd ${KIS_INSTALL_DIR}/plugins/
rsync -prul --delete --delete-excluded ./ \
--exclude kritaquicklook.qlgenerator \
${KRITA_DMG}/krita.app/Contents/PlugIns
cd ${BUILDROOT}
rsync -prul ${KIS_INSTALL_DIR}/lib/kritaplugins/ ${KRITA_DMG}/krita.app/Contents/PlugIns
# rsync -prul {KIS_INSTALL_DIR}/lib/libkrita* Frameworks/
# To avoid errors macdeployqt must be run from bin location
# ext_qt will not build macdeployqt by default so it must be build manually
# cd ${BUILDROOT}/depbuild/ext_qt/ext_qt-prefix/src/ext_qt/qttools/src
# make sub-macdeployqt-all
# make sub-macdeployqt-install_subtargets
# make install
echo "Running macdeployqt..."
cd ${KIS_INSTALL_DIR}/bin
./macdeployqt ${KRITA_DMG}/krita.app \
-verbose=0 \
-executable=${KRITA_DMG}/krita.app/Contents/MacOS/krita \
-libpath=${KIS_INSTALL_DIR}/lib \
-qmldir=${KIS_INSTALL_DIR}/qml \
# -extra-plugins=${KIS_INSTALL_DIR}/lib/kritaplugins \
# -extra-plugins=${KIS_INSTALL_DIR}/lib/plugins \
# -extra-plugins=${KIS_INSTALL_DIR}/plugins
cd ${BUILDROOT}
echo "macdeployqt done!"
echo "Copying python..."
# Copy this framework last!
# It is best that macdeployqt does not modify Python.framework
# folders with period in name are treated as Frameworks for codesign
rsync -prul ${KIS_INSTALL_DIR}/lib/Python.framework ${KRITA_DMG}/krita.app/Contents/Frameworks/
rsync -prul ${KIS_INSTALL_DIR}/lib/krita-python-libs ${KRITA_DMG}/krita.app/Contents/Frameworks/
# change perms on Python to allow header change
chmod +w ${KRITA_DMG}/krita.app/Contents/Frameworks/Python.framework/Python
fix_python_framework
strip_python_dmginstall
# fix python pyc
# precompile all pyc so the dont alter signature
echo "Precompiling all python files..."
cd ${KRITA_DMG}/krita.app
${KIS_INSTALL_DIR}/bin/python -m compileall . &> /dev/null
install_name_tool -delete_rpath @loader_path/../../../../lib ${KRITA_DMG}/krita.app/Contents/MacOS/krita
rm -rf ${KRITA_DMG}/krita.app/Contents/PlugIns/kf5/org.kde.kwindowsystem.platforms
# Fix permissions
find "${KRITA_DMG}/krita.app/Contents" -type f -name "*.dylib" -or -name "*.so" | xargs -P4 -I FILE chmod a+x FILE
find "${KRITA_DMG}/krita.app/Contents/Resources/applications" -name "*.desktop" | xargs -P4 -I FILE chmod a-x FILE
# repair krita for plugins
printf "Searching for missing libraries\n"
krita_findmissinglibs $(find ${KRITA_DMG}/krita.app/Contents -type f -perm 755 -or -name "*.dylib" -or -name "*.so")
printf "removing absolute or broken linksys, if any\n"
find "${KRITA_DMG}/krita.app/Contents" -type l \( -lname "/*" -or -not -exec test -e {} \; \) -print | xargs rm
printf "clean any left over rpath\n"
libs_clean_rpath $(find "${KRITA_DMG}/krita.app/Contents" -type f -perm 755 -or -name "*.dylib" -or -name "*.so")
- find "${KRITA_DMG}/krita.app/Contents/Frameworks/" -type f -name "lib*" | delete_install_rpath
+# libs_clean_rpath $(find "${KRITA_DMG}/krita.app/Contents/" -type f -name "lib*")
echo "Done!"
}
# helper to define function only once
batch_codesign() {
xargs -P4 -I FILE codesign --options runtime --timestamp -f -s "${CODE_SIGNATURE}" --entitlements "${KIS_SRC_DIR}/packaging/macos/entitlements.plist" FILE
}
# Code sign must be done as recommended by apple "sign code inside out in individual stages"
signBundle() {
cd ${KRITA_DMG}
# sign Frameworks and libs
cd ${KRITA_DMG}/krita.app/Contents/Frameworks
# remove debug version as both versions can't be signed.
rm ${KRITA_DMG}/krita.app/Contents/Frameworks/QtScript.framework/Versions/Current/QtScript_debug
find . -type f -perm 755 -or -name "*.dylib" -or -name "*.so" | batch_codesign
find . -type d -name "*.framework" | xargs printf "%s/Versions/Current\n" | batch_codesign
# Sign all other files in Framework (needed)
# there are many files in python do we need to sign them all?
find krita-python-libs -type f | batch_codesign
# find python -type f | batch_codesign
# Sign only libraries and plugins
cd ${KRITA_DMG}/krita.app/Contents/PlugIns
find . -type f | batch_codesign
cd ${KRITA_DMG}/krita.app/Contents/Library/QuickLook
printf "kritaquicklook.qlgenerator" | batch_codesign
# It is recommended to sign every Resource file
cd ${KRITA_DMG}/krita.app/Contents/Resources
find . -type f | batch_codesign
#Finally sign krita and krita.app
printf "${KRITA_DMG}/krita.app/Contents/MacOS/krita" | batch_codesign
printf "${KRITA_DMG}/krita.app" | batch_codesign
}
# Notarize build on macOS servers
# based on https://github.com/Beep6581/RawTherapee/blob/6fa533c40b34dec527f1176d47cc6c683422a73f/tools/osx/macosx_bundle.sh#L225-L250
notarize_build() {
local NOT_SRC_DIR=${1}
local NOT_SRC_FILE=${2}
if [[ ${NOTARIZE} = "true" ]]; then
printf "performing notarization of %s\n" "${2}"
cd "${NOT_SRC_DIR}"
ditto -c -k --sequesterRsrc --keepParent "${NOT_SRC_FILE}" "${BUILDROOT}/tmp_notarize/${NOT_SRC_FILE}.zip"
# echo "xcrun altool --notarize-app --primary-bundle-id \"org.krita\" --username \"${NOTARIZE_ACC}\" --password \"${NOTARIZE_PASS}\" --file \"${BUILDROOT}/tmp_notarize/${NOT_SRC_FILE}.zip\""
local altoolResponse="$(xcrun altool --notarize-app --primary-bundle-id "org.krita" --username "${NOTARIZE_ACC}" --password "${NOTARIZE_PASS}" ${ASC_PROVIDER_OP} --file "${BUILDROOT}/tmp_notarize/${NOT_SRC_FILE}.zip" 2>&1)"
if [[ -n "$(grep 'Error' <<< ${altoolResponse})" ]]; then
printf "ERROR: xcrun altool exited with the following error! \n\n%s\n\n" "${altoolResponse}"
printf "This could mean there is an error in AppleID authentication!\n"
printf "aborting notarization\n"
NOTARIZE="false"
return
else
printf "Response:\n\n%s\n\n" "${altoolResponse}"
fi
local uuid="$(grep 'RequestUUID' <<< ${altoolResponse} | awk '{ print $NF }')"
echo "RequestUUID = ${uuid}" # Display identifier string
waiting_fixed "Waiting to retrieve notarize status" 60
while true ; do
fullstatus=$(xcrun altool --notarization-info "${uuid}" --username "${NOTARIZE_ACC}" --password "${NOTARIZE_PASS}" ${ASC_PROVIDER_OP} 2>&1) # get the status
notarize_status=`echo "${fullstatus}" | grep 'Status\:' | awk '{ print $2 }'`
echo "${fullstatus}"
if [[ "${notarize_status}" = "success" ]]; then
xcrun stapler staple "${NOT_SRC_FILE}" #staple the ticket
xcrun stapler validate -v "${NOT_SRC_FILE}"
print_msg "Notarization success!"
break
elif [[ "${notarize_status}" = "in" ]]; then
waiting_fixed "Notarization still in progress, sleeping for 60 seconds and trying again" 60
else
echo "Notarization failed! full status below"
echo "${fullstatus}"
exit 1
fi
done
fi
}
createDMG () {
printf "Creating of dmg with contents of %s...\n" "${KRITA_DMG}"
cd ${BUILDROOT}
DMG_size=700
if [[ -z "${DMG_NAME}" ]]; then
# Add git version number
GIT_SHA=$(grep "#define KRITA_GIT_SHA1_STRING" ${KIS_BUILD_DIR}/libs/version/kritagitversion.h | awk '{gsub(/"/, "", $3); printf $3}')
DMG_NAME="krita-nightly_${GIT_SHA}.dmg"
else
DMG_NAME="${DMG_NAME}.dmg"
fi
## Build dmg from folder
# create dmg on local system
# usage of -fsargs minimze gaps at front of filesystem (reduce size)
hdiutil create -srcfolder "${KRITA_DMG}" -volname "${DMG_title}" -fs HFS+ \
-fsargs "-c c=64,a=16,e=16" -format UDRW -size ${DMG_size}m krita.temp.dmg
# Next line is only useful if we have a dmg as a template!
# previous hdiutil must be uncommented
# cp krita-template.dmg krita.dmg
device=$(hdiutil attach -readwrite -noverify -noautoopen "krita.temp.dmg" | egrep '^/dev/' | sed 1q | awk '{print $1}')
# rsync -priul --delete ${KRITA_DMG}/krita.app "/Volumes/${DMG_title}"
# Set style for dmg
if [[ ! -d "/Volumes/${DMG_title}/.background" ]]; then
mkdir "/Volumes/${DMG_title}/.background"
fi
cp -v ${DMG_background} "/Volumes/${DMG_title}/.background/"
mkdir "/Volumes/${DMG_title}/Terms of Use"
cp -v "${KIS_SRC_DIR}/packaging/macos/Terms_of_use.rtf" "/Volumes/${DMG_title}/Terms of Use/"
ln -s "/Applications" "/Volumes/${DMG_title}/Applications"
## Apple script to set style
style="$(<"${DMG_STYLE}")"
printf "${style}" "${DMG_title}" "${DMG_background##*/}" | osascript
#Set Icon for DMG
cp -v "${SCRIPT_SOURCE_DIR}/KritaIcon.icns" "/Volumes/${DMG_title}/.VolumeIcon.icns"
SetFile -a C "/Volumes/${DMG_title}"
chmod -Rf go-w "/Volumes/${DMG_title}"
# ensure all writing operations to dmg are over
sync
hdiutil detach $device
hdiutil convert "krita.temp.dmg" -format UDZO -imagekey -zlib-level=9 -o krita-out.dmg
mv krita-out.dmg ${DMG_NAME}
echo "moved krita-out.dmg to ${DMG_NAME}"
rm krita.temp.dmg
if [[ -n "${CODE_SIGNATURE}" ]]; then
printf "${DMG_NAME}" | batch_codesign
fi
notarize_build "${BUILDROOT}" "${DMG_NAME}"
echo "dmg done!"
}
#######################
# Program starts!!
########################
# Run deploy command, installation is assumed to exist in BUILDROOT/i
krita_deploy
# Code sign krita.app if signature given
if [[ -n "${CODE_SIGNATURE}" ]]; then
signBundle
fi
# notarize app
notarize_build "${KRITA_DMG}" krita.app
# Create DMG from files inside ${KRITA_DMG} folder
createDMG
if [[ "${NOTARIZE}" = "false" ]]; then
macosVersion="$(sw_vers | grep ProductVersion | awk '
BEGIN { FS = "[ .\t]" }
{ print $3}
')"
if (( ${macosVersion} == 15 )); then
print_error "Build not notarized! Needed for macOS versions above 10.14"
fi
fi
diff --git a/plugins/dockers/animation/timeline_frames_model.cpp b/plugins/dockers/animation/timeline_frames_model.cpp
index d672ae59a7..480e4e6b1a 100644
--- a/plugins/dockers/animation/timeline_frames_model.cpp
+++ b/plugins/dockers/animation/timeline_frames_model.cpp
@@ -1,1027 +1,1021 @@
/*
* Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "timeline_frames_model.h"
#include <QFont>
#include <QSize>
#include <QColor>
#include <QMimeData>
#include <QPointer>
#include <KisResourceModel.h>
#include "kis_layer.h"
#include "kis_config.h"
#include "kis_global.h"
#include "kis_debug.h"
#include "kis_image.h"
#include "kis_image_animation_interface.h"
#include "kis_undo_adapter.h"
#include "kis_node_dummies_graph.h"
#include "kis_dummies_facade_base.h"
#include "KisNodeDisplayModeAdapter.h"
#include "kis_signal_compressor.h"
#include "kis_signal_compressor_with_param.h"
#include "kis_keyframe_channel.h"
#include "kundo2command.h"
#include "kis_post_execution_undo_adapter.h"
#include <commands/kis_node_property_list_command.h>
#include <commands_new/kis_switch_current_time_command.h>
#include "kis_animation_utils.h"
#include "timeline_color_scheme.h"
#include "kis_node_model.h"
#include "kis_projection_leaf.h"
#include "kis_time_range.h"
#include "kis_node_view_color_scheme.h"
#include "krita_utils.h"
#include "KisPart.h"
#include <QApplication>
#include "KisDocument.h"
#include "KisViewManager.h"
#include "kis_processing_applicator.h"
#include <KisImageBarrierLockerWithFeedback.h>
#include "kis_node_uuid_info.h"
struct TimelineFramesModel::Private
{
Private()
: activeLayerIndex(0),
dummiesFacade(0),
needFinishInsertRows(false),
needFinishRemoveRows(false),
updateTimer(200, KisSignalCompressor::FIRST_INACTIVE),
parentOfRemovedNode(0)
{}
int activeLayerIndex;
QPointer<KisDummiesFacadeBase> dummiesFacade;
KisImageWSP image;
bool needFinishInsertRows;
bool needFinishRemoveRows;
QList<KisNodeDummy*> updateQueue;
KisSignalCompressor updateTimer;
KisNodeDummy* parentOfRemovedNode;
QScopedPointer<TimelineNodeListKeeper> converter;
QScopedPointer<NodeManipulationInterface> nodeInterface;
QPersistentModelIndex lastClickedIndex;
QVariant layerName(int row) const {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return QVariant();
return dummy->node()->name();
}
bool layerEditable(int row) const {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return true;
return dummy->node()->visible() && !dummy->node()->userLocked();
}
bool frameExists(int row, int column) const {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return false;
KisKeyframeChannel *primaryChannel = dummy->node()->getKeyframeChannel(KisKeyframeChannel::Content.id());
return (primaryChannel && primaryChannel->keyframeAt(column));
}
bool frameHasContent(int row, int column) {
KisNodeDummy *dummy = converter->dummyFromRow(row);
KisKeyframeChannel *primaryChannel = dummy->node()->getKeyframeChannel(KisKeyframeChannel::Content.id());
if (!primaryChannel) return false;
// first check if we are a key frame
KisKeyframeSP frame = primaryChannel->activeKeyframeAt(column);
if (!frame) return false;
return frame->hasContent();
}
bool specialKeyframeExists(int row, int column) {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return false;
Q_FOREACH(KisKeyframeChannel *channel, dummy->node()->keyframeChannels()) {
if (channel->id() != KisKeyframeChannel::Content.id() && channel->keyframeAt(column)) {
return true;
}
}
return false;
}
int frameColorLabel(int row, int column) {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return -1;
KisKeyframeChannel *primaryChannel = dummy->node()->getKeyframeChannel(KisKeyframeChannel::Content.id());
if (!primaryChannel) return -1;
KisKeyframeSP frame = primaryChannel->activeKeyframeAt(column);
if (!frame) return -1;
return frame->colorLabel();
}
void setFrameColorLabel(int row, int column, int color) {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return;
KisKeyframeChannel *primaryChannel = dummy->node()->getKeyframeChannel(KisKeyframeChannel::Content.id());
if (!primaryChannel) return;
KisKeyframeSP frame = primaryChannel->keyframeAt(column);
if (!frame) return;
frame->setColorLabel(color);
}
int layerColorLabel(int row) const {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return -1;
return dummy->node()->colorLabelIndex();
}
QVariant layerProperties(int row) const {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return QVariant();
PropertyList props = dummy->node()->sectionModelProperties();
return QVariant::fromValue(props);
}
bool setLayerProperties(int row, PropertyList props) {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return false;
nodeInterface->setNodeProperties(dummy->node(), image, props);
return true;
}
bool addKeyframe(int row, int column, bool copy) {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return false;
KisNodeSP node = dummy->node();
if (!KisAnimationUtils::supportsContentFrames(node)) return false;
KisAnimationUtils::createKeyframeLazy(image, node, KisKeyframeChannel::Content.id(), column, copy);
return true;
}
bool addNewLayer(int row) {
Q_UNUSED(row);
if (nodeInterface) {
KisLayerSP layer = nodeInterface->addPaintLayer();
layer->setPinnedToTimeline(true);
}
return true;
}
bool removeLayer(int row) {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return false;
if (nodeInterface) {
nodeInterface->removeNode(dummy->node());
}
return true;
}
};
TimelineFramesModel::TimelineFramesModel(QObject *parent)
: ModelWithExternalNotifications(parent),
m_d(new Private)
{
connect(&m_d->updateTimer, SIGNAL(timeout()), SLOT(processUpdateQueue()));
}
TimelineFramesModel::~TimelineFramesModel()
{
}
bool TimelineFramesModel::hasConnectionToCanvas() const
{
return m_d->dummiesFacade;
}
void TimelineFramesModel::setNodeManipulationInterface(NodeManipulationInterface *iface)
{
m_d->nodeInterface.reset(iface);
}
KisNodeSP TimelineFramesModel::nodeAt(QModelIndex index) const
{
/**
* The dummy might not exist because the user could (quickly) change
* active layer and the list of the nodes in m_d->converter will change.
*/
KisNodeDummy *dummy = m_d->converter->dummyFromRow(index.row());
return dummy ? dummy->node() : 0;
}
QMap<QString, KisKeyframeChannel*> TimelineFramesModel::channelsAt(QModelIndex index) const
{
KisNodeDummy *srcDummy = m_d->converter->dummyFromRow(index.row());
return srcDummy->node()->keyframeChannels();
}
void TimelineFramesModel::setDummiesFacade(KisDummiesFacadeBase *dummiesFacade,
KisImageSP image,
KisNodeDisplayModeAdapter *displayModeAdapter)
{
KisDummiesFacadeBase *oldDummiesFacade = m_d->dummiesFacade;
if (m_d->dummiesFacade && m_d->image) {
m_d->image->animationInterface()->disconnect(this);
m_d->image->disconnect(this);
m_d->dummiesFacade->disconnect(this);
}
m_d->image = image;
KisTimeBasedItemModel::setImage(image);
m_d->dummiesFacade = dummiesFacade;
m_d->converter.reset();
if (m_d->dummiesFacade) {
m_d->converter.reset(new TimelineNodeListKeeper(this, m_d->dummiesFacade, displayModeAdapter));
connect(m_d->dummiesFacade, SIGNAL(sigDummyChanged(KisNodeDummy*)),
SLOT(slotDummyChanged(KisNodeDummy*)));
connect(m_d->image->animationInterface(),
SIGNAL(sigFullClipRangeChanged()), SIGNAL(sigInfiniteTimelineUpdateNeeded()));
connect(m_d->image->animationInterface(),
SIGNAL(sigAudioChannelChanged()), SIGNAL(sigAudioChannelChanged()));
connect(m_d->image->animationInterface(),
SIGNAL(sigAudioVolumeChanged()), SIGNAL(sigAudioChannelChanged()));
connect(m_d->image, SIGNAL(sigImageModified()), SLOT(slotImageContentChanged()));
}
if (m_d->dummiesFacade != oldDummiesFacade) {
beginResetModel();
endResetModel();
}
if (m_d->dummiesFacade) {
emit sigInfiniteTimelineUpdateNeeded();
emit sigAudioChannelChanged();
slotCurrentTimeChanged(m_d->image->animationInterface()->currentUITime());
}
}
void TimelineFramesModel::slotDummyChanged(KisNodeDummy *dummy)
{
if (!m_d->updateQueue.contains(dummy)) {
m_d->updateQueue.append(dummy);
}
m_d->updateTimer.start();
}
void TimelineFramesModel::slotImageContentChanged()
{
if (m_d->activeLayerIndex < 0) return;
KisNodeDummy *dummy = m_d->converter->dummyFromRow(m_d->activeLayerIndex);
if (!dummy) return;
slotDummyChanged(dummy);
}
void TimelineFramesModel::processUpdateQueue()
{
if (!m_d->converter) return;
Q_FOREACH (KisNodeDummy *dummy, m_d->updateQueue) {
int row = m_d->converter->rowForDummy(dummy);
if (row >= 0) {
emit headerDataChanged (Qt::Vertical, row, row);
emit dataChanged(this->index(row, 0), this->index(row, columnCount() - 1));
}
}
m_d->updateQueue.clear();
}
void TimelineFramesModel::slotCurrentNodeChanged(KisNodeSP node)
{
if (!node) {
m_d->activeLayerIndex = -1;
return;
}
KisNodeDummy *dummy = m_d->dummiesFacade->dummyForNode(node);
if (!dummy) {
// It's perfectly normal that dummyForNode returns 0; that happens
// when views get activated while Krita is closing down.
return;
}
m_d->converter->updateActiveDummy(dummy);
const int row = m_d->converter->rowForDummy(dummy);
if (row < 0) {
qWarning() << "WARNING: TimelineFramesModel::slotCurrentNodeChanged: node not found!";
}
if (row >= 0 && m_d->activeLayerIndex != row) {
setData(index(row, 0), true, ActiveLayerRole);
}
}
int TimelineFramesModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
if(!m_d->dummiesFacade) return 0;
return m_d->converter->rowCount();
}
QVariant TimelineFramesModel::data(const QModelIndex &index, int role) const
{
if(!m_d->dummiesFacade) return QVariant();
switch (role) {
case ActiveLayerRole: {
return index.row() == m_d->activeLayerIndex;
}
case FrameEditableRole: {
return m_d->layerEditable(index.row());
}
case FrameHasContent: {
return m_d->frameHasContent(index.row(), index.column());
}
case FrameExistsRole: {
return m_d->frameExists(index.row(), index.column());
}
case SpecialKeyframeExists: {
return m_d->specialKeyframeExists(index.row(), index.column());
}
case FrameColorLabelIndexRole: {
int label = m_d->frameColorLabel(index.row(), index.column());
return label > 0 ? label : QVariant();
}
case Qt::DisplayRole: {
return m_d->layerName(index.row());
}
case Qt::TextAlignmentRole: {
return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);
}
case Qt::UserRole + KisResourceModel::LargeThumbnail: {
KisNodeDummy *dummy = m_d->converter->dummyFromRow(index.row());
if (!dummy) {
return QVariant();
}
const int maxSize = 200;
- QSize size = dummy->node()->extent().size();
- size.scale(maxSize, maxSize, Qt::KeepAspectRatio);
- if (size.width() == 0 || size.height() == 0) {
- // No thumbnail can be shown if there isn't width or height...
- return QVariant();
- }
- QImage image(dummy->node()->createThumbnailForFrame(size.width(), size.height(), index.column()));
+ QImage image(dummy->node()->createThumbnailForFrame(maxSize, maxSize, index.column(), Qt::KeepAspectRatio));
return image;
}
}
return ModelWithExternalNotifications::data(index, role);
}
bool TimelineFramesModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid() || !m_d->dummiesFacade) return false;
switch (role) {
case ActiveLayerRole: {
if (value.toBool() &&
index.row() != m_d->activeLayerIndex) {
int prevLayer = m_d->activeLayerIndex;
m_d->activeLayerIndex = index.row();
emit dataChanged(this->index(prevLayer, 0), this->index(prevLayer, columnCount() - 1));
emit dataChanged(this->index(m_d->activeLayerIndex, 0), this->index(m_d->activeLayerIndex, columnCount() - 1));
emit headerDataChanged(Qt::Vertical, prevLayer, prevLayer);
emit headerDataChanged(Qt::Vertical, m_d->activeLayerIndex, m_d->activeLayerIndex);
KisNodeDummy *dummy = m_d->converter->dummyFromRow(m_d->activeLayerIndex);
KIS_ASSERT_RECOVER(dummy) { return true; }
emit requestCurrentNodeChanged(dummy->node());
emit sigEnsureRowVisible(m_d->activeLayerIndex);
}
break;
}
case FrameColorLabelIndexRole: {
m_d->setFrameColorLabel(index.row(), index.column(), value.toInt());
}
break;
}
return ModelWithExternalNotifications::setData(index, value, role);
}
QVariant TimelineFramesModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if(!m_d->dummiesFacade) return QVariant();
if (orientation == Qt::Vertical) {
switch (role) {
case ActiveLayerRole:
return section == m_d->activeLayerIndex;
case Qt::DisplayRole: {
QVariant value = headerData(section, orientation, Qt::ToolTipRole);
if (!value.isValid()) return value;
QString name = value.toString();
const int maxNameSize = 13;
if (name.size() > maxNameSize) {
name = QString("%1...").arg(name.left(maxNameSize));
}
return name;
}
case Qt::TextColorRole: {
// WARNING: this role doesn't work for header views! Use
// bold font to show isolated mode instead!
return QVariant();
}
case Qt::FontRole: {
KisNodeDummy *dummy = m_d->converter->dummyFromRow(section);
if (!dummy) return QVariant();
KisNodeSP node = dummy->node();
QFont baseFont;
if (node->projectionLeaf()->isDroppedNode()) {
baseFont.setStrikeOut(true);
} else if (m_d->image && m_d->image->isolatedModeRoot() &&
KisNodeModel::belongsToIsolatedGroup(m_d->image, node, m_d->dummiesFacade)) {
baseFont.setBold(true);
}
return baseFont;
}
case Qt::ToolTipRole: {
return m_d->layerName(section);
}
case TimelinePropertiesRole: {
return QVariant::fromValue(m_d->layerProperties(section));
}
case OtherLayersRole: {
TimelineNodeListKeeper::OtherLayersList list =
m_d->converter->otherLayersList();
return QVariant::fromValue(list);
}
case LayerUsedInTimelineRole: {
KisNodeDummy *dummy = m_d->converter->dummyFromRow(section);
if (!dummy) return QVariant();
return dummy->node()->isPinnedToTimeline();
}
case Qt::BackgroundRole: {
int label = m_d->layerColorLabel(section);
if (label > 0) {
KisNodeViewColorScheme scm;
QColor color = scm.colorLabel(label);
QPalette pal = qApp->palette();
color = KritaUtils::blendColors(color, pal.color(QPalette::Button), 0.3);
return QBrush(color);
} else {
return QVariant();
}
}
}
}
return ModelWithExternalNotifications::headerData(section, orientation, role);
}
bool TimelineFramesModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role)
{
if (!m_d->dummiesFacade) return false;
if (orientation == Qt::Vertical) {
switch (role) {
case ActiveLayerRole: {
setData(index(section, 0), value, role);
break;
}
case TimelinePropertiesRole: {
TimelineFramesModel::PropertyList props = value.value<TimelineFramesModel::PropertyList>();
int result = m_d->setLayerProperties(section, props);
emit headerDataChanged (Qt::Vertical, section, section);
return result;
}
case LayerUsedInTimelineRole: {
KisNodeDummy *dummy = m_d->converter->dummyFromRow(section);
if (!dummy) return false;
dummy->node()->setPinnedToTimeline(value.toBool());
return true;
}
}
}
return ModelWithExternalNotifications::setHeaderData(section, orientation, value, role);
}
Qt::DropActions TimelineFramesModel::supportedDragActions() const
{
return Qt::MoveAction | Qt::CopyAction;
}
Qt::DropActions TimelineFramesModel::supportedDropActions() const
{
return Qt::MoveAction | Qt::CopyAction;
}
QStringList TimelineFramesModel::mimeTypes() const
{
QStringList types;
types << QLatin1String("application/x-krita-frame");
return types;
}
void TimelineFramesModel::setLastClickedIndex(const QModelIndex &index)
{
m_d->lastClickedIndex = index;
}
QMimeData* TimelineFramesModel::mimeData(const QModelIndexList &indexes) const
{
return mimeDataExtended(indexes, m_d->lastClickedIndex, UndefinedPolicy);
}
QMimeData *TimelineFramesModel::mimeDataExtended(const QModelIndexList &indexes,
const QModelIndex &baseIndex,
TimelineFramesModel::MimeCopyPolicy copyPolicy) const
{
QMimeData *data = new QMimeData();
QByteArray encoded;
QDataStream stream(&encoded, QIODevice::WriteOnly);
const int baseRow = baseIndex.row();
const int baseColumn = baseIndex.column();
const QByteArray uuidDataRoot = m_d->image->root()->uuid().toRfc4122();
stream << int(uuidDataRoot.size());
stream.writeRawData(uuidDataRoot.data(), uuidDataRoot.size());
stream << indexes.size();
stream << baseRow << baseColumn;
Q_FOREACH (const QModelIndex &index, indexes) {
KisNodeSP node = nodeAt(index);
KIS_SAFE_ASSERT_RECOVER(node) { continue; }
stream << index.row() - baseRow << index.column() - baseColumn;
const QByteArray uuidData = node->uuid().toRfc4122();
stream << int(uuidData.size());
stream.writeRawData(uuidData.data(), uuidData.size());
}
stream << int(copyPolicy);
data->setData("application/x-krita-frame", encoded);
return data;
}
inline void decodeBaseIndex(QByteArray *encoded, int *row, int *col)
{
int size_UNUSED = 0;
QDataStream stream(encoded, QIODevice::ReadOnly);
stream >> size_UNUSED >> *row >> *col;
}
bool TimelineFramesModel::canDropFrameData(const QMimeData */*data*/, const QModelIndex &index)
{
if (!index.isValid()) return false;
/**
* Now we support D&D around any layer, so just return 'true' all
* the time.
*/
return true;
}
bool TimelineFramesModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
Q_UNUSED(row);
Q_UNUSED(column);
return dropMimeDataExtended(data, action, parent);
}
bool TimelineFramesModel::dropMimeDataExtended(const QMimeData *data, Qt::DropAction action, const QModelIndex &parent, bool *dataMoved)
{
bool result = false;
if ((action != Qt::MoveAction && action != Qt::CopyAction) ||
!parent.isValid()) return result;
QByteArray encoded = data->data("application/x-krita-frame");
QDataStream stream(&encoded, QIODevice::ReadOnly);
int uuidLenRoot = 0;
stream >> uuidLenRoot;
QByteArray uuidDataRoot(uuidLenRoot, '\0');
stream.readRawData(uuidDataRoot.data(), uuidLenRoot);
QUuid nodeUuidRoot = QUuid::fromRfc4122(uuidDataRoot);
KisPart *partInstance = KisPart::instance();
QList<QPointer<KisDocument>> documents = partInstance->documents();
KisImageSP srcImage = 0;
Q_FOREACH(KisDocument *doc, documents) {
KisImageSP tmpSrcImage = doc->image();
if (tmpSrcImage->root()->uuid() == nodeUuidRoot) {
srcImage = tmpSrcImage;
break;
}
}
if (!srcImage) {
KisPart *kisPartInstance = KisPart::instance();
kisPartInstance->currentMainwindow()->viewManager()->showFloatingMessage(
i18n("Dropped frames are not available in this Krita instance")
, QIcon());
return false;
}
int size, baseRow, baseColumn;
stream >> size >> baseRow >> baseColumn;
const QPoint offset(parent.column() - baseColumn, parent.row() - baseRow);
KisAnimationUtils::FrameMovePairList frameMoves;
for (int i = 0; i < size; i++) {
int relRow, relColumn;
stream >> relRow >> relColumn;
const int srcRow = baseRow + relRow;
const int srcColumn = baseColumn + relColumn;
int uuidLen = 0;
stream >> uuidLen;
QByteArray uuidData(uuidLen, '\0');
stream.readRawData(uuidData.data(), uuidLen);
QUuid nodeUuid = QUuid::fromRfc4122(uuidData);
KisNodeSP srcNode;
if (!nodeUuid.isNull()) {
KisNodeUuidInfo nodeInfo(nodeUuid);
srcNode = nodeInfo.findNode(srcImage->root());
} else {
QModelIndex index = this->index(srcRow, srcColumn);
srcNode = nodeAt(index);
}
KIS_SAFE_ASSERT_RECOVER(srcNode) { continue; }
const QModelIndex dstRowIndex = this->index(srcRow + offset.y(), 0);
if (!dstRowIndex.isValid()) continue;
KisNodeSP dstNode = nodeAt(dstRowIndex);
KIS_SAFE_ASSERT_RECOVER(dstNode) { continue; }
Q_FOREACH (KisKeyframeChannel *channel, srcNode->keyframeChannels().values()) {
KisAnimationUtils::FrameItem srcItem(srcNode, channel->id(), srcColumn);
KisAnimationUtils::FrameItem dstItem(dstNode, channel->id(), srcColumn + offset.x());
frameMoves << std::make_pair(srcItem, dstItem);
}
}
MimeCopyPolicy copyPolicy = UndefinedPolicy;
if (!stream.atEnd()) {
int value = 0;
stream >> value;
copyPolicy = MimeCopyPolicy(value);
}
const bool copyFrames =
copyPolicy == UndefinedPolicy ?
action == Qt::CopyAction :
copyPolicy == CopyFramesPolicy;
if (dataMoved) {
*dataMoved = !copyFrames;
}
KUndo2Command *cmd = 0;
if (!frameMoves.isEmpty()) {
KisImageBarrierLockerWithFeedback locker(m_d->image);
cmd = KisAnimationUtils::createMoveKeyframesCommand(frameMoves, copyFrames, false, 0);
}
if (cmd) {
KisProcessingApplicator::runSingleCommandStroke(m_d->image, cmd,
KisStrokeJobData::BARRIER,
KisStrokeJobData::EXCLUSIVE);
}
return cmd;
}
Qt::ItemFlags TimelineFramesModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags flags = ModelWithExternalNotifications::flags(index);
if (!index.isValid()) return flags;
if (m_d->frameExists(index.row(), index.column()) || m_d->specialKeyframeExists(index.row(), index.column())) {
if (data(index, FrameEditableRole).toBool()) {
flags |= Qt::ItemIsDragEnabled;
}
}
/**
* Basically we should forbid overrides only if we D&D a single frame
* and allow it when we D&D multiple frames. But we cannot distinguish
* it here... So allow all the time.
*/
flags |= Qt::ItemIsDropEnabled;
return flags;
}
bool TimelineFramesModel::insertRows(int row, int count, const QModelIndex &parent)
{
Q_UNUSED(parent);
KIS_ASSERT_RECOVER(count == 1) { return false; }
if (row < 0 || row > rowCount()) return false;
bool result = m_d->addNewLayer(row);
return result;
}
bool TimelineFramesModel::removeRows(int row, int count, const QModelIndex &parent)
{
Q_UNUSED(parent);
KIS_ASSERT_RECOVER(count == 1) { return false; }
if (row < 0 || row >= rowCount()) return false;
bool result = m_d->removeLayer(row);
return result;
}
bool TimelineFramesModel::insertOtherLayer(int index, int dstRow)
{
Q_UNUSED(dstRow);
TimelineNodeListKeeper::OtherLayersList list =
m_d->converter->otherLayersList();
if (index < 0 || index >= list.size()) return false;
list[index].dummy->node()->setPinnedToTimeline(true);
dstRow = m_d->converter->rowForDummy(list[index].dummy);
setData(this->index(dstRow, 0), true, ActiveLayerRole);
return true;
}
int TimelineFramesModel::activeLayerRow() const
{
return m_d->activeLayerIndex;
}
bool TimelineFramesModel::createFrame(const QModelIndex &dstIndex)
{
if (!dstIndex.isValid()) return false;
return m_d->addKeyframe(dstIndex.row(), dstIndex.column(), false);
}
bool TimelineFramesModel::copyFrame(const QModelIndex &dstIndex)
{
if (!dstIndex.isValid()) return false;
return m_d->addKeyframe(dstIndex.row(), dstIndex.column(), true);
}
bool TimelineFramesModel::insertFrames(int dstColumn, const QList<int> &dstRows, int count, int timing)
{
if (dstRows.isEmpty() || count <= 0) return true;
timing = qMax(timing, 1);
KUndo2Command *parentCommand = new KUndo2Command(kundo2_i18np("Insert frame", "Insert %1 frames", count));
{
KisImageBarrierLockerWithFeedback locker(m_d->image);
QModelIndexList indexes;
Q_FOREACH (int row, dstRows) {
for (int column = dstColumn; column < columnCount(); column++) {
indexes << index(row, column);
}
}
setLastVisibleFrame(columnCount() + (count * timing) - 1);
createOffsetFramesCommand(indexes, QPoint((count * timing), 0), false, false, parentCommand);
Q_FOREACH (int row, dstRows) {
KisNodeDummy *dummy = m_d->converter->dummyFromRow(row);
if (!dummy) continue;
KisNodeSP node = dummy->node();
if (!KisAnimationUtils::supportsContentFrames(node)) continue;
for (int column = dstColumn; column < dstColumn + (count * timing); column += timing) {
KisAnimationUtils::createKeyframeCommand(m_d->image, node, KisKeyframeChannel::Content.id(), column, false, parentCommand);
}
}
const int oldTime = m_d->image->animationInterface()->currentUITime();
const int newTime = dstColumn > oldTime ? dstColumn : dstColumn + (count * timing) - 1;
new KisSwitchCurrentTimeCommand(m_d->image->animationInterface(),
oldTime,
newTime, parentCommand);
}
KisProcessingApplicator::runSingleCommandStroke(m_d->image, parentCommand,
KisStrokeJobData::BARRIER,
KisStrokeJobData::EXCLUSIVE);
return true;
}
bool TimelineFramesModel::insertHoldFrames(QModelIndexList selectedIndexes, int count)
{
if (selectedIndexes.isEmpty() || count == 0) return true;
QScopedPointer<KUndo2Command> parentCommand(new KUndo2Command(kundo2_i18np("Insert frame", "Insert %1 frames", count)));
{
KisImageBarrierLockerWithFeedback locker(m_d->image);
QSet<KisKeyframeSP> uniqueKeyframesInSelection;
int minSelectedTime = std::numeric_limits<int>::max();
Q_FOREACH (const QModelIndex &index, selectedIndexes) {
KisNodeSP node = nodeAt(index);
KIS_SAFE_ASSERT_RECOVER(node) { continue; }
KisKeyframeChannel *channel = node->getKeyframeChannel(KisKeyframeChannel::Content.id());
if (!channel) continue;
minSelectedTime = qMin(minSelectedTime, index.column());
KisKeyframeSP keyFrame = channel->activeKeyframeAt(index.column());
if (keyFrame) {
uniqueKeyframesInSelection.insert(keyFrame);
}
}
QList<KisKeyframeSP> keyframesToMove;
for (auto it = uniqueKeyframesInSelection.begin(); it != uniqueKeyframesInSelection.end(); ++it) {
KisKeyframeSP keyframe = *it;
KisKeyframeChannel *channel = keyframe->channel();
KisKeyframeSP nextKeyframe = channel->nextKeyframe(keyframe);
if (nextKeyframe) {
keyframesToMove << nextKeyframe;
}
}
std::sort(keyframesToMove.begin(), keyframesToMove.end(),
[] (KisKeyframeSP lhs, KisKeyframeSP rhs) {
return lhs->time() > rhs->time();
});
if (keyframesToMove.isEmpty()) return true;
const int maxColumn = columnCount();
if (count > 0) {
setLastVisibleFrame(columnCount() + count);
}
Q_FOREACH (KisKeyframeSP keyframe, keyframesToMove) {
int plannedFrameMove = count;
if (count < 0) {
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(keyframe->time() > 0, false);
KisKeyframeSP prevFrame = keyframe->channel()->previousKeyframe(keyframe);
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(prevFrame, false);
plannedFrameMove = qMax(count, prevFrame->time() - keyframe->time() + 1);
minSelectedTime = qMin(minSelectedTime, prevFrame->time());
}
KisNodeDummy *dummy = m_d->dummiesFacade->dummyForNode(keyframe->channel()->node());
KIS_SAFE_ASSERT_RECOVER(dummy) { continue; }
const int row = m_d->converter->rowForDummy(dummy);
KIS_SAFE_ASSERT_RECOVER(row >= 0) { continue; }
QModelIndexList indexes;
for (int column = keyframe->time(); column < maxColumn; column++) {
indexes << index(row, column);
}
createOffsetFramesCommand(indexes,
QPoint(plannedFrameMove, 0),
false, true, parentCommand.data());
}
const int oldTime = m_d->image->animationInterface()->currentUITime();
const int newTime = minSelectedTime;
new KisSwitchCurrentTimeCommand(m_d->image->animationInterface(),
oldTime,
newTime, parentCommand.data());
}
KisProcessingApplicator::runSingleCommandStroke(m_d->image, parentCommand.take(),
KisStrokeJobData::BARRIER,
KisStrokeJobData::EXCLUSIVE);
return true;
}
QString TimelineFramesModel::audioChannelFileName() const
{
return m_d->image ? m_d->image->animationInterface()->audioChannelFileName() : QString();
}
void TimelineFramesModel::setAudioChannelFileName(const QString &fileName)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->image);
m_d->image->animationInterface()->setAudioChannelFileName(fileName);
}
bool TimelineFramesModel::isAudioMuted() const
{
return m_d->image ? m_d->image->animationInterface()->isAudioMuted() : false;
}
void TimelineFramesModel::setAudioMuted(bool value)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->image);
m_d->image->animationInterface()->setAudioMuted(value);
}
qreal TimelineFramesModel::audioVolume() const
{
return m_d->image ? m_d->image->animationInterface()->audioVolume() : 0.5;
}
void TimelineFramesModel::setAudioVolume(qreal value)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->image);
m_d->image->animationInterface()->setAudioVolume(value);
}
void TimelineFramesModel::setFullClipRangeStart(int column)
{
m_d->image->animationInterface()->setFullClipRangeStartTime(column);
}
void TimelineFramesModel::setFullClipRangeEnd(int column)
{
m_d->image->animationInterface()->setFullClipRangeEndTime(column);
}
diff --git a/plugins/extensions/pykrita/plugin/pyqtpluginsettings.cpp b/plugins/extensions/pykrita/plugin/pyqtpluginsettings.cpp
index d0e3e0b5c1..314ab30ba5 100644
--- a/plugins/extensions/pykrita/plugin/pyqtpluginsettings.cpp
+++ b/plugins/extensions/pykrita/plugin/pyqtpluginsettings.cpp
@@ -1,112 +1,112 @@
/*
* Copyright (c) 2014 Boudewijn Rempt <boud@valdyas.org>
*
* This program 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; version 2 of the License.
*
* 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 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 "pyqtpluginsettings.h"
#include "ui_manager.h"
#include <QVBoxLayout>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QSortFilterProxyModel>
#include <kconfiggroup.h>
#include <QTreeView>
-#include <KoIcon.h>
#include "kis_config.h"
+#include "kis_icon_utils.h"
#include "PythonPluginManager.h"
PyQtPluginSettings::PyQtPluginSettings(PythonPluginManager *pluginManager, QWidget *parent)
: KisPreferenceSet(parent)
, m_pluginManager(pluginManager)
, m_page(new Ui::ManagerPage)
{
m_page->setupUi(this);
QSortFilterProxyModel* const proxy_model = new QSortFilterProxyModel(this);
proxy_model->setSourceModel(pluginManager->model());
m_page->pluginsList->setModel(proxy_model);
m_page->pluginsList->resizeColumnToContents(0);
m_page->pluginsList->sortByColumn(0, Qt::AscendingOrder);
const bool is_enabled = bool(pluginManager);
const bool is_visible = !is_enabled;
m_page->errorLabel->setVisible(is_visible);
m_page->pluginsList->setEnabled(is_enabled);
m_page->textBrowser->setEnabled(is_enabled);
connect(m_page->pluginsList, SIGNAL(clicked(QModelIndex)), SLOT(updateManual(QModelIndex)));
}
PyQtPluginSettings::~PyQtPluginSettings()
{
delete m_page;
}
QString PyQtPluginSettings::id()
{
return QString("pykritapluginmanager");
}
QString PyQtPluginSettings::name()
{
return header();
}
QString PyQtPluginSettings::header()
{
return QString(i18n("Python Plugin Manager"));
}
QIcon PyQtPluginSettings::icon()
{
- return koIcon("applications-development");
+ return KisIconUtils::loadIcon("python");
}
void PyQtPluginSettings::savePreferences() const
{
Q_EMIT(settingsChanged());
}
void PyQtPluginSettings::loadPreferences()
{
}
void PyQtPluginSettings::loadDefaultPreferences()
{
}
void PyQtPluginSettings::updateManual(const QModelIndex &index)
{
QModelIndex unsortedIndex = static_cast<QSortFilterProxyModel*>(m_page->pluginsList->model())->mapToSource(index);
PythonPlugin *plugin = m_pluginManager->model()->plugin(unsortedIndex);
if (plugin && !plugin->manual().isEmpty()) {
QString manual = plugin->manual();
if (manual.startsWith("<html")) {
m_page->textBrowser->setHtml(manual);
}
else {
m_page->textBrowser->setText(manual);
}
}
else {
m_page->textBrowser->setHtml("<html><body><h1>No Manual Available</h2></body></html>");
}
}
diff --git a/plugins/extensions/pykrita/sip/krita/Scratchpad.sip b/plugins/extensions/pykrita/sip/krita/Scratchpad.sip
new file mode 100644
index 0000000000..9f056193d9
--- /dev/null
+++ b/plugins/extensions/pykrita/sip/krita/Scratchpad.sip
@@ -0,0 +1,19 @@
+class Scratchpad : public QWidget /NoDefaultCtors/
+{
+%TypeHeaderCode
+#include "Scratchpad.h"
+%End
+
+public:
+ Scratchpad(View* view , const QString & defaultColor, QWidget* parent /TransferThis/ = 0);
+ virtual ~Scratchpad();
+
+public Q_SLOTS:
+ void clear();
+ void setModeManually(bool value);
+ void setMode(QString modeName);
+ void setFillColor(QColor color);
+ void loadScratchpadImage(QImage image);
+ QImage copyScratchpadImageData();
+
+};
diff --git a/plugins/extensions/pykrita/sip/krita/kritamod.sip b/plugins/extensions/pykrita/sip/krita/kritamod.sip
index 92fd05ad91..bf3450748b 100644
--- a/plugins/extensions/pykrita/sip/krita/kritamod.sip
+++ b/plugins/extensions/pykrita/sip/krita/kritamod.sip
@@ -1,50 +1,51 @@
%Module PyKrita.krita
%ModuleHeaderCode
#pragma GCC visibility push(default)
%End
%Import QtCore/QtCoremod.sip
%Import QtGui/QtGuimod.sip
%Import QtXml/QtXmlmod.sip
%Import QtWidgets/QtWidgetsmod.sip
%Include Conversions.sip
%Include Shape.sip
%Include GroupShape.sip
%Include Canvas.sip
%Include Channel.sip
%Include DockWidgetFactoryBase.sip
%Include DockWidget.sip
%Include Document.sip
%Include Filter.sip
%Include InfoObject.sip
%Include Extension.sip
%Include View.sip
%Include Window.sip
%Include Krita.sip
%Include Node.sip
%Include GroupLayer.sip
%Include CloneLayer.sip
%Include FilterLayer.sip
%Include FileLayer.sip
%Include FillLayer.sip
%Include VectorLayer.sip
%Include FilterMask.sip
%Include SelectionMask.sip
%Include Notifier.sip
%Include Resource.sip
%Include Selection.sip
%Include Extension.sip
%Include PresetChooser.sip
+%Include Scratchpad.sip
%Include Palette.sip
%Include PaletteView.sip
%Include ManagedColor.sip
%Include Swatch.sip
%Include KisCubicCurve.sip
diff --git a/plugins/flake/CMakeLists.txt b/plugins/flake/CMakeLists.txt
index 5dd1c0c5cb..2e86d07c22 100644
--- a/plugins/flake/CMakeLists.txt
+++ b/plugins/flake/CMakeLists.txt
@@ -1,4 +1,2 @@
add_subdirectory( imageshape )
-add_subdirectory( artistictextshape )
add_subdirectory( pathshapes )
-add_subdirectory( textshape )
diff --git a/plugins/flake/artistictextshape/AddTextRangeCommand.cpp b/plugins/flake/artistictextshape/AddTextRangeCommand.cpp
deleted file mode 100644
index 1fc1852878..0000000000
--- a/plugins/flake/artistictextshape/AddTextRangeCommand.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007,2011 Jan Hambrecht <jaham@gmx.net>
- * Copyright (C) 2008 Rob Buis <buis@kde.org>
- *
- * 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 "AddTextRangeCommand.h"
-#include "ArtisticTextShape.h"
-#include <klocalizedstring.h>
-
-AddTextRangeCommand::AddTextRangeCommand(ArtisticTextTool *tool, ArtisticTextShape *shape, const QString &text, int from)
- : m_tool(tool)
- , m_shape(shape)
- , m_plainText(text)
- , m_formattedText(QString()
- , QFont())
- , m_from(from)
-{
- setText(kundo2_i18n("Add text range"));
- m_oldFormattedText = shape->text();
-}
-
-AddTextRangeCommand::AddTextRangeCommand(ArtisticTextTool *tool, ArtisticTextShape *shape, const ArtisticTextRange &text, int from)
- : m_tool(tool), m_shape(shape), m_formattedText(text), m_from(from)
-{
- setText(kundo2_i18n("Add text range"));
- m_oldFormattedText = shape->text();
-}
-
-void AddTextRangeCommand::redo()
-{
- KUndo2Command::redo();
-
- if (!m_shape) {
- return;
- }
-
- if (m_plainText.isEmpty()) {
- m_shape->insertText(m_from, m_formattedText);
- } else {
- m_shape->insertText(m_from, m_plainText);
- }
-
- if (m_tool) {
- if (m_plainText.isEmpty()) {
- m_tool->setTextCursor(m_shape, m_from + m_formattedText.text().length());
- } else {
- m_tool->setTextCursor(m_shape, m_from + m_plainText.length());
- }
- }
-}
-
-void AddTextRangeCommand::undo()
-{
- KUndo2Command::undo();
-
- if (! m_shape) {
- return;
- }
-
- m_shape->clear();
- Q_FOREACH (const ArtisticTextRange &range, m_oldFormattedText) {
- m_shape->appendText(range);
- }
- if (m_tool) {
- m_tool->setTextCursor(m_shape, m_from);
- }
-}
diff --git a/plugins/flake/artistictextshape/AddTextRangeCommand.h b/plugins/flake/artistictextshape/AddTextRangeCommand.h
deleted file mode 100644
index 3ea3306e41..0000000000
--- a/plugins/flake/artistictextshape/AddTextRangeCommand.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007,2011 Jan Hambrecht <jaham@gmx.net>
- * Copyright (C) 2008 Rob Buis <buis@kde.org>
- *
- * 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 ADDTEXTRANGECOMMAND_H
-#define ADDTEXTRANGECOMMAND_H
-
-#include <kundo2command.h>
-#include "ArtisticTextTool.h"
-#include "ArtisticTextRange.h"
-#include <QPointer>
-
-class ArtisticTextShape;
-
-/// Undo command to add a range of text to a artistic text shape
-class AddTextRangeCommand : public KUndo2Command
-{
-public:
- AddTextRangeCommand(ArtisticTextTool *tool, ArtisticTextShape *shape, const QString &text, int from);
- AddTextRangeCommand(ArtisticTextTool *tool, ArtisticTextShape *shape, const ArtisticTextRange &text, int from);
-
- void redo() override;
- void undo() override;
-
-private:
- QPointer<ArtisticTextTool> m_tool;
- ArtisticTextShape *m_shape;
- QString m_plainText;
- ArtisticTextRange m_formattedText;
- QList<ArtisticTextRange> m_oldFormattedText;
- int m_from;
-};
-
-#endif // ADDTEXTRANGECOMMAND_H
diff --git a/plugins/flake/artistictextshape/ArtisticTextLoadingContext.cpp b/plugins/flake/artistictextshape/ArtisticTextLoadingContext.cpp
deleted file mode 100644
index 0d72d862b7..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextLoadingContext.cpp
+++ /dev/null
@@ -1,270 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "ArtisticTextLoadingContext.h"
-#include "SvgUtil.h"
-#include "SvgGraphicContext.h"
-
-#include <KoXmlReader.h>
-#include <QDebug>
-
-#include <math.h>
-
-ArtisticTextLoadingContext::ArtisticTextLoadingContext()
- : m_textPosition(HUGE_VAL, HUGE_VAL)
-{
-}
-
-QString ArtisticTextLoadingContext::simplifyText(const QString &text, bool preserveWhiteSpace)
-{
- // simplifies text according ot the svg specification
- QString simple = text;
- simple.remove('\n');
- simple.replace('\t', ' ');
- if (preserveWhiteSpace) {
- return simple;
- }
-
- QString stripped = simple.simplified();
- // preserve last whitespace character
- if (simple.endsWith(' ')) {
- stripped += QChar(' ');
- }
-
- return stripped;
-}
-
-ArtisticTextLoadingContext::OffsetType ArtisticTextLoadingContext::xOffsetType() const
-{
- if (m_currentAbsolutePosX.data.count()) {
- return Absolute;
- } else if (m_currentRelativePosY.data.count()) {
- return Relative;
- } else {
- if (m_absolutePosX.count() && m_absolutePosX.last().data.count()) {
- return Absolute;
- } else if (m_relativePosX.count() && m_relativePosX.last().data.count()) {
- return Relative;
- }
- }
- return None;
-}
-
-ArtisticTextLoadingContext::OffsetType ArtisticTextLoadingContext::yOffsetType() const
-{
- if (m_currentAbsolutePosY.data.count()) {
- return Absolute;
- } else if (m_currentRelativePosY.data.count()) {
- return Relative;
- } else {
- if (m_absolutePosY.count() && m_absolutePosY.last().data.count()) {
- return Absolute;
- } else if (m_relativePosY.count() && m_relativePosY.last().data.count()) {
- return Relative;
- }
- }
- return None;
-}
-
-CharTransforms ArtisticTextLoadingContext::xOffsets(int count)
-{
- switch (xOffsetType()) {
- case Absolute: {
- const QPointF origin = textPosition();
- CharTransforms offsets = collectValues(count, m_currentAbsolutePosX, m_absolutePosX);
- const int offsetCount = offsets.count();
- for (int i = 0; i < offsetCount; ++i) {
- offsets[i] -= origin.x();
- }
- return offsets;
- }
- case Relative:
- return collectValues(count, m_currentRelativePosX, m_relativePosX);
- default:
- return CharTransforms();
- }
-}
-
-CharTransforms ArtisticTextLoadingContext::yOffsets(int count)
-{
- switch (yOffsetType()) {
- case Absolute: {
- const QPointF origin = textPosition();
- CharTransforms offsets = collectValues(count, m_currentAbsolutePosY, m_absolutePosY);
- const int offsetCount = offsets.count();
- for (int i = 0; i < offsetCount; ++i) {
- offsets[i] -= origin.y();
- }
- return offsets;
- }
- case Relative:
- return collectValues(count, m_currentRelativePosY, m_relativePosY);
- default:
- return CharTransforms();
- }
-}
-
-CharTransforms ArtisticTextLoadingContext::rotations(int count)
-{
- return collectValues(count, m_currentRotations, m_rotations);
-}
-
-QPointF ArtisticTextLoadingContext::textPosition() const
-{
- qreal x = 0.0, y = 0.0;
- if (m_textPosition.x() != HUGE_VAL) {
- x = m_textPosition.x();
- }
- if (m_textPosition.y() != HUGE_VAL) {
- y = m_textPosition.y();
- }
-
- return QPointF(x, y);
-}
-
-/// Parses current character transforms (x,y,dx,dy,rotate)
-void ArtisticTextLoadingContext::parseCharacterTransforms(const KoXmlElement &element, SvgGraphicsContext *gc)
-{
- m_currentAbsolutePosX = parseList(element.attribute("x"), gc, XLength);
- m_currentAbsolutePosY = parseList(element.attribute("y"), gc, YLength);
- m_currentRelativePosX = parseList(element.attribute("dx"), gc, XLength);
- m_currentRelativePosY = parseList(element.attribute("dy"), gc, YLength);
- m_currentRotations = parseList(element.attribute("rotate"), gc, Number);
-
- if (m_textPosition.x() == HUGE_VAL && m_currentAbsolutePosX.data.count()) {
- m_textPosition.setX(m_currentAbsolutePosX.data.first());
- }
- if (m_textPosition.y() == HUGE_VAL && m_currentAbsolutePosY.data.count()) {
- m_textPosition.setY(m_currentAbsolutePosY.data.first());
- }
-}
-
-void ArtisticTextLoadingContext::pushCharacterTransforms()
-{
- m_absolutePosX.append(m_currentAbsolutePosX);
- m_currentAbsolutePosX = CharTransformState();
- m_absolutePosY.append(m_currentAbsolutePosY);
- m_currentAbsolutePosY = CharTransformState();
- m_relativePosX.append(m_currentRelativePosX);
- m_currentRelativePosX = CharTransformState();
- m_relativePosY.append(m_currentRelativePosY);
- m_currentRelativePosY = CharTransformState();
- m_rotations.append(m_currentRotations);
- m_currentRotations = CharTransformState();
-}
-
-void ArtisticTextLoadingContext::popCharacterTransforms()
-{
- m_currentAbsolutePosX = m_absolutePosX.last();
- m_absolutePosX.pop_back();
- m_currentAbsolutePosY = m_absolutePosY.last();
- m_absolutePosY.pop_back();
- m_currentRelativePosX = m_relativePosX.last();
- m_relativePosX.pop_back();
- m_currentRelativePosY = m_relativePosY.last();
- m_relativePosY.pop_back();
- m_currentRotations = m_rotations.last();
- m_rotations.pop_back();
-}
-
-CharTransforms ArtisticTextLoadingContext::parseList(const QString &listString, SvgGraphicsContext *gc, ValueType type)
-{
- if (listString.isEmpty()) {
- return CharTransforms();
- } else {
- CharTransforms values;
- QStringList offsets = QString(listString).replace(',', ' ').simplified().split(' ');
- Q_FOREACH (const QString &offset, offsets) {
- switch (type) {
- case Number:
- values.append(offset.toDouble());
- break;
- case XLength:
- values.append(SvgUtil::parseUnitX(gc, offset));
- break;
- case YLength:
- values.append(SvgUtil::parseUnitY(gc, offset));
- break;
- }
- }
- return values;
- }
-}
-
-CharTransforms ArtisticTextLoadingContext::collectValues(int count, CharTransformState &current, CharTransformStack &stack)
-{
- CharTransforms collected;
-
- if (current.hasData) {
- // use value from current data if that has initial values
- collected = current.extract(count);
- } else {
- collected = current.extract(count);
- // collect values from ancestors
- const int stackCount = stack.count();
- for (int i = stackCount - 1; i >= 0; --i) {
- CharTransformState &state = stack[i];
- // determine the number of values we need / can get from this ancestor
- const int copyCount = qMin(count - collected.count(), state.data.count());
- // extract values so they are not consumed more than once
- collected.append(state.extract(copyCount));
- // ok this ancestor had initial data, so we stop collecting values here
- if (state.hasData) {
- if (collected.isEmpty()) {
- collected.append(state.lastTransform);
- }
- break;
- }
- if (copyCount == 0) {
- break;
- }
- }
- }
- return collected;
-}
-
-void ArtisticTextLoadingContext::printDebug()
-{
- QString indent;
- Q_FOREACH (const CharTransformState &state, CharTransformStack(m_absolutePosX) << m_currentAbsolutePosX) {
- qDebug() << indent << state.data << state.hasData << state.lastTransform;
- indent.append(" ");
- }
- indent.clear();
- Q_FOREACH (const CharTransformState &state, CharTransformStack(m_absolutePosY) << m_currentAbsolutePosY) {
- qDebug() << indent << state.data << state.hasData << state.lastTransform;
- indent.append(" ");
- }
- indent.clear();
- Q_FOREACH (const CharTransformState &state, CharTransformStack(m_relativePosX) << m_currentRelativePosX) {
- qDebug() << indent << state.data << state.hasData << state.lastTransform;
- indent.append(" ");
- }
- indent.clear();
- Q_FOREACH (const CharTransformState &state, CharTransformStack(m_relativePosY) << m_currentRelativePosY) {
- qDebug() << indent << state.data << state.hasData << state.lastTransform;
- indent.append(" ");
- }
- indent.clear();
- Q_FOREACH (const CharTransformState &state, CharTransformStack(m_rotations) << m_currentRotations) {
- qDebug() << indent << state.data << state.hasData << state.lastTransform;
- indent.append(" ");
- }
- indent.clear();
-}
diff --git a/plugins/flake/artistictextshape/ArtisticTextLoadingContext.h b/plugins/flake/artistictextshape/ArtisticTextLoadingContext.h
deleted file mode 100644
index 82889a3666..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextLoadingContext.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 SVGTEXTHELPER_H
-#define SVGTEXTHELPER_H
-
-#include <QVector>
-#include <QString>
-#include <QList>
-#include <QPointF>
-
-typedef QList<qreal> CharTransforms;
-
-#include <KoXmlReaderForward.h>
-class SvgGraphicsContext;
-
-class ArtisticTextLoadingContext
-{
-public:
- enum OffsetType {
- None,
- Absolute,
- Relative
- };
-
- ArtisticTextLoadingContext();
-
- static QString simplifyText(const QString &text, bool preserveWhiteSpace = false);
-
- /// Parses current character transforms (x,y,dx,dy,rotate)
- void parseCharacterTransforms(const KoXmlElement &element, SvgGraphicsContext *gc);
-
- /// Pushes the current character transforms to the stack
- void pushCharacterTransforms();
-
- /// Pops last character transforms from the stack
- void popCharacterTransforms();
-
- /// Checks current x-offset type
- OffsetType xOffsetType() const;
-
- /// Checks current y-offset type
- OffsetType yOffsetType() const;
-
- /// Returns x-offsets from stack
- CharTransforms xOffsets(int count);
-
- /// Returns y-offsets from stack
- CharTransforms yOffsets(int count);
-
- /// Returns rotations from stack
- CharTransforms rotations(int count);
-
- /// Returns the text position
- QPointF textPosition() const;
-
-private:
- void printDebug();
-
- struct CharTransformState {
- CharTransformState()
- : hasData(false), lastTransform(0.0)
- {
- }
-
- CharTransformState(const CharTransforms &initialData)
- : data(initialData), hasData(!initialData.isEmpty())
- , lastTransform(initialData.isEmpty() ? 0.0 : initialData.last())
- {
- }
-
- CharTransforms extract(int count)
- {
- const int copyCount = qMin(data.count(), count);
- CharTransforms extracted = data.mid(0, copyCount);
- data = data.mid(copyCount);
- return extracted;
- }
-
- CharTransforms data;
- bool hasData;
- qreal lastTransform;
- };
-
- typedef QList<CharTransformState> CharTransformStack;
-
- enum ValueType {
- Number,
- XLength,
- YLength
- };
-
- /// Parses offset values from the given string
- CharTransforms parseList(const QString &listString, SvgGraphicsContext *gc, ValueType type);
-
- /// Collects number of specified transforms values from the stack
- CharTransforms collectValues(int count, CharTransformState &current, CharTransformStack &stack);
-
- CharTransformState m_currentAbsolutePosX; ///< current absolute character x-positions
- CharTransformState m_currentAbsolutePosY; ///< current absolute character y-positions
- CharTransformState m_currentRelativePosX; ///< current relative character x-positions
- CharTransformState m_currentRelativePosY; ///< current relative character y-positions
- CharTransformState m_currentRotations; ///< current character rotations
- CharTransformStack m_absolutePosX; ///< stack of absolute character x-positions
- CharTransformStack m_absolutePosY; ///< stack of absolute character y-positions
- CharTransformStack m_relativePosX; ///< stack of relative character x-positions
- CharTransformStack m_relativePosY; ///< stack of relative character y-positions
- CharTransformStack m_rotations; ///< stack of character rotations
-
- QPointF m_textPosition;
-};
-
-#endif // SVGTEXTHELPER_H
diff --git a/plugins/flake/artistictextshape/ArtisticTextRange.cpp b/plugins/flake/artistictextshape/ArtisticTextRange.cpp
deleted file mode 100644
index b832a5b4d8..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextRange.cpp
+++ /dev/null
@@ -1,240 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007-2009 Jan Hambrecht <jaham@gmx.net>
- * Copyright (C) 2008 Rob Buis <buis@kde.org>
- *
- * 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 "ArtisticTextRange.h"
-#include <QDebug>
-
-ArtisticTextRange::ArtisticTextRange(const QString &text, const QFont &font)
- : m_text(text)
- , m_font(font)
- , m_letterSpacing(0.0)
- , m_wordSpacing(0.0)
- , m_baselineShift(None)
- , m_baselineShiftValue(0.0)
-{
-}
-
-ArtisticTextRange::~ArtisticTextRange()
-{
-}
-
-void ArtisticTextRange::setText(const QString &text)
-{
- m_text = text;
-}
-
-QString ArtisticTextRange::text() const
-{
- return m_text;
-}
-
-void ArtisticTextRange::insertText(int charIndex, const QString &text)
-{
- m_text.insert(charIndex, text);
-}
-
-void ArtisticTextRange::appendText(const QString &text)
-{
- m_text += text;
-}
-
-void ArtisticTextRange::setFont(const QFont &font)
-{
- if (m_font == font) {
- return;
- }
-
- m_font = font;
-}
-
-QFont ArtisticTextRange::font() const
-{
- return m_font;
-}
-
-ArtisticTextRange ArtisticTextRange::extract(int from, int count)
-{
- // copy text and font
- ArtisticTextRange extracted(m_text.mid(from, count), m_font);
- // copy corresponding character transformations
- if (from < m_xOffsets.count()) {
- extracted.setXOffsets(m_xOffsets.mid(from, count), m_xOffsetType);
- }
- if (from < m_yOffsets.count()) {
- extracted.setYOffsets(m_yOffsets.mid(from, count), m_yOffsetType);
- }
- if (from < m_rotations.count()) {
- extracted.setRotations(m_rotations.mid(from, count));
- }
-
- extracted.setLetterSpacing(m_letterSpacing);
- extracted.setWordSpacing(m_wordSpacing);
- extracted.setBaselineShift(m_baselineShift, m_baselineShiftValue);
-
- // remove text
- m_text.remove(from, count < 0 ? m_text.length() - from : count);
- // remove character transformations
- m_xOffsets = m_xOffsets.mid(0, from);
- m_yOffsets = m_yOffsets.mid(0, from);
- m_rotations = m_rotations.mid(0, from);
-
- return extracted;
-}
-
-bool ArtisticTextRange::hasEqualStyle(const ArtisticTextRange &other) const
-{
- return m_font == other.m_font;
-}
-
-void ArtisticTextRange::setXOffsets(const QList<qreal> &offsets, OffsetType type)
-{
- m_xOffsets = offsets;
- m_xOffsetType = type;
-}
-
-void ArtisticTextRange::setYOffsets(const QList<qreal> &offsets, OffsetType type)
-{
- m_yOffsets = offsets;
- m_yOffsetType = type;
-}
-
-qreal ArtisticTextRange::xOffset(int charIndex) const
-{
- return m_xOffsets.value(charIndex);
-}
-
-qreal ArtisticTextRange::yOffset(int charIndex) const
-{
- return m_yOffsets.value(charIndex);
-}
-
-bool ArtisticTextRange::hasXOffset(int charIndex) const
-{
- return charIndex >= 0 && charIndex < m_xOffsets.count();
-}
-
-bool ArtisticTextRange::hasYOffset(int charIndex) const
-{
- return charIndex >= 0 && charIndex < m_yOffsets.count();
-}
-
-bool ArtisticTextRange::hasXOffsets() const
-{
- return !m_xOffsets.isEmpty();
-}
-
-bool ArtisticTextRange::hasYOffsets() const
-{
- return !m_yOffsets.isEmpty();
-}
-
-ArtisticTextRange::OffsetType ArtisticTextRange::xOffsetType() const
-{
- return m_xOffsetType;
-}
-
-ArtisticTextRange::OffsetType ArtisticTextRange::yOffsetType() const
-{
- return m_yOffsetType;
-}
-
-void ArtisticTextRange::setRotations(const QList<qreal> &rotations)
-{
- m_rotations = rotations;
-}
-
-bool ArtisticTextRange::hasRotation(int charIndex) const
-{
- return charIndex >= 0 && charIndex < m_rotations.count();
-}
-
-bool ArtisticTextRange::hasRotations() const
-{
- return !m_rotations.isEmpty();
-}
-
-qreal ArtisticTextRange::rotation(int charIndex) const
-{
- return m_rotations.value(charIndex);
-}
-
-void ArtisticTextRange::setLetterSpacing(qreal letterSpacing)
-{
- m_letterSpacing = letterSpacing;
-}
-
-qreal ArtisticTextRange::letterSpacing() const
-{
- return m_letterSpacing;
-}
-
-void ArtisticTextRange::setWordSpacing(qreal wordSpacing)
-{
- m_wordSpacing = wordSpacing;
-}
-
-qreal ArtisticTextRange::wordSpacing() const
-{
- return m_wordSpacing;
-}
-
-ArtisticTextRange::BaselineShift ArtisticTextRange::baselineShift() const
-{
- return m_baselineShift;
-}
-
-qreal ArtisticTextRange::baselineShiftValue() const
-{
- return m_baselineShiftValue;
-}
-
-void ArtisticTextRange::setBaselineShift(BaselineShift mode, qreal value)
-{
- m_baselineShift = mode;
- m_baselineShiftValue = value;
-}
-
-qreal ArtisticTextRange::subAndSuperScriptSizeFactor()
-{
- return 0.58; // taken from wikipedia
-}
-
-void ArtisticTextRange::printDebug() const
-{
- qDebug() << "text:" << m_text;
- qDebug() << "font:" << m_font;
- switch (m_xOffsetType) {
- case AbsoluteOffset:
- qDebug() << "x:" << m_xOffsets;
- break;
- case RelativeOffset:
- qDebug() << "dx:" << m_xOffsets;
- break;
- }
- switch (m_yOffsetType) {
- case AbsoluteOffset:
- qDebug() << "y:" << m_yOffsets;
- break;
- case RelativeOffset:
- qDebug() << "dy:" << m_yOffsets;
- break;
- }
- qDebug() << "rotate:" << m_rotations;
-}
diff --git a/plugins/flake/artistictextshape/ArtisticTextRange.h b/plugins/flake/artistictextshape/ArtisticTextRange.h
deleted file mode 100644
index c0cc6c8d05..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextRange.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007-2008,2011 Jan Hambrecht <jaham@gmx.net>
- * Copyright (C) 2008 Rob Buis <buis@kde.org>
- *
- * 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 ARTISITICTEXTRANGE_H
-#define ARTISITICTEXTRANGE_H
-
-#include <QString>
-#include <QPointF>
-#include <QFont>
-
-/// Represents a range of characters with the same text properties
-class ArtisticTextRange
-{
-public:
- enum OffsetType {
- AbsoluteOffset,
- RelativeOffset
- };
-
- enum BaselineShift {
- None, ///< no baseline shift
- Sub, ///< subscript baseline shift
- Super, ///< superscript baseline shift
- Percent, ///< percentage baseline shift
- Length ///< absolute baseline shift
- };
-
- ArtisticTextRange(const QString &text, const QFont &font);
- ~ArtisticTextRange();
-
- /// Returns the text content
- QString text() const;
-
- /// Sets the text to display
- void setText(const QString &text);
-
- /// Inserts new text at the given position
- void insertText(int charIndex, const QString &text);
-
- /// Appends text to the text range
- void appendText(const QString &text);
-
- /**
- * Sets the font used for drawing
- * Note that it is expected that the font has its point size set
- * in postscript points.
- */
- void setFont(const QFont &font);
-
- /// Returns the font
- QFont font() const;
-
- /// Extracts specified part of the text range
- ArtisticTextRange extract(int from, int count = -1);
-
- /// Checks if specified text range has the same style as this text range
- bool hasEqualStyle(const ArtisticTextRange &other) const;
-
- /// Sets individual character x-offsets
- void setXOffsets(const QList<qreal> &offsets, OffsetType type);
-
- /// Sets individual character y-offsets
- void setYOffsets(const QList<qreal> &offsets, OffsetType type);
-
- /// Returns the character x-offset for the specified character
- qreal xOffset(int charIndex) const;
-
- /// Returns the character y-offset for the specified character
- qreal yOffset(int charIndex) const;
-
- /// Checks if specified character has an x-offset value
- bool hasXOffset(int charIndex) const;
-
- /// Checks if specified character has an y-offset value
- bool hasYOffset(int charIndex) const;
-
- /// Checks if range has x-offsets
- bool hasXOffsets() const;
-
- /// Checks if range has y-offsets
- bool hasYOffsets() const;
-
- /// Returns the type of the x-offsets
- OffsetType xOffsetType() const;
-
- /// Returns the type of the y-offsets
- OffsetType yOffsetType() const;
-
- /// Sets individual character rotations
- void setRotations(const QList<qreal> &rotations);
-
- /// Checks if specified character has a rotation
- bool hasRotation(int charIndex) const;
-
- /// Checks if range has character rotations
- bool hasRotations() const;
-
- /// Returns the character rotation for the specified character
- qreal rotation(int charIndex) const;
-
- /// Sets additional spacing between characters
- void setLetterSpacing(qreal letterSpacing);
-
- /// Returns the letter spacing
- qreal letterSpacing() const;
-
- /// Sets additional spacing between words
- void setWordSpacing(qreal wordSpacing);
-
- /// Returns the word spacing
- qreal wordSpacing() const;
-
- /// Returns baseline shift mode
- BaselineShift baselineShift() const;
-
- /// Returns the optional baseline shift value
- qreal baselineShiftValue() const;
-
- /// Returns the normalized baseline shift value in point
- qreal baselineShiftValueNormalized() const;
-
- /// Sets baseline shift mode and optional value
- void setBaselineShift(BaselineShift mode, qreal value = 0.0);
-
- /// Returns the factor to calculate sub and super script font size
- static qreal subAndSuperScriptSizeFactor();
-
- /// Prints debug output
- void printDebug() const;
-
-private:
- QString m_text; ///< the text of the text range
- QFont m_font; ///< the font of the text range
- QList<qreal> m_xOffsets; ///< character x-offsets
- QList<qreal> m_yOffsets; ///< character y-offsets
- OffsetType m_xOffsetType; ///< character x-offset type
- OffsetType m_yOffsetType; ///< character y-offset type
- QList<qreal> m_rotations; ///< character rotations
- qreal m_letterSpacing; ///< additional inter character spacing
- qreal m_wordSpacing; ///< additional inter word spacing
- BaselineShift m_baselineShift; ///< baseline shift mode
- qreal m_baselineShiftValue; ///< optional baseline shift value
-};
-
-#endif // ARTISITICTEXTRANGE_H
diff --git a/plugins/flake/artistictextshape/ArtisticTextShape.cpp b/plugins/flake/artistictextshape/ArtisticTextShape.cpp
deleted file mode 100644
index a8ef42fa8a..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextShape.cpp
+++ /dev/null
@@ -1,1405 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007-2009,2011 Jan Hambrecht <jaham@gmx.net>
- * Copyright (C) 2008 Rob Buis <buis@kde.org>
- *
- * 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 "ArtisticTextShape.h"
-#include "ArtisticTextLoadingContext.h"
-
-#include <KoPathShape.h>
-#include <KoShapeSavingContext.h>
-#include <KoShapeLoadingContext.h>
-#include <KoXmlNS.h>
-#include <KoXmlWriter.h>
-#include <KoXmlReader.h>
-#include <KoPathShapeLoader.h>
-#include <KoShapeBackground.h>
-#include <KoEmbeddedDocumentSaver.h>
-#include <SvgSavingContext.h>
-#include <SvgLoadingContext.h>
-#include <SvgGraphicContext.h>
-#include <SvgUtil.h>
-#include <SvgStyleParser.h>
-#include <SvgWriter.h>
-#include <SvgStyleWriter.h>
-#include <KisQPainterStateSaver.h>
-
-#include <klocalizedstring.h>
-
-#include <QDebug>
-#include <QBuffer>
-#include <QPen>
-#include <QPainter>
-#include <QFont>
-
-ArtisticTextShape::ArtisticTextShape()
- : m_path(0)
- , m_startOffset(0.0)
- , m_textAnchor(AnchorStart)
- , m_textUpdateCounter(0)
- , m_defaultFont("ComicSans", 20)
-{
- setShapeId(ArtisticTextShapeID);
- cacheGlyphOutlines();
- updateSizeAndPosition();
-}
-
-ArtisticTextShape::~ArtisticTextShape()
-{
- if (m_path) {
- m_path->removeDependee(this);
- }
-}
-
-KoShape *ArtisticTextShape::cloneShape() const
-{
- ArtisticTextShape *clone = new ArtisticTextShape();
- clone->m_ranges = m_ranges;
- if (m_path) {
- clone->m_path = static_cast<KoPathShape*>(m_path->cloneShape());
- }
- clone->m_charOutlines = m_charOutlines;
- clone->m_startOffset = m_startOffset;
- clone->m_outlineOrigin = m_outlineOrigin;
- clone->m_outline = m_outline;
- clone->m_baseline = m_baseline;
- clone->m_textAnchor = m_textAnchor;
- clone->m_charOffsets = m_charOffsets;
- clone->m_charPositions = m_charPositions;
- clone->m_textUpdateCounter = m_textUpdateCounter;
- clone->m_defaultFont = m_defaultFont;
- return clone;
-}
-
-void ArtisticTextShape::paint(QPainter &painter, KoShapePaintingContext &paintContext) const
-{
- KisQPainterStateSaver saver(&painter);
-
- if (background()) {
- background()->paint(painter, paintContext, outline());
- }
-}
-
-void ArtisticTextShape::saveOdf(KoShapeSavingContext &context) const
-{
- SvgWriter svgWriter(QList<KoShape *>() << const_cast<ArtisticTextShape *>(this));
- QByteArray fileContent;
- QBuffer fileContentDevice(&fileContent);
- if (!fileContentDevice.open(QIODevice::WriteOnly)) {
- return;
- }
-
- if (!svgWriter.save(fileContentDevice, size())) {
- qWarning() << "Could not write svg content";
- return;
- }
-
- const QString fileName = context.embeddedSaver().getFilename("SvgImages/Image");
- const QString mimeType = "image/svg+xml";
-
- context.xmlWriter().startElement("draw:frame");
- context.embeddedSaver().embedFile(context.xmlWriter(), "draw:image", fileName, mimeType.toLatin1(), fileContent);
- context.xmlWriter().endElement(); // draw:frame
-}
-
-bool ArtisticTextShape::loadOdf(const KoXmlElement &/*element*/, KoShapeLoadingContext &/*context*/)
-{
- return false;
-}
-
-QSizeF ArtisticTextShape::size() const
-{
- if (m_ranges.isEmpty()) {
- return nullBoundBox().size();
- } else {
- return outline().boundingRect().size();
- }
-}
-
-void ArtisticTextShape::setSize(const QSizeF &newSize)
-{
- QSizeF oldSize = size();
- if (!oldSize.isNull()) {
- qreal zoomX = newSize.width() / oldSize.width();
- qreal zoomY = newSize.height() / oldSize.height();
- QTransform matrix(zoomX, 0, 0, zoomY, 0, 0);
-
- update();
- applyTransformation(matrix);
- update();
- }
- KoShape::setSize(newSize);
-}
-
-QPainterPath ArtisticTextShape::outline() const
-{
- return m_outline;
-}
-
-QRectF ArtisticTextShape::nullBoundBox() const
-{
- QFontMetrics metrics(defaultFont());
- QPointF tl(0.0, -metrics.ascent());
- QPointF br(metrics.averageCharWidth(), metrics.descent());
- return QRectF(tl, br);
-}
-
-QFont ArtisticTextShape::defaultFont() const
-{
- return m_defaultFont;
-}
-
-qreal baselineShiftForFontSize(const ArtisticTextRange &range, qreal fontSize)
-{
- switch (range.baselineShift()) {
- case ArtisticTextRange::Sub:
- return fontSize / 3.; // taken from wikipedia
- case ArtisticTextRange::Super:
- return -fontSize / 3.; // taken from wikipedia
- case ArtisticTextRange::Percent:
- return range.baselineShiftValue() * fontSize;
- case ArtisticTextRange::Length:
- return range.baselineShiftValue();
- default:
- return 0.0;
- }
-}
-
-QVector<QPointF> ArtisticTextShape::calculateAbstractCharacterPositions()
-{
- const int totalTextLength = plainText().length();
-
- QVector<QPointF> charPositions;
-
- // one more than the number of characters for position after the last character
- charPositions.resize(totalTextLength + 1);
-
- // the character index within the text shape
- int globalCharIndex = 0;
-
- QPointF charPos(0, 0);
- QPointF advance(0, 0);
-
- const bool attachedToPath = isOnPath();
-
- Q_FOREACH (const ArtisticTextRange &range, m_ranges) {
- QFontMetricsF metrics(QFont(range.font(), &m_paintDevice));
- const QString textRange = range.text();
- const qreal letterSpacing = range.letterSpacing();
- const int localTextLength = textRange.length();
-
- const bool absoluteXOffset = range.xOffsetType() == ArtisticTextRange::AbsoluteOffset;
- const bool absoluteYOffset = range.yOffsetType() == ArtisticTextRange::AbsoluteOffset;
-
- // set baseline shift
- const qreal baselineShift = baselineShiftForFontSize(range, defaultFont().pointSizeF());
-
- for (int localCharIndex = 0; localCharIndex < localTextLength; ++localCharIndex, ++globalCharIndex) {
- // apply offset to character
- if (range.hasXOffset(localCharIndex)) {
- if (absoluteXOffset) {
- charPos.rx() = range.xOffset(localCharIndex);
- } else {
- charPos.rx() += range.xOffset(localCharIndex);
- }
- } else {
- charPos.rx() += advance.x();
- }
- if (range.hasYOffset(localCharIndex)) {
- if (absoluteYOffset) {
- // when attached to a path, absolute y-offsets are ignored
- if (!attachedToPath) {
- charPos.ry() = range.yOffset(localCharIndex);
- }
- } else {
- charPos.ry() += range.yOffset(localCharIndex);
- }
- } else {
- charPos.ry() += advance.y();
- }
-
- // apply baseline shift
- charPos.ry() += baselineShift;
-
- // save character position of current character
- charPositions[globalCharIndex] = charPos;
- // advance character position
- advance = QPointF(metrics.width(textRange[localCharIndex]) + letterSpacing, 0.0);
-
- charPos.ry() -= baselineShift;
- }
- }
- charPositions[globalCharIndex] = charPos + advance;
-
- return charPositions;
-}
-
-void ArtisticTextShape::createOutline()
-{
- // reset relevant data
- m_outline = QPainterPath();
- m_charPositions.clear();
- m_charOffsets.clear();
-
- // calculate character positions in baseline coordinates
- m_charPositions = calculateAbstractCharacterPositions();
-
- // the character index within the text shape
- int globalCharIndex = 0;
-
- if (isOnPath()) {
- // one more than the number of characters for offset after the last character
- m_charOffsets.insert(0, m_charPositions.size(), -1);
- // the current character position
- qreal startCharOffset = m_startOffset * m_baseline.length();
- // calculate total text width
- qreal totalTextWidth = 0.0;
- foreach (const ArtisticTextRange &range, m_ranges) {
- QFontMetricsF metrics(QFont(range.font(), &m_paintDevice));
- totalTextWidth += metrics.width(range.text());
- }
- // adjust starting character position to anchor point
- if (m_textAnchor == AnchorMiddle) {
- startCharOffset -= 0.5 * totalTextWidth;
- } else if (m_textAnchor == AnchorEnd) {
- startCharOffset -= totalTextWidth;
- }
-
- QPointF pathPoint;
- qreal rotation = 0.0;
- qreal charOffset;
-
- foreach (const ArtisticTextRange &range, m_ranges) {
- QFontMetricsF metrics(QFont(range.font(), &m_paintDevice));
- const QString localText = range.text();
- const int localTextLength = localText.length();
-
- for (int localCharIndex = 0; localCharIndex < localTextLength; ++localCharIndex, ++globalCharIndex) {
- QPointF charPos = m_charPositions[globalCharIndex];
-
- // apply advance along baseline
- charOffset = startCharOffset + charPos.x();
-
- const qreal charMidPoint = charOffset + 0.5 * metrics.width(localText[localCharIndex]);
- // get the normalized position of the middle of the character
- const qreal midT = m_baseline.percentAtLength(charMidPoint);
- // is the character midpoint beyond the baseline ends?
- if (midT <= 0.0 || midT >= 1.0) {
- if (midT >= 1.0) {
- pathPoint = m_baseline.pointAtPercent(1.0);
- for (int i = globalCharIndex; i < m_charPositions.size(); ++i) {
- m_charPositions[i] = pathPoint;
- m_charOffsets[i] = 1.0;
- }
- break;
- } else {
- m_charPositions[globalCharIndex] = m_baseline.pointAtPercent(0.0);
- m_charOffsets[globalCharIndex] = 0.0;
- continue;
- }
- }
- // get the percent value of the actual char position
- qreal t = m_baseline.percentAtLength(charOffset);
-
- // get the path point of the given path position
- pathPoint = m_baseline.pointAtPercent(t);
-
- // save character offset as fraction of baseline length
- m_charOffsets[globalCharIndex] = m_baseline.percentAtLength(charOffset);
- // save character position as point
- m_charPositions[globalCharIndex] = pathPoint;
-
- // get the angle at the given path position
- const qreal angle = m_baseline.angleAtPercent(midT);
- if (range.hasRotation(localCharIndex)) {
- rotation = range.rotation(localCharIndex);
- }
-
- QTransform m;
- m.translate(pathPoint.x(), pathPoint.y());
- m.rotate(360. - angle + rotation);
- m.translate(0.0, charPos.y());
- m_outline.addPath(m.map(m_charOutlines[globalCharIndex]));
- }
- }
- // save offset and position after last character
- m_charOffsets[globalCharIndex] = m_baseline.percentAtLength(startCharOffset + m_charPositions[globalCharIndex].x());
- m_charPositions[globalCharIndex] = m_baseline.pointAtPercent(m_charOffsets[globalCharIndex]);
- } else {
- qreal rotation = 0.0;
- Q_FOREACH (const ArtisticTextRange &range, m_ranges) {
- const QString textRange = range.text();
- const int localTextLength = textRange.length();
- for (int localCharIndex = 0; localCharIndex < localTextLength; ++localCharIndex, ++globalCharIndex) {
- const QPointF &charPos = m_charPositions[globalCharIndex];
- if (range.hasRotation(localCharIndex)) {
- rotation = range.rotation(localCharIndex);
- }
-
- QTransform m;
- m.translate(charPos.x(), charPos.y());
- m.rotate(rotation);
- m_outline.addPath(m.map(m_charOutlines[globalCharIndex]));
- }
- }
- }
-}
-
-void ArtisticTextShape::setPlainText(const QString &newText)
-{
- if (plainText() == newText) {
- return;
- }
-
- beginTextUpdate();
-
- if (newText.isEmpty()) {
- // remove all text ranges
- m_ranges.clear();
- } else if (isEmpty()) {
- // create new text range
- m_ranges.append(ArtisticTextRange(newText, defaultFont()));
- } else {
- // set text to first range
- m_ranges.first().setText(newText);
- // remove all ranges except the first
- while (m_ranges.count() > 1) {
- m_ranges.pop_back();
- }
- }
-
- finishTextUpdate();
-}
-
-QString ArtisticTextShape::plainText() const
-{
- QString allText;
- Q_FOREACH (const ArtisticTextRange &range, m_ranges) {
- allText += range.text();
- }
-
- return allText;
-}
-
-QList<ArtisticTextRange> ArtisticTextShape::text() const
-{
- return m_ranges;
-}
-
-bool ArtisticTextShape::isEmpty() const
-{
- return m_ranges.isEmpty();
-}
-
-void ArtisticTextShape::clear()
-{
- beginTextUpdate();
- m_ranges.clear();
- finishTextUpdate();
-}
-
-void ArtisticTextShape::setFont(const QFont &newFont)
-{
- // no text
- if (isEmpty()) {
- return;
- }
-
- const int rangeCount = m_ranges.count();
- // only one text range with the same font
- if (rangeCount == 1 && m_ranges.first().font() == newFont) {
- return;
- }
-
- beginTextUpdate();
-
- // set font on ranges
- for (int i = 0; i < rangeCount; ++i) {
- m_ranges[i].setFont(newFont);
- }
-
- m_defaultFont = newFont;
-
- finishTextUpdate();
-}
-
-void ArtisticTextShape::setFont(int charIndex, int charCount, const QFont &font)
-{
- if (isEmpty() || charCount <= 0) {
- return;
- }
-
- if (charIndex == 0 && charCount == plainText().length()) {
- setFont(font);
- return;
- }
-
- CharIndex charPos = indexOfChar(charIndex);
- if (charPos.first < 0 || charPos.first >= m_ranges.count()) {
- return;
- }
-
- beginTextUpdate();
-
- int remainingCharCount = charCount;
- while (remainingCharCount > 0) {
- ArtisticTextRange &currRange = m_ranges[charPos.first];
- // does this range have a different font ?
- if (currRange.font() != font) {
- if (charPos.second == 0 && currRange.text().length() < remainingCharCount) {
- // set font on all characters of this range
- currRange.setFont(font);
- remainingCharCount -= currRange.text().length();
- } else {
- ArtisticTextRange changedRange = currRange.extract(charPos.second, remainingCharCount);
- changedRange.setFont(font);
- if (charPos.second == 0) {
- m_ranges.insert(charPos.first, changedRange);
- } else if (charPos.second >= currRange.text().length()) {
- m_ranges.insert(charPos.first + 1, changedRange);
- } else {
- ArtisticTextRange remainingRange = currRange.extract(charPos.second);
- m_ranges.insert(charPos.first + 1, changedRange);
- m_ranges.insert(charPos.first + 2, remainingRange);
- }
- charPos.first++;
- remainingCharCount -= changedRange.text().length();
- }
- }
- charPos.first++;
- if (charPos.first >= m_ranges.count()) {
- break;
- }
- charPos.second = 0;
- }
-
- finishTextUpdate();
-}
-
-QFont ArtisticTextShape::fontAt(int charIndex) const
-{
- if (isEmpty()) {
- return defaultFont();
- }
- if (charIndex < 0) {
- return m_ranges.first().font();
- }
- const int rangeIndex = indexOfChar(charIndex).first;
- if (rangeIndex < 0) {
- return m_ranges.last().font();
- }
-
- return m_ranges[rangeIndex].font();
-}
-
-void ArtisticTextShape::setStartOffset(qreal offset)
-{
- if (m_startOffset == offset) {
- return;
- }
-
- update();
- m_startOffset = qBound<qreal>(0.0, offset, 1.0);
- updateSizeAndPosition();
- update();
- notifyChanged();
-}
-
-qreal ArtisticTextShape::startOffset() const
-{
- return m_startOffset;
-}
-
-qreal ArtisticTextShape::baselineOffset() const
-{
- return m_charPositions.value(0).y();
-}
-
-void ArtisticTextShape::setTextAnchor(TextAnchor anchor)
-{
- if (anchor == m_textAnchor) {
- return;
- }
-
- qreal totalTextWidth = 0.0;
- foreach (const ArtisticTextRange &range, m_ranges) {
- QFontMetricsF metrics(QFont(range.font(), &m_paintDevice));
- totalTextWidth += metrics.width(range.text());
- }
-
- qreal oldOffset = 0.0;
- if (m_textAnchor == AnchorMiddle) {
- oldOffset = -0.5 * totalTextWidth;
- } else if (m_textAnchor == AnchorEnd) {
- oldOffset = -totalTextWidth;
- }
-
- m_textAnchor = anchor;
-
- qreal newOffset = 0.0;
- if (m_textAnchor == AnchorMiddle) {
- newOffset = -0.5 * totalTextWidth;
- } else if (m_textAnchor == AnchorEnd) {
- newOffset = -totalTextWidth;
- }
-
- update();
- updateSizeAndPosition();
- if (! isOnPath()) {
- QTransform m;
- m.translate(newOffset - oldOffset, 0.0);
- setTransformation(transformation() * m);
- }
- update();
- notifyChanged();
-}
-
-ArtisticTextShape::TextAnchor ArtisticTextShape::textAnchor() const
-{
- return m_textAnchor;
-}
-
-bool ArtisticTextShape::putOnPath(KoPathShape *path)
-{
- if (! path) {
- return false;
- }
-
- if (path->outline().isEmpty()) {
- return false;
- }
-
- if (! path->addDependee(this)) {
- return false;
- }
-
- update();
-
- m_path = path;
-
- // use the paths outline converted to document coordinates as the baseline
- m_baseline = m_path->absoluteTransformation().map(m_path->outline());
-
- // reset transformation
- setTransformation(QTransform());
- updateSizeAndPosition();
- // move to correct position
- setAbsolutePosition(m_outlineOrigin, KoFlake::TopLeft);
- update();
-
- return true;
-}
-
-bool ArtisticTextShape::putOnPath(const QPainterPath &path)
-{
- if (path.isEmpty()) {
- return false;
- }
-
- update();
- if (m_path) {
- m_path->removeDependee(this);
- }
- m_path = 0;
- m_baseline = path;
-
- // reset transformation
- setTransformation(QTransform());
- updateSizeAndPosition();
- // move to correct position
- setAbsolutePosition(m_outlineOrigin, KoFlake::TopLeft);
- update();
-
- return true;
-}
-
-void ArtisticTextShape::removeFromPath()
-{
- update();
- if (m_path) {
- m_path->removeDependee(this);
- }
- m_path = 0;
- m_baseline = QPainterPath();
- updateSizeAndPosition();
- update();
-}
-
-bool ArtisticTextShape::isOnPath() const
-{
- return (m_path != 0 || ! m_baseline.isEmpty());
-}
-
-ArtisticTextShape::LayoutMode ArtisticTextShape::layout() const
-{
- if (m_path) {
- return OnPathShape;
- } else if (! m_baseline.isEmpty()) {
- return OnPath;
- } else {
- return Straight;
- }
-}
-
-QPainterPath ArtisticTextShape::baseline() const
-{
- return m_baseline;
-}
-
-KoPathShape *ArtisticTextShape::baselineShape() const
-{
- return m_path;
-}
-
-QList<ArtisticTextRange> ArtisticTextShape::removeText(int charIndex, int charCount)
-{
- QList<ArtisticTextRange> extractedRanges;
- if (!charCount) {
- return extractedRanges;
- }
-
- if (charIndex == 0 && charCount >= plainText().length()) {
- beginTextUpdate();
- extractedRanges = m_ranges;
- m_ranges.clear();
- finishTextUpdate();
- return extractedRanges;
- }
-
- CharIndex charPos = indexOfChar(charIndex);
- if (charPos.first < 0 || charPos.first >= m_ranges.count()) {
- return extractedRanges;
- }
-
- beginTextUpdate();
-
- int extractedTextLength = 0;
- while (extractedTextLength < charCount) {
- ArtisticTextRange r = m_ranges[charPos.first].extract(charPos.second, charCount - extractedTextLength);
- extractedTextLength += r.text().length();
- extractedRanges.append(r);
- if (extractedTextLength == charCount) {
- break;
- }
- charPos.first++;
- if (charPos.first >= m_ranges.count()) {
- break;
- }
- charPos.second = 0;
- }
-
- // now remove all empty ranges
- const int rangeCount = m_ranges.count();
- for (int i = charPos.first; i < rangeCount; ++i) {
- if (m_ranges[charPos.first].text().isEmpty()) {
- m_ranges.removeAt(charPos.first);
- }
- }
-
- finishTextUpdate();
-
- return extractedRanges;
-}
-
-QList<ArtisticTextRange> ArtisticTextShape::copyText(int charIndex, int charCount)
-{
- QList<ArtisticTextRange> extractedRanges;
- if (!charCount) {
- return extractedRanges;
- }
-
- CharIndex charPos = indexOfChar(charIndex);
- if (charPos.first < 0 || charPos.first >= m_ranges.count()) {
- return extractedRanges;
- }
-
- int extractedTextLength = 0;
- while (extractedTextLength < charCount) {
- ArtisticTextRange copy = m_ranges[charPos.first];
- ArtisticTextRange r = copy.extract(charPos.second, charCount - extractedTextLength);
- extractedTextLength += r.text().length();
- extractedRanges.append(r);
- if (extractedTextLength == charCount) {
- break;
- }
- charPos.first++;
- if (charPos.first >= m_ranges.count()) {
- break;
- }
- charPos.second = 0;
- }
-
- return extractedRanges;
-}
-
-void ArtisticTextShape::insertText(int charIndex, const QString &str)
-{
- if (isEmpty()) {
- appendText(str);
- return;
- }
-
- CharIndex charPos = indexOfChar(charIndex);
- if (charIndex < 0) {
- // insert before first character
- charPos = CharIndex(0, 0);
- } else if (charIndex >= plainText().length()) {
- // insert after last character
- charPos = CharIndex(m_ranges.count() - 1, m_ranges.last().text().length());
- }
-
- // check range index, just in case
- if (charPos.first < 0) {
- return;
- }
-
- beginTextUpdate();
-
- m_ranges[charPos.first].insertText(charPos.second, str);
-
- finishTextUpdate();
-}
-
-void ArtisticTextShape::insertText(int charIndex, const ArtisticTextRange &textRange)
-{
- QList<ArtisticTextRange> ranges;
- ranges.append(textRange);
- insertText(charIndex, ranges);
-}
-
-void ArtisticTextShape::insertText(int charIndex, const QList<ArtisticTextRange> &textRanges)
-{
- if (isEmpty()) {
- beginTextUpdate();
- m_ranges = textRanges;
- finishTextUpdate();
- return;
- }
-
- CharIndex charPos = indexOfChar(charIndex);
- if (charIndex < 0) {
- // insert before first character
- charPos = CharIndex(0, 0);
- } else if (charIndex >= plainText().length()) {
- // insert after last character
- charPos = CharIndex(m_ranges.count() - 1, m_ranges.last().text().length());
- }
-
- // check range index, just in case
- if (charPos.first < 0) {
- return;
- }
-
- beginTextUpdate();
-
- ArtisticTextRange &hitRange = m_ranges[charPos.first];
- if (charPos.second == 0) {
- // insert ranges before the hit range
- Q_FOREACH (const ArtisticTextRange &range, textRanges) {
- m_ranges.insert(charPos.first, range);
- charPos.first++;
- }
- } else if (charPos.second == hitRange.text().length()) {
- // insert ranges after the hit range
- Q_FOREACH (const ArtisticTextRange &range, textRanges) {
- m_ranges.insert(charPos.first + 1, range);
- charPos.first++;
- }
- } else {
- // insert ranges inside hit range
- ArtisticTextRange right = hitRange.extract(charPos.second, hitRange.text().length());
- m_ranges.insert(charPos.first + 1, right);
- // now insert after the left part of hit range
- Q_FOREACH (const ArtisticTextRange &range, textRanges) {
- m_ranges.insert(charPos.first + 1, range);
- charPos.first++;
- }
- }
-
- // TODO: merge ranges with same style
-
- finishTextUpdate();
-}
-
-void ArtisticTextShape::appendText(const QString &text)
-{
- beginTextUpdate();
-
- if (isEmpty()) {
- m_ranges.append(ArtisticTextRange(text, defaultFont()));
- } else {
- m_ranges.last().appendText(text);
- }
-
- finishTextUpdate();
-}
-
-void ArtisticTextShape::appendText(const ArtisticTextRange &text)
-{
- beginTextUpdate();
-
- m_ranges.append(text);
-
- // TODO: merge ranges with same style
-
- finishTextUpdate();
-}
-
-bool ArtisticTextShape::replaceText(int charIndex, int charCount, const ArtisticTextRange &textRange)
-{
- QList<ArtisticTextRange> ranges;
- ranges.append(textRange);
- return replaceText(charIndex, charCount, ranges);
-}
-
-bool ArtisticTextShape::replaceText(int charIndex, int charCount, const QList<ArtisticTextRange> &textRanges)
-{
- CharIndex charPos = indexOfChar(charIndex);
- if (charPos.first < 0 || !charCount) {
- return false;
- }
-
- beginTextUpdate();
-
- removeText(charIndex, charCount);
- insertText(charIndex, textRanges);
-
- finishTextUpdate();
-
- return true;
-}
-
-qreal ArtisticTextShape::charAngleAt(int charIndex) const
-{
- if (isOnPath()) {
- qreal t = m_charOffsets.value(qBound(0, charIndex, m_charOffsets.size() - 1));
- return m_baseline.angleAtPercent(t);
- }
-
- return 0.0;
-}
-
-QPointF ArtisticTextShape::charPositionAt(int charIndex) const
-{
- return m_charPositions.value(qBound(0, charIndex, m_charPositions.size() - 1));
-}
-
-QRectF ArtisticTextShape::charExtentsAt(int charIndex) const
-{
- CharIndex charPos = indexOfChar(charIndex);
- if (charIndex < 0 || isEmpty()) {
- charPos = CharIndex(0, 0);
- } else if (charPos.first < 0) {
- charPos = CharIndex(m_ranges.count() - 1, m_ranges.last().text().length() - 1);
- }
-
- if (charPos.first < m_ranges.size()) {
- const ArtisticTextRange &range = m_ranges.at(charPos.first);
- QFontMetrics metrics(range.font());
-#if QT_VERSION >= QT_VERSION_CHECK(5,11,0)
- QChar c = range.text().at(charPos.second);
- int w = metrics.horizontalAdvance(c);
-#else
- int w = metrics.charWidth(range.text(), charPos.second);
-#endif
- return QRectF(0, 0, w, metrics.height());
- }
-
- return QRectF();
-}
-
-void ArtisticTextShape::updateSizeAndPosition(bool global)
-{
- QTransform shapeTransform = absoluteTransformation();
-
- // determine baseline position in document coordinates
- QPointF oldBaselinePosition = shapeTransform.map(QPointF(0, baselineOffset()));
-
- createOutline();
-
- QRectF bbox = m_outline.boundingRect();
- if (bbox.isEmpty()) {
- bbox = nullBoundBox();
- }
-
- if (isOnPath()) {
- // calculate the offset we have to apply to keep our position
- QPointF offset = m_outlineOrigin - bbox.topLeft();
- // cache topleft corner of baseline path
- m_outlineOrigin = bbox.topLeft();
- // the outline position is in document coordinates
- // so we adjust our position
- QTransform m;
- m.translate(-offset.x(), -offset.y());
- global ? applyAbsoluteTransformation(m) : applyTransformation(m);
- } else {
- // determine the new baseline position in document coordinates
- QPointF newBaselinePosition = shapeTransform.map(QPointF(0, -bbox.top()));
- // apply a transformation to compensate any translation of
- // our baseline position
- QPointF delta = oldBaselinePosition - newBaselinePosition;
- QTransform m;
- m.translate(delta.x(), delta.y());
- applyAbsoluteTransformation(m);
- }
-
- setSize(bbox.size());
-
- // map outline to shape coordinate system
- QTransform normalizeMatrix;
- normalizeMatrix.translate(-bbox.left(), -bbox.top());
- m_outline = normalizeMatrix.map(m_outline);
- const int charCount = m_charPositions.count();
- for (int i = 0; i < charCount; ++i) {
- m_charPositions[i] = normalizeMatrix.map(m_charPositions[i]);
- }
-}
-
-void ArtisticTextShape::cacheGlyphOutlines()
-{
- m_charOutlines.clear();
-
- Q_FOREACH (const ArtisticTextRange &range, m_ranges) {
- const QString rangeText = range.text();
- const QFont rangeFont(range.font(), &m_paintDevice);
- const int textLength = rangeText.length();
- for (int charIdx = 0; charIdx < textLength; ++charIdx) {
- QPainterPath charOutline;
- charOutline.addText(QPointF(), rangeFont, rangeText[charIdx]);
- m_charOutlines.append(charOutline);
- }
- }
-}
-
-void ArtisticTextShape::shapeChanged(ChangeType type, KoShape *shape)
-{
- if (m_path && shape == m_path) {
- if (type == KoShape::Deleted) {
- // baseline shape was deleted
- m_path = 0;
- } else if (type == KoShape::ParentChanged && !shape->parent()) {
- // baseline shape was probably removed from the document
- m_path->removeDependee(this);
- m_path = 0;
- } else {
- update();
- // use the paths outline converted to document coordinates as the baseline
- m_baseline = m_path->absoluteTransformation().map(m_path->outline());
- updateSizeAndPosition(true);
- update();
- }
- }
-}
-
-CharIndex ArtisticTextShape::indexOfChar(int charIndex) const
-{
- if (isEmpty()) {
- return CharIndex(-1, -1);
- }
-
- int rangeIndex = 0;
- int textLength = 0;
- Q_FOREACH (const ArtisticTextRange &range, m_ranges) {
- const int rangeTextLength = range.text().length();
- if (static_cast<int>(charIndex) < textLength + rangeTextLength) {
- return CharIndex(rangeIndex, charIndex - textLength);
- }
- textLength += rangeTextLength;
- rangeIndex++;
- }
-
- return CharIndex(-1, -1);
-}
-
-void ArtisticTextShape::beginTextUpdate()
-{
- if (m_textUpdateCounter) {
- return;
- }
-
- m_textUpdateCounter++;
- update();
-}
-
-void ArtisticTextShape::finishTextUpdate()
-{
- if (!m_textUpdateCounter) {
- return;
- }
-
- cacheGlyphOutlines();
- updateSizeAndPosition();
- update();
- notifyChanged();
-
- m_textUpdateCounter--;
-}
-
-bool ArtisticTextShape::saveSvg(SvgSavingContext &context)
-{
- context.shapeWriter().startElement("text", false);
- context.shapeWriter().addAttribute("id", context.getID(this));
-
- SvgStyleWriter::saveSvgStyle(this, context);
-
- const QList<ArtisticTextRange> formattedText = text();
-
- // if we have only a single text range, save the font on the text element
- const bool hasSingleRange = formattedText.size() == 1;
- if (hasSingleRange) {
- saveSvgFont(formattedText.first().font(), context);
- }
-
- qreal anchorOffset = 0.0;
- if (textAnchor() == ArtisticTextShape::AnchorMiddle) {
- anchorOffset += 0.5 * this->size().width();
- context.shapeWriter().addAttribute("text-anchor", "middle");
- } else if (textAnchor() == ArtisticTextShape::AnchorEnd) {
- anchorOffset += this->size().width();
- context.shapeWriter().addAttribute("text-anchor", "end");
- }
-
- // check if we are set on a path
- if (layout() == ArtisticTextShape::Straight) {
- context.shapeWriter().addAttribute("x", anchorOffset);
- context.shapeWriter().addAttribute("y", baselineOffset());
- SvgUtil::writeTransformAttributeLazy("transform", transformation(), context.shapeWriter());
- Q_FOREACH (const ArtisticTextRange &range, formattedText) {
- saveSvgTextRange(range, context, !hasSingleRange, baselineOffset());
- }
- } else {
- KoPathShape *baselineShape = KoPathShape::createShapeFromPainterPath(baseline());
-
- QString id = context.createUID("baseline");
- context.styleWriter().startElement("path");
- context.styleWriter().addAttribute("id", id);
- context.styleWriter().addAttribute("d", baselineShape->toString(baselineShape->absoluteTransformation() * context.userSpaceTransform()));
- context.styleWriter().endElement();
-
- context.shapeWriter().startElement("textPath");
- context.shapeWriter().addAttribute("xlink:href", QLatin1Char('#') + id);
- if (startOffset() > 0.0) {
- context.shapeWriter().addAttribute("startOffset", QString("%1%").arg(startOffset() * 100.0));
- }
- Q_FOREACH (const ArtisticTextRange &range, formattedText) {
- saveSvgTextRange(range, context, !hasSingleRange, baselineOffset());
- }
- context.shapeWriter().endElement();
-
- delete baselineShape;
- }
-
- context.shapeWriter().endElement();
-
- return true;
-}
-
-void ArtisticTextShape::saveSvgFont(const QFont &font, SvgSavingContext &context)
-{
- context.shapeWriter().addAttribute("font-family", font.family());
- context.shapeWriter().addAttribute("font-size", font.pointSizeF());
-
- if (font.bold()) {
- context.shapeWriter().addAttribute("font-weight", "bold");
- }
- if (font.italic()) {
- context.shapeWriter().addAttribute("font-style", "italic");
- }
-}
-
-void ArtisticTextShape::saveSvgTextRange(const ArtisticTextRange &range, SvgSavingContext &context, bool saveRangeFont, qreal baselineOffset)
-{
- context.shapeWriter().startElement("tspan", false);
- if (range.hasXOffsets()) {
- const char *attributeName = (range.xOffsetType() == ArtisticTextRange::AbsoluteOffset ? "x" : "dx");
- QString attributeValue;
- int charIndex = 0;
- while (range.hasXOffset(charIndex)) {
- if (charIndex) {
- attributeValue += QLatin1Char(',');
- }
- attributeValue += QString("%1").arg(SvgUtil::toUserSpace(range.xOffset(charIndex++)));
- }
- context.shapeWriter().addAttribute(attributeName, attributeValue);
- }
- if (range.hasYOffsets()) {
- if (range.yOffsetType() != ArtisticTextRange::AbsoluteOffset) {
- baselineOffset = 0;
- }
- const char *attributeName = (range.yOffsetType() == ArtisticTextRange::AbsoluteOffset ? " y" : " dy");
- QString attributeValue;
- int charIndex = 0;
- while (range.hasYOffset(charIndex)) {
- if (charIndex) {
- attributeValue += QLatin1Char(',');
- }
- attributeValue += QString("%1").arg(SvgUtil::toUserSpace(baselineOffset + range.yOffset(charIndex++)));
- }
- context.shapeWriter().addAttribute(attributeName, attributeValue);
- }
- if (range.hasRotations()) {
- QString attributeValue;
- int charIndex = 0;
- while (range.hasRotation(charIndex)) {
- if (charIndex) {
- attributeValue += ',';
- }
- attributeValue += QString("%1").arg(range.rotation(charIndex++));
- }
- context.shapeWriter().addAttribute("rotate", attributeValue);
- }
- if (range.baselineShift() != ArtisticTextRange::None) {
- switch (range.baselineShift()) {
- case ArtisticTextRange::Sub:
- context.shapeWriter().addAttribute("baseline-shift", "sub");
- break;
- case ArtisticTextRange::Super:
- context.shapeWriter().addAttribute("baseline-shift", "super");
- break;
- case ArtisticTextRange::Percent:
- context.shapeWriter().addAttribute("baseline-shift", QString("%1%").arg(range.baselineShiftValue() * 100));
- break;
- case ArtisticTextRange::Length:
- context.shapeWriter().addAttribute("baseline-shift", QString("%1%").arg(SvgUtil::toUserSpace(range.baselineShiftValue())));
- break;
- default:
- break;
- }
- }
- if (saveRangeFont) {
- saveSvgFont(range.font(), context);
- }
- context.shapeWriter().addTextNode(range.text());
- context.shapeWriter().endElement();
-}
-
-bool ArtisticTextShape::loadSvg(const KoXmlElement &textElement, SvgLoadingContext &context)
-{
- clear();
-
- QString anchor;
- if (!textElement.attribute("text-anchor").isEmpty()) {
- anchor = textElement.attribute("text-anchor");
- }
-
- SvgStyles elementStyles = context.styleParser().collectStyles(textElement);
- context.styleParser().parseFont(elementStyles);
-
- ArtisticTextLoadingContext textContext;
- textContext.parseCharacterTransforms(textElement, context.currentGC());
-
- KoXmlElement parentElement = textElement;
- // first check if we have a "textPath" child element
- for (KoXmlNode n = textElement.firstChild(); !n.isNull(); n = n.nextSibling()) {
- KoXmlElement e = n.toElement();
- if (e.tagName() == "textPath") {
- parentElement = e;
- break;
- }
- }
-
- KoPathShape *path = 0;
- bool pathInDocument = false;
- double offset = 0.0;
-
- const bool hasTextPathElement = parentElement != textElement && parentElement.hasAttribute("xlink:href");
- if (hasTextPathElement) {
- // create the referenced path shape
- context.pushGraphicsContext(parentElement);
- context.styleParser().parseFont(context.styleParser().collectStyles(parentElement));
- textContext.pushCharacterTransforms();
- textContext.parseCharacterTransforms(parentElement, context.currentGC());
-
- QString href = parentElement.attribute("xlink:href").mid(1);
- if (context.hasDefinition(href)) {
- const KoXmlElement &p = context.definition(href);
- // must be a path element as per svg spec
- if (p.tagName() == "path") {
- pathInDocument = false;
- path = new KoPathShape();
- path->clear();
-
- KoPathShapeLoader loader(path);
- loader.parseSvg(p.attribute("d"), true);
- path->setPosition(path->normalize());
-
- QPointF newPosition = QPointF(SvgUtil::fromUserSpace(path->position().x()),
- SvgUtil::fromUserSpace(path->position().y()));
- QSizeF newSize = QSizeF(SvgUtil::fromUserSpace(path->size().width()),
- SvgUtil::fromUserSpace(path->size().height()));
-
- path->setSize(newSize);
- path->setPosition(newPosition);
- path->applyAbsoluteTransformation(context.currentGC()->matrix);
- }
- } else {
- path = dynamic_cast<KoPathShape *>(context.shapeById(href));
- if (path) {
- pathInDocument = true;
- }
- }
- // parse the start offset
- if (! parentElement.attribute("startOffset").isEmpty()) {
- QString start = parentElement.attribute("startOffset");
- if (start.endsWith('%')) {
- offset = 0.01 * start.remove('%').toDouble();
- } else {
- const float pathLength = path ? path->outline().length() : 0.0;
- if (pathLength > 0.0) {
- offset = start.toDouble() / pathLength;
- }
- }
- }
- }
-
- if (parentElement.hasChildNodes()) {
- // parse child elements
- parseTextRanges(parentElement, context, textContext);
- if (!context.currentGC()->preserveWhitespace) {
- const QString text = plainText();
- if (text.endsWith(' ')) {
- removeText(text.length() - 1, 1);
- }
- }
- setPosition(textContext.textPosition());
- } else {
- // a single text range
- appendText(createTextRange(textElement.text(), textContext, context.currentGC()));
- setPosition(textContext.textPosition());
- }
-
- if (hasTextPathElement) {
- if (path) {
- if (pathInDocument) {
- putOnPath(path);
- } else {
- putOnPath(path->absoluteTransformation().map(path->outline()));
- delete path;
- }
-
- if (offset > 0.0) {
- setStartOffset(offset);
- }
- }
- textContext.popCharacterTransforms();
- context.popGraphicsContext();
- }
-
- // adjust position by baseline offset
- if (! isOnPath()) {
- setPosition(position() - QPointF(0, baselineOffset()));
- }
-
- if (anchor == "middle") {
- setTextAnchor(ArtisticTextShape::AnchorMiddle);
- } else if (anchor == "end") {
- setTextAnchor(ArtisticTextShape::AnchorEnd);
- }
-
- return true;
-}
-
-void ArtisticTextShape::parseTextRanges(const KoXmlElement &element, SvgLoadingContext &context, ArtisticTextLoadingContext &textContext)
-{
- for (KoXmlNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) {
- KoXmlElement e = n.toElement();
- if (e.isNull()) {
- ArtisticTextRange range = createTextRange(n.toText().data(), textContext, context.currentGC());
- appendText(range);
- } else if (e.tagName() == "tspan") {
- SvgGraphicsContext *gc = context.pushGraphicsContext(e);
- context.styleParser().parseFont(context.styleParser().collectStyles(e));
- textContext.pushCharacterTransforms();
- textContext.parseCharacterTransforms(e, gc);
- parseTextRanges(e, context, textContext);
- textContext.popCharacterTransforms();
- context.popGraphicsContext();
- } else if (e.tagName() == "tref") {
- if (e.attribute("xlink:href").isEmpty()) {
- continue;
- }
-
- QString href = e.attribute("xlink:href").mid(1);
- ArtisticTextShape *refText = dynamic_cast<ArtisticTextShape *>(context.shapeById(href));
- if (refText) {
- foreach (const ArtisticTextRange &range, refText->text()) {
- appendText(range);
- }
- } else if (context.hasDefinition(href)) {
- const KoXmlElement &p = context.definition(href);
- SvgGraphicsContext *gc = context.currentGC();
- appendText(ArtisticTextRange(textContext.simplifyText(p.text(), gc->preserveWhitespace), gc->font));
- }
- } else {
- continue;
- }
- }
-}
-
-ArtisticTextRange ArtisticTextShape::createTextRange(const QString &text, ArtisticTextLoadingContext &context, SvgGraphicsContext *gc)
-{
- ArtisticTextRange range(context.simplifyText(text, gc->preserveWhitespace), gc->font);
-
- const int textLength = range.text().length();
- switch (context.xOffsetType()) {
- case ArtisticTextLoadingContext::Absolute:
- range.setXOffsets(context.xOffsets(textLength), ArtisticTextRange::AbsoluteOffset);
- break;
- case ArtisticTextLoadingContext::Relative:
- range.setXOffsets(context.xOffsets(textLength), ArtisticTextRange::RelativeOffset);
- break;
- default:
- // no x-offsets
- break;
- }
- switch (context.yOffsetType()) {
- case ArtisticTextLoadingContext::Absolute:
- range.setYOffsets(context.yOffsets(textLength), ArtisticTextRange::AbsoluteOffset);
- break;
- case ArtisticTextLoadingContext::Relative:
- range.setYOffsets(context.yOffsets(textLength), ArtisticTextRange::RelativeOffset);
- break;
- default:
- // no y-offsets
- break;
- }
-
- range.setRotations(context.rotations(textLength));
-
-#if 0
- range.setLetterSpacing(gc->letterSpacing);
- range.setWordSpacing(gc->wordSpacing);
-
- if (gc->baselineShift == "sub") {
- range.setBaselineShift(ArtisticTextRange::Sub);
- } else if (gc->baselineShift == "super") {
- range.setBaselineShift(ArtisticTextRange::Super);
- } else if (gc->baselineShift.endsWith('%')) {
- range.setBaselineShift(ArtisticTextRange::Percent, SvgUtil::fromPercentage(gc->baselineShift));
- } else {
- qreal value = SvgUtil::parseUnitX(gc, gc->baselineShift);
- if (value != 0.0) {
- range.setBaselineShift(ArtisticTextRange::Length, value);
- }
- }
-#endif
-
- //range.printDebug();
-
- return range;
-}
diff --git a/plugins/flake/artistictextshape/ArtisticTextShape.h b/plugins/flake/artistictextshape/ArtisticTextShape.h
deleted file mode 100644
index 47ceb4d89d..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextShape.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007-2008,2011 Jan Hambrecht <jaham@gmx.net>
- * Copyright (C) 2008 Rob Buis <buis@kde.org>
- *
- * 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 ARTISTICTEXTSHAPE_H
-#define ARTISTICTEXTSHAPE_H
-
-#include "ArtisticTextRange.h"
-#include <KoShape.h>
-#include <KoPostscriptPaintDevice.h>
-#include <SvgShape.h>
-#include <QFont>
-#include <QPainterPath>
-#include <QVector>
-
-class QPainter;
-class KoPathShape;
-class ArtisticTextLoadingContext;
-class SvgGraphicsContext;
-
-#define ArtisticTextShapeID "ArtisticText"
-
-/// Character position within text shape (range index, range character index)
-typedef QPair<int, int> CharIndex;
-
-class ArtisticTextShape : public KoShape, public SvgShape
-{
-public:
- enum TextAnchor { AnchorStart, AnchorMiddle, AnchorEnd };
-
- enum LayoutMode {
- Straight, ///< baseline is a straight line
- OnPath, ///< baseline is a QPainterPath
- OnPathShape ///< baseline is the outline of a path shape
- };
-
- ArtisticTextShape();
- ~ArtisticTextShape() override;
- virtual KoShape *cloneShape() const override;
-
- /// reimplemented
- void paint(QPainter &painter, KoShapePaintingContext &paintContext) const override;
- /// reimplemented
- void saveOdf(KoShapeSavingContext &context) const override;
- /// reimplemented
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
- /// reimplemented
- QSizeF size() const override;
- /// reimplemented
- void setSize(const QSizeF &size) override;
- /// reimplemented
- QPainterPath outline() const override;
- /// reimplemented from SvgShape
- bool saveSvg(SvgSavingContext &context) override;
- /// reimplemented from SvgShape
- bool loadSvg(const KoXmlElement &element, SvgLoadingContext &context) override;
-
- /// Sets the plain text to display
- void setPlainText(const QString &newText);
-
- /// Returns the plain text content
- QString plainText() const;
-
- /// Returns formatted text
- QList<ArtisticTextRange> text() const;
-
- /// Returns if text shape is empty, i.e. no text
- bool isEmpty() const;
-
- /// Clears the text shape
- void clear();
-
- /**
- * Sets the font used for drawing
- * Note that it is expected that the font has its point size set
- * in postscript points.
- */
- void setFont(const QFont &font);
-
- /**
- * Sets the font for the specified range of characters
- * @param charIndex the index of the first character of the range
- * @param charCount the number of characters of the range
- * @param font the new font to set
- */
- void setFont(int charIndex, int charCount, const QFont &font);
-
- /**
- * Returns the font at the specified character position
- * If the text shape is empty it will return the default font.
- * If the character index is smaller than zero it will return the font
- * of the first character. If the character index is greater than the
- * last character index it will return the font of the last character.
- */
- QFont fontAt(int charIndex) const;
-
- /// Returns the default font
- QFont defaultFont() const;
-
- /// Attaches this text shape to the given path shape
- bool putOnPath(KoPathShape *path);
-
- /// Puts the text on the given path, the path is expected to be in document coordinates
- bool putOnPath(const QPainterPath &path);
-
- /// Detaches this text shape from an already attached path shape
- void removeFromPath();
-
- /// Returns if shape is attached to a path shape
- bool isOnPath() const;
-
- /// Sets the offset for for text on path
- void setStartOffset(qreal offset);
-
- /// Returns the start offset for text on path
- qreal startOffset() const;
-
- /**
- * Returns the y-offset from the top-left corner to the baseline.
- * This is usable for being able to exactly position the texts baseline.
- * Note: The value makes only sense for text not attached to a path.
- */
- qreal baselineOffset() const;
-
- /// Sets the text anchor
- void setTextAnchor(TextAnchor anchor);
-
- /// Returns the actual text anchor
- TextAnchor textAnchor() const;
-
- /// Returns the current layout mode
- LayoutMode layout() const;
-
- /// Returns the baseline path
- QPainterPath baseline() const;
-
- /// Returns a pointer to the shape used as baseline
- KoPathShape *baselineShape() const;
-
- /// Removes a range of text starting from the given character
- QList<ArtisticTextRange> removeText(int charIndex, int charCount);
-
- /// Copies a range of text starting from the given character
- QList<ArtisticTextRange> copyText(int charIndex, int charCount);
-
- /// Adds a range of text at the given index
- void insertText(int charIndex, const QString &plainText);
-
- /// Adds range of text at the given index
- void insertText(int charIndex, const ArtisticTextRange &textRange);
-
- /// Adds ranges of text at the given index
- void insertText(int charIndex, const QList<ArtisticTextRange> &textRanges);
-
- /// Appends plain text to the last text range
- void appendText(const QString &plainText);
-
- /// Appends a single formatted range of text
- void appendText(const ArtisticTextRange &text);
-
- /// Replaces a range of text with the specified text range
- bool replaceText(int charIndex, int charCount, const ArtisticTextRange &textRange);
-
- /// Replaces a range of text with the specified text ranges
- bool replaceText(int charIndex, int charCount, const QList<ArtisticTextRange> &textRanges);
-
- /// Gets the angle of the char with the given index
- qreal charAngleAt(int charIndex) const;
-
- /// Gets the position of the char with the given index in shape coordinates
- QPointF charPositionAt(int charIndex) const;
-
- /// Gets the extents of the char with the given index
- QRectF charExtentsAt(int charIndex) const;
-
- /// Returns index of range and index within range of specified character
- CharIndex indexOfChar(int charIndex) const;
-
- /// reimplemented from KoShape
- void shapeChanged(ChangeType type, KoShape *shape) override;
-
-private:
- void updateSizeAndPosition(bool global = false);
- void cacheGlyphOutlines();
- bool pathHasChanged() const;
- void createOutline();
-
- void beginTextUpdate();
- void finishTextUpdate();
-
- /// Calculates abstract character positions in baseline coordinates
- QVector<QPointF> calculateAbstractCharacterPositions();
-
- /// Returns the bounding box for an empty text shape
- QRectF nullBoundBox() const;
-
- /// Saves svg font
- void saveSvgFont(const QFont &font, SvgSavingContext &context);
- /// Saves svg text range
- void saveSvgTextRange(const ArtisticTextRange &range, SvgSavingContext &context, bool saveFont, qreal baselineOffset);
- /// Parse nested text ranges
- void parseTextRanges(const KoXmlElement &element, SvgLoadingContext &context, ArtisticTextLoadingContext &textContext);
- /// Creates text range
- ArtisticTextRange createTextRange(const QString &text, ArtisticTextLoadingContext &context, SvgGraphicsContext *gc);
-
- QList<ArtisticTextRange> m_ranges;
- KoPostscriptPaintDevice m_paintDevice;
- KoPathShape *m_path; ///< the path shape we are attached to
- QList<QPainterPath> m_charOutlines; ///< cached character oulines
- qreal m_startOffset; ///< the offset from the attached path start point
- QPointF m_outlineOrigin; ///< the top-left corner of the non-normalized text outline
- QPainterPath m_outline; ///< the actual text outline
- QPainterPath m_baseline; ///< the baseline path the text is put on
- TextAnchor m_textAnchor; ///< the actual text anchor
- QVector<qreal> m_charOffsets; ///< char positions [0..1] on baseline path
- QVector<QPointF> m_charPositions; ///< char positions in shape coordinates
- int m_textUpdateCounter;
- QFont m_defaultFont;
-};
-
-#endif // ARTISTICTEXTSHAPE_H
diff --git a/plugins/flake/artistictextshape/ArtisticTextShapeConfigWidget.cpp b/plugins/flake/artistictextshape/ArtisticTextShapeConfigWidget.cpp
deleted file mode 100644
index bb2cdf915b..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextShapeConfigWidget.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007,2011 Jan Hambrecht <jaham@gmx.net>
- * Copyright (C) 2008 Rob Buis <buis@kde.org>
- *
- * 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 "ArtisticTextShapeConfigWidget.h"
-#include "ArtisticTextTool.h"
-#include "ArtisticTextToolSelection.h"
-#include "ArtisticTextShape.h"
-
-#include <QAction>
-
-ArtisticTextShapeConfigWidget::ArtisticTextShapeConfigWidget(ArtisticTextTool *textTool)
- : m_textTool(textTool)
-{
- Q_ASSERT(m_textTool);
-
- widget.setupUi(this);
-
- widget.bold->setDefaultAction(textTool->action("artistictext_font_bold"));
- widget.italic->setDefaultAction(textTool->action("artistictext_font_italic"));
- widget.superScript->setDefaultAction(textTool->action("artistictext_superscript"));
- widget.subScript->setDefaultAction(textTool->action("artistictext_subscript"));
- widget.anchorStart->setDefaultAction(textTool->action("artistictext_anchor_start"));
- widget.anchorMiddle->setDefaultAction(textTool->action("artistictext_anchor_middle"));
- widget.anchorEnd->setDefaultAction(textTool->action("artistictext_anchor_end"));
- widget.fontSize->setRange(2, 1000);
-
- connect(widget.fontFamily, SIGNAL(currentFontChanged(QFont)), this, SIGNAL(fontFamilyChanged(QFont)));
- connect(widget.fontSize, SIGNAL(valueChanged(int)), this, SIGNAL(fontSizeChanged(int)));
-}
-
-void ArtisticTextShapeConfigWidget::blockChildSignals(bool block)
-{
- widget.fontFamily->blockSignals(block);
- widget.fontSize->blockSignals(block);
-}
-
-void ArtisticTextShapeConfigWidget::updateWidget()
-{
- ArtisticTextToolSelection *selection = dynamic_cast<ArtisticTextToolSelection *>(m_textTool->selection());
- if (!selection) {
- return;
- }
-
- ArtisticTextShape *currentText = selection->selectedShape();
- if (!currentText) {
- return;
- }
-
- blockChildSignals(true);
-
- QFont font = currentText->fontAt(m_textTool->textCursor());
-
- widget.fontSize->setValue(font.pointSize());
- font.setPointSize(8);
- widget.fontFamily->setCurrentFont(font);
-
- blockChildSignals(false);
-}
diff --git a/plugins/flake/artistictextshape/ArtisticTextShapeConfigWidget.h b/plugins/flake/artistictextshape/ArtisticTextShapeConfigWidget.h
deleted file mode 100644
index 0e7c8cb085..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextShapeConfigWidget.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- * Copyright (C) 2008 Rob Buis <buis@kde.org>
- *
- * 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 ARTISTICTEXTSHAPECONFIGWIDGET_H
-#define ARTISTICTEXTSHAPECONFIGWIDGET_H
-
-#include <ui_ArtisticTextShapeConfigWidget.h>
-
-#include <KoShapeConfigWidgetBase.h>
-
-class ArtisticTextTool;
-
-class ArtisticTextShapeConfigWidget : public QWidget
-{
- Q_OBJECT
-public:
- explicit ArtisticTextShapeConfigWidget(ArtisticTextTool *textTool);
-
-public Q_SLOTS:
- /// updates the widget form the current artistic text shape
- void updateWidget();
-
-Q_SIGNALS:
- /// Triggered whenever the font familiy has changed
- void fontFamilyChanged(const QFont &);
-
- /// Triggered whenever the font size has changed
- void fontSizeChanged(int);
-
-private:
- void blockChildSignals(bool block);
- Ui::ArtisticTextShapeConfigWidget widget;
- ArtisticTextTool *m_textTool;
-};
-
-#endif // ARTISTICTEXTSHAPECONFIGWIDGET_H
diff --git a/plugins/flake/artistictextshape/ArtisticTextShapeConfigWidget.ui b/plugins/flake/artistictextshape/ArtisticTextShapeConfigWidget.ui
deleted file mode 100644
index 53c0b931bc..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextShapeConfigWidget.ui
+++ /dev/null
@@ -1,156 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ArtisticTextShapeConfigWidget</class>
- <widget class="QWidget" name="ArtisticTextShapeConfigWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>259</width>
- <height>73</height>
- </rect>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Ignored" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <property name="leftMargin">
- <number>0</number>
- </property>
- <property name="topMargin">
- <number>0</number>
- </property>
- <property name="rightMargin">
- <number>0</number>
- </property>
- <property name="bottomMargin">
- <number>0</number>
- </property>
- <item row="0" column="0">
- <widget class="QFontComboBox" name="fontFamily">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="KisIntParseSpinBox" name="fontSize">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- <item row="1" column="0" colspan="2">
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QToolButton" name="anchorStart">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="anchorMiddle">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="anchorEnd">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="Line" name="line">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="bold">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="italic">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="Line" name="line_2">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="superScript">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="subScript">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item row="2" column="0" colspan="2">
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>KisIntParseSpinBox</class>
- <extends>QSpinBox</extends>
- <header>kis_int_parse_spin_box.h</header>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/artistictextshape/ArtisticTextShapeFactory.cpp b/plugins/flake/artistictextshape/ArtisticTextShapeFactory.cpp
deleted file mode 100644
index 8067cac7f4..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextShapeFactory.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "ArtisticTextShapeFactory.h"
-#include "ArtisticTextShape.h"
-
-#include <KoXmlNS.h>
-#include <KoColorBackground.h>
-
-#include <QColor>
-
-#include <KoIcon.h>
-#include <klocalizedstring.h>
-
-ArtisticTextShapeFactory::ArtisticTextShapeFactory()
- : KoShapeFactoryBase(ArtisticTextShapeID, i18n("ArtisticTextShape"))
-{
- setToolTip(i18n("A shape which shows a single text line"));
- setIconName(koIconNameCStr("x-shape-text"));
- setLoadingPriority(5);
- //setXmlElementNames(KoXmlNS::svg, QStringList("text"));
-}
-
-KoShape *ArtisticTextShapeFactory::createDefaultShape(KoDocumentResourceManager *) const
-{
- ArtisticTextShape *text = new ArtisticTextShape();
- text->setBackground(QSharedPointer<KoShapeBackground>(new KoColorBackground(QColor(Qt::black))));
- text->setPlainText(i18n("Artistic Text"));
- return text;
-}
-
-bool ArtisticTextShapeFactory::supports(const KoXmlElement &/*element*/, KoShapeLoadingContext &/*context*/) const
-{
- // the artistic text shape is embedded as svg into an odf file
- // so we tell the caller we do not support any element
- return false;
-}
diff --git a/plugins/flake/artistictextshape/ArtisticTextShapeFactory.h b/plugins/flake/artistictextshape/ArtisticTextShapeFactory.h
deleted file mode 100644
index 3bf75d2306..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextShapeFactory.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 ARTISTICTEXTSHAPEFACTORY_H
-#define ARTISTICTEXTSHAPEFACTORY_H
-
-#include <KoShapeFactoryBase.h>
-
-class KoShape;
-
-class ArtisticTextShapeFactory : public KoShapeFactoryBase
-{
-public:
- ArtisticTextShapeFactory();
- ~ArtisticTextShapeFactory() override {}
-
- KoShape *createDefaultShape(KoDocumentResourceManager *documentResources = 0) const override;
- // reimplemented from KoShapeFactoryBase
- bool supports(const KoXmlElement &e, KoShapeLoadingContext &context) const override;
-};
-
-#endif // ARTISTICTEXTSHAPEFACTORY_H
diff --git a/plugins/flake/artistictextshape/ArtisticTextShapeLoadingUpdater.cpp b/plugins/flake/artistictextshape/ArtisticTextShapeLoadingUpdater.cpp
deleted file mode 100644
index 3f76d6bb80..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextShapeLoadingUpdater.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2009 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 "ArtisticTextShapeLoadingUpdater.h"
-
-#include "ArtisticTextShape.h"
-#include <KoPathShape.h>
-
-ArtisticTextShapeLoadingUpdater::ArtisticTextShapeLoadingUpdater(ArtisticTextShape *artisticTextShape)
- : m_artisticTextShape(artisticTextShape)
-{
-}
-
-ArtisticTextShapeLoadingUpdater::~ArtisticTextShapeLoadingUpdater()
-{
-}
-
-void ArtisticTextShapeLoadingUpdater::update(KoShape *shape)
-{
- // we have already loaded the correct transformation, so save it here
- // and apply after putting us on the path shape
- QTransform matrix = m_artisticTextShape->transformation();
-
- // putting us on the path shape resulting in a changed transformation
- m_artisticTextShape->putOnPath(dynamic_cast<KoPathShape *>(shape));
-
- // resetting the transformation to the former state
- m_artisticTextShape->setTransformation(matrix);
-}
diff --git a/plugins/flake/artistictextshape/ArtisticTextShapeLoadingUpdater.h b/plugins/flake/artistictextshape/ArtisticTextShapeLoadingUpdater.h
deleted file mode 100644
index 108cc5a740..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextShapeLoadingUpdater.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2009 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 ARTISTICTEXTSHAPELOADINGUPDATER_H
-#define ARTISTICTEXTSHAPELOADINGUPDATER_H
-
-#include <KoLoadingShapeUpdater.h>
-
-class ArtisticTextShape;
-
-class ArtisticTextShapeLoadingUpdater : public KoLoadingShapeUpdater
-{
-public:
- explicit ArtisticTextShapeLoadingUpdater(ArtisticTextShape *artisticTextShape);
- ~ArtisticTextShapeLoadingUpdater() override;
- void update(KoShape *shape) override;
-
-private:
- ArtisticTextShape *m_artisticTextShape;
-};
-
-#endif // ARTISTICTEXTSHAPELOADINGUPDATER_H
diff --git a/plugins/flake/artistictextshape/ArtisticTextShapeOnPathWidget.cpp b/plugins/flake/artistictextshape/ArtisticTextShapeOnPathWidget.cpp
deleted file mode 100644
index 7a8604a618..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextShapeOnPathWidget.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "ArtisticTextShapeOnPathWidget.h"
-#include "ui_ArtisticTextShapeOnPathWidget.h"
-#include "ArtisticTextTool.h"
-#include <QAction>
-
-ArtisticTextShapeOnPathWidget::ArtisticTextShapeOnPathWidget(ArtisticTextTool *tool, QWidget *parent)
- : QWidget(parent)
- , ui(new Ui::ArtisticTextShapeOnPathWidget)
- , m_textTool(tool)
-{
- ui->setupUi(this);
- ui->detachFromPath->setDefaultAction(tool->action("artistictext_detach_from_path"));
- ui->convertToPath->setDefaultAction(tool->action("artistictext_convert_to_path"));
-
- connect(ui->startOffset, SIGNAL(valueChanged(int)), this, SIGNAL(offsetChanged(int)));
-}
-
-ArtisticTextShapeOnPathWidget::~ArtisticTextShapeOnPathWidget()
-{
- delete ui;
-}
-
-void ArtisticTextShapeOnPathWidget::updateWidget()
-{
- ArtisticTextToolSelection *selection = dynamic_cast<ArtisticTextToolSelection *>(m_textTool->selection());
- if (!selection) {
- return;
- }
-
- ArtisticTextShape *currentText = selection->selectedShape();
- if (!currentText) {
- return;
- }
-
- ui->startOffset->blockSignals(true);
- ui->startOffset->setValue(static_cast<int>(currentText->startOffset() * 100.0));
- ui->startOffset->setEnabled(currentText->isOnPath());
- ui->startOffset->blockSignals(false);
-}
diff --git a/plugins/flake/artistictextshape/ArtisticTextShapeOnPathWidget.h b/plugins/flake/artistictextshape/ArtisticTextShapeOnPathWidget.h
deleted file mode 100644
index b43060c312..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextShapeOnPathWidget.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 ARTISTICTEXTSHAPEONPATHWIDGET_H
-#define ARTISTICTEXTSHAPEONPATHWIDGET_H
-
-#include <QWidget>
-
-namespace Ui
-{
-class ArtisticTextShapeOnPathWidget;
-}
-
-class ArtisticTextTool;
-
-class ArtisticTextShapeOnPathWidget : public QWidget
-{
- Q_OBJECT
-
-public:
- explicit ArtisticTextShapeOnPathWidget(ArtisticTextTool *tool, QWidget *parent = 0);
- ~ArtisticTextShapeOnPathWidget() override;
-
-public Q_SLOTS:
- void updateWidget();
-
-Q_SIGNALS:
- /// triggered whenever the start offset has changed
- void offsetChanged(int);
-
-private:
- Ui::ArtisticTextShapeOnPathWidget *ui;
- ArtisticTextTool *m_textTool;
-};
-
-#endif // ARTISTICTEXTSHAPEONPATHWIDGET_H
diff --git a/plugins/flake/artistictextshape/ArtisticTextShapeOnPathWidget.ui b/plugins/flake/artistictextshape/ArtisticTextShapeOnPathWidget.ui
deleted file mode 100644
index 9bea362e9c..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextShapeOnPathWidget.ui
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ArtisticTextShapeOnPathWidget</class>
- <widget class="QWidget" name="ArtisticTextShapeOnPathWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>208</width>
- <height>59</height>
- </rect>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <property name="margin">
- <number>0</number>
- </property>
- <item row="0" column="0">
- <widget class="QToolButton" name="detachFromPath">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="Line" name="line">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- </widget>
- </item>
- <item row="0" column="2">
- <widget class="QToolButton" name="convertToPath">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="0" column="3">
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>138</width>
- <height>25</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="0" colspan="4">
- <widget class="QSlider" name="startOffset">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>75</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/artistictextshape/ArtisticTextShapePlugin.cpp b/plugins/flake/artistictextshape/ArtisticTextShapePlugin.cpp
deleted file mode 100644
index c64f39608c..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextShapePlugin.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "ArtisticTextShapePlugin.h"
-#include "ArtisticTextShapeFactory.h"
-#include "ArtisticTextToolFactory.h"
-
-#include <KoShapeRegistry.h>
-#include <KoToolRegistry.h>
-
-#include <kpluginfactory.h>
-
-K_PLUGIN_FACTORY_WITH_JSON(ArtisticTextShapePluginFactory, "calligra_shape_artistictext.json",
- registerPlugin<ArtisticTextShapePlugin>();)
-
-ArtisticTextShapePlugin::ArtisticTextShapePlugin(QObject *parent, const QVariantList &)
- : QObject(parent)
-{
- KoShapeRegistry::instance()->add(new ArtisticTextShapeFactory());
- //KoToolRegistry::instance()->add(new ArtisticTextToolFactory());
-}
-
-ArtisticTextShapePlugin::~ArtisticTextShapePlugin()
-{
-}
-
-#include <ArtisticTextShapePlugin.moc>
diff --git a/plugins/flake/artistictextshape/ArtisticTextShapePlugin.h b/plugins/flake/artistictextshape/ArtisticTextShapePlugin.h
deleted file mode 100644
index a8dd859e05..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextShapePlugin.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 ARTISTICTEXTSHAPEPLUGIN_H
-#define ARTISTICTEXTSHAPEPLUGIN_H
-
-#include <QObject>
-#include <QVariantList>
-
-class ArtisticTextShapePlugin : public QObject
-{
- Q_OBJECT
-
-public:
- ArtisticTextShapePlugin(QObject *parent, const QVariantList &);
- ~ArtisticTextShapePlugin() override;
-};
-
-#endif // ARTISTICTEXTSHAPEPLUGIN_H
diff --git a/plugins/flake/artistictextshape/ArtisticTextTool.cpp b/plugins/flake/artistictextshape/ArtisticTextTool.cpp
deleted file mode 100644
index 7eb29d354a..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextTool.cpp
+++ /dev/null
@@ -1,1008 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007,2011 Jan Hambrecht <jaham@gmx.net>
- * Copyright (C) 2008 Rob Buis <buis@kde.org>
- *
- * 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 "ArtisticTextTool.h"
-#include "ArtisticTextToolSelection.h"
-#include "AttachTextToPathCommand.h"
-#include "DetachTextFromPathCommand.h"
-#include "AddTextRangeCommand.h"
-#include "RemoveTextRangeCommand.h"
-#include "ArtisticTextShapeConfigWidget.h"
-#include "ArtisticTextShapeOnPathWidget.h"
-#include "MoveStartOffsetStrategy.h"
-#include "SelectTextStrategy.h"
-#include "ChangeTextOffsetCommand.h"
-#include "ChangeTextFontCommand.h"
-#include "ChangeTextAnchorCommand.h"
-#include "ReplaceTextRangeCommand.h"
-
-#include <KoCanvasBase.h>
-#include <KoSelection.h>
-#include <KoShapeManager.h>
-#include <KoSelectedShapesProxy.h>
-#include <KoPointerEvent.h>
-#include <KoPathShape.h>
-#include <KoShapeBackground.h>
-#include <KoShapeController.h>
-#include <KoShapeContainer.h>
-#include <KoInteractionStrategy.h>
-#include <KoIcon.h>
-#include <KoViewConverter.h>
-#include "kis_action_registry.h"
-
-#include <klocalizedstring.h>
-#include <kstandardaction.h>
-#include <QAction>
-#include <QDebug>
-
-#include <QGridLayout>
-#include <QToolButton>
-#include <QCheckBox>
-#include <QPainter>
-#include <QPainterPath>
-#include <kundo2command.h>
-
-#include <float.h>
-#include <math.h>
-
-const int BlinkInterval = 500;
-
-static bool hit(const QKeySequence &input, KStandardShortcut::StandardShortcut shortcut)
-{
- foreach (const QKeySequence &ks, KStandardShortcut::shortcut(shortcut)) {
- if (input == ks) {
- return true;
- }
- }
- return false;
-}
-
-ArtisticTextTool::ArtisticTextTool(KoCanvasBase *canvas)
- : KoToolBase(canvas)
- , m_selection(canvas, this)
- , m_currentShape(0)
- , m_hoverText(0)
- , m_hoverPath(0)
- , m_hoverHandle(false)
- , m_textCursor(-1)
- , m_showCursor(true)
- , m_currentStrategy(0)
-{
- KisActionRegistry *actionRegistry = KisActionRegistry::instance();
- m_detachPath = actionRegistry->makeQAction("artistictext_detach_from_path", this);
- m_detachPath->setEnabled(false);
- connect(m_detachPath, SIGNAL(triggered()), this, SLOT(detachPath()));
-// addAction("artistictext_detach_from_path", m_detachPath);
-
- m_convertText = actionRegistry->makeQAction("artistictext_convert_to_path", this);
- m_convertText->setEnabled(false);
- connect(m_convertText, SIGNAL(triggered()), this, SLOT(convertText()));
-// addAction("artistictext_convert_to_path", m_convertText);
-
- m_fontBold = actionRegistry->makeQAction("artistictext_font_bold", this);
- connect(m_fontBold, SIGNAL(toggled(bool)), this, SLOT(toggleFontBold(bool)));
-// addAction("artistictext_font_bold", m_fontBold);
-
- m_fontItalic = actionRegistry->makeQAction("artistictext_font_italic", this);
- connect(m_fontItalic, SIGNAL(toggled(bool)), this, SLOT(toggleFontItalic(bool)));
-// addAction("artistictext_font_italic", m_fontItalic);
-
- m_superScript = actionRegistry->makeQAction("artistictext_superscript", this);
- connect(m_superScript, SIGNAL(triggered()), this, SLOT(setSuperScript()));
-// addAction("artistictext_superscript", m_superScript);
-
- m_subScript = actionRegistry->makeQAction("artistictext_subscript", this);
- connect(m_subScript, SIGNAL(triggered()), this, SLOT(setSubScript()));
-// addAction("artistictext_subscript", m_subScript);
-
- QAction *anchorStart = actionRegistry->makeQAction("artistictext_anchor_start", this);
- anchorStart->setData(ArtisticTextShape::AnchorStart);
-// addAction("artistictext_anchor_start", anchorStart);
-
- QAction *anchorMiddle = actionRegistry->makeQAction("artistictext_anchor_middle", this);
- anchorMiddle->setData(ArtisticTextShape::AnchorMiddle);
-// addAction("artistictext_anchor_middle", anchorMiddle);
-
- QAction *anchorEnd = actionRegistry->makeQAction("artistictext_anchor_end", this);
- anchorEnd->setData(ArtisticTextShape::AnchorEnd);
-// addAction("artistictext_anchor_end", anchorEnd);
-
- m_anchorGroup = new QActionGroup(this);
- m_anchorGroup->setExclusive(true);
- m_anchorGroup->addAction(anchorStart);
- m_anchorGroup->addAction(anchorMiddle);
- m_anchorGroup->addAction(anchorEnd);
- connect(m_anchorGroup, SIGNAL(triggered(QAction*)), this, SLOT(anchorChanged(QAction*)));
-
- connect(canvas->selectedShapesProxy(), SIGNAL(selectionContentChanged()), this, SLOT(textChanged()));
-
-// addAction("edit_select_all", KStandardAction::selectAll(this, SLOT(selectAll()), this));
-// addAction("edit_deselect_all", KStandardAction::deselect(this, SLOT(deselectAll()), this));
-
- setTextMode(true);
-}
-
-ArtisticTextTool::~ArtisticTextTool()
-{
- delete m_currentStrategy;
-}
-
-QTransform ArtisticTextTool::cursorTransform() const
-{
- if (!m_currentShape) {
- return QTransform();
- }
-
- QTransform transform;
-
- const int textLength = m_currentShape->plainText().length();
- if (m_textCursor <= textLength) {
- const QPointF pos = m_currentShape->charPositionAt(m_textCursor);
- const qreal angle = m_currentShape->charAngleAt(m_textCursor);
- QFontMetrics metrics(m_currentShape->fontAt(m_textCursor));
-
- transform.translate(pos.x() - 1, pos.y());
- transform.rotate(360. - angle);
- transform.translate(0, metrics.descent());
- } else if (m_textCursor <= textLength + m_linefeedPositions.size()) {
- const QPointF pos = m_linefeedPositions.value(m_textCursor - textLength - 1);
- QFontMetrics metrics(m_currentShape->fontAt(textLength - 1));
- transform.translate(pos.x(), pos.y());
- transform.translate(0, metrics.descent());
- }
-
- return transform * m_currentShape->absoluteTransformation();
-}
-
-void ArtisticTextTool::paint(QPainter &painter, const KoViewConverter &converter)
-{
- if (! m_currentShape) {
- return;
- }
-
- if (m_showCursor && m_blinkingCursor.isActive() && !m_currentStrategy) {
- painter.save();
- painter.setTransform(converter.documentToView(), true);
- painter.setBrush(Qt::black);
- painter.setWorldTransform(cursorTransform(), true);
- painter.setClipping(false);
- painter.drawPath(m_textCursorShape);
- painter.restore();
- }
- m_showCursor = !m_showCursor;
-
- if (m_currentShape->isOnPath()) {
- painter.save();
- painter.setTransform(converter.documentToView(), true);
- if (!m_currentShape->baselineShape()) {
- painter.setPen(Qt::DotLine);
- painter.setBrush(Qt::NoBrush);
- painter.drawPath(m_currentShape->baseline());
- }
- painter.setPen(Qt::blue);
- painter.setBrush(m_hoverHandle ? Qt::red : Qt::white);
- painter.drawPath(offsetHandleShape());
- painter.restore();
- }
- if (m_selection.hasSelection()) {
- painter.save();
- painter.setTransform(converter.documentToView(), true);
- m_selection.paint(painter);
- painter.restore();
- }
-}
-
-void ArtisticTextTool::repaintDecorations()
-{
- canvas()->updateCanvas(offsetHandleShape().boundingRect());
- if (m_currentShape && m_currentShape->isOnPath()) {
- if (!m_currentShape->baselineShape()) {
- canvas()->updateCanvas(m_currentShape->baseline().boundingRect());
- }
- }
- m_selection.repaintDecoration();
-}
-
-int ArtisticTextTool::cursorFromMousePosition(const QPointF &mousePosition)
-{
- if (!m_currentShape) {
- return -1;
- }
-
- const QPointF pos = m_currentShape->documentToShape(mousePosition);
- const int len = m_currentShape->plainText().length();
- int hit = -1;
- qreal mindist = DBL_MAX;
- for (int i = 0; i <= len; ++i) {
- QPointF center = pos - m_currentShape->charPositionAt(i);
- if ((fabs(center.x()) + fabs(center.y())) < mindist) {
- hit = i;
- mindist = fabs(center.x()) + fabs(center.y());
- }
- }
- return hit;
-}
-
-void ArtisticTextTool::mousePressEvent(KoPointerEvent *event)
-{
- if (m_hoverHandle) {
- m_currentStrategy = new MoveStartOffsetStrategy(this, m_currentShape);
- }
- if (m_hoverText) {
- KoSelection *selection = canvas()->selectedShapesProxy()->selection();
- if (m_hoverText != m_currentShape) {
- // if we hit another text shape, select that shape
- selection->deselectAll();
- setCurrentShape(m_hoverText);
- selection->select(m_currentShape);
- }
- // change the text cursor position
- int hitCursorPos = cursorFromMousePosition(event->point);
- if (hitCursorPos >= 0) {
- setTextCursorInternal(hitCursorPos);
- m_selection.clear();
- }
- m_currentStrategy = new SelectTextStrategy(this, m_textCursor);
- }
- event->ignore();
-}
-
-void ArtisticTextTool::mouseMoveEvent(KoPointerEvent *event)
-{
- m_hoverPath = 0;
- m_hoverText = 0;
-
- if (m_currentStrategy) {
- m_currentStrategy->handleMouseMove(event->point, event->modifiers());
- return;
- }
-
- const bool textOnPath = m_currentShape && m_currentShape->isOnPath();
- if (textOnPath) {
- QPainterPath handle = offsetHandleShape();
- QPointF handleCenter = handle.boundingRect().center();
- if (handleGrabRect(event->point).contains(handleCenter)) {
- // mouse is on offset handle
- if (!m_hoverHandle) {
- canvas()->updateCanvas(handle.boundingRect());
- }
- m_hoverHandle = true;
- } else {
- if (m_hoverHandle) {
- canvas()->updateCanvas(handle.boundingRect());
- }
- m_hoverHandle = false;
- }
- }
- if (!m_hoverHandle) {
- // find text or path shape at cursor position
- QList<KoShape *> shapes = canvas()->shapeManager()->shapesAt(handleGrabRect(event->point));
- if (shapes.contains(m_currentShape)) {
- m_hoverText = m_currentShape;
- } else {
- Q_FOREACH (KoShape *shape, shapes) {
- ArtisticTextShape *text = dynamic_cast<ArtisticTextShape *>(shape);
- if (text && !m_hoverText) {
- m_hoverText = text;
- }
- KoPathShape *path = dynamic_cast<KoPathShape *>(shape);
- if (path && !m_hoverPath) {
- m_hoverPath = path;
- }
- if (m_hoverPath && m_hoverText) {
- break;
- }
- }
- }
- }
-
- const bool hoverOnBaseline = textOnPath && m_currentShape && m_currentShape->baselineShape() == m_hoverPath;
- // update cursor and status text
- if (m_hoverText) {
- useCursor(QCursor(Qt::IBeamCursor));
- if (m_hoverText == m_currentShape) {
- emit statusTextChanged(i18n("Click to change cursor position."));
- } else {
- emit statusTextChanged(i18n("Click to select text shape."));
- }
- } else if (m_hoverPath && m_currentShape && !hoverOnBaseline) {
- useCursor(QCursor(Qt::PointingHandCursor));
- emit statusTextChanged(i18n("Double click to put text on path."));
- } else if (m_hoverHandle) {
- useCursor(QCursor(Qt::ArrowCursor));
- emit statusTextChanged(i18n("Drag handle to change start offset."));
- } else {
- useCursor(QCursor(Qt::ArrowCursor));
- if (m_currentShape) {
- emit statusTextChanged(i18n("Press escape to finish editing."));
- } else {
- emit statusTextChanged(QString());
- }
- }
-}
-
-void ArtisticTextTool::mouseReleaseEvent(KoPointerEvent *event)
-{
- if (m_currentStrategy) {
- m_currentStrategy->finishInteraction(event->modifiers());
- KUndo2Command *cmd = m_currentStrategy->createCommand();
- if (cmd) {
- canvas()->addCommand(cmd);
- }
- delete m_currentStrategy;
- m_currentStrategy = 0;
- }
- updateActions();
-}
-
-void ArtisticTextTool::shortcutOverrideEvent(QKeyEvent *event)
-{
- QKeySequence item(event->key() | ((Qt::ControlModifier | Qt::AltModifier) & event->modifiers()));
- if (hit(item, KStandardShortcut::Begin) ||
- hit(item, KStandardShortcut::End)) {
- event->accept();
- }
-}
-
-void ArtisticTextTool::mouseDoubleClickEvent(KoPointerEvent */*event*/)
-{
- if (m_hoverPath && m_currentShape) {
- if (!m_currentShape->isOnPath() || m_currentShape->baselineShape() != m_hoverPath) {
- m_blinkingCursor.stop();
- m_showCursor = false;
- updateTextCursorArea();
- canvas()->addCommand(new AttachTextToPathCommand(m_currentShape, m_hoverPath));
- m_blinkingCursor.start(BlinkInterval);
- updateActions();
- m_hoverPath = 0;
- m_linefeedPositions.clear();
- return;
- }
- }
-}
-
-void ArtisticTextTool::keyPressEvent(QKeyEvent *event)
-{
- if (event->key() == Qt::Key_Escape) {
- event->ignore();
- return;
- }
-
- event->accept();
- if (m_currentShape && textCursor() > -1) {
- switch (event->key()) {
- case Qt::Key_Delete:
- if (m_selection.hasSelection()) {
- removeFromTextCursor(m_selection.selectionStart(), m_selection.selectionCount());
- } else if (textCursor() >= 0 && textCursor() < m_currentShape->plainText().length()) {
- removeFromTextCursor(textCursor(), 1);
- }
- break;
- case Qt::Key_Backspace:
- if (m_selection.hasSelection()) {
- removeFromTextCursor(m_selection.selectionStart(), m_selection.selectionCount());
- } else {
- removeFromTextCursor(textCursor() - 1, 1);
- }
- break;
- case Qt::Key_Right:
- if (event->modifiers() & Qt::ShiftModifier) {
- int selectionStart, selectionEnd;
- if (m_selection.hasSelection()) {
- selectionStart = m_selection.selectionStart();
- selectionEnd = selectionStart + m_selection.selectionCount();
- if (textCursor() == selectionStart) {
- selectionStart = textCursor() + 1;
- } else if (textCursor() == selectionEnd) {
- selectionEnd = textCursor() + 1;
- }
- } else {
- selectionStart = textCursor();
- selectionEnd = textCursor() + 1;
- }
- m_selection.selectText(selectionStart, selectionEnd);
- } else {
- m_selection.clear();
- }
- setTextCursor(m_currentShape, textCursor() + 1);
- break;
- case Qt::Key_Left:
- if (event->modifiers() & Qt::ShiftModifier) {
- int selectionStart, selectionEnd;
- if (m_selection.hasSelection()) {
- selectionStart = m_selection.selectionStart();
- selectionEnd = selectionStart + m_selection.selectionCount();
- if (textCursor() == selectionStart) {
- selectionStart = textCursor() - 1;
- } else if (textCursor() == selectionEnd) {
- selectionEnd = textCursor() - 1;
- }
- } else {
- selectionEnd = textCursor();
- selectionStart = textCursor() - 1;
- }
- m_selection.selectText(selectionStart, selectionEnd);
- } else {
- m_selection.clear();
- }
- setTextCursor(m_currentShape, textCursor() - 1);
- break;
- case Qt::Key_Home:
- if (event->modifiers() & Qt::ShiftModifier) {
- const int selectionStart = 0;
- const int selectionEnd = m_selection.hasSelection() ? m_selection.selectionStart() + m_selection.selectionCount() : m_textCursor;
- m_selection.selectText(selectionStart, selectionEnd);
- } else {
- m_selection.clear();
- }
- setTextCursor(m_currentShape, 0);
- break;
- case Qt::Key_End:
- if (event->modifiers() & Qt::ShiftModifier) {
- const int selectionStart = m_selection.hasSelection() ? m_selection.selectionStart() : m_textCursor;
- const int selectionEnd = m_currentShape->plainText().length();
- m_selection.selectText(selectionStart, selectionEnd);
- } else {
- m_selection.clear();
- }
- setTextCursor(m_currentShape, m_currentShape->plainText().length());
- break;
- case Qt::Key_Return:
- case Qt::Key_Enter: {
- const int textLength = m_currentShape->plainText().length();
- if (m_textCursor >= textLength) {
- // get font metrics for last character
- QFontMetrics metrics(m_currentShape->fontAt(textLength - 1));
- const qreal offset = m_currentShape->size().height() + (m_linefeedPositions.size() + 1) * metrics.height();
- m_linefeedPositions.append(QPointF(0, offset));
- setTextCursor(m_currentShape, textCursor() + 1);
- }
- break;
- }
- default:
- if (event->text().isEmpty()) {
- event->ignore();
- return;
- }
- if (m_selection.hasSelection()) {
- removeFromTextCursor(m_selection.selectionStart(), m_selection.selectionCount());
- }
- addToTextCursor(event->text());
- }
- } else {
- event->ignore();
- }
-}
-
-void ArtisticTextTool::activate(ToolActivation activation, const QSet<KoShape *> &shapes)
-{
- KoToolBase::activate(activation, shapes);
-
- foreach (KoShape *shape, shapes) {
- ArtisticTextShape *text = dynamic_cast<ArtisticTextShape *>(shape);
- if (text) {
- setCurrentShape(text);
- break;
- }
- }
- if (!m_currentShape) {
- // none found
- emit done();
- return;
- }
-
- m_hoverText = 0;
- m_hoverPath = 0;
-
- updateActions();
- emit statusTextChanged(i18n("Press return to finish editing."));
- repaintDecorations();
-
- connect(canvas()->selectedShapesProxy(), SIGNAL(selectionChanged()), this, SLOT(shapeSelectionChanged()));
-}
-
-void ArtisticTextTool::blinkCursor()
-{
- updateTextCursorArea();
-}
-
-void ArtisticTextTool::deactivate()
-{
- if (m_currentShape) {
- if (m_currentShape->plainText().isEmpty()) {
- canvas()->addCommand(canvas()->shapeController()->removeShape(m_currentShape));
- }
- setCurrentShape(0);
- }
- m_hoverPath = 0;
- m_hoverText = 0;
-
- disconnect(canvas()->selectedShapesProxy(), SIGNAL(selectionChanged()), this, SLOT(shapeSelectionChanged()));
-
- KoToolBase::deactivate();
-}
-
-void ArtisticTextTool::updateActions()
-{
- if (m_currentShape) {
- const QFont font = m_currentShape->fontAt(textCursor());
- const CharIndex index = m_currentShape->indexOfChar(textCursor());
- ArtisticTextRange::BaselineShift baselineShift = ArtisticTextRange::None;
- if (index.first >= 0) {
- baselineShift = m_currentShape->text().at(index.first).baselineShift();
- }
- m_fontBold->blockSignals(true);
- m_fontBold->setChecked(font.bold());
- m_fontBold->blockSignals(false);
- m_fontBold->setEnabled(true);
- m_fontItalic->blockSignals(true);
- m_fontItalic->setChecked(font.italic());
- m_fontItalic->blockSignals(false);
- m_fontItalic->setEnabled(true);
- m_detachPath->setEnabled(m_currentShape->isOnPath());
- m_convertText->setEnabled(true);
- m_anchorGroup->blockSignals(true);
- Q_FOREACH (QAction *action, m_anchorGroup->actions()) {
- if (action->data().toInt() == m_currentShape->textAnchor()) {
- action->setChecked(true);
- }
- }
- m_anchorGroup->blockSignals(false);
- m_anchorGroup->setEnabled(true);
- m_superScript->blockSignals(true);
- m_superScript->setChecked(baselineShift == ArtisticTextRange::Super);
- m_superScript->blockSignals(false);
- m_subScript->blockSignals(true);
- m_subScript->setChecked(baselineShift == ArtisticTextRange::Sub);
- m_subScript->blockSignals(false);
- m_superScript->setEnabled(true);
- m_subScript->setEnabled(true);
- } else {
- m_detachPath->setEnabled(false);
- m_convertText->setEnabled(false);
- m_fontBold->setEnabled(false);
- m_fontItalic->setEnabled(false);
- m_anchorGroup->setEnabled(false);
- m_superScript->setEnabled(false);
- m_subScript->setEnabled(false);
- }
-}
-
-void ArtisticTextTool::detachPath()
-{
- if (m_currentShape && m_currentShape->isOnPath()) {
- canvas()->addCommand(new DetachTextFromPathCommand(m_currentShape));
- updateActions();
- }
-}
-
-void ArtisticTextTool::convertText()
-{
- if (! m_currentShape) {
- return;
- }
-
- KoPathShape *path = KoPathShape::createShapeFromPainterPath(m_currentShape->outline());
- path->setZIndex(m_currentShape->zIndex());
- path->setStroke(m_currentShape->stroke());
- path->setBackground(m_currentShape->background());
- path->setTransformation(m_currentShape->transformation());
- path->setShapeId(KoPathShapeId);
-
- KUndo2Command *cmd = canvas()->shapeController()->addShapeDirect(path, 0);
- cmd->setText(kundo2_i18n("Convert to Path"));
- canvas()->shapeController()->removeShape(m_currentShape, cmd);
- canvas()->addCommand(cmd);
-
- emit done();
-}
-
-QList<QPointer<QWidget> > ArtisticTextTool::createOptionWidgets()
-{
- QList<QPointer<QWidget> > widgets;
-
- ArtisticTextShapeConfigWidget *configWidget = new ArtisticTextShapeConfigWidget(this);
- configWidget->setObjectName("ArtisticTextConfigWidget");
- configWidget->setWindowTitle(i18n("Text Properties"));
- connect(configWidget, SIGNAL(fontFamilyChanged(QFont)), this, SLOT(setFontFamiliy(QFont)));
- connect(configWidget, SIGNAL(fontSizeChanged(int)), this, SLOT(setFontSize(int)));
- connect(this, SIGNAL(shapeSelected()), configWidget, SLOT(updateWidget()));
- connect(canvas()->selectedShapesProxy(), SIGNAL(selectionContentChanged()),
- configWidget, SLOT(updateWidget()));
- widgets.append(configWidget);
-
- ArtisticTextShapeOnPathWidget *pathWidget = new ArtisticTextShapeOnPathWidget(this);
- pathWidget->setObjectName("ArtisticTextPathWidget");
- pathWidget->setWindowTitle(i18n("Text On Path"));
- connect(pathWidget, SIGNAL(offsetChanged(int)), this, SLOT(setStartOffset(int)));
- connect(this, SIGNAL(shapeSelected()), pathWidget, SLOT(updateWidget()));
- connect(canvas()->selectedShapesProxy(), SIGNAL(selectionContentChanged()),
- pathWidget, SLOT(updateWidget()));
- widgets.append(pathWidget);
-
- if (m_currentShape) {
- pathWidget->updateWidget();
- configWidget->updateWidget();
- }
-
- return widgets;
-}
-
-KoToolSelection *ArtisticTextTool::selection()
-{
- return &m_selection;
-}
-
-void ArtisticTextTool::enableTextCursor(bool enable)
-{
- if (enable) {
- if (m_currentShape) {
- setTextCursorInternal(m_currentShape->plainText().length());
- }
- connect(&m_blinkingCursor, SIGNAL(timeout()), this, SLOT(blinkCursor()));
- m_blinkingCursor.start(BlinkInterval);
- } else {
- m_blinkingCursor.stop();
- disconnect(&m_blinkingCursor, SIGNAL(timeout()), this, SLOT(blinkCursor()));
- setTextCursorInternal(-1);
- m_showCursor = false;
- }
-}
-
-void ArtisticTextTool::setTextCursor(ArtisticTextShape *textShape, int textCursor)
-{
- if (!m_currentShape || textShape != m_currentShape) {
- return;
- }
- if (m_textCursor == textCursor || textCursor < 0) {
- return;
- }
- const int textLength = m_currentShape->plainText().length() + m_linefeedPositions.size();
- if (textCursor > textLength) {
- return;
- }
- setTextCursorInternal(textCursor);
-}
-
-int ArtisticTextTool::textCursor() const
-{
- return m_textCursor;
-}
-
-void ArtisticTextTool::updateTextCursorArea() const
-{
- if (! m_currentShape || m_textCursor < 0) {
- return;
- }
-
- QRectF bbox = cursorTransform().mapRect(m_textCursorShape.boundingRect());
- canvas()->updateCanvas(bbox);
-}
-
-void ArtisticTextTool::setCurrentShape(ArtisticTextShape *currentShape)
-{
- if (m_currentShape == currentShape) {
- return;
- }
- enableTextCursor(false);
- m_currentShape = currentShape;
- m_selection.setSelectedShape(m_currentShape);
- if (m_currentShape) {
- enableTextCursor(true);
- }
- emit shapeSelected();
-}
-
-void ArtisticTextTool::setTextCursorInternal(int textCursor)
-{
- updateTextCursorArea();
- m_textCursor = textCursor;
- createTextCursorShape();
- updateTextCursorArea();
- updateActions();
- emit shapeSelected();
-}
-
-void ArtisticTextTool::createTextCursorShape()
-{
- if (m_textCursor < 0 || ! m_currentShape) {
- return;
- }
- const QRectF extents = m_currentShape->charExtentsAt(m_textCursor);
- m_textCursorShape = QPainterPath();
- m_textCursorShape.addRect(0, 0, 1, -extents.height());
- m_textCursorShape.closeSubpath();
-}
-
-void ArtisticTextTool::removeFromTextCursor(int from, unsigned int count)
-{
- if (from >= 0) {
- if (m_selection.hasSelection()) {
- // clear selection before text is removed, or else selection will be invalid
- m_selection.clear();
- }
- KUndo2Command *cmd = new RemoveTextRangeCommand(this, m_currentShape, from, count);
- canvas()->addCommand(cmd);
- }
-}
-
-void ArtisticTextTool::addToTextCursor(const QString &str)
-{
- if (!str.isEmpty() && m_textCursor > -1) {
- QString printable;
- for (int i = 0; i < str.length(); i++) {
- if (str[i].isPrint()) {
- printable.append(str[i]);
- }
- }
- unsigned int len = printable.length();
- if (len) {
- const int textLength = m_currentShape->plainText().length();
- if (m_textCursor <= textLength) {
- KUndo2Command *cmd = new AddTextRangeCommand(this, m_currentShape, printable, m_textCursor);
- canvas()->addCommand(cmd);
- } else if (m_textCursor <= textLength + m_linefeedPositions.size()) {
- const QPointF pos = m_linefeedPositions.value(m_textCursor - textLength - 1);
- ArtisticTextRange newLine(printable, m_currentShape->fontAt(textLength - 1));
- newLine.setXOffsets(QList<qreal>() << pos.x(), ArtisticTextRange::AbsoluteOffset);
- newLine.setYOffsets(QList<qreal>() << pos.y() - m_currentShape->baselineOffset(), ArtisticTextRange::AbsoluteOffset);
- KUndo2Command *cmd = new AddTextRangeCommand(this, m_currentShape, newLine, m_textCursor);
- canvas()->addCommand(cmd);
- m_linefeedPositions.clear();
- }
- }
- }
-}
-
-void ArtisticTextTool::textChanged()
-{
- if (!m_currentShape) {
- return;
- }
-
- const QString currentText = m_currentShape->plainText();
- if (m_textCursor > currentText.length()) {
- setTextCursorInternal(currentText.length());
- }
-}
-
-void ArtisticTextTool::shapeSelectionChanged()
-{
- KoSelection *selection = canvas()->selectedShapesProxy()->selection();
- if (selection->isSelected(m_currentShape)) {
- return;
- }
-
- foreach (KoShape *shape, selection->selectedShapes()) {
- ArtisticTextShape *text = dynamic_cast<ArtisticTextShape *>(shape);
- if (text) {
- setCurrentShape(text);
- break;
- }
- }
-}
-
-QPainterPath ArtisticTextTool::offsetHandleShape()
-{
- QPainterPath handle;
- if (!m_currentShape || !m_currentShape->isOnPath()) {
- return handle;
- }
-
- const QPainterPath baseline = m_currentShape->baseline();
- const qreal offset = m_currentShape->startOffset();
- QPointF offsetPoint = baseline.pointAtPercent(offset);
- QSizeF paintSize = handlePaintRect(QPointF()).size();
-
- handle.moveTo(0, 0);
- handle.lineTo(0.5 * paintSize.width(), paintSize.height());
- handle.lineTo(-0.5 * paintSize.width(), paintSize.height());
- handle.closeSubpath();
-
- QTransform transform;
- transform.translate(offsetPoint.x(), offsetPoint.y());
- transform.rotate(360. - baseline.angleAtPercent(offset));
-
- return transform.map(handle);
-}
-
-void ArtisticTextTool::setStartOffset(int offset)
-{
- if (!m_currentShape || !m_currentShape->isOnPath()) {
- return;
- }
-
- const qreal newOffset = static_cast<qreal>(offset) / 100.0;
- if (newOffset != m_currentShape->startOffset()) {
- canvas()->addCommand(new ChangeTextOffsetCommand(m_currentShape, m_currentShape->startOffset(), newOffset));
- }
-}
-
-void ArtisticTextTool::changeFontProperty(FontProperty property, const QVariant &value)
-{
- if (!m_currentShape || !m_selection.hasSelection()) {
- return;
- }
-
- // build font ranges
- const int selectedCharCount = m_selection.selectionCount();
- const int selectedCharStart = m_selection.selectionStart();
- QList<ArtisticTextRange> ranges = m_currentShape->text();
- CharIndex index = m_currentShape->indexOfChar(selectedCharStart);
- if (index.first < 0) {
- return;
- }
-
- KUndo2Command *cmd = new KUndo2Command;
- int collectedCharCount = 0;
- while (collectedCharCount < selectedCharCount) {
- ArtisticTextRange &range = ranges[index.first];
- QFont font = range.font();
- switch (property) {
- case BoldProperty:
- font.setBold(value.toBool());
- break;
- case ItalicProperty:
- font.setItalic(value.toBool());
- break;
- case FamiliyProperty:
- font.setFamily(value.toString());
- break;
- case SizeProperty:
- font.setPointSize(value.toInt());
- break;
- }
-
- const int changeCount = qMin(selectedCharCount - collectedCharCount, range.text().count() - index.second);
- const int changeStart = selectedCharStart + collectedCharCount;
- new ChangeTextFontCommand(m_currentShape, changeStart, changeCount, font, cmd);
- index.first++;
- index.second = 0;
- collectedCharCount += changeCount;
- }
-
- canvas()->addCommand(cmd);
-}
-
-void ArtisticTextTool::toggleFontBold(bool enabled)
-{
- changeFontProperty(BoldProperty, QVariant(enabled));
-}
-
-void ArtisticTextTool::toggleFontItalic(bool enabled)
-{
- changeFontProperty(ItalicProperty, QVariant(enabled));
-}
-
-void ArtisticTextTool::anchorChanged(QAction *action)
-{
- if (!m_currentShape) {
- return;
- }
-
- ArtisticTextShape::TextAnchor newAnchor = static_cast<ArtisticTextShape::TextAnchor>(action->data().toInt());
- if (newAnchor != m_currentShape->textAnchor()) {
- canvas()->addCommand(new ChangeTextAnchorCommand(m_currentShape, newAnchor));
- }
-}
-
-void ArtisticTextTool::setFontFamiliy(const QFont &font)
-{
- changeFontProperty(FamiliyProperty, QVariant(font.family()));
-}
-
-void ArtisticTextTool::setFontSize(int size)
-{
- changeFontProperty(SizeProperty, QVariant(size));
-}
-
-void ArtisticTextTool::setSuperScript()
-{
- toggleSubSuperScript(ArtisticTextRange::Super);
-}
-
-void ArtisticTextTool::setSubScript()
-{
- toggleSubSuperScript(ArtisticTextRange::Sub);
-}
-
-void ArtisticTextTool::toggleSubSuperScript(ArtisticTextRange::BaselineShift mode)
-{
- if (!m_currentShape || !m_selection.hasSelection()) {
- return;
- }
-
- const int from = m_selection.selectionStart();
- const int count = m_selection.selectionCount();
-
- QList<ArtisticTextRange> ranges = m_currentShape->copyText(from, count);
- const int rangeCount = ranges.count();
- if (!rangeCount) {
- return;
- }
-
- // determine if we want to disable the specified mode
- const bool disableMode = ranges.first().baselineShift() == mode;
- const qreal fontSize = m_currentShape->defaultFont().pointSizeF();
-
- for (int i = 0; i < rangeCount; ++i) {
- ArtisticTextRange &currentRange = ranges[i];
- QFont font = currentRange.font();
- if (disableMode) {
- currentRange.setBaselineShift(ArtisticTextRange::None);
- font.setPointSizeF(fontSize);
- } else {
- currentRange.setBaselineShift(mode);
- font.setPointSizeF(fontSize * ArtisticTextRange::subAndSuperScriptSizeFactor());
- }
- currentRange.setFont(font);
- }
- canvas()->addCommand(new ReplaceTextRangeCommand(m_currentShape, ranges, from, count, this));
-}
-
-void ArtisticTextTool::selectAll()
-{
- if (m_currentShape) {
- m_selection.selectText(0, m_currentShape->plainText().count());
- }
-}
-
-void ArtisticTextTool::deselectAll()
-{
- if (m_currentShape) {
- m_selection.clear();
- }
-}
-
-QVariant ArtisticTextTool::inputMethodQuery(Qt::InputMethodQuery query, const KoViewConverter &converter) const
-{
- if (!m_currentShape) {
- return QVariant();
- }
-
- switch (query) {
- case Qt::ImMicroFocus: {
- // The rectangle covering the area of the input cursor in widget coordinates.
- QRectF rect = m_textCursorShape.boundingRect();
- rect.moveTop(rect.bottom());
- QTransform shapeMatrix = m_currentShape->absoluteTransformation();
- qreal zoomX, zoomY;
- converter.zoom(&zoomX, &zoomY);
- shapeMatrix.scale(zoomX, zoomY);
- rect = shapeMatrix.mapRect(rect);
- return rect.toRect();
- }
- case Qt::ImFont:
- // The currently used font for text input.
- return m_currentShape->fontAt(m_textCursor);
- case Qt::ImCursorPosition:
- // The logical position of the cursor within the text surrounding the input area (see ImSurroundingText).
- return m_currentShape->charPositionAt(m_textCursor);
- case Qt::ImSurroundingText:
- // The plain text around the input area, for example the current paragraph.
- return m_currentShape->plainText();
- case Qt::ImCurrentSelection:
- // The currently selected text.
- return QVariant();
- default:
- ; // Qt 4.6 adds ImMaximumTextLength and ImAnchorPosition
- }
- return QVariant();
-}
diff --git a/plugins/flake/artistictextshape/ArtisticTextTool.h b/plugins/flake/artistictextshape/ArtisticTextTool.h
deleted file mode 100644
index 298fc36363..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextTool.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007,2011 Jan Hambrecht <jaham@gmx.net>
- * Copyright (C) 2008 Rob Buis <buis@kde.org>
- *
- * 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 ARTISTICTEXTTOOL_H
-#define ARTISTICTEXTTOOL_H
-
-#include "ArtisticTextShape.h"
-#include "ArtisticTextToolSelection.h"
-
-#include <KoToolBase.h>
-#include <QTimer>
-
-class QAction;
-class QActionGroup;
-class KoInteractionStrategy;
-
-/// This is the tool for the artistic text shape.
-class ArtisticTextTool : public KoToolBase
-{
- Q_OBJECT
-public:
- explicit ArtisticTextTool(KoCanvasBase *canvas);
- ~ArtisticTextTool() override;
-
- /// reimplemented
- void paint(QPainter &painter, const KoViewConverter &converter) override;
- /// reimplemented
- void repaintDecorations() override;
- /// reimplemented
- void mousePressEvent(KoPointerEvent *event) override;
- /// reimplemented
- void mouseMoveEvent(KoPointerEvent *event) override;
- /// reimplemented
- void mouseReleaseEvent(KoPointerEvent *event) override;
- /// reimplemented
- virtual void shortcutOverrideEvent(QKeyEvent *event);
- /// reimplemented
- void mouseDoubleClickEvent(KoPointerEvent *event) override;
- /// reimplemented
- void activate(ToolActivation activation, const QSet<KoShape *> &shapes) override;
- /// reimplemented
- void deactivate() override;
- /// reimplemented
- QList<QPointer<QWidget> > createOptionWidgets() override;
- /// reimplemented
- void keyPressEvent(QKeyEvent *event) override;
- /// reimplemented
- KoToolSelection *selection() override;
-
- /// reimplemented from superclass
- QVariant inputMethodQuery(Qt::InputMethodQuery query, const KoViewConverter &converter) const override;
-
- /// Sets cursor for specified text shape it is the current text shape
- void setTextCursor(ArtisticTextShape *textShape, int textCursor);
-
- /// Returns the current text cursor position
- int textCursor() const;
-
- /**
- * Determines cursor position from specified mouse position.
- * @param mousePosition mouse position in document coordinates
- * @return cursor position, -1 means invalid cursor
- */
- int cursorFromMousePosition(const QPointF &mousePosition);
-
-protected:
- void enableTextCursor(bool enable);
- void removeFromTextCursor(int from, unsigned int count);
- void addToTextCursor(const QString &str);
-
-private Q_SLOTS:
- void detachPath();
- void convertText();
- void blinkCursor();
- void textChanged();
- void shapeSelectionChanged();
- void setStartOffset(int offset);
- void toggleFontBold(bool enabled);
- void toggleFontItalic(bool enabled);
- void anchorChanged(QAction *);
- void setFontFamiliy(const QFont &font);
- void setFontSize(int size);
- void setSuperScript();
- void setSubScript();
- void selectAll();
- void deselectAll();
-
-Q_SIGNALS:
- void shapeSelected();
-
-private:
- void updateActions();
- void setTextCursorInternal(int textCursor);
- void createTextCursorShape();
- void updateTextCursorArea() const;
- void setCurrentShape(ArtisticTextShape *currentShape);
-
- enum FontProperty {
- BoldProperty,
- ItalicProperty,
- FamiliyProperty,
- SizeProperty
- };
-
- /// Changes the specified font property for the current text selection
- void changeFontProperty(FontProperty property, const QVariant &value);
-
- /// Toggle sub and super script
- void toggleSubSuperScript(ArtisticTextRange::BaselineShift mode);
-
- /// returns the transformation matrix for the text cursor
- QTransform cursorTransform() const;
-
- /// Returns the offset handle shape for the current text shape
- QPainterPath offsetHandleShape();
-
- ArtisticTextToolSelection m_selection; ///< the tools selection
- ArtisticTextShape *m_currentShape; ///< the current text shape we are working on
- ArtisticTextShape *m_hoverText; ///< the text shape the mouse cursor is hovering over
- KoPathShape *m_hoverPath; ///< the path shape the mouse cursor is hovering over
- QPainterPath m_textCursorShape; ///< our visual text cursor representation
- bool m_hoverHandle;
-
- QAction *m_detachPath;
- QAction *m_convertText;
- QAction *m_fontBold;
- QAction *m_fontItalic;
- QAction *m_superScript;
- QAction *m_subScript;
- QActionGroup *m_anchorGroup;
-
- int m_textCursor;
- QTimer m_blinkingCursor;
- bool m_showCursor;
- QList<QPointF> m_linefeedPositions; ///< offset positions for temporary line feeds
- KoInteractionStrategy *m_currentStrategy;
-};
-
-#endif // ARTISTICTEXTTOOL_H
diff --git a/plugins/flake/artistictextshape/ArtisticTextToolFactory.cpp b/plugins/flake/artistictextshape/ArtisticTextToolFactory.cpp
deleted file mode 100644
index 9b60b2f069..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextToolFactory.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "ArtisticTextToolFactory.h"
-#include "ArtisticTextTool.h"
-#include "ArtisticTextShape.h"
-
-#include <KoIcon.h>
-#include <klocalizedstring.h>
-
-ArtisticTextToolFactory::ArtisticTextToolFactory()
- : KoToolFactoryBase("ArtisticTextTool")
-{
- setToolTip(i18n("Artistic text editing"));
- setSection(dynamicToolType());
- setIconName(koIconNameCStr("artistic_text"));
- setPriority(1);
- setActivationShapeId(ArtisticTextShapeID);
-}
-
-ArtisticTextToolFactory::~ArtisticTextToolFactory()
-{
-}
-
-KoToolBase *ArtisticTextToolFactory::createTool(KoCanvasBase *canvas)
-{
- return new ArtisticTextTool(canvas);
-}
-
diff --git a/plugins/flake/artistictextshape/ArtisticTextToolFactory.h b/plugins/flake/artistictextshape/ArtisticTextToolFactory.h
deleted file mode 100644
index 227858f901..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextToolFactory.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 ARTISTICTEXTTOOLFACTORY_H
-#define ARTISTICTEXTTOOLFACTORY_H
-
-#include <KoToolFactoryBase.h>
-
-class ArtisticTextToolFactory : public KoToolFactoryBase
-{
-public:
- ArtisticTextToolFactory();
- ~ArtisticTextToolFactory() override;
-
- KoToolBase *createTool(KoCanvasBase *canvas) override;
-};
-
-#endif // ARTISTICTEXTTOOLFACTORY_H
diff --git a/plugins/flake/artistictextshape/ArtisticTextToolSelection.cpp b/plugins/flake/artistictextshape/ArtisticTextToolSelection.cpp
deleted file mode 100644
index d64a39c962..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextToolSelection.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "ArtisticTextToolSelection.h"
-#include "ArtisticTextShape.h"
-
-#include <KoCanvasBase.h>
-
-#include <QDebug>
-
-#include <QPainter>
-#include <QFontMetrics>
-
-ArtisticTextToolSelection::ArtisticTextToolSelection(KoCanvasBase *canvas, QObject *parent)
- : KoToolSelection(parent)
- , m_canvas(canvas)
- , m_currentShape(0)
- , m_selectionStart(-1)
- , m_selectionCount(0)
-{
- Q_ASSERT(m_canvas);
-}
-
-ArtisticTextToolSelection::~ArtisticTextToolSelection()
-{
-
-}
-
-bool ArtisticTextToolSelection::hasSelection()
-{
- return m_currentShape && m_selectionCount > 0;
-}
-
-void ArtisticTextToolSelection::setSelectedShape(ArtisticTextShape *textShape)
-{
- if (textShape == m_currentShape) {
- return;
- }
- clear();
- m_currentShape = textShape;
-}
-
-ArtisticTextShape *ArtisticTextToolSelection::selectedShape() const
-{
- return m_currentShape;
-}
-
-void ArtisticTextToolSelection::selectText(int from, int to)
-{
- if (!m_currentShape) {
- return;
- }
-
- repaintDecoration();
-
- const int textCount = m_currentShape->plainText().count();
- m_selectionStart = qBound(0, from, textCount - 1);
- m_selectionCount = qBound(from, to, textCount) - m_selectionStart;
-
- repaintDecoration();
-}
-
-int ArtisticTextToolSelection::selectionStart() const
-{
- return m_selectionStart;
-}
-
-int ArtisticTextToolSelection::selectionCount() const
-{
- return m_selectionCount;
-}
-
-void ArtisticTextToolSelection::clear()
-{
- repaintDecoration();
- m_selectionStart = -1;
- m_selectionCount = 0;
-}
-
-void ArtisticTextToolSelection::paint(QPainter &painter)
-{
- if (!hasSelection()) {
- return;
- }
- painter.setPen(Qt::NoPen);
- painter.setBrush(QColor(0, 0, 255, 127));
- painter.drawPath(outline());
-}
-
-QPainterPath ArtisticTextToolSelection::outline()
-{
- if (!hasSelection()) {
- return QPainterPath();
- }
-
- CharIndex charPos = m_currentShape->indexOfChar(m_selectionStart);
- if (charPos.first < 0) {
- return QPainterPath();
- }
-
- QPainterPath outline;
-
- QPolygonF polygon;
-
- QList<ArtisticTextRange> ranges = m_currentShape->text();
- if (ranges.size() == 0) {
- return outline;
- }
-
- int globalCharIndex = m_selectionStart;
- int remainingChars = m_selectionCount;
- while (remainingChars && ranges.size() > charPos.first) {
- const ArtisticTextRange &currentRange = ranges[charPos.first];
-
- int currentTextLength = currentRange.text().length();
- while (charPos.second < currentTextLength && remainingChars > 0) {
- const QPointF pos = m_currentShape->charPositionAt(globalCharIndex);
- const qreal angle = m_currentShape->charAngleAt(globalCharIndex);
-
- QTransform charTransform;
- charTransform.translate(pos.x() - 1, pos.y());
- charTransform.rotate(360. - angle);
-
- QFontMetricsF metrics(currentRange.font());
-
- polygon.prepend(charTransform.map(QPointF(0.0, -metrics.ascent())));
- polygon.append(charTransform.map(QPointF(0.0, metrics.descent())));
-
- // advance to next character
- charPos.second++;
- globalCharIndex++;
- remainingChars--;
-
- // next character has y-offset or we are at the end of this text range
- const bool hasYOffset = currentRange.hasYOffset(charPos.second);
- const bool atRangeEnd = charPos.second == currentTextLength;
- const bool atSelectionEnd = remainingChars == 0;
- if (hasYOffset || atRangeEnd || atSelectionEnd) {
- if (hasYOffset || atRangeEnd) {
- const QChar c = currentRange.text().at(charPos.second - 1);
- const qreal w = metrics.width(c);
- polygon.prepend(charTransform.map(QPointF(w, -metrics.ascent())));
- polygon.append(charTransform.map(QPointF(w, metrics.descent())));
- } else {
- const QPointF pos = m_currentShape->charPositionAt(globalCharIndex);
- const qreal angle = m_currentShape->charAngleAt(globalCharIndex);
- charTransform.reset();
- charTransform.translate(pos.x() - 1, pos.y());
- charTransform.rotate(360. - angle);
- polygon.prepend(charTransform.map(QPointF(0.0, -metrics.ascent())));
- polygon.append(charTransform.map(QPointF(0.0, metrics.descent())));
- }
- QPainterPath p;
- p.addPolygon(polygon);
- outline = outline.united(p);
- polygon.clear();
- }
- }
-
- // go to first character of next text range
- charPos.first++;
- charPos.second = 0;
- }
-
- // transform to document coordinates
- return m_currentShape->absoluteTransformation().map(outline);
-}
-
-void ArtisticTextToolSelection::repaintDecoration()
-{
- if (hasSelection()) {
- m_canvas->updateCanvas(outline().boundingRect());
- }
-}
diff --git a/plugins/flake/artistictextshape/ArtisticTextToolSelection.h b/plugins/flake/artistictextshape/ArtisticTextToolSelection.h
deleted file mode 100644
index 89599f0213..0000000000
--- a/plugins/flake/artistictextshape/ArtisticTextToolSelection.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 ARTISTICTEXTTOOLSELECTION_H
-#define ARTISTICTEXTTOOLSELECTION_H
-
-#include <KoToolSelection.h>
-#include <QPainterPath>
-#include <QPointer>
-
-#include <KoCanvasBase.h>
-
-class ArtisticTextShape;
-class QPainter;
-
-class ArtisticTextToolSelection : public KoToolSelection
-{
-public:
- explicit ArtisticTextToolSelection(KoCanvasBase *canvas, QObject *parent = 0);
- ~ArtisticTextToolSelection() override;
-
- // reimplemented from KoToolSelection
- bool hasSelection() override;
-
- /// Sets the currently selected text shape
- void setSelectedShape(ArtisticTextShape *textShape);
-
- /// Returns the currently selected text shape
- ArtisticTextShape *selectedShape() const;
-
- /// Selects specified range of characters
- void selectText(int from, int to);
-
- /// Returns the start character index of the selection
- int selectionStart() const;
-
- /// Returns number of selected characters
- int selectionCount() const;
-
- /// Clears the selection
- void clear();
-
- /// Paints the selection
- void paint(QPainter &painter);
-
- /// Triggers a repaint of the selection
- void repaintDecoration();
-
-private:
- /// Returns the outline of the selection in document coordinates
- QPainterPath outline();
-
- QPointer<KoCanvasBase> m_canvas;
- ArtisticTextShape *m_currentShape; ///< the currently selected text shape
- int m_selectionStart;
- int m_selectionCount;
-};
-
-#endif // ARTISTICTEXTTOOLSELECTION_H
diff --git a/plugins/flake/artistictextshape/AttachTextToPathCommand.cpp b/plugins/flake/artistictextshape/AttachTextToPathCommand.cpp
deleted file mode 100644
index 397ee363be..0000000000
--- a/plugins/flake/artistictextshape/AttachTextToPathCommand.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "AttachTextToPathCommand.h"
-#include "ArtisticTextShape.h"
-
-#include <klocalizedstring.h>
-
-AttachTextToPathCommand::AttachTextToPathCommand(ArtisticTextShape *textShape, KoPathShape *pathShape, KUndo2Command *parent)
- : KUndo2Command(parent)
- , m_textShape(textShape)
- , m_pathShape(pathShape)
-{
- setText(kundo2_i18n("Attach Path"));
- m_oldMatrix = m_textShape->transformation();
-}
-
-void AttachTextToPathCommand::redo()
-{
- KUndo2Command::redo();
- m_textShape->update();
- m_textShape->putOnPath(m_pathShape);
- m_textShape->update();
-}
-
-void AttachTextToPathCommand::undo()
-{
- m_textShape->update();
- m_textShape->removeFromPath();
- m_textShape->setTransformation(m_oldMatrix);
- m_textShape->update();
- KUndo2Command::undo();
-}
diff --git a/plugins/flake/artistictextshape/AttachTextToPathCommand.h b/plugins/flake/artistictextshape/AttachTextToPathCommand.h
deleted file mode 100644
index 3e7aa10cc3..0000000000
--- a/plugins/flake/artistictextshape/AttachTextToPathCommand.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 ATTACHTEXTTOPATHCOMMAND_H
-#define ATTACHTEXTTOPATHCOMMAND_H
-
-#include <kundo2command.h>
-#include <QTransform>
-
-class ArtisticTextShape;
-class KoPathShape;
-
-class AttachTextToPathCommand : public KUndo2Command
-{
-public:
- AttachTextToPathCommand(ArtisticTextShape *textShape, KoPathShape *pathShape, KUndo2Command *parent = 0);
- /// reimplemented from KUndo2Command
- void redo() override;
- /// reimplemented from KUndo2Command
- void undo() override;
-private:
- ArtisticTextShape *m_textShape;
- KoPathShape *m_pathShape;
- QTransform m_oldMatrix;
-};
-
-#endif // ATTACHTEXTTOPATHCOMMAND_H
diff --git a/plugins/flake/artistictextshape/CMakeLists.txt b/plugins/flake/artistictextshape/CMakeLists.txt
deleted file mode 100644
index 5d6d9f656f..0000000000
--- a/plugins/flake/artistictextshape/CMakeLists.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-project( artistictextshape )
-
-include_directories(
- ${CMAKE_SOURCE_DIR}/libs/widgets
-)
-
-set ( ArtisticTextShape_SRCS
- ArtisticTextShapePlugin.cpp
- ArtisticTextShape.cpp
- ArtisticTextRange.cpp
- ArtisticTextShapeFactory.cpp
- ArtisticTextTool.cpp
- ArtisticTextToolFactory.cpp
- ArtisticTextToolSelection.cpp
- ArtisticTextShapeConfigWidget.cpp
- ArtisticTextShapeOnPathWidget.cpp
- ArtisticTextShapeLoadingUpdater.cpp
- ArtisticTextLoadingContext.cpp
- AttachTextToPathCommand.cpp
- DetachTextFromPathCommand.cpp
- ChangeTextOffsetCommand.cpp
- ChangeTextFontCommand.cpp
- ChangeTextAnchorCommand.cpp
- AddTextRangeCommand.cpp
- RemoveTextRangeCommand.cpp
- MoveStartOffsetStrategy.cpp
- SelectTextStrategy.cpp
- ReplaceTextRangeCommand.cpp
-)
-
-ki18n_wrap_ui( ArtisticTextShape_SRCS
- ArtisticTextShapeConfigWidget.ui
- ArtisticTextShapeOnPathWidget.ui
-)
-
-qt5_add_resources(ArtisticTextShape_SRCS artistictextshape.qrc)
-
-add_library(krita_shape_artistictext MODULE ${ArtisticTextShape_SRCS} )
-
-target_link_libraries(krita_shape_artistictext kritaflake kritaui)
-
-install( TARGETS krita_shape_artistictext DESTINATION ${KRITA_PLUGIN_INSTALL_DIR} )
diff --git a/plugins/flake/artistictextshape/ChangeTextAnchorCommand.cpp b/plugins/flake/artistictextshape/ChangeTextAnchorCommand.cpp
deleted file mode 100644
index c449f12f0a..0000000000
--- a/plugins/flake/artistictextshape/ChangeTextAnchorCommand.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- * Copyright (C) 2008 Rob Buis <buis@kde.org>
- *
- * 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 "ChangeTextAnchorCommand.h"
-#include <klocalizedstring.h>
-
-ChangeTextAnchorCommand::ChangeTextAnchorCommand(ArtisticTextShape *shape, ArtisticTextShape::TextAnchor anchor)
- : m_shape(shape)
- , m_anchor(anchor)
-{
- setText(kundo2_i18n("Change text anchor"));
-}
-
-void ChangeTextAnchorCommand::undo()
-{
- if (m_shape) {
- m_shape->setTextAnchor(m_oldAnchor);
- }
-}
-
-void ChangeTextAnchorCommand::redo()
-{
- if (m_shape) {
- m_oldAnchor = m_shape->textAnchor();
- m_shape->setTextAnchor(m_anchor);
- }
-}
diff --git a/plugins/flake/artistictextshape/ChangeTextAnchorCommand.h b/plugins/flake/artistictextshape/ChangeTextAnchorCommand.h
deleted file mode 100644
index 28a955699a..0000000000
--- a/plugins/flake/artistictextshape/ChangeTextAnchorCommand.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- * Copyright (C) 2008 Rob Buis <buis@kde.org>
- *
- * 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 CHANGETEXTANCHORCOMMAND_H
-#define CHANGETEXTANCHORCOMMAND_H
-
-#include "ArtisticTextShape.h"
-#include <kundo2command.h>
-
-class ChangeTextAnchorCommand : public KUndo2Command
-{
-public:
- ChangeTextAnchorCommand(ArtisticTextShape *shape, ArtisticTextShape::TextAnchor anchor);
- void undo() override;
- void redo() override;
-private:
- ArtisticTextShape *m_shape;
- ArtisticTextShape::TextAnchor m_anchor;
- ArtisticTextShape::TextAnchor m_oldAnchor;
-};
-
-#endif // CHANGETEXTANCHORCOMMAND_H
diff --git a/plugins/flake/artistictextshape/ChangeTextFontCommand.cpp b/plugins/flake/artistictextshape/ChangeTextFontCommand.cpp
deleted file mode 100644
index 09eb7b2ce5..0000000000
--- a/plugins/flake/artistictextshape/ChangeTextFontCommand.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007,2011 Jan Hambrecht <jaham@gmx.net>
- * Copyright (C) 2008 Rob Buis <buis@kde.org>
- *
- * 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 "ChangeTextFontCommand.h"
-#include "ArtisticTextShape.h"
-#include <klocalizedstring.h>
-
-ChangeTextFontCommand::ChangeTextFontCommand(ArtisticTextShape *shape, const QFont &font, KUndo2Command *parent)
- : KUndo2Command(parent)
- , m_shape(shape)
- , m_newFont(font)
- , m_rangeStart(-1)
- , m_rangeCount(-1)
-{
- Q_ASSERT(m_shape);
- setText(kundo2_i18n("Change font"));
-}
-
-ChangeTextFontCommand::ChangeTextFontCommand(ArtisticTextShape *shape, int from, int count, const QFont &font, KUndo2Command *parent)
- : KUndo2Command(parent)
- , m_shape(shape)
- , m_newFont(font)
- , m_rangeStart(from)
- , m_rangeCount(count)
-{
- Q_ASSERT(m_shape);
-}
-
-void ChangeTextFontCommand::redo()
-{
- if (m_oldText.isEmpty()) {
- m_oldText = m_shape->text();
- if (m_rangeStart >= 0) {
- m_shape->setFont(m_rangeStart, m_rangeCount, m_newFont);
- } else {
- m_shape->setFont(m_newFont);
- }
- if (m_newText.isEmpty()) {
- m_newText = m_shape->text();
- }
- } else {
- m_shape->clear();
- Q_FOREACH (const ArtisticTextRange &range, m_newText) {
- m_shape->appendText(range);
- }
- }
-}
-
-void ChangeTextFontCommand::undo()
-{
- m_shape->clear();
- Q_FOREACH (const ArtisticTextRange &range, m_oldText) {
- m_shape->appendText(range);
- }
-}
-
diff --git a/plugins/flake/artistictextshape/ChangeTextFontCommand.h b/plugins/flake/artistictextshape/ChangeTextFontCommand.h
deleted file mode 100644
index b13a7789dc..0000000000
--- a/plugins/flake/artistictextshape/ChangeTextFontCommand.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007,2011 Jan Hambrecht <jaham@gmx.net>
- * Copyright (C) 2008 Rob Buis <buis@kde.org>
- *
- * 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 CHANGETEXTFONTCOMMAND_H
-#define CHANGETEXTFONTCOMMAND_H
-
-#include "ArtisticTextRange.h"
-#include <kundo2command.h>
-#include <QFont>
-
-class ArtisticTextShape;
-
-class ChangeTextFontCommand : public KUndo2Command
-{
-public:
- ChangeTextFontCommand(ArtisticTextShape *shape, const QFont &font, KUndo2Command *parent = 0);
- ChangeTextFontCommand(ArtisticTextShape *shape, int from, int count, const QFont &font, KUndo2Command *parent = 0);
- void undo() override;
- void redo() override;
-
-private:
- ArtisticTextShape *m_shape;
- QFont m_newFont;
- QList<ArtisticTextRange> m_oldText;
- QList<ArtisticTextRange> m_newText;
- int m_rangeStart;
- int m_rangeCount;
-};
-
-#endif // CHANGETEXTFONTCOMMAND_H
diff --git a/plugins/flake/artistictextshape/ChangeTextOffsetCommand.cpp b/plugins/flake/artistictextshape/ChangeTextOffsetCommand.cpp
deleted file mode 100644
index f7724d6f58..0000000000
--- a/plugins/flake/artistictextshape/ChangeTextOffsetCommand.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2009 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "ChangeTextOffsetCommand.h"
-#include "ArtisticTextShape.h"
-
-#include <klocalizedstring.h>
-
-ChangeTextOffsetCommand::ChangeTextOffsetCommand(ArtisticTextShape *textShape, qreal oldOffset, qreal newOffset, KUndo2Command *parent)
- : KUndo2Command(parent)
- , m_textShape(textShape)
- , m_oldOffset(oldOffset)
- , m_newOffset(newOffset)
-{
- setText(kundo2_i18n("Change Text Offset"));
-}
-
-void ChangeTextOffsetCommand::redo()
-{
- KUndo2Command::redo();
- m_textShape->update();
- m_textShape->setStartOffset(m_newOffset);
- m_textShape->update();
-}
-
-void ChangeTextOffsetCommand::undo()
-{
- m_textShape->update();
- m_textShape->setStartOffset(m_oldOffset);
- m_textShape->update();
- KUndo2Command::undo();
-}
diff --git a/plugins/flake/artistictextshape/ChangeTextOffsetCommand.h b/plugins/flake/artistictextshape/ChangeTextOffsetCommand.h
deleted file mode 100644
index 490c01437c..0000000000
--- a/plugins/flake/artistictextshape/ChangeTextOffsetCommand.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2009 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 CHANGETEXTOFFSETCOMMAND_H
-#define CHANGETEXTOFFSETCOMMAND_H
-
-#include <kundo2command.h>
-
-class ArtisticTextShape;
-
-class ChangeTextOffsetCommand : public KUndo2Command
-{
-public:
- ChangeTextOffsetCommand(ArtisticTextShape *textShape, qreal oldOffset, qreal newOffset, KUndo2Command *parent = 0);
- /// reimplemented from KUndo2Command
- void redo() override;
- /// reimplemented from KUndo2Command
- void undo() override;
-private:
- ArtisticTextShape *m_textShape;
- qreal m_oldOffset;
- qreal m_newOffset;
-};
-
-#endif // CHANGETEXTOFFSETCOMMAND_H
diff --git a/plugins/flake/artistictextshape/DetachTextFromPathCommand.cpp b/plugins/flake/artistictextshape/DetachTextFromPathCommand.cpp
deleted file mode 100644
index 228d547c9b..0000000000
--- a/plugins/flake/artistictextshape/DetachTextFromPathCommand.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "DetachTextFromPathCommand.h"
-#include "ArtisticTextShape.h"
-#include <klocalizedstring.h>
-
-DetachTextFromPathCommand::DetachTextFromPathCommand(ArtisticTextShape *textShape, KUndo2Command *parent)
- : KUndo2Command(parent)
- , m_textShape(textShape)
- , m_pathShape(0)
-{
- setText(kundo2_i18n("Detach Path"));
-
- Q_ASSERT(m_textShape->layout() != ArtisticTextShape::Straight);
-
- if (m_textShape->layout() == ArtisticTextShape::OnPath) {
- m_path = m_textShape->baseline();
- } else {
- m_pathShape = m_textShape->baselineShape();
- }
-}
-
-void DetachTextFromPathCommand::redo()
-{
- KUndo2Command::redo();
-
- m_textShape->update();
- m_textShape->removeFromPath();
- m_textShape->update();
-}
-
-void DetachTextFromPathCommand::undo()
-{
- m_textShape->update();
-
- if (m_pathShape) {
- m_textShape->putOnPath(m_pathShape);
- } else {
- m_textShape->putOnPath(m_path);
- }
-
- m_textShape->update();
-
- KUndo2Command::undo();
-}
diff --git a/plugins/flake/artistictextshape/DetachTextFromPathCommand.h b/plugins/flake/artistictextshape/DetachTextFromPathCommand.h
deleted file mode 100644
index 85ed56f241..0000000000
--- a/plugins/flake/artistictextshape/DetachTextFromPathCommand.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 DETACHTEXTFROMPATHCOMMAND_H
-#define DETACHTEXTFROMPATHCOMMAND_H
-
-#include <kundo2command.h>
-#include <QPainterPath>
-
-class ArtisticTextShape;
-class KoPathShape;
-
-class DetachTextFromPathCommand : public KUndo2Command
-{
-public:
- explicit DetachTextFromPathCommand(ArtisticTextShape *textShape, KUndo2Command *parent = 0);
- /// reimplemented from KUndo2Command
- void redo() override;
- /// reimplemented from KUndo2Command
- void undo() override;
-private:
- ArtisticTextShape *m_textShape;
- KoPathShape *m_pathShape;
- QPainterPath m_path;
-};
-
-#endif // DETACHTEXTFROMPATHCOMMAND_H
diff --git a/plugins/flake/artistictextshape/MoveStartOffsetStrategy.cpp b/plugins/flake/artistictextshape/MoveStartOffsetStrategy.cpp
deleted file mode 100644
index 72000998d8..0000000000
--- a/plugins/flake/artistictextshape/MoveStartOffsetStrategy.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "MoveStartOffsetStrategy.h"
-#include "ChangeTextOffsetCommand.h"
-#include "ArtisticTextShape.h"
-#include <KoPathShape.h>
-#include <KoPathSegment.h>
-#include <KoToolBase.h>
-#include <math.h>
-
-// helper function to calculate the squared distance between two points
-qreal squaredDistance(const QPointF &p1, const QPointF &p2)
-{
- qreal dx = p1.x() - p2.x();
- qreal dy = p1.y() - p2.y();
- return dx * dx + dy * dy;
-}
-
-MoveStartOffsetStrategy::MoveStartOffsetStrategy(KoToolBase *tool, ArtisticTextShape *text)
- : KoInteractionStrategy(tool)
- , m_text(text)
-{
- m_oldStartOffset = m_text->startOffset();
- m_baselineShape = KoPathShape::createShapeFromPainterPath(m_text->baseline());
- // cache number of segments and their length
- const int subpathCount = m_baselineShape->subpathCount();
- for (int i = 0; i < subpathCount; ++i) {
- const int subpathPointCount = m_baselineShape->subpathPointCount(i);
- for (int j = 0; j < subpathPointCount; ++j) {
- KoPathSegment s = m_baselineShape->segmentByIndex(KoPathPointIndex(i, j));
- if (s.isValid()) {
- const qreal length = s.length();
- m_segmentLengths.append(length);
- m_totalLength += length;
- }
- }
- }
-}
-
-MoveStartOffsetStrategy::~MoveStartOffsetStrategy()
-{
- delete m_baselineShape;
-}
-
-void MoveStartOffsetStrategy::handleMouseMove(const QPointF &mouseLocation, Qt::KeyboardModifiers /*modifiers*/)
-{
- // map the global mouse position to local coordinates of our baseline path
- const QPointF localMousePoint = m_baselineShape->transformation().inverted().map(mouseLocation);
-
- // create a roi to check segments at
- QRectF grabRect;
- grabRect.setHeight(2 * grabSensitivity());
- grabRect.setWidth(2 * grabSensitivity());
- grabRect.moveCenter(localMousePoint);
-
- // get all segments intersecting our roi
- QList<KoPathSegment> segments = m_baselineShape->segmentsAt(grabRect);
-
- // now find the nearest point of all picked segments
- KoPathSegment nearestSegment;
- qreal nearestPointParam = 0.0;
- KoPathPointIndex nearestPathPoint;
- qreal minDistance = HUGE_VAL;
- Q_FOREACH (const KoPathSegment &s, segments) {
- qreal t = s.nearestPoint(localMousePoint);
- qreal distance = squaredDistance(localMousePoint, s.pointAt(t));
- if (distance < minDistance) {
- nearestPointParam = t;
- nearestSegment = s;
- nearestPathPoint = m_baselineShape->pathPointIndex(s.first());
- minDistance = distance;
- }
- }
-
- // now we need to map back to the length of the baseline path
- if (nearestSegment.isValid()) {
- // count number of path segments
- int segmentCount = 0;
- int nearestSegment = 0;
- const int subpathCount = m_baselineShape->subpathCount();
- for (int i = 0; i < subpathCount; ++i) {
- const int subpathPointCount = m_baselineShape->subpathPointCount(i);
- if (i == nearestPathPoint.first) {
- nearestSegment = segmentCount + nearestPathPoint.second;
- }
- segmentCount += m_baselineShape->isClosedSubpath(i) ? subpathPointCount : subpathPointCount - 1;
- }
- qreal length = 0.0;
- for (int i = 0; i < nearestSegment; ++i) {
- length += m_segmentLengths[i];
- }
- length += nearestPointParam * m_segmentLengths[nearestSegment];
- tool()->repaintDecorations();
- m_text->setStartOffset(length / m_totalLength);
- tool()->repaintDecorations();
- }
-}
-
-KUndo2Command *MoveStartOffsetStrategy::createCommand()
-{
- return new ChangeTextOffsetCommand(m_text, m_oldStartOffset, m_text->startOffset());
-}
-
-void MoveStartOffsetStrategy::finishInteraction(Qt::KeyboardModifiers /*modifiers*/)
-{
-
-}
diff --git a/plugins/flake/artistictextshape/MoveStartOffsetStrategy.h b/plugins/flake/artistictextshape/MoveStartOffsetStrategy.h
deleted file mode 100644
index 762ce898c0..0000000000
--- a/plugins/flake/artistictextshape/MoveStartOffsetStrategy.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 MOVESTARTOFFSETSTRATEGY_H
-#define MOVESTARTOFFSETSTRATEGY_H
-
-#include <KoInteractionStrategy.h>
-#include <QList>
-
-class KoPathShape;
-class ArtisticTextShape;
-class KoToolBase;
-
-/// A strategy to change the offset of a text when put on a path
-class MoveStartOffsetStrategy : public KoInteractionStrategy
-{
-public:
- MoveStartOffsetStrategy(KoToolBase *tool, ArtisticTextShape *text);
- ~MoveStartOffsetStrategy() override;
-
- // reimplemented from KoInteractionStrategy
- void handleMouseMove(const QPointF &mouseLocation, Qt::KeyboardModifiers modifiers) override;
- // reimplemented from KoInteractionStrategy
- KUndo2Command *createCommand() override;
- // reimplemented from KoInteractionStrategy
- void finishInteraction(Qt::KeyboardModifiers modifiers) override;
-private:
- ArtisticTextShape *m_text {0}; ///< the text shape we are working on
- KoPathShape *m_baselineShape {0}; ///< path shape the text is put on
- qreal m_oldStartOffset {0}; ///< the initial start offset
- QList<qreal> m_segmentLengths; ///< cached lengths of baseline path segments
- qreal m_totalLength {0.0}; ///< total length of baseline path
-};
-
-#endif // MOVESTARTOFFSETSTRATEGY_H
diff --git a/plugins/flake/artistictextshape/RemoveTextRangeCommand.cpp b/plugins/flake/artistictextshape/RemoveTextRangeCommand.cpp
deleted file mode 100644
index c82fb7bf60..0000000000
--- a/plugins/flake/artistictextshape/RemoveTextRangeCommand.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007,2011 Jan Hambrecht <jaham@gmx.net>
- * Copyright (C) 2008 Rob Buis <buis@kde.org>
- *
- * 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 "RemoveTextRangeCommand.h"
-#include "ArtisticTextShape.h"
-#include <klocalizedstring.h>
-
-RemoveTextRangeCommand::RemoveTextRangeCommand(ArtisticTextTool *tool, ArtisticTextShape *shape, int from, unsigned int count)
- : m_tool(tool)
- , m_shape(shape)
- , m_from(from)
- , m_count(count)
-{
- m_cursor = tool->textCursor();
- setText(kundo2_i18n("Remove text range"));
-}
-
-void RemoveTextRangeCommand::redo()
-{
- KUndo2Command::redo();
-
- if (!m_shape) {
- return;
- }
-
- if (m_tool) {
- if (m_cursor > m_from) {
- m_tool->setTextCursor(m_shape, m_from);
- }
- }
- m_text = m_shape->removeText(m_from, m_count);
-}
-
-void RemoveTextRangeCommand::undo()
-{
- KUndo2Command::undo();
-
- if (!m_shape) {
- return;
- }
-
- m_shape->insertText(m_from, m_text);
-
- if (m_tool) {
- m_tool->setTextCursor(m_shape, m_cursor);
- }
-}
diff --git a/plugins/flake/artistictextshape/RemoveTextRangeCommand.h b/plugins/flake/artistictextshape/RemoveTextRangeCommand.h
deleted file mode 100644
index 1fba42dfa4..0000000000
--- a/plugins/flake/artistictextshape/RemoveTextRangeCommand.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007,2011 Jan Hambrecht <jaham@gmx.net>
- * Copyright (C) 2008 Rob Buis <buis@kde.org>
- *
- * 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 REMOVETEXTRANGECOMMAND_H
-#define REMOVETEXTRANGECOMMAND_H
-
-#include <kundo2command.h>
-#include <QPointer>
-#include "ArtisticTextTool.h"
-
-class ArtisticTextShape;
-
-/// Undo command to remove a range of text from an artistic text shape
-class RemoveTextRangeCommand : public KUndo2Command
-{
-public:
- RemoveTextRangeCommand(ArtisticTextTool *tool, ArtisticTextShape *shape, int from, unsigned int count);
-
- void redo() override;
- void undo() override;
-
-private:
- QPointer<ArtisticTextTool> m_tool;
- ArtisticTextShape *m_shape;
- int m_from;
- int m_count;
- QList<ArtisticTextRange> m_text;
- int m_cursor;
-};
-
-#endif // REMOVETEXTRANGECOMMAND_H
-
diff --git a/plugins/flake/artistictextshape/ReplaceTextRangeCommand.cpp b/plugins/flake/artistictextshape/ReplaceTextRangeCommand.cpp
deleted file mode 100644
index 566f097456..0000000000
--- a/plugins/flake/artistictextshape/ReplaceTextRangeCommand.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "ReplaceTextRangeCommand.h"
-#include "ArtisticTextShape.h"
-#include <klocalizedstring.h>
-
-ReplaceTextRangeCommand::ReplaceTextRangeCommand(ArtisticTextShape *shape, const QString &text, int from, int count, ArtisticTextTool *tool, KUndo2Command *parent)
- : KUndo2Command(parent)
- , m_tool(tool)
- , m_shape(shape)
- , m_from(from)
- , m_count(count)
-{
- setText(kundo2_i18n("Replace text range"));
- m_newFormattedText.append(ArtisticTextRange(text, shape->fontAt(m_from)));
- m_oldFormattedText = shape->text();
-}
-
-ReplaceTextRangeCommand::ReplaceTextRangeCommand(ArtisticTextShape *shape, const ArtisticTextRange &text, int from, int count, ArtisticTextTool *tool, KUndo2Command *parent)
- : KUndo2Command(parent)
- , m_tool(tool)
- , m_shape(shape)
- , m_from(from)
- , m_count(count)
-{
- setText(kundo2_i18n("Replace text range"));
- m_newFormattedText.append(text);
- m_oldFormattedText = shape->text();
-}
-
-ReplaceTextRangeCommand::ReplaceTextRangeCommand(ArtisticTextShape *shape, const QList<ArtisticTextRange> &text, int from, int count, ArtisticTextTool *tool, KUndo2Command *parent)
- : KUndo2Command(parent)
- , m_tool(tool)
- , m_shape(shape)
- , m_from(from)
- , m_count(count)
-{
- setText(kundo2_i18n("Replace text range"));
- m_newFormattedText = text;
- m_oldFormattedText = shape->text();
-}
-
-void ReplaceTextRangeCommand::redo()
-{
- KUndo2Command::redo();
-
- if (!m_shape) {
- return;
- }
-
- m_shape->replaceText(m_from, m_count, m_newFormattedText);
-
- if (m_tool) {
- int length = 0;
- Q_FOREACH (const ArtisticTextRange &range, m_newFormattedText) {
- length += range.text().length();
- }
- m_tool->setTextCursor(m_shape, m_from + length);
- }
-}
-
-void ReplaceTextRangeCommand::undo()
-{
- KUndo2Command::undo();
-
- if (! m_shape) {
- return;
- }
-
- m_shape->clear();
- Q_FOREACH (const ArtisticTextRange &range, m_oldFormattedText) {
- m_shape->appendText(range);
- }
- if (m_tool) {
- m_tool->setTextCursor(m_shape, m_from);
- }
-}
diff --git a/plugins/flake/artistictextshape/ReplaceTextRangeCommand.h b/plugins/flake/artistictextshape/ReplaceTextRangeCommand.h
deleted file mode 100644
index 45c8ef83c1..0000000000
--- a/plugins/flake/artistictextshape/ReplaceTextRangeCommand.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 REPLACETEXTRANGECOMMAND_H
-#define REPLACETEXTRANGECOMMAND_H
-
-#include <kundo2command.h>
-#include "ArtisticTextTool.h"
-#include "ArtisticTextRange.h"
-#include <QPointer>
-
-class ArtisticTextShape;
-
-/// Undo command to replace a range of text on an artistic text shape
-class ReplaceTextRangeCommand : public KUndo2Command
-{
-public:
- ReplaceTextRangeCommand(ArtisticTextShape *shape, const QString &text, int from, int count, ArtisticTextTool *tool, KUndo2Command *parent = 0);
- ReplaceTextRangeCommand(ArtisticTextShape *shape, const ArtisticTextRange &text, int from, int count, ArtisticTextTool *tool, KUndo2Command *parent = 0);
- ReplaceTextRangeCommand(ArtisticTextShape *shape, const QList<ArtisticTextRange> &text, int from, int count, ArtisticTextTool *tool, KUndo2Command *parent = 0);
-
- void redo() override;
- void undo() override;
-
-private:
- QPointer<ArtisticTextTool> m_tool;
- ArtisticTextShape *m_shape;
- QList<ArtisticTextRange> m_newFormattedText;
- QList<ArtisticTextRange> m_oldFormattedText;
- int m_from;
- int m_count;
-};
-
-#endif // REPLACETEXTRANGECOMMAND_H
diff --git a/plugins/flake/artistictextshape/SelectTextStrategy.cpp b/plugins/flake/artistictextshape/SelectTextStrategy.cpp
deleted file mode 100644
index b0aeeeb36e..0000000000
--- a/plugins/flake/artistictextshape/SelectTextStrategy.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "SelectTextStrategy.h"
-#include "ArtisticTextTool.h"
-#include "ArtisticTextToolSelection.h"
-
-SelectTextStrategy::SelectTextStrategy(ArtisticTextTool *textTool, int cursor)
- : KoInteractionStrategy(textTool)
- , m_selection(0)
- , m_oldCursor(cursor)
- , m_newCursor(cursor)
-{
- m_selection = dynamic_cast<ArtisticTextToolSelection *>(textTool->selection());
- Q_ASSERT(m_selection);
-}
-
-SelectTextStrategy::~SelectTextStrategy()
-{
-
-}
-
-void SelectTextStrategy::handleMouseMove(const QPointF &mouseLocation, Qt::KeyboardModifiers /*modifiers*/)
-{
- ArtisticTextTool *textTool = dynamic_cast<ArtisticTextTool *>(tool());
- if (!textTool) {
- return;
- }
-
- m_newCursor = textTool->cursorFromMousePosition(mouseLocation);
- if (m_newCursor >= 0) {
- m_selection->selectText(qMin(m_oldCursor, m_newCursor), qMax(m_oldCursor, m_newCursor));
- }
-}
-
-KUndo2Command *SelectTextStrategy::createCommand()
-{
- return 0;
-}
-
-void SelectTextStrategy::finishInteraction(Qt::KeyboardModifiers /*modifiers*/)
-{
- ArtisticTextTool *textTool = dynamic_cast<ArtisticTextTool *>(tool());
- if (!textTool) {
- return;
- }
-
- if (m_newCursor >= 0) {
- textTool->setTextCursor(m_selection->selectedShape(), m_newCursor);
- }
-}
diff --git a/plugins/flake/artistictextshape/SelectTextStrategy.h b/plugins/flake/artistictextshape/SelectTextStrategy.h
deleted file mode 100644
index 2dac5a7c95..0000000000
--- a/plugins/flake/artistictextshape/SelectTextStrategy.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 SELECTTEXTSTRATEGY_H
-#define SELECTTEXTSTRATEGY_H
-
-#include <KoInteractionStrategy.h>
-
-class ArtisticTextTool;
-class ArtisticTextToolSelection;
-
-/// A strategy to select text on a artistic text shape
-class SelectTextStrategy : public KoInteractionStrategy
-{
-public:
- SelectTextStrategy(ArtisticTextTool *textTool, int cursor);
- ~SelectTextStrategy() override;
-
- // reimplemented from KoInteractionStrategy
- void handleMouseMove(const QPointF &mouseLocation, Qt::KeyboardModifiers modifiers) override;
- // reimplemented from KoInteractionStrategy
- KUndo2Command *createCommand() override;
- // reimplemented from KoInteractionStrategy
- void finishInteraction(Qt::KeyboardModifiers modifiers) override;
-
-private:
- ArtisticTextToolSelection *m_selection;
- int m_oldCursor;
- int m_newCursor;
-};
-
-#endif // SELECTTEXTSTRATEGY_H
diff --git a/plugins/flake/artistictextshape/artistictextshape.qrc b/plugins/flake/artistictextshape/artistictextshape.qrc
deleted file mode 100644
index 2e308de61b..0000000000
--- a/plugins/flake/artistictextshape/artistictextshape.qrc
+++ /dev/null
@@ -1,8 +0,0 @@
-<!DOCTYPE RCC>
-<RCC version="1.0">
- <qresource>
- <file alias="artisttext-attach-path.png">hi22-action-artistictext-attach-path.png</file>
- <file alias="artistictext-detach-path.png">hi22-action-artistictext-detach-path.png</file>
- <file alias="artistictext-tool.png">hi22-action-artistictext-tool.png</file>
- </qresource>
-</RCC>
diff --git a/plugins/flake/artistictextshape/calligra_shape_artistictext.json b/plugins/flake/artistictextshape/calligra_shape_artistictext.json
deleted file mode 100644
index b6737df41c..0000000000
--- a/plugins/flake/artistictextshape/calligra_shape_artistictext.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "Id": "Artistic Text Shape",
- "Type": "Service",
- "X-Flake-MinVersion": "28",
- "X-Flake-PluginVersion": "28",
- "X-KDE-Library": "krita_shape_artistictext",
- "X-KDE-PluginInfo-Name": "krita_artistictextshape",
- "X-KDE-ServiceTypes": [
- "Krita/Shape"
- ]
-}
diff --git a/plugins/flake/artistictextshape/hi22-action-artistictext-attach-path.png b/plugins/flake/artistictextshape/hi22-action-artistictext-attach-path.png
deleted file mode 100644
index dc3fa20af7..0000000000
Binary files a/plugins/flake/artistictextshape/hi22-action-artistictext-attach-path.png and /dev/null differ
diff --git a/plugins/flake/artistictextshape/hi22-action-artistictext-detach-path.png b/plugins/flake/artistictextshape/hi22-action-artistictext-detach-path.png
deleted file mode 100644
index 0e91385676..0000000000
Binary files a/plugins/flake/artistictextshape/hi22-action-artistictext-detach-path.png and /dev/null differ
diff --git a/plugins/flake/artistictextshape/hi22-action-artistictext-tool.png b/plugins/flake/artistictextshape/hi22-action-artistictext-tool.png
deleted file mode 100644
index e6b6eb1e03..0000000000
Binary files a/plugins/flake/artistictextshape/hi22-action-artistictext-tool.png and /dev/null differ
diff --git a/plugins/flake/artistictextshape/hisc-action-artistictext-attach-path.svg b/plugins/flake/artistictextshape/hisc-action-artistictext-attach-path.svg
deleted file mode 100644
index e357ea0866..0000000000
--- a/plugins/flake/artistictextshape/hisc-action-artistictext-attach-path.svg
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
-<!-- Created using Karbon14, part of calligra: http://www.calligra.org/karbon -->
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="62.3623pt" height="62.3623pt">
- <defs>
- <linearGradient id="defitem21" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.90778 0 0 1.36505 0 0)" x1="-6.44091" y1="11.8111" x2="21.2862" y2="23.2188" spreadMethod="pad" >
- <stop stop-color="#ffffff" offset="0" stop-opacity="1" />
- <stop stop-color="#bf0303" offset="1" stop-opacity="1" />
- </linearGradient>
- <linearGradient id="defitem23" gradientUnits="userSpaceOnUse" x1="-5.04873" y1="16.9134" x2="39.9685" y2="17.0332" spreadMethod="pad" >
- <stop stop-color="#ffffff" offset="0" stop-opacity="1" />
- <stop stop-color="#00458a" offset="0.813271" stop-opacity="1" />
- </linearGradient>
- </defs>
- <g id="defitem18">
- <path id="defitem19" fill="none" stroke="#000000" stroke-opacity="1" stroke-width="5.31497" stroke-linecap="square" stroke-linejoin="bevel" d="M0 71.9987C49.986 71.8149 72.2298 50.512 71.9969 0" transform="translate(2.68883, 2.9129)" />
- <path id="defitem20" fill="url(#defitem21)" fill-rule="evenodd" d="M38.5927 20.4877C36.5008 28.9275 34.9738 36.7688 40.5932 45.1837C30.9656 45.3823 15.626 41.4945 4.69528 30.4547C10.4121 32.2785 16.7943 30.9449 20.2548 30.2333C7.35707 21.2797 2.17127 6.27255 0 0.455287C6.07615 2.52393 18.0512 0.587709 23.9224 0C24.2325 4.15371 17.4062 15.4153 26.7009 28.9043C30.7129 27.6871 33.489 27.5582 38.5927 20.4877Z" transform="translate(7.14255, 18.8217)" />
- <text id="defitem22" fill="url(#defitem23)" font-family="Liberation Serif" font-size="30pt" font-weight="bold" x="0pt" y="19.6406pt" transform="matrix(1.02495 0 0 1.23786 -0.0730813 0.650024)">
-Txt </text>
- </g>
-</svg>
diff --git a/plugins/flake/artistictextshape/hisc-action-artistictext-detach-path.svg b/plugins/flake/artistictextshape/hisc-action-artistictext-detach-path.svg
deleted file mode 100644
index 3e316a5850..0000000000
--- a/plugins/flake/artistictextshape/hisc-action-artistictext-detach-path.svg
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
-<!-- Created using Karbon14, part of calligra: http://www.calligra.org/karbon -->
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="62.3623pt" height="62.3623pt">
- <defs>
- <linearGradient id="defitem41" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.90778 0 0 1.36505 0 0)" x1="22.5575" y1="44.6835" x2="9.68552" y2="14.2279" spreadMethod="pad" >
- <stop stop-color="#ffffff" offset="0" stop-opacity="1" />
- <stop stop-color="#bf0303" offset="1" stop-opacity="1" />
- </linearGradient>
- <linearGradient id="defitem43" gradientUnits="userSpaceOnUse" x1="20.7557" y1="1.02987" x2="48.166" y2="41.9868" spreadMethod="pad" >
- <stop stop-color="#ffffff" offset="0" stop-opacity="1" />
- <stop stop-color="#00458a" offset="0.813271" stop-opacity="1" />
- </linearGradient>
- <path id="defitem44" d="M2.68883 74.9116C52.6748 74.7278 74.9186 53.4249 74.6857 2.9129" />
- </defs>
- <g id="defitem38">
- <path id="defitem39" fill="none" stroke="#000000" stroke-opacity="1" stroke-width="5.31497" stroke-linecap="square" stroke-linejoin="bevel" d="M0 71.9987C49.986 71.8149 72.2298 50.512 71.9969 0" transform="translate(2.68883, 2.9129)" />
- <path id="defitem40" fill="url(#defitem41)" fill-rule="evenodd" d="M38.5927 20.4877C36.5008 28.9275 35.1819 41.0605 38.2388 49.9995C27.3057 46.2574 15.626 41.4945 4.69528 30.4547C10.4121 32.2785 16.7943 30.9449 20.2548 30.2333C7.35707 21.2797 2.17127 6.27255 0 0.455287C6.07615 2.52393 18.0512 0.587709 23.9224 0C24.2325 4.15371 17.4062 15.4153 26.7009 28.9043C30.7129 27.6871 33.489 27.5582 38.5927 20.4877Z" transform="matrix(-0.916533 0.399959 -0.399959 -0.916533 56.7877 32.7505)" />
- <text id="defitem42" fill="url(#defitem43)" font-family="Liberation Serif" font-size="46pt" font-weight="bold" >
-<textPath xlink:href="#defitem44">T x t</textPath>
- </text>
- </g>
-</svg>
diff --git a/plugins/flake/artistictextshape/hisc-action-artistictext-tool.svg b/plugins/flake/artistictextshape/hisc-action-artistictext-tool.svg
deleted file mode 100644
index ccc2b09cde..0000000000
--- a/plugins/flake/artistictextshape/hisc-action-artistictext-tool.svg
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
-<!-- Created using Karbon14, part of calligra: http://www.calligra.org/karbon -->
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="62.3623pt" height="62.3623pt">
- <defs>
- <linearGradient id="defitem3" gradientUnits="userSpaceOnUse" x1="22.833" y1="1.90365" x2="49.8333" y2="41.3398" spreadMethod="pad" >
- <stop stop-color="#ffffff" offset="0" stop-opacity="1" />
- <stop stop-color="#00458a" offset="0.813271" stop-opacity="1" />
- </linearGradient>
- <path id="defitem4" d="M2.68883 75.1618C52.8486 74.9774 75.1697 53.6004 74.9359 2.9129" />
- </defs>
- <g id="defitem0">
- <path id="defitem1" fill="none" stroke="#000000" stroke-opacity="1" stroke-width="5.31497" stroke-linecap="square" stroke-linejoin="bevel" d="M0 72.2489C50.1598 72.0645 72.4809 50.6875 72.2471 0" transform="translate(2.68883, 2.9129)" />
- <text id="defitem2" fill="url(#defitem3)" font-family="Liberation Serif" font-size="46pt" font-weight="bold" >
-<textPath xlink:href="#defitem4">T x t</textPath>
- </text>
- </g>
-</svg>
diff --git a/plugins/flake/imageshape/ImageShape.cpp b/plugins/flake/imageshape/ImageShape.cpp
index 9a97c6341a..f94a70aa27 100644
--- a/plugins/flake/imageshape/ImageShape.cpp
+++ b/plugins/flake/imageshape/ImageShape.cpp
@@ -1,186 +1,173 @@
/*
* Copyright (c) 2016 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <KoTosContainer_p.h>
#include "ImageShape.h"
#include "kis_debug.h"
#include <QPainter>
#include <SvgLoadingContext.h>
#include <SvgSavingContext.h>
#include <SvgUtil.h>
#include <QFileInfo>
#include <QBuffer>
#include <KisMimeDatabase.h>
#include <KoXmlWriter.h>
#include "kis_dom_utils.h"
#include <QRegularExpression>
#include "KisQPainterStateSaver.h"
struct Q_DECL_HIDDEN ImageShape::Private : public QSharedData
{
Private() {}
Private(const Private &rhs)
: QSharedData(),
image(rhs.image),
ratioParser(rhs.ratioParser ? new SvgUtil::PreserveAspectRatioParser(*rhs.ratioParser) : 0),
viewBoxTransform(rhs.viewBoxTransform)
{
}
QImage image;
QScopedPointer<SvgUtil::PreserveAspectRatioParser> ratioParser;
QTransform viewBoxTransform;
};
ImageShape::ImageShape()
: m_d(new Private)
{
}
ImageShape::ImageShape(const ImageShape &rhs)
: KoTosContainer(rhs),
m_d(rhs.m_d)
{
}
ImageShape::~ImageShape()
{
}
KoShape *ImageShape::cloneShape() const
{
return new ImageShape(*this);
}
void ImageShape::paint(QPainter &painter, KoShapePaintingContext &paintContext) const
{
Q_UNUSED(paintContext);
KisQPainterStateSaver saver(&painter);
const QRectF myrect(QPointF(), size());
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.setClipRect(QRectF(QPointF(), size()), Qt::IntersectClip);
painter.setTransform(m_d->viewBoxTransform, true);
painter.drawImage(QPoint(), m_d->image);
}
void ImageShape::setSize(const QSizeF &size)
{
KoTosContainer::setSize(size);
}
-void ImageShape::saveOdf(KoShapeSavingContext &context) const
-{
- Q_UNUSED(context);
-}
-
-bool ImageShape::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- Q_UNUSED(element);
- Q_UNUSED(context);
-
- return false;
-}
-
bool ImageShape::saveSvg(SvgSavingContext &context)
{
const QString uid = context.createUID("image");
context.shapeWriter().startElement("image");
context.shapeWriter().addAttribute("id", uid);
SvgUtil::writeTransformAttributeLazy("transform", transformation(), context.shapeWriter());
context.shapeWriter().addAttribute("width", QString("%1px").arg(KisDomUtils::toString(size().width())));
context.shapeWriter().addAttribute("height", QString("%1px").arg(KisDomUtils::toString(size().height())));
QString aspectString = m_d->ratioParser->toString();
if (!aspectString.isEmpty()) {
context.shapeWriter().addAttribute("preserveAspectRatio", aspectString);
}
QByteArray ba;
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
if (m_d->image.save(&buffer, "PNG")) {
const QString mimeType = KisMimeDatabase::mimeTypeForSuffix("*.png");
context.shapeWriter().addAttribute("xlink:href", "data:"+ mimeType + ";base64," + ba.toBase64());
}
context.shapeWriter().endElement(); // image
return true;
}
bool ImageShape::loadSvg(const KoXmlElement &element, SvgLoadingContext &context)
{
const qreal x = SvgUtil::parseUnitX(context.currentGC(), element.attribute("x"));
const qreal y = SvgUtil::parseUnitY(context.currentGC(), element.attribute("y"));
const qreal w = SvgUtil::parseUnitX(context.currentGC(), element.attribute("width"));
const qreal h = SvgUtil::parseUnitY(context.currentGC(), element.attribute("height"));
setSize(QSizeF(w, h));
setPosition(QPointF(x, y));
if (w == 0.0 || h == 0.0) {
setVisible(false);
}
QString fileName = element.attribute("xlink:href");
QByteArray data;
if (fileName.startsWith("data:")) {
QRegularExpression re("data:(.+?);base64,(.+)");
QRegularExpressionMatch match = re.match(fileName);
data = match.captured(2).toLatin1();
data = QByteArray::fromBase64(data);
} else {
data = context.fetchExternalFile(fileName);
}
if (!data.isEmpty()) {
QBuffer buffer(&data);
m_d->image.load(&buffer, "");
}
const QString aspectString = element.attribute("preserveAspectRatio", "xMidYMid meet");
m_d->ratioParser.reset(new SvgUtil::PreserveAspectRatioParser(aspectString));
if (!m_d->image.isNull()) {
m_d->viewBoxTransform =
QTransform::fromScale(w / m_d->image.width(), h / m_d->image.height());
SvgUtil::parseAspectRatio(*m_d->ratioParser,
QRectF(QPointF(), size()),
QRect(QPoint(), m_d->image.size()),
&m_d->viewBoxTransform);
}
if (m_d->ratioParser->defer) {
// TODO:
}
return true;
}
diff --git a/plugins/flake/imageshape/ImageShape.h b/plugins/flake/imageshape/ImageShape.h
index 108cc8c28f..a5789a0b5a 100644
--- a/plugins/flake/imageshape/ImageShape.h
+++ b/plugins/flake/imageshape/ImageShape.h
@@ -1,56 +1,53 @@
/*
* Copyright (c) 2016 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef IMAGESHAPE_H
#define IMAGESHAPE_H
#include <QSharedDataPointer>
#include "KoTosContainer.h"
#include <SvgShape.h>
#define ImageShapeId "ImageShape"
class ImageShape : public KoTosContainer, public SvgShape
{
public:
ImageShape();
~ImageShape() override;
KoShape *cloneShape() const override;
void paint(QPainter &painter, KoShapePaintingContext &paintContext) const override;
void setSize(const QSizeF &size) override;
- void saveOdf(KoShapeSavingContext &context) const override;
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
-
bool saveSvg(SvgSavingContext &context) override;
bool loadSvg(const KoXmlElement &element, SvgLoadingContext &context) override;
private:
ImageShape(const ImageShape &rhs);
private:
struct Private;
QSharedDataPointer<Private> m_d;
};
#endif // IMAGESHAPE_H
diff --git a/plugins/flake/imageshape/ImageShapeFactory.cpp b/plugins/flake/imageshape/ImageShapeFactory.cpp
index e44313e988..9f57d41389 100644
--- a/plugins/flake/imageshape/ImageShapeFactory.cpp
+++ b/plugins/flake/imageshape/ImageShapeFactory.cpp
@@ -1,70 +1,69 @@
/* This file is part of the KDE project
*
* Copyright (C) 2009 Inge Wallin <inge@lysator.liu.se>
*
* 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.
*/
// Own
#include "ImageShapeFactory.h"
// ImageShape
#include "ImageShape.h"
//#include "ImageShapeConfigWidget.h"
// Calligra
#include <KoXmlNS.h>
#include <KoShapeLoadingContext.h>
-#include <KoOdfLoadingContext.h>
#include <KoIcon.h>
// KDE
#include <klocalizedstring.h>
ImageShapeFactory::ImageShapeFactory()
: KoShapeFactoryBase(ImageShapeId, i18n("Image shape"))
{
setToolTip(i18n("A shape that shows an image (PNG/JPG/TIFF)"));
setIconName(koIconNameCStrNeededWithSubs("a generic image image icon", "x-shape-vectorimage", "application-x-wmf"));
QList<QPair<QString, QStringList> > elementNamesList;
elementNamesList.append(qMakePair(QString(KoXmlNS::draw), QStringList("image")));
elementNamesList.append(qMakePair(QString(KoXmlNS::svg), QStringList("image")));
setXmlElements(elementNamesList);
setLoadingPriority(1);
}
KoShape *ImageShapeFactory::createDefaultShape(KoDocumentResourceManager */*documentResources*/) const
{
ImageShape *shape = new ImageShape();
shape->setShapeId(ImageShapeId);
return shape;
}
bool ImageShapeFactory::supports(const KoXmlElement &e, KoShapeLoadingContext &context) const
{
Q_UNUSED(context);
return e.localName() == "image" &&
(e.namespaceURI() == KoXmlNS::draw || e.namespaceURI() == KoXmlNS::svg);
}
QList<KoShapeConfigWidgetBase *> ImageShapeFactory::createShapeOptionPanels()
{
QList<KoShapeConfigWidgetBase *> result;
//result.append(new ImageShapeConfigWidget());
return result;
}
diff --git a/plugins/flake/pathshapes/ellipse/EllipseShape.cpp b/plugins/flake/pathshapes/ellipse/EllipseShape.cpp
index b5610d9477..2e2758e9d2 100644
--- a/plugins/flake/pathshapes/ellipse/EllipseShape.cpp
+++ b/plugins/flake/pathshapes/ellipse/EllipseShape.cpp
@@ -1,550 +1,456 @@
/* This file is part of the KDE project
Copyright (C) 2006-2008 Thorsten Zachmann <zachmann@kde.org>
Copyright (C) 2006,2008 Jan Hambrecht <jaham@gmx.net>
Copyright (C) 2009 Thomas Zander <zander@kde.org>
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 "EllipseShape.h"
#include <KoPathPoint.h>
#include <KoShapeSavingContext.h>
#include <KoXmlReader.h>
#include <KoXmlWriter.h>
#include <KoXmlNS.h>
#include <KoUnit.h>
-#include <KoOdfWorkaround.h>
#include <SvgSavingContext.h>
#include <SvgLoadingContext.h>
#include <SvgUtil.h>
#include <SvgStyleWriter.h>
#include <KoParameterShape_p.h>
#include "kis_global.h"
#include <math.h>
EllipseShape::EllipseShape()
: m_startAngle(0)
, m_endAngle(0)
, m_kindAngle(M_PI)
, m_type(Arc)
{
QList<QPointF> handles;
handles.push_back(QPointF(100, 50));
handles.push_back(QPointF(100, 50));
handles.push_back(QPointF(0, 50));
setHandles(handles);
QSizeF size(100, 100);
m_radii = QPointF(size.width() / 2.0, size.height() / 2.0);
m_center = QPointF(m_radii.x(), m_radii.y());
updatePath(size);
}
EllipseShape::EllipseShape(const EllipseShape &rhs)
: KoParameterShape(rhs),
m_startAngle(rhs.m_startAngle),
m_endAngle(rhs.m_endAngle),
m_kindAngle(rhs.m_kindAngle),
m_center(rhs.m_center),
m_radii(rhs.m_radii),
m_type(rhs.m_type)
{
}
EllipseShape::~EllipseShape()
{
}
KoShape *EllipseShape::cloneShape() const
{
return new EllipseShape(*this);
}
-void EllipseShape::saveOdf(KoShapeSavingContext &context) const
-{
- if (isParametricShape()) {
- context.xmlWriter().startElement("draw:ellipse");
- saveOdfAttributes(context, OdfAllAttributes);
-
- switch (m_type) {
- case Arc:
- context.xmlWriter().addAttribute("draw:kind", sweepAngle() == 360 ? "full" : "arc");
- break;
- case Pie:
- context.xmlWriter().addAttribute("draw:kind", "section");
- break;
- case Chord:
- context.xmlWriter().addAttribute("draw:kind", "cut");
- break;
- default:
- context.xmlWriter().addAttribute("draw:kind", "full");
- }
- if (m_type != Arc || sweepAngle() != 360) {
- context.xmlWriter().addAttribute("draw:start-angle", m_startAngle);
- context.xmlWriter().addAttribute("draw:end-angle", m_endAngle);
- }
- saveOdfCommonChildElements(context);
- saveText(context);
- context.xmlWriter().endElement();
- } else {
- KoPathShape::saveOdf(context);
- }
-}
-
-bool EllipseShape::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- QSizeF size;
-
- bool radiusGiven = true;
-
- QString kind = element.attributeNS(KoXmlNS::draw, "kind", "full");
-
- if (element.hasAttributeNS(KoXmlNS::svg, "rx") && element.hasAttributeNS(KoXmlNS::svg, "ry")) {
- qreal rx = KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "rx"));
- qreal ry = KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "ry"));
- size = QSizeF(2 * rx, 2 * ry);
- } else if (element.hasAttributeNS(KoXmlNS::svg, "r")) {
- qreal r = KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "r"));
- size = QSizeF(2 * r, 2 * r);
- } else {
- size.setWidth(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "width", QString())));
- size.setHeight(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "height", QString())));
-#ifndef NWORKAROUND_ODF_BUGS
- radiusGiven = KoOdfWorkaround::fixEllipse(kind, context);
-#else
- radiusGiven = false;
-#endif
- }
- setSize(size);
-
- QPointF pos;
-
- if (element.hasAttributeNS(KoXmlNS::svg, "cx") && element.hasAttributeNS(KoXmlNS::svg, "cy")) {
- qreal cx = KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "cx"));
- qreal cy = KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "cy"));
- pos = QPointF(cx - 0.5 * size.width(), cy - 0.5 * size.height());
- } else {
- pos.setX(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "x", QString())));
- pos.setY(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "y", QString())));
- }
- setPosition(pos);
-
- if (kind == "section") {
- setType(Pie);
- } else if (kind == "cut") {
- setType(Chord);
- } else {
- setType(Arc);
- }
-
- setStartAngle(element.attributeNS(KoXmlNS::draw, "start-angle", "0").toDouble());
- setEndAngle(element.attributeNS(KoXmlNS::draw, "end-angle", "360").toDouble());
- if (!radiusGiven) {
- // is the size was given by width and height we have to reset the data as the size of the
- // part of the cut/pie is given.
- setSize(size);
- setPosition(pos);
- }
-
- loadOdfAttributes(element, context, OdfMandatories | OdfTransformation | OdfAdditionalAttributes | OdfCommonChildElements);
-
- loadText(element, context);
-
- return true;
-}
-
void EllipseShape::setSize(const QSizeF &newSize)
{
QTransform matrix(resizeMatrix(newSize));
m_center = matrix.map(m_center);
m_radii = matrix.map(m_radii);
KoParameterShape::setSize(newSize);
}
QPointF EllipseShape::normalize()
{
QPointF offset(KoParameterShape::normalize());
QTransform matrix;
matrix.translate(-offset.x(), -offset.y());
m_center = matrix.map(m_center);
return offset;
}
void EllipseShape::moveHandleAction(int handleId, const QPointF &point, Qt::KeyboardModifiers modifiers)
{
Q_UNUSED(modifiers);
QPointF p(point);
QPointF diff(m_center - point);
diff.setX(-diff.x());
qreal angle = 0;
if (diff.x() == 0) {
angle = (diff.y() < 0 ? 270 : 90) * M_PI / 180.0;
} else {
diff.setY(diff.y() * m_radii.x() / m_radii.y());
angle = atan(diff.y() / diff.x());
if (angle < 0) {
angle += M_PI;
}
if (diff.y() < 0) {
angle += M_PI;
}
}
QList<QPointF> handles = this->handles();
switch (handleId) {
case 0:
p = QPointF(m_center + QPointF(cos(angle) * m_radii.x(), -sin(angle) * m_radii.y()));
m_startAngle = kisRadiansToDegrees(angle);
handles[handleId] = p;
break;
case 1:
p = QPointF(m_center + QPointF(cos(angle) * m_radii.x(), -sin(angle) * m_radii.y()));
m_endAngle = kisRadiansToDegrees(angle);
handles[handleId] = p;
break;
case 2: {
QList<QPointF> kindHandlePositions;
kindHandlePositions.push_back(QPointF(m_center + QPointF(cos(m_kindAngle) * m_radii.x(), -sin(m_kindAngle) * m_radii.y())));
kindHandlePositions.push_back(m_center);
kindHandlePositions.push_back((handles[0] + handles[1]) / 2.0);
QPointF diff = m_center * 2.0;
int handlePos = 0;
for (int i = 0; i < kindHandlePositions.size(); ++i) {
QPointF pointDiff(p - kindHandlePositions[i]);
if (i == 0 || qAbs(pointDiff.x()) + qAbs(pointDiff.y()) < qAbs(diff.x()) + qAbs(diff.y())) {
diff = pointDiff;
handlePos = i;
}
}
handles[handleId] = kindHandlePositions[handlePos];
m_type = EllipseType(handlePos);
}
break;
}
setHandles(handles);
if (handleId != 2) {
updateKindHandle();
}
}
void EllipseShape::updatePath(const QSizeF &size)
{
Q_UNUSED(size);
QPointF startpoint(handles()[0]);
QPointF curvePoints[12];
const qreal distance = sweepAngle();
const bool sameAngles = distance > 359.9;
int pointCnt = arcToCurve(m_radii.x(), m_radii.y(), m_startAngle, distance, startpoint, curvePoints);
KIS_SAFE_ASSERT_RECOVER_RETURN(pointCnt);
int curvePointCount = 1 + pointCnt / 3;
int requiredPointCount = curvePointCount;
if (m_type == Pie) {
requiredPointCount++;
} else if (m_type == Arc && sameAngles) {
curvePointCount--;
requiredPointCount--;
}
createPoints(requiredPointCount);
KoSubpath &points = *subpaths()[0];
int curveIndex = 0;
points[0]->setPoint(startpoint);
points[0]->removeControlPoint1();
points[0]->setProperty(KoPathPoint::StartSubpath);
for (int i = 1; i < curvePointCount; ++i) {
points[i - 1]->setControlPoint2(curvePoints[curveIndex++]);
points[i]->setControlPoint1(curvePoints[curveIndex++]);
points[i]->setPoint(curvePoints[curveIndex++]);
points[i]->removeControlPoint2();
}
if (m_type == Pie) {
points[requiredPointCount - 1]->setPoint(m_center);
points[requiredPointCount - 1]->removeControlPoint1();
points[requiredPointCount - 1]->removeControlPoint2();
} else if (m_type == Arc && sameAngles) {
points[curvePointCount - 1]->setControlPoint2(curvePoints[curveIndex]);
points[0]->setControlPoint1(curvePoints[++curveIndex]);
}
for (int i = 0; i < requiredPointCount; ++i) {
points[i]->unsetProperty(KoPathPoint::StopSubpath);
points[i]->unsetProperty(KoPathPoint::CloseSubpath);
}
subpaths()[0]->last()->setProperty(KoPathPoint::StopSubpath);
if (m_type == Arc && !sameAngles) {
subpaths()[0]->first()->unsetProperty(KoPathPoint::CloseSubpath);
subpaths()[0]->last()->unsetProperty(KoPathPoint::CloseSubpath);
} else {
subpaths()[0]->first()->setProperty(KoPathPoint::CloseSubpath);
subpaths()[0]->last()->setProperty(KoPathPoint::CloseSubpath);
}
notifyPointsChanged();
normalize();
}
void EllipseShape::createPoints(int requiredPointCount)
{
if (subpaths().count() != 1) {
clear();
subpaths().append(new KoSubpath());
}
int currentPointCount = subpaths()[0]->count();
if (currentPointCount > requiredPointCount) {
for (int i = 0; i < currentPointCount - requiredPointCount; ++i) {
delete subpaths()[0]->front();
subpaths()[0]->pop_front();
}
} else if (requiredPointCount > currentPointCount) {
for (int i = 0; i < requiredPointCount - currentPointCount; ++i) {
subpaths()[0]->append(new KoPathPoint(this, QPointF()));
}
}
notifyPointsChanged();
}
void EllipseShape::updateKindHandle()
{
qreal angle = 0.5 * (m_startAngle + m_endAngle);
if (m_startAngle > m_endAngle) {
angle += 180.0;
}
m_kindAngle = normalizeAngle(kisDegreesToRadians(angle));
QList<QPointF> handles = this->handles();
switch (m_type) {
case Arc:
handles[2] = m_center + QPointF(cos(m_kindAngle) * m_radii.x(), -sin(m_kindAngle) * m_radii.y());
break;
case Pie:
handles[2] = m_center;
break;
case Chord:
handles[2] = (handles[0] + handles[1]) / 2.0;
break;
}
setHandles(handles);
}
void EllipseShape::updateAngleHandles()
{
qreal startRadian = kisDegreesToRadians(normalizeAngleDegrees(m_startAngle));
qreal endRadian = kisDegreesToRadians(normalizeAngleDegrees(m_endAngle));
QList<QPointF> handles = this->handles();
handles[0] = m_center + QPointF(cos(startRadian) * m_radii.x(), -sin(startRadian) * m_radii.y());
handles[1] = m_center + QPointF(cos(endRadian) * m_radii.x(), -sin(endRadian) * m_radii.y());
setHandles(handles);
}
qreal EllipseShape::sweepAngle() const
{
const qreal a1 = normalizeAngle(kisDegreesToRadians(m_startAngle));
const qreal a2 = normalizeAngle(kisDegreesToRadians(m_endAngle));
qreal sAngle = a2 - a1;
if (a1 > a2) {
sAngle = 2 * M_PI + sAngle;
}
if (qAbs(a1 - a2) < 0.05 / M_PI) {
sAngle = 2 * M_PI;
}
return kisRadiansToDegrees(sAngle);
}
void EllipseShape::setType(EllipseType type)
{
m_type = type;
updateKindHandle();
updatePath(size());
}
EllipseShape::EllipseType EllipseShape::type() const
{
return m_type;
}
void EllipseShape::setStartAngle(qreal angle)
{
m_startAngle = angle;
updateKindHandle();
updateAngleHandles();
updatePath(size());
}
qreal EllipseShape::startAngle() const
{
return m_startAngle;
}
void EllipseShape::setEndAngle(qreal angle)
{
m_endAngle = angle;
updateKindHandle();
updateAngleHandles();
updatePath(size());
}
qreal EllipseShape::endAngle() const
{
return m_endAngle;
}
QString EllipseShape::pathShapeId() const
{
return EllipseShapeId;
}
bool EllipseShape::saveSvg(SvgSavingContext &context)
{
// let basic path saiving code handle our saving
if (!isParametricShape()) return false;
if (type() == EllipseShape::Arc && startAngle() == endAngle()) {
const QSizeF size = this->size();
const bool isCircle = size.width() == size.height();
context.shapeWriter().startElement(isCircle ? "circle" : "ellipse");
context.shapeWriter().addAttribute("id", context.getID(this));
SvgUtil::writeTransformAttributeLazy("transform", transformation(), context.shapeWriter());
if (isCircle) {
context.shapeWriter().addAttribute("r", 0.5 * size.width());
} else {
context.shapeWriter().addAttribute("rx", 0.5 * size.width());
context.shapeWriter().addAttribute("ry", 0.5 * size.height());
}
context.shapeWriter().addAttribute("cx", 0.5 * size.width());
context.shapeWriter().addAttribute("cy", 0.5 * size.height());
SvgStyleWriter::saveSvgStyle(this, context);
context.shapeWriter().endElement();
} else {
context.shapeWriter().startElement("path");
context.shapeWriter().addAttribute("id", context.getID(this));
SvgUtil::writeTransformAttributeLazy("transform", transformation(), context.shapeWriter());
context.shapeWriter().addAttribute("sodipodi:type", "arc");
context.shapeWriter().addAttribute("sodipodi:rx", m_radii.x());
context.shapeWriter().addAttribute("sodipodi:ry", m_radii.y());
context.shapeWriter().addAttribute("sodipodi:cx", m_center.x());
context.shapeWriter().addAttribute("sodipodi:cy", m_center.y());
context.shapeWriter().addAttribute("sodipodi:start", 2 * M_PI - kisDegreesToRadians(endAngle()));
context.shapeWriter().addAttribute("sodipodi:end", 2 * M_PI - kisDegreesToRadians(startAngle()));
switch (type()) {
case Pie:
// noop
break;
case Chord:
context.shapeWriter().addAttribute("sodipodi:arc-type", "chord");
break;
case Arc:
context.shapeWriter().addAttribute("sodipodi:open", "true");
break;
}
context.shapeWriter().addAttribute("d", this->toString(context.userSpaceTransform()));
SvgStyleWriter::saveSvgStyle(this, context);
context.shapeWriter().endElement();
}
return true;
}
bool EllipseShape::loadSvg(const KoXmlElement &element, SvgLoadingContext &context)
{
qreal rx = 0, ry = 0;
qreal cx = 0;
qreal cy = 0;
qreal start = 0;
qreal end = 0;
EllipseType type = Arc;
const QString extendedNamespace =
element.attribute("sodipodi:type") == "arc" ? "sodipodi" :
element.attribute("krita:type") == "arc" ? "krita" : "";
if (element.tagName() == "ellipse") {
rx = SvgUtil::parseUnitX(context.currentGC(), element.attribute("rx"));
ry = SvgUtil::parseUnitY(context.currentGC(), element.attribute("ry"));
cx = SvgUtil::parseUnitX(context.currentGC(), element.attribute("cx", "0"));
cy = SvgUtil::parseUnitY(context.currentGC(), element.attribute("cy", "0"));
} else if (element.tagName() == "circle") {
rx = ry = SvgUtil::parseUnitXY(context.currentGC(), element.attribute("r"));
cx = SvgUtil::parseUnitX(context.currentGC(), element.attribute("cx", "0"));
cy = SvgUtil::parseUnitY(context.currentGC(), element.attribute("cy", "0"));
} else if (element.tagName() == "path" && !extendedNamespace.isEmpty()) {
rx = SvgUtil::parseUnitX(context.currentGC(), element.attribute(extendedNamespace + ":rx"));
ry = SvgUtil::parseUnitY(context.currentGC(), element.attribute(extendedNamespace + ":ry"));
cx = SvgUtil::parseUnitX(context.currentGC(), element.attribute(extendedNamespace + ":cx", "0"));
cy = SvgUtil::parseUnitY(context.currentGC(), element.attribute(extendedNamespace + ":cy", "0"));
start = 2 * M_PI - SvgUtil::parseNumber(element.attribute(extendedNamespace + ":end"));
end = 2 * M_PI - SvgUtil::parseNumber(element.attribute(extendedNamespace + ":start"));
const QString kritaArcType =
element.attribute("sodipodi:arc-type", element.attribute("krita:arcType"));
if (kritaArcType.isEmpty()) {
if (element.attribute("sodipodi:open", "false") == "false") {
type = Pie;
}
} else if (kritaArcType == "pie") {
type = Pie;
} else if (kritaArcType == "chord") {
type = Chord;
}
} else {
return false;
}
setSize(QSizeF(2 * rx, 2 * ry));
setPosition(QPointF(cx - rx, cy - ry));
if (rx == 0.0 || ry == 0.0) {
setVisible(false);
}
if (start != 0 || start != end) {
setStartAngle(kisRadiansToDegrees(start));
setEndAngle(kisRadiansToDegrees(end));
setType(type);
}
return true;
}
diff --git a/plugins/flake/pathshapes/ellipse/EllipseShape.h b/plugins/flake/pathshapes/ellipse/EllipseShape.h
index bdaa481044..e69db26a74 100644
--- a/plugins/flake/pathshapes/ellipse/EllipseShape.h
+++ b/plugins/flake/pathshapes/ellipse/EllipseShape.h
@@ -1,122 +1,118 @@
/* This file is part of the KDE project
Copyright (C) 2006-2007 Thorsten Zachmann <zachmann@kde.org>
Copyright (C) 2006 Jan Hambrecht <jaham@gmx.net>
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 KOELLIPSESHAPE_H
#define KOELLIPSESHAPE_H
#include "KoParameterShape.h"
#include <SvgShape.h>
#define EllipseShapeId "EllipseShape"
/**
* This class adds support for arc, pie, chord, circle and ellipse
* shapes. The ellipse/circle radii are defined by the actual size
* of the ellipse shape which can be changed with the setSize
* method.
*/
class EllipseShape : public KoParameterShape, public SvgShape
{
public:
/// the possible ellipse types
enum EllipseType {
Arc = 0, ///< an ellipse arc
Pie = 1, ///< an ellipse pie
Chord = 2 ///< an ellipse chord
};
EllipseShape();
~EllipseShape() override;
KoShape* cloneShape() const override;
void setSize(const QSizeF &newSize) override;
QPointF normalize() override;
/**
* Sets the type of the ellipse.
* @param type the new ellipse type
*/
void setType(EllipseType type);
/// Returns the actual ellipse type
EllipseType type() const;
/**
* Sets the start angle of the ellipse.
* @param angle the new start angle in degree
*/
void setStartAngle(qreal angle);
/// Returns the actual ellipse start angle in degree
qreal startAngle() const;
/**
* Sets the end angle of the ellipse.
* @param angle the new end angle in degree
*/
void setEndAngle(qreal angle);
/// Returns the actual ellipse end angle in degree
qreal endAngle() const;
/// reimplemented
QString pathShapeId() const override;
/// reimplemented from SvgShape
bool saveSvg(SvgSavingContext &context) override;
/// reimplemented from SvgShape
bool loadSvg(const KoXmlElement &element, SvgLoadingContext &context) override;
protected:
- // reimplemented
- void saveOdf(KoShapeSavingContext &context) const override;
- // reimplemented
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
void moveHandleAction(int handleId, const QPointF &point, Qt::KeyboardModifiers modifiers = Qt::NoModifier) override;
void updatePath(const QSizeF &size) override;
void createPoints(int requiredPointCount);
private:
qreal sweepAngle() const;
void updateKindHandle();
void updateAngleHandles();
EllipseShape(const EllipseShape &rhs);
// start angle in degree
qreal m_startAngle;
// end angle in degree
qreal m_endAngle;
// angle for modifying the kind in radiant
qreal m_kindAngle;
// the center of the ellipse
QPointF m_center;
// the radii of the ellipse
QPointF m_radii;
// the actual ellipse type
EllipseType m_type;
};
#endif /* KOELLIPSESHAPE_H */
diff --git a/plugins/flake/pathshapes/enhancedpath/EnhancedPathHandle.cpp b/plugins/flake/pathshapes/enhancedpath/EnhancedPathHandle.cpp
index 30d81576b8..4ccd9d7fd2 100644
--- a/plugins/flake/pathshapes/enhancedpath/EnhancedPathHandle.cpp
+++ b/plugins/flake/pathshapes/enhancedpath/EnhancedPathHandle.cpp
@@ -1,238 +1,158 @@
/* This file is part of the KDE project
* Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
*
* 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 "EnhancedPathHandle.h"
#include "EnhancedPathShape.h"
#include "EnhancedPathParameter.h"
#include <KoShapeSavingContext.h>
#include <KoXmlReader.h>
#include <KoXmlWriter.h>
#include <KoXmlNS.h>
#include <KoShapeLoadingContext.h>
-#include <KoOdfWorkaround.h>
#include <math.h>
EnhancedPathHandle::EnhancedPathHandle(EnhancedPathShape *parent)
: m_parent(parent)
, m_positionX(0)
, m_positionY(0)
, m_minimumX(0)
, m_minimumY(0)
, m_maximumX(0)
, m_maximumY(0)
, m_polarX(0)
, m_polarY(0)
, m_minRadius(0)
, m_maxRadius(0)
{
Q_ASSERT(m_parent);
}
EnhancedPathHandle::~EnhancedPathHandle()
{
}
bool EnhancedPathHandle::hasPosition() const
{
return m_positionX && m_positionY;
}
void EnhancedPathHandle::setPosition(EnhancedPathParameter *positionX, EnhancedPathParameter *positionY)
{
m_positionX = positionX;
m_positionY = positionY;
}
QPointF EnhancedPathHandle::position()
{
if (!hasPosition()) {
return QPointF();
}
QPointF position(m_positionX->evaluate(), m_positionY->evaluate());
if (isPolar()) {
// convert polar coordinates into cartesian coordinates
QPointF center(m_polarX->evaluate(), m_polarY->evaluate());
qreal angleInRadian = position.x() * M_PI / 180.0;
position = center + position.y() * QPointF(cos(angleInRadian), sin(angleInRadian));
}
return position;
}
void EnhancedPathHandle::changePosition(const QPointF &position)
{
if (!hasPosition()) {
return;
}
QPointF constrainedPosition(position);
if (isPolar()) {
// convert cartesian coordinates into polar coordinates
QPointF polarCenter(m_polarX->evaluate(), m_polarY->evaluate());
QPointF diff = constrainedPosition - polarCenter;
// compute the polar radius
qreal radius = sqrt(diff.x() * diff.x() + diff.y() * diff.y());
// compute the polar angle
qreal angle = atan2(diff.y(), diff.x());
if (angle < 0.0) {
angle += 2 * M_PI;
}
// constrain the radius
if (m_minRadius) {
radius = qMax(m_minRadius->evaluate(), radius);
}
if (m_maxRadius) {
radius = qMin(m_maxRadius->evaluate(), radius);
}
constrainedPosition.setX(angle * 180.0 / M_PI);
constrainedPosition.setY(radius);
} else {
// constrain x coordinate
if (m_minimumX) {
constrainedPosition.setX(qMax(m_minimumX->evaluate(), constrainedPosition.x()));
}
if (m_maximumX) {
constrainedPosition.setX(qMin(m_maximumX->evaluate(), constrainedPosition.x()));
}
// constrain y coordinate
if (m_minimumY) {
constrainedPosition.setY(qMax(m_minimumY->evaluate(), constrainedPosition.y()));
}
if (m_maximumY) {
constrainedPosition.setY(qMin(m_maximumY->evaluate(), constrainedPosition.y()));
}
}
m_positionX->modify(constrainedPosition.x());
m_positionY->modify(constrainedPosition.y());
}
void EnhancedPathHandle::setRangeX(EnhancedPathParameter *minX, EnhancedPathParameter *maxX)
{
m_minimumX = minX;
m_maximumX = maxX;
}
void EnhancedPathHandle::setRangeY(EnhancedPathParameter *minY, EnhancedPathParameter *maxY)
{
m_minimumY = minY;
m_maximumY = maxY;
}
void EnhancedPathHandle::setPolarCenter(EnhancedPathParameter *polarX, EnhancedPathParameter *polarY)
{
m_polarX = polarX;
m_polarY = polarY;
}
void EnhancedPathHandle::setRadiusRange(EnhancedPathParameter *minRadius, EnhancedPathParameter *maxRadius)
{
m_minRadius = minRadius;
m_maxRadius = maxRadius;
}
bool EnhancedPathHandle::isPolar() const
{
return m_polarX && m_polarY;
}
-
-void EnhancedPathHandle::saveOdf(KoShapeSavingContext &context) const
-{
- if (!hasPosition()) {
- return;
- }
- context.xmlWriter().startElement("draw:handle");
- context.xmlWriter().addAttribute("draw:handle-position", m_positionX->toString() + ' ' + m_positionY->toString());
- if (isPolar()) {
- context.xmlWriter().addAttribute("draw:handle-polar", m_polarX->toString() + ' ' + m_polarY->toString());
- if (m_minRadius) {
- context.xmlWriter().addAttribute("draw:handle-radius-range-minimum", m_minRadius->toString());
- }
- if (m_maxRadius) {
- context.xmlWriter().addAttribute("draw:handle-radius-range-maximum", m_maxRadius->toString());
- }
- } else {
- if (m_minimumX) {
- context.xmlWriter().addAttribute("draw:handle-range-x-minimum", m_minimumX->toString());
- }
- if (m_maximumX) {
- context.xmlWriter().addAttribute("draw:handle-range-x-maximum", m_maximumX->toString());
- }
- if (m_minimumY) {
- context.xmlWriter().addAttribute("draw:handle-range-y-minimum", m_minimumY->toString());
- }
- if (m_maximumY) {
- context.xmlWriter().addAttribute("draw:handle-range-y-maximum", m_maximumY->toString());
- }
- }
- context.xmlWriter().endElement(); // draw:handle
-}
-
-bool EnhancedPathHandle::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- if (element.localName() != "handle" || element.namespaceURI() != KoXmlNS::draw) {
- return false;
- }
-
- QString position = element.attributeNS(KoXmlNS::draw, "handle-position");
-#ifndef NWORKAROUND_ODF_BUGS
- KoOdfWorkaround::fixEnhancedPathPolarHandlePosition(position, element, context);
-#endif
- QStringList tokens = position.simplified().split(' ');
- if (tokens.count() != 2) {
- return false;
- }
-
- setPosition(m_parent->parameter(tokens[0]), m_parent->parameter(tokens[1]));
-
- // check if we have a polar handle
- if (element.hasAttributeNS(KoXmlNS::draw, "handle-polar")) {
- QString polar = element.attributeNS(KoXmlNS::draw, "handle-polar");
- QStringList tokens = polar.simplified().split(' ');
- if (tokens.count() == 2) {
- setPolarCenter(m_parent->parameter(tokens[0]), m_parent->parameter(tokens[1]));
-
- QString minRadius = element.attributeNS(KoXmlNS::draw, "handle-radius-range-minimum");
- QString maxRadius = element.attributeNS(KoXmlNS::draw, "handle-radius-range-maximum");
- if (!minRadius.isEmpty() && !maxRadius.isEmpty()) {
- setRadiusRange(m_parent->parameter(minRadius), m_parent->parameter(maxRadius));
- }
- }
- } else {
- QString minX = element.attributeNS(KoXmlNS::draw, "handle-range-x-minimum");
- QString maxX = element.attributeNS(KoXmlNS::draw, "handle-range-x-maximum");
- if (!minX.isEmpty() && ! maxX.isEmpty()) {
- setRangeX(m_parent->parameter(minX), m_parent->parameter(maxX));
- }
-
- QString minY = element.attributeNS(KoXmlNS::draw, "handle-range-y-minimum");
- QString maxY = element.attributeNS(KoXmlNS::draw, "handle-range-y-maximum");
- if (!minY.isEmpty() && ! maxY.isEmpty()) {
- setRangeY(m_parent->parameter(minY), m_parent->parameter(maxY));
- }
- }
-
- return hasPosition();
-}
diff --git a/plugins/flake/pathshapes/enhancedpath/EnhancedPathHandle.h b/plugins/flake/pathshapes/enhancedpath/EnhancedPathHandle.h
index 5603585122..43571b0f92 100644
--- a/plugins/flake/pathshapes/enhancedpath/EnhancedPathHandle.h
+++ b/plugins/flake/pathshapes/enhancedpath/EnhancedPathHandle.h
@@ -1,138 +1,134 @@
/* This file is part of the KDE project
* Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
*
* 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 KOENHANCEDPATHHANDLE_H
#define KOENHANCEDPATHHANDLE_H
#include <QPointF>
#include <KoXmlReaderForward.h>
class EnhancedPathShape;
class EnhancedPathParameter;
class KoShapeSavingContext;
class KoShapeLoadingContext;
/**
* An interaction handle used by the EnhancedPathShape for
* changing the shape interactively.
*/
class EnhancedPathHandle
{
public:
/**
* Constructs a new empty handle;
*
* Note that an empty handle is not valid, as long as there are no
* positional parameters set with setPosition.
*/
explicit EnhancedPathHandle(EnhancedPathShape *parent);
/// Destroys the handle
~EnhancedPathHandle();
/**
* Evaluates the position of the handle.
* @return the actual handle position
*/
QPointF position();
/**
* Attempts to changes the position of the handle.
* Only the coordinates of the handle which reference a modifier
* can be changed. The new position is automatically stored into
* the modifier of the given enhanced path.
*
* @param position the new position the handle to set
* @param path the enhanced path the handle is referenced from
*/
void changePosition(const QPointF &position);
/// Returns if the handle has valid positional parameters.S
bool hasPosition() const;
/**
* Sets the positional parameters, making the handle valid.
*
* It replaces the actual positional parameters.
*
* @param positionX the x-coordinate of the handle position
* @param positionY the y-coordinate of the handle position
*/
void setPosition(EnhancedPathParameter *positionX, EnhancedPathParameter *positionY);
/**
* Sets the range of the handles x-coordinate.
*
* A zero pointer has the effect of no maximum/minimum value.
*
* @param minX the minimum x-coordinate
* @param maxX the maximum x-coordinate
*/
void setRangeX(EnhancedPathParameter *minX, EnhancedPathParameter *maxX);
/**
* Sets the range of the handles y-coordinate.
*
* A zero pointer has the effect of no maximum/minimum value.
*
* @param minY the minimum y-coordinate
* @param maxY the maximum y-coordinate
*/
void setRangeY(EnhancedPathParameter *minY, EnhancedPathParameter *maxY);
/**
* Sets the center of a polar handle.
*
* If both parameters are valid pointers, then the handle behaves like
* a polar handle. This means the x-coordinate of the position represents
* an angle in degree and the y-coordinate a radius.
*
* @param polarX the polar center x-coordinate
* @param polarY the polar center y-coordinate
*/
void setPolarCenter(EnhancedPathParameter *polarX, EnhancedPathParameter *polarY);
/**
* Sets the range of the radius for polar handles.
* @param minRadius the minimum polar radius
* @param maxRadius the maximum polar radius
*/
void setRadiusRange(EnhancedPathParameter *minRadius, EnhancedPathParameter *maxRadius);
- /// save to the given shape saving context
- void saveOdf(KoShapeSavingContext &context) const;
- /// load handle from given element
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context);
private:
/// Returns if handle is polar
bool isPolar() const;
EnhancedPathShape *m_parent; ///< the enhanced path shape owning this handle
EnhancedPathParameter *m_positionX; ///< the position x-coordinate
EnhancedPathParameter *m_positionY; ///< the position y-coordinate
EnhancedPathParameter *m_minimumX; ///< the minimum x-coordinate
EnhancedPathParameter *m_minimumY; ///< the minmum y-coordinate
EnhancedPathParameter *m_maximumX; ///< the maximum x-coordinate
EnhancedPathParameter *m_maximumY; ///< the maximum y-coordinate
EnhancedPathParameter *m_polarX; ///< the polar center x-coordinate
EnhancedPathParameter *m_polarY; ///< the polar center y-coordinate
EnhancedPathParameter *m_minRadius; ///< the minimum polar radius
EnhancedPathParameter *m_maxRadius; ///< the maximum polar radius
};
#endif // KOENHANCEDPATHHANDLE_H
diff --git a/plugins/flake/pathshapes/enhancedpath/EnhancedPathShape.cpp b/plugins/flake/pathshapes/enhancedpath/EnhancedPathShape.cpp
index 4a85d1f431..8502048819 100644
--- a/plugins/flake/pathshapes/enhancedpath/EnhancedPathShape.cpp
+++ b/plugins/flake/pathshapes/enhancedpath/EnhancedPathShape.cpp
@@ -1,742 +1,558 @@
/* This file is part of the KDE project
* Copyright (C) 2007,2010,2011 Jan Hambrecht <jaham@gmx.net>
* Copyright (C) 2009-2010 Thomas Zander <zander@kde.org>
* Copyright (C) 2010 Carlos Licea <carlos@kdab.com>
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
* Contact: Suresh Chande suresh.chande@nokia.com
* Copyright (C) 2009-2010 Thorsten Zachmann <zachmann@kde.org>
*
* 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 <KoParameterShape_p.h>
#include "EnhancedPathShape.h"
#include "EnhancedPathCommand.h"
#include "EnhancedPathParameter.h"
#include "EnhancedPathHandle.h"
#include "EnhancedPathFormula.h"
#include <QPainterPath>
#include <KoXmlNS.h>
#include <KoXmlWriter.h>
#include <KoXmlReader.h>
#include <KoShapeSavingContext.h>
#include <KoUnit.h>
-#include <KoOdfWorkaround.h>
#include <KoPathPoint.h>
EnhancedPathShape::EnhancedPathShape(const QRect &viewBox)
: m_viewBox(viewBox)
, m_viewBoxOffset(0.0, 0.0)
, m_mirrorVertically(false)
, m_mirrorHorizontally(false)
, m_pathStretchPointX(-1)
, m_pathStretchPointY(-1)
, m_cacheResults(false)
{
}
EnhancedPathShape::EnhancedPathShape(const EnhancedPathShape &rhs)
: KoParameterShape(rhs),
m_viewBox(rhs.m_viewBox),
m_viewBound(rhs.m_viewBound),
m_viewMatrix(rhs.m_viewMatrix),
m_mirrorMatrix(rhs.m_mirrorMatrix),
m_viewBoxOffset(rhs.m_viewBoxOffset),
m_textArea(rhs.m_textArea),
m_commands(rhs.m_commands),
m_enhancedHandles(rhs.m_enhancedHandles),
m_formulae(rhs.m_formulae),
m_modifiers(rhs.m_modifiers),
m_parameters(rhs.m_parameters),
m_mirrorVertically(rhs.m_mirrorVertically),
m_mirrorHorizontally(rhs.m_mirrorHorizontally),
m_pathStretchPointX(rhs.m_pathStretchPointX),
m_pathStretchPointY(rhs.m_pathStretchPointY),
m_resultCache(rhs.m_resultCache),
m_cacheResults(rhs.m_cacheResults)
{
}
EnhancedPathShape::~EnhancedPathShape()
{
reset();
}
KoShape *EnhancedPathShape::cloneShape() const
{
return new EnhancedPathShape(*this);
}
void EnhancedPathShape::reset()
{
qDeleteAll(m_commands);
m_commands.clear();
qDeleteAll(m_enhancedHandles);
m_enhancedHandles.clear();
setHandles(QList<QPointF>());
qDeleteAll(m_formulae);
m_formulae.clear();
qDeleteAll(m_parameters);
m_parameters.clear();
m_modifiers.clear();
m_viewMatrix.reset();
m_viewBoxOffset = QPointF();
clear();
m_textArea.clear();
}
void EnhancedPathShape::moveHandleAction(int handleId, const QPointF &point, Qt::KeyboardModifiers modifiers)
{
Q_UNUSED(modifiers);
EnhancedPathHandle *handle = m_enhancedHandles[ handleId ];
if (handle) {
handle->changePosition(shapeToViewbox(point));
}
}
void EnhancedPathShape::updatePath(const QSizeF &size)
{
if (isParametricShape()) {
clear();
enableResultCache(true);
foreach (EnhancedPathCommand *cmd, m_commands) {
cmd->execute();
}
enableResultCache(false);
qreal stretchPointsScale = 1;
bool isStretched = useStretchPoints(size, stretchPointsScale);
m_viewBound = outline().boundingRect();
m_mirrorMatrix.reset();
m_mirrorMatrix.translate(m_viewBound.center().x(), m_viewBound.center().y());
m_mirrorMatrix.scale(m_mirrorHorizontally ? -1 : 1, m_mirrorVertically ? -1 : 1);
m_mirrorMatrix.translate(-m_viewBound.center().x(), -m_viewBound.center().y());
QTransform matrix(1.0, 0.0, 0.0, 1.0, m_viewBoxOffset.x(), m_viewBoxOffset.y());
// if stretch points are set than stretch the path manually
if (isStretched) {
//if the path was stretched manually the stretch matrix is not more valid
//and it has to be recalculated so that stretching in x and y direction is the same
matrix.scale(stretchPointsScale, stretchPointsScale);
matrix = m_mirrorMatrix * matrix;
} else {
matrix = m_mirrorMatrix * m_viewMatrix * matrix;
}
foreach (KoSubpath *subpath, subpaths()) {
foreach (KoPathPoint *point, *subpath) {
point->map(matrix);
}
}
const int handleCount = m_enhancedHandles.count();
QList<QPointF> handles;
for (int i = 0; i < handleCount; ++i) {
handles.append(matrix.map(m_enhancedHandles[i]->position()));
}
setHandles(handles);
normalize();
}
}
void EnhancedPathShape::setSize(const QSizeF &newSize)
{
// handle offset
KoParameterShape::setSize(newSize);
// calculate scaling factors from viewbox size to shape size
qreal xScale = m_viewBound.width() == 0 ? 1 : newSize.width() / m_viewBound.width();
qreal yScale = m_viewBound.height() == 0 ? 1 : newSize.height() / m_viewBound.height();
// create view matrix, take mirroring into account
m_viewMatrix.reset();
m_viewMatrix.scale(xScale, yScale);
updatePath(newSize);
}
QPointF EnhancedPathShape::normalize()
{
QPointF offset = KoParameterShape::normalize();
m_viewBoxOffset -= offset;
return offset;
}
QPointF EnhancedPathShape::shapeToViewbox(const QPointF &point) const
{
return (m_mirrorMatrix * m_viewMatrix).inverted().map(point - m_viewBoxOffset);
}
void EnhancedPathShape::evaluateHandles()
{
const int handleCount = m_enhancedHandles.count();
QList<QPointF> handles;
for (int i = 0; i < handleCount; ++i) {
handles.append(m_enhancedHandles[i]->position());
}
setHandles(handles);
}
QRect EnhancedPathShape::viewBox() const
{
return m_viewBox;
}
qreal EnhancedPathShape::evaluateReference(const QString &reference)
{
if (reference.isEmpty()) {
return 0.0;
}
const char c = reference[0].toLatin1();
qreal res = 0.0;
switch (c) {
// referenced modifier
case '$': {
bool success = false;
int modifierIndex = reference.mid(1).toInt(&success);
res = m_modifiers.value(modifierIndex);
break;
}
// referenced formula
case '?': {
QString fname = reference.mid(1);
if (m_cacheResults && m_resultCache.contains(fname)) {
res = m_resultCache.value(fname);
} else {
FormulaStore::const_iterator formulaIt = m_formulae.constFind(fname);
if (formulaIt != m_formulae.constEnd()) {
EnhancedPathFormula *formula = formulaIt.value();
if (formula) {
res = formula->evaluate();
if (m_cacheResults) {
m_resultCache.insert(fname, res);
}
}
}
}
break;
}
// maybe an identifier ?
default:
EnhancedPathNamedParameter p(reference, this);
res = p.evaluate();
break;
}
return res;
}
qreal EnhancedPathShape::evaluateConstantOrReference(const QString &val)
{
bool ok = true;
qreal res = val.toDouble(&ok);
if (ok) {
return res;
}
return evaluateReference(val);
}
void EnhancedPathShape::modifyReference(const QString &reference, qreal value)
{
if (reference.isEmpty()) {
return;
}
const char c = reference[0].toLatin1();
if (c == '$') {
bool success = false;
int modifierIndex = reference.mid(1).toInt(&success);
if (modifierIndex >= 0 && modifierIndex < m_modifiers.count()) {
m_modifiers[modifierIndex] = value;
}
}
}
EnhancedPathParameter *EnhancedPathShape::parameter(const QString &text)
{
Q_ASSERT(! text.isEmpty());
ParameterStore::const_iterator parameterIt = m_parameters.constFind(text);
if (parameterIt != m_parameters.constEnd()) {
return parameterIt.value();
} else {
EnhancedPathParameter *parameter = 0;
const char c = text[0].toLatin1();
if (c == '$' || c == '?') {
parameter = new EnhancedPathReferenceParameter(text, this);
} else {
bool success = false;
qreal constant = text.toDouble(&success);
if (success) {
parameter = new EnhancedPathConstantParameter(constant, this);
} else {
Identifier identifier = EnhancedPathNamedParameter::identifierFromString(text);
if (identifier != IdentifierUnknown) {
parameter = new EnhancedPathNamedParameter(identifier, this);
}
}
}
if (parameter) {
m_parameters[text] = parameter;
}
return parameter;
}
}
void EnhancedPathShape::addFormula(const QString &name, const QString &formula)
{
if (name.isEmpty() || formula.isEmpty()) {
return;
}
m_formulae[name] = new EnhancedPathFormula(formula, this);
}
void EnhancedPathShape::addHandle(const QMap<QString, QVariant> &handle)
{
if (handle.isEmpty()) {
return;
}
if (!handle.contains("draw:handle-position")) {
return;
}
QVariant position = handle.value("draw:handle-position");
QStringList tokens = position.toString().simplified().split(' ');
if (tokens.count() < 2) {
return;
}
EnhancedPathHandle *newHandle = new EnhancedPathHandle(this);
newHandle->setPosition(parameter(tokens[0]), parameter(tokens[1]));
// check if we have a polar handle
if (handle.contains("draw:handle-polar")) {
QVariant polar = handle.value("draw:handle-polar");
QStringList tokens = polar.toString().simplified().split(' ');
if (tokens.count() == 2) {
newHandle->setPolarCenter(parameter(tokens[0]), parameter(tokens[1]));
QVariant minRadius = handle.value("draw:handle-radius-range-minimum");
QVariant maxRadius = handle.value("draw:handle-radius-range-maximum");
if (minRadius.isValid() && maxRadius.isValid()) {
newHandle->setRadiusRange(parameter(minRadius.toString()), parameter(maxRadius.toString()));
}
}
} else {
QVariant minX = handle.value("draw:handle-range-x-minimum");
QVariant maxX = handle.value("draw:handle-range-x-maximum");
if (minX.isValid() && maxX.isValid()) {
newHandle->setRangeX(parameter(minX.toString()), parameter(maxX.toString()));
}
QVariant minY = handle.value("draw:handle-range-y-minimum");
QVariant maxY = handle.value("draw:handle-range-y-maximum");
if (minY.isValid() && maxY.isValid()) {
newHandle->setRangeY(parameter(minY.toString()), parameter(maxY.toString()));
}
}
m_enhancedHandles.append(newHandle);
evaluateHandles();
}
void EnhancedPathShape::addModifiers(const QString &modifiers)
{
if (modifiers.isEmpty()) {
return;
}
QStringList tokens = modifiers.simplified().split(' ');
int tokenCount = tokens.count();
for (int i = 0; i < tokenCount; ++i) {
m_modifiers.append(tokens[i].toDouble());
}
}
void EnhancedPathShape::addCommand(const QString &command)
{
addCommand(command, true);
}
void EnhancedPathShape::addCommand(const QString &command, bool triggerUpdate)
{
QString commandStr = command.simplified();
if (commandStr.isEmpty()) {
return;
}
// the first character is the command
EnhancedPathCommand *cmd = new EnhancedPathCommand(commandStr[0], this);
// strip command char
commandStr = commandStr.mid(1).simplified();
// now parse the command parameters
if (!commandStr.isEmpty()) {
QStringList tokens = commandStr.split(' ');
for (int i = 0; i < tokens.count(); ++i) {
cmd->addParameter(parameter(tokens[i]));
}
}
m_commands.append(cmd);
if (triggerUpdate) {
updatePath(size());
}
}
bool EnhancedPathShape::useStretchPoints(const QSizeF &size, qreal &scale)
{
bool retval = false;
if (m_pathStretchPointX != -1 && m_pathStretchPointY != -1) {
qreal scaleX = size.width();
qreal scaleY = size.height();
if (qreal(m_viewBox.width()) / m_viewBox.height() < qreal(scaleX) / scaleY) {
qreal deltaX = (scaleX * m_viewBox.height()) / scaleY - m_viewBox.width();
foreach (KoSubpath *subpath, subpaths()) {
foreach (KoPathPoint *currPoint, *subpath) {
if (currPoint->point().x() >= m_pathStretchPointX &&
currPoint->controlPoint1().x() >= m_pathStretchPointX &&
currPoint->controlPoint2().x() >= m_pathStretchPointX) {
currPoint->setPoint(QPointF(currPoint->point().x() + deltaX, currPoint->point().y()));
currPoint->setControlPoint1(QPointF(currPoint->controlPoint1().x() + deltaX,
currPoint->controlPoint1().y()));
currPoint->setControlPoint2(QPointF(currPoint->controlPoint2().x() + deltaX,
currPoint->controlPoint2().y()));
retval = true;
}
}
}
scale = scaleY / m_viewBox.height();
} else if (qreal(m_viewBox.width()) / m_viewBox.height() > qreal(scaleX) / scaleY) {
qreal deltaY = (m_viewBox.width() * scaleY) / scaleX - m_viewBox.height();
foreach (KoSubpath *subpath, subpaths()) {
foreach (KoPathPoint *currPoint, *subpath) {
if (currPoint->point().y() >= m_pathStretchPointY &&
currPoint->controlPoint1().y() >= m_pathStretchPointY &&
currPoint->controlPoint2().y() >= m_pathStretchPointY) {
currPoint->setPoint(QPointF(currPoint->point().x(), currPoint->point().y() + deltaY));
currPoint->setControlPoint1(QPointF(currPoint->controlPoint1().x(),
currPoint->controlPoint1().y() + deltaY));
currPoint->setControlPoint2(QPointF(currPoint->controlPoint2().x(),
currPoint->controlPoint2().y() + deltaY));
retval = true;
}
}
}
scale = scaleX / m_viewBox.width();
}
notifyPointsChanged();
}
return retval;
}
-void EnhancedPathShape::saveOdf(KoShapeSavingContext &context) const
-{
- if (isParametricShape()) {
- context.xmlWriter().startElement("draw:custom-shape");
-
- const QSizeF currentSize = outline().boundingRect().size();
-
- // save the right position so that when loading we fit the viewbox
- // to the right position without getting any wrong scaling
- // -> calculate the right position from the current 0 position / viewbound ratio
- // this is e.g. the case when there is a callout that goes into negative viewbound coordinates
- QPointF topLeft = m_viewBound.topLeft();
- QPointF diff;
- if (qAbs(topLeft.x()) > 1E-5) {
- diff.setX(topLeft.x()*currentSize.width() / m_viewBound.width());
- }
- if (qAbs(topLeft.y()) > 1E-5) {
- diff.setY(topLeft.y()*currentSize.height() / m_viewBound.height());
- }
-
- if (diff.isNull()) {
- saveOdfAttributes(context, OdfAllAttributes & ~OdfSize);
- } else {
- //FIXME: this needs to be fixed for shapes that are transformed by rotation or skewing
- QTransform offset(context.shapeOffset(this));
- QTransform newOffset(offset);
- newOffset.translate(-diff.x(), -diff.y());
- context.addShapeOffset(this, newOffset);
- saveOdfAttributes(context, OdfAllAttributes & ~OdfSize);
- if (offset.isIdentity()) {
- context.removeShapeOffset(this);
- } else {
- context.addShapeOffset(this, offset);
- }
- }
-
- // save the right size so that when loading we fit the viewbox
- // to the right size without getting any wrong scaling
- // -> calculate the right size from the current size/viewbound ratio
- context.xmlWriter().addAttribute("svg:width", currentSize.width() == 0 ? 0 : m_viewBox.width()*currentSize.width() / m_viewBound.width());
- context.xmlWriter().addAttribute("svg:height", currentSize.height() == 0 ? 0 : m_viewBox.height()*currentSize.height() / m_viewBound.height());
-
- saveText(context);
-
- context.xmlWriter().startElement("draw:enhanced-geometry");
- context.xmlWriter().addAttribute("svg:viewBox", QString("%1 %2 %3 %4").arg(m_viewBox.x()).arg(m_viewBox.y()).arg(m_viewBox.width()).arg(m_viewBox.height()));
-
- if (m_pathStretchPointX != -1) {
- context.xmlWriter().addAttribute("draw:path-stretchpoint-x", m_pathStretchPointX);
- }
- if (m_pathStretchPointY != -1) {
- context.xmlWriter().addAttribute("draw:path-stretchpoint-y", m_pathStretchPointY);
- }
-
- if (m_mirrorHorizontally) {
- context.xmlWriter().addAttribute("draw:mirror-horizontal", "true");
- }
- if (m_mirrorVertically) {
- context.xmlWriter().addAttribute("draw:mirror-vertical", "true");
- }
-
- QString modifiers;
- foreach (qreal modifier, m_modifiers) {
- modifiers += QString::number(modifier) + ' ';
- }
- context.xmlWriter().addAttribute("draw:modifiers", modifiers.trimmed());
-
- if (m_textArea.size() >= 4) {
- context.xmlWriter().addAttribute("draw:text-areas", m_textArea.join(" "));
- }
-
- QString path;
- foreach (EnhancedPathCommand *c, m_commands) {
- path += c->toString() + ' ';
- }
- context.xmlWriter().addAttribute("draw:enhanced-path", path.trimmed());
-
- FormulaStore::const_iterator i = m_formulae.constBegin();
- for (; i != m_formulae.constEnd(); ++i) {
- context.xmlWriter().startElement("draw:equation");
- context.xmlWriter().addAttribute("draw:name", i.key());
- context.xmlWriter().addAttribute("draw:formula", i.value()->toString());
- context.xmlWriter().endElement(); // draw:equation
- }
-
- foreach (EnhancedPathHandle *handle, m_enhancedHandles) {
- handle->saveOdf(context);
- }
-
- context.xmlWriter().endElement(); // draw:enhanced-geometry
- saveOdfCommonChildElements(context);
- context.xmlWriter().endElement(); // draw:custom-shape
-
- } else {
- KoPathShape::saveOdf(context);
- }
-}
-
-bool EnhancedPathShape::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- reset();
-
- const KoXmlElement enhancedGeometry(KoXml::namedItemNS(element, KoXmlNS::draw, "enhanced-geometry"));
- if (!enhancedGeometry.isNull()) {
-
- setPathStretchPointX(enhancedGeometry.attributeNS(KoXmlNS::draw, "path-stretchpoint-x", "-1").toDouble());
- setPathStretchPointY(enhancedGeometry.attributeNS(KoXmlNS::draw, "path-stretchpoint-y", "-1").toDouble());
-
- // load the modifiers
- QString modifiers = enhancedGeometry.attributeNS(KoXmlNS::draw, "modifiers", "");
- if (!modifiers.isEmpty()) {
- addModifiers(modifiers);
- }
-
- m_textArea = enhancedGeometry.attributeNS(KoXmlNS::draw, "text-areas", "").split(' ');
- if (m_textArea.size() >= 4) {
- setResizeBehavior(TextFollowsPreferredTextRect);
- }
-
- KoXmlElement grandChild;
- forEachElement(grandChild, enhancedGeometry) {
- if (grandChild.namespaceURI() != KoXmlNS::draw) {
- continue;
- }
- if (grandChild.localName() == "equation") {
- QString name = grandChild.attributeNS(KoXmlNS::draw, "name");
- QString formula = grandChild.attributeNS(KoXmlNS::draw, "formula");
- addFormula(name, formula);
- } else if (grandChild.localName() == "handle") {
- EnhancedPathHandle *handle = new EnhancedPathHandle(this);
- if (handle->loadOdf(grandChild, context)) {
- m_enhancedHandles.append(handle);
- evaluateHandles();
- } else {
- delete handle;
- }
- }
-
- }
-
- setMirrorHorizontally(enhancedGeometry.attributeNS(KoXmlNS::draw, "mirror-horizontal") == "true");
- setMirrorVertically(enhancedGeometry.attributeNS(KoXmlNS::draw, "mirror-vertical") == "true");
-
- // load the enhanced path data
- QString path = enhancedGeometry.attributeNS(KoXmlNS::draw, "enhanced-path", "");
-#ifndef NWORKAROUND_ODF_BUGS
- KoOdfWorkaround::fixEnhancedPath(path, enhancedGeometry, context);
-#endif
- // load the viewbox
- m_viewBox = loadOdfViewbox(enhancedGeometry);
-
- if (!path.isEmpty()) {
- parsePathData(path);
- }
-
- if (m_viewBox.isEmpty()) {
- // if there is no view box defined make it is big as the path.
- m_viewBox = m_viewBound.toAlignedRect();
- }
-
- }
-
- QSizeF size;
- size.setWidth(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "width", QString())));
- size.setHeight(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "height", QString())));
- // the viewbox is to be fitted into the size of the shape, so before setting
- // the size we just loaded // we set the viewbox to be the basis to calculate
- // the viewbox matrix from
- m_viewBound = m_viewBox;
- setSize(size);
-
- QPointF pos;
- pos.setX(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "x", QString())));
- pos.setY(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "y", QString())));
- setPosition(pos - m_viewMatrix.map(QPointF(0, 0)) - m_viewBoxOffset);
-
- loadOdfAttributes(element, context, OdfMandatories | OdfTransformation | OdfAdditionalAttributes | OdfCommonChildElements);
-
- loadText(element, context);
-
- return true;
-}
-
void EnhancedPathShape::parsePathData(const QString &data)
{
if (data.isEmpty()) {
return;
}
int start = -1;
bool separator = true;
for (int i = 0; i < data.length(); ++i) {
QChar ch = data.at(i);
ushort uni_ch = ch.unicode();
if (separator && (uni_ch == 'M' || uni_ch == 'L'
|| uni_ch == 'C' || uni_ch == 'Z'
|| uni_ch == 'N' || uni_ch == 'F'
|| uni_ch == 'S' || uni_ch == 'T'
|| uni_ch == 'U' || uni_ch == 'A'
|| uni_ch == 'B' || uni_ch == 'W'
|| uni_ch == 'V' || uni_ch == 'X'
|| uni_ch == 'Y' || uni_ch == 'Q')) {
if (start != -1) { // process last chars
addCommand(data.mid(start, i - start), false);
}
start = i;
}
separator = ch.isSpace();
}
if (start < data.length()) {
addCommand(data.mid(start));
}
if (start != -1) {
updatePath(size());
}
}
void EnhancedPathShape::setMirrorHorizontally(bool mirrorHorizontally)
{
if (m_mirrorHorizontally != mirrorHorizontally) {
m_mirrorHorizontally = mirrorHorizontally;
updatePath(size());
}
}
void EnhancedPathShape::setMirrorVertically(bool mirrorVertically)
{
if (m_mirrorVertically != mirrorVertically) {
m_mirrorVertically = mirrorVertically;
updatePath(size());
}
}
void EnhancedPathShape::shapeChanged(ChangeType type, KoShape *shape)
{
KoParameterShape::shapeChanged(type, shape);
if (!shape || shape == this) {
if (type == ParentChanged || type == ParameterChanged) {
updateTextArea();
}
}
}
void EnhancedPathShape::updateTextArea()
{
if (m_textArea.size() >= 4) {
QRectF r = m_viewBox;
r.setLeft(evaluateConstantOrReference(m_textArea[0]));
r.setTop(evaluateConstantOrReference(m_textArea[1]));
r.setRight(evaluateConstantOrReference(m_textArea[2]));
r.setBottom(evaluateConstantOrReference(m_textArea[3]));
r = m_viewMatrix.mapRect(r).translated(m_viewBoxOffset);
setPreferredTextRect(r);
}
}
void EnhancedPathShape::enableResultCache(bool enable)
{
m_resultCache.clear();
m_cacheResults = enable;
}
void EnhancedPathShape::setPathStretchPointX(qreal pathStretchPointX)
{
if (m_pathStretchPointX != pathStretchPointX) {
m_pathStretchPointX = pathStretchPointX;
}
}
void EnhancedPathShape::setPathStretchPointY(qreal pathStretchPointY)
{
if (m_pathStretchPointY != pathStretchPointY) {
m_pathStretchPointY = pathStretchPointY;
}
}
diff --git a/plugins/flake/pathshapes/enhancedpath/EnhancedPathShape.h b/plugins/flake/pathshapes/enhancedpath/EnhancedPathShape.h
index 46d74f9b8e..2ee916238d 100644
--- a/plugins/flake/pathshapes/enhancedpath/EnhancedPathShape.h
+++ b/plugins/flake/pathshapes/enhancedpath/EnhancedPathShape.h
@@ -1,185 +1,181 @@
/* This file is part of the KDE project
* Copyright (C) 2007,2010,2011 Jan Hambrecht <jaham@gmx.net>
* Copyright (C) 2010 Carlos Licea <carlos@kdab.com>
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
* Contact: Suresh Chande suresh.chande@nokia.com
*
* 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 KOENHANCEDPATHSHAPE_H
#define KOENHANCEDPATHSHAPE_H
#include <KoParameterShape.h>
#include <QList>
#include <QMap>
#include <QRectF>
#include <QStringList>
#define EnhancedPathShapeId "EnhancedPathShape"
class EnhancedPathCommand;
class EnhancedPathHandle;
class EnhancedPathFormula;
class EnhancedPathParameter;
class KoShapeSavingContext;
class KoShapeLoadingContext;
/**
* An enhanced shape is a custom shape which can be defined
* by enhanced geometry data.
* The data consists of a list of commands like moveto,
* lineto, curveto, etc. which are used to create the outline
* of the shape. The coordinates or parameters of the commands
* can be constant values, named variables (identifiers),
* modifiers, functions or formulae.
*/
class EnhancedPathShape : public KoParameterShape
{
public:
EnhancedPathShape(const QRect &viewBox);
~EnhancedPathShape() override;
KoShape* cloneShape() const override;
/**
* Evaluates the given reference to a identifier, modifier or formula.
* @param reference the reference to evaluate
* @return the result of the evaluation
*/
qreal evaluateReference(const QString &reference);
/**
* Evaluates the given constant or reference to a identifier, modifier
* or formula.
* @param val the value to evaluate
* @return the result of the evaluation
*/
qreal evaluateConstantOrReference(const QString &val);
/**
* Attempts to modify a given reference.
*
* Only modifiers can me modified, others silently ignore the attempt.
*
* @param reference the reference to modify
* @param value the new value
*/
void modifyReference(const QString &reference, qreal value);
// from KoShape
void setSize(const QSizeF &newSize) override;
// from KoParameterShape
QPointF normalize() override;
/// Add formula with given name and textual representation
void addFormula(const QString &name, const QString &formula);
/// Add a single handle with format: x y minX maxX minY maxY
void addHandle(const QMap<QString, QVariant> &handle);
/// Add modifiers with format: modifier0 modifier1 modifier2 ...
void addModifiers(const QString &modifiers);
/// Add command for instance "M 0 0"
void addCommand(const QString &command);
/// Returns the viewbox of the enhanced path shape
QRect viewBox() const;
/// Converts from shape coordinates to viewbox coordinates
QPointF shapeToViewbox(const QPointF &point) const;
/// Sets if the shape is to be mirrored horizontally before applying any other transformations
//NOTE: in the standard nothing is mentioned about the priorities of the transformations"
//it's assumed like this because of the behavior shwon in OOo
void setMirrorHorizontally(bool mirrorHorizontally);
/// Sets if the shape is to be mirrored vertically before applying any other transformations
//NOTE: in the standard nothing is mentioned about the priorities of the transformations"
//it's assumed like this because of the behavior shown in OOo
void setMirrorVertically(bool mirrorVertically);
// Sets member variable representing draw:path-stretchpoint-x attribute
void setPathStretchPointX(qreal pathStretchPointX);
// Sets member variable representing draw:path-stretchpoint-y attribute
void setPathStretchPointY(qreal pathStretchPointY);
/// Returns parameter from given textual representation
EnhancedPathParameter *parameter(const QString &text);
protected:
- // from KoShape
- void saveOdf(KoShapeSavingContext &context) const override;
- // from KoShape
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
//from KoShape
void shapeChanged(ChangeType type, KoShape *shape = 0) override;
// from KoParameterShape
void moveHandleAction(int handleId, const QPointF &point, Qt::KeyboardModifiers modifiers = Qt::NoModifier) override;
// from KoParameterShape
void updatePath(const QSizeF &size) override;
private:
EnhancedPathShape(const EnhancedPathShape &rhs);
void evaluateHandles();
void reset();
/// parses the enhanced path data
void parsePathData(const QString &data);
/// Adds a new command
void addCommand(const QString &command, bool triggerUpdate);
/// Updates the size and position of an optionally existing text-on-shape text area
void updateTextArea();
/// Enables caching results
void enableResultCache(bool enable);
// This function checks if draw:path-stretchpoint-x or draw:path-stretchpoint-y attributes are set.
// If the attributes are set the path shape coordinates (m_subpaths) are changed so that the form
// of the shape is preserved after stretching. It is needed for example in round-rectangles, to
// have the corners round after stretching. Without it the corners would be elliptical.
// Returns true if any points were actually changed, otherwise false.
bool useStretchPoints(const QSizeF &size, qreal &scale);
typedef QMap<QString, EnhancedPathFormula *> FormulaStore;
typedef QList<qreal> ModifierStore;
typedef QMap<QString, EnhancedPathParameter *> ParameterStore;
QRect m_viewBox; ///< the viewbox rectangle
QRectF m_viewBound; ///< the bounding box of the path in viewbox coordinates
QTransform m_viewMatrix; ///< matrix to convert from viewbox coordinates to shape coordinates
QTransform m_mirrorMatrix; ///< matrix to used for mirroring
QPointF m_viewBoxOffset;
QStringList m_textArea;
QList<EnhancedPathCommand *> m_commands; ///< the commands creating the outline
QList<EnhancedPathHandle *> m_enhancedHandles; ///< the handles for modifying the shape
FormulaStore m_formulae; ///< the formulae
ModifierStore m_modifiers; ///< the modifier values
ParameterStore m_parameters; ///< the shared parameters
bool m_mirrorVertically; ///<whether or not the shape is to be mirrored vertically before transforming it
bool m_mirrorHorizontally; ///<whether or not the shape is to be mirrored horizontally before transforming it
qreal m_pathStretchPointX; ///< draw:path-stretchpoint-x attribute
qreal m_pathStretchPointY; ///< draw:path-stretchpoint-y attribute
QHash<QString, qreal> m_resultCache; ///< cache for intermediate results used when evaluating path
bool m_cacheResults; ///< indicates if result cache is enabled
};
#endif // KOENHANCEDPATHSHAPE_H
diff --git a/plugins/flake/pathshapes/rectangle/RectangleShape.cpp b/plugins/flake/pathshapes/rectangle/RectangleShape.cpp
index bd21d994ea..010e5d0d41 100644
--- a/plugins/flake/pathshapes/rectangle/RectangleShape.cpp
+++ b/plugins/flake/pathshapes/rectangle/RectangleShape.cpp
@@ -1,384 +1,340 @@
/* This file is part of the KDE project
Copyright (C) 2006-2008 Thorsten Zachmann <zachmann@kde.org>
Copyright (C) 2006-2008 Jan Hambrecht <jaham@gmx.net>
Copyright (C) 2009 Thomas Zander <zander@kde.org>
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 "RectangleShape.h"
#include <KoParameterShape_p.h>
#include <KoPathPoint.h>
#include <KoShapeSavingContext.h>
#include <KoXmlReader.h>
#include <KoXmlWriter.h>
#include <KoXmlNS.h>
#include <KoUnit.h>
#include <SvgSavingContext.h>
#include <SvgLoadingContext.h>
#include <SvgUtil.h>
#include <SvgStyleWriter.h>
RectangleShape::RectangleShape()
: KoParameterShape()
, m_cornerRadiusX(0)
, m_cornerRadiusY(0)
{
QList<QPointF> handles;
handles.push_back(QPointF(100, 0));
handles.push_back(QPointF(100, 0));
setHandles(handles);
QSizeF size(100, 100);
updatePath(size);
}
RectangleShape::RectangleShape(const RectangleShape &rhs)
: KoParameterShape(rhs),
m_cornerRadiusX(rhs.m_cornerRadiusX),
m_cornerRadiusY(rhs.m_cornerRadiusY)
{
}
RectangleShape::~RectangleShape()
{
}
KoShape *RectangleShape::cloneShape() const
{
return new RectangleShape(*this);
}
-bool RectangleShape::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- loadOdfAttributes(element, context, OdfMandatories | OdfGeometry | OdfAdditionalAttributes | OdfCommonChildElements);
-
- if (element.hasAttributeNS(KoXmlNS::svg, "rx") && element.hasAttributeNS(KoXmlNS::svg, "ry")) {
- qreal rx = KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "rx", "0"));
- qreal ry = KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "ry", "0"));
- m_cornerRadiusX = rx / (0.5 * size().width()) * 100;
- m_cornerRadiusY = ry / (0.5 * size().height()) * 100;
- } else {
- QString cornerRadius = element.attributeNS(KoXmlNS::draw, "corner-radius", "");
- if (!cornerRadius.isEmpty()) {
- qreal radius = KoUnit::parseValue(cornerRadius);
- m_cornerRadiusX = qMin<qreal>(radius / (0.5 * size().width()) * 100, qreal(100));
- m_cornerRadiusY = qMin<qreal>(radius / (0.5 * size().height()) * 100, qreal(100));
- }
- }
-
- updatePath(size());
- updateHandles();
-
- loadOdfAttributes(element, context, OdfTransformation);
- loadText(element, context);
-
- return true;
-}
-
-void RectangleShape::saveOdf(KoShapeSavingContext &context) const
-{
- if (isParametricShape()) {
- context.xmlWriter().startElement("draw:rect");
- saveOdfAttributes(context, OdfAllAttributes);
- if (m_cornerRadiusX > 0 && m_cornerRadiusY > 0) {
- context.xmlWriter().addAttribute("svg:rx", m_cornerRadiusX * (0.5 * size().width()) / 100.0);
- context.xmlWriter().addAttribute("svg:ry", m_cornerRadiusY * (0.5 * size().height()) / 100.0);
- }
- saveOdfCommonChildElements(context);
- saveText(context);
- context.xmlWriter().endElement();
- } else {
- KoPathShape::saveOdf(context);
- }
-}
-
void RectangleShape::moveHandleAction(int handleId, const QPointF &point, Qt::KeyboardModifiers modifiers)
{
Q_UNUSED(modifiers);
QPointF p(point);
qreal width2 = size().width() / 2.0;
qreal height2 = size().height() / 2.0;
switch (handleId) {
case 0:
if (p.x() < width2) {
p.setX(width2);
} else if (p.x() > size().width()) {
p.setX(size().width());
}
p.setY(0);
m_cornerRadiusX = (size().width() - p.x()) / width2 * 100.0;
if (!(modifiers & Qt::ControlModifier)) {
m_cornerRadiusY = (size().width() - p.x()) / height2 * 100.0;
}
break;
case 1:
if (p.y() < 0) {
p.setY(0);
} else if (p.y() > height2) {
p.setY(height2);
}
p.setX(size().width());
m_cornerRadiusY = p.y() / height2 * 100.0;
if (!(modifiers & Qt::ControlModifier)) {
m_cornerRadiusX = p.y() / width2 * 100.0;
}
break;
}
// this is needed otherwise undo/redo might not end in the same result
if (100 - m_cornerRadiusX < 1e-10) {
m_cornerRadiusX = 100;
}
if (100 - m_cornerRadiusY < 1e-10) {
m_cornerRadiusY = 100;
}
updateHandles();
}
void RectangleShape::updateHandles()
{
QList<QPointF> handles;
handles.append(QPointF(size().width() - m_cornerRadiusX / 100.0 * 0.5 * size().width(), 0.0));
handles.append(QPointF(size().width(), m_cornerRadiusY / 100.0 * 0.5 * size().height()));
setHandles(handles);
}
void RectangleShape::updatePath(const QSizeF &size)
{
qreal rx = 0;
qreal ry = 0;
if (m_cornerRadiusX > 0 && m_cornerRadiusY > 0) {
rx = size.width() / 200.0 * m_cornerRadiusX;
ry = size.height() / 200.0 * m_cornerRadiusY;
}
qreal x2 = size.width() - rx;
qreal y2 = size.height() - ry;
QPointF curvePoints[12];
int requiredCurvePointCount = 4;
if (rx && m_cornerRadiusX < 100) {
requiredCurvePointCount += 2;
}
if (ry && m_cornerRadiusY < 100) {
requiredCurvePointCount += 2;
}
createPoints(requiredCurvePointCount);
KoSubpath &points = *subpaths()[0];
int cp = 0;
// first path starts and closes path
points[cp]->setProperty(KoPathPoint::StartSubpath);
points[cp]->setProperty(KoPathPoint::CloseSubpath);
points[cp]->setPoint(QPointF(rx, 0));
points[cp]->removeControlPoint1();
points[cp]->removeControlPoint2();
if (m_cornerRadiusX < 100 || m_cornerRadiusY == 0) {
// end point of the top edge
points[++cp]->setPoint(QPointF(x2, 0));
points[cp]->removeControlPoint1();
points[cp]->removeControlPoint2();
}
if (rx) {
// the top right radius
arcToCurve(rx, ry, 90, -90, points[cp]->point(), curvePoints);
points[cp]->setControlPoint2(curvePoints[0]);
points[++cp]->setControlPoint1(curvePoints[1]);
points[cp]->setPoint(curvePoints[2]);
points[cp]->removeControlPoint2();
}
if (m_cornerRadiusY < 100 || m_cornerRadiusX == 0) {
// the right edge
points[++cp]->setPoint(QPointF(size.width(), y2));
points[cp]->removeControlPoint1();
points[cp]->removeControlPoint2();
}
if (rx) {
// the bottom right radius
arcToCurve(rx, ry, 0, -90, points[cp]->point(), curvePoints);
points[cp]->setControlPoint2(curvePoints[0]);
points[++cp]->setControlPoint1(curvePoints[1]);
points[cp]->setPoint(curvePoints[2]);
points[cp]->removeControlPoint2();
}
if (m_cornerRadiusX < 100 || m_cornerRadiusY == 0) {
// the bottom edge
points[++cp]->setPoint(QPointF(rx, size.height()));
points[cp]->removeControlPoint1();
points[cp]->removeControlPoint2();
}
if (rx) {
// the bottom left radius
arcToCurve(rx, ry, 270, -90, points[cp]->point(), curvePoints);
points[cp]->setControlPoint2(curvePoints[0]);
points[++cp]->setControlPoint1(curvePoints[1]);
points[cp]->setPoint(curvePoints[2]);
points[cp]->removeControlPoint2();
}
if ((m_cornerRadiusY < 100 || m_cornerRadiusX == 0) && ry) {
// the right edge
points[++cp]->setPoint(QPointF(0, ry));
points[cp]->removeControlPoint1();
points[cp]->removeControlPoint2();
}
if (rx) {
// the top left radius
arcToCurve(rx, ry, 180, -90, points[cp]->point(), curvePoints);
points[cp]->setControlPoint2(curvePoints[0]);
points[0]->setControlPoint1(curvePoints[1]);
points[0]->setPoint(curvePoints[2]);
}
// unset all stop/close path properties
for (int i = 1; i < cp; ++i) {
points[i]->unsetProperty(KoPathPoint::StopSubpath);
points[i]->unsetProperty(KoPathPoint::CloseSubpath);
}
// last point stops and closes path
points.last()->setProperty(KoPathPoint::StopSubpath);
points.last()->setProperty(KoPathPoint::CloseSubpath);
notifyPointsChanged();
}
void RectangleShape::createPoints(int requiredPointCount)
{
if (subpaths().count() != 1) {
clear();
subpaths().append(new KoSubpath());
}
int currentPointCount = subpaths()[0]->count();
if (currentPointCount > requiredPointCount) {
for (int i = 0; i < currentPointCount - requiredPointCount; ++i) {
delete subpaths()[0]->front();
subpaths()[0]->pop_front();
}
} else if (requiredPointCount > currentPointCount) {
for (int i = 0; i < requiredPointCount - currentPointCount; ++i) {
subpaths()[0]->append(new KoPathPoint(this, QPointF()));
}
}
notifyPointsChanged();
}
qreal RectangleShape::cornerRadiusX() const
{
return m_cornerRadiusX;
}
void RectangleShape::setCornerRadiusX(qreal radius)
{
radius = qBound(0.0, radius, 100.0);
m_cornerRadiusX = radius;
updatePath(size());
updateHandles();
}
qreal RectangleShape::cornerRadiusY() const
{
return m_cornerRadiusY;
}
void RectangleShape::setCornerRadiusY(qreal radius)
{
radius = qBound(0.0, radius, 100.0);
m_cornerRadiusY = radius;
updatePath(size());
updateHandles();
}
QString RectangleShape::pathShapeId() const
{
return RectangleShapeId;
}
bool RectangleShape::saveSvg(SvgSavingContext &context)
{
// let basic path saiving code handle our saving
if (!isParametricShape()) return false;
context.shapeWriter().startElement("rect");
context.shapeWriter().addAttribute("id", context.getID(this));
SvgUtil::writeTransformAttributeLazy("transform", transformation(), context.shapeWriter());
SvgStyleWriter::saveSvgStyle(this, context);
const QSizeF size = this->size();
context.shapeWriter().addAttribute("width", size.width());
context.shapeWriter().addAttribute("height", size.height());
double rx = cornerRadiusX();
if (rx > 0.0) {
context.shapeWriter().addAttribute("rx", 0.01 * rx * 0.5 * size.width());
}
double ry = cornerRadiusY();
if (ry > 0.0) {
context.shapeWriter().addAttribute("ry", 0.01 * ry * 0.5 * size.height());
}
context.shapeWriter().endElement();
return true;
}
bool RectangleShape::loadSvg(const KoXmlElement &element, SvgLoadingContext &context)
{
const qreal x = SvgUtil::parseUnitX(context.currentGC(), element.attribute("x"));
const qreal y = SvgUtil::parseUnitY(context.currentGC(), element.attribute("y"));
const qreal w = SvgUtil::parseUnitX(context.currentGC(), element.attribute("width"));
const qreal h = SvgUtil::parseUnitY(context.currentGC(), element.attribute("height"));
const QString rxStr = element.attribute("rx");
const QString ryStr = element.attribute("ry");
qreal rx = rxStr.isEmpty() ? 0.0 : SvgUtil::parseUnitX(context.currentGC(), rxStr);
qreal ry = ryStr.isEmpty() ? 0.0 : SvgUtil::parseUnitY(context.currentGC(), ryStr);
// if one radius is given but not the other, use the same value for both
if (!rxStr.isEmpty() && ryStr.isEmpty()) {
ry = rx;
}
if (rxStr.isEmpty() && !ryStr.isEmpty()) {
rx = ry;
}
setSize(QSizeF(w, h));
setPosition(QPointF(x, y));
if (rx >= 0.0) {
setCornerRadiusX(qMin(qreal(100.0), qreal(rx / (0.5 * w) * 100.0)));
}
if (ry >= 0.0) {
setCornerRadiusY(qMin(qreal(100.0), qreal(ry / (0.5 * h) * 100.0)));
}
if (w == 0.0 || h == 0.0) {
setVisible(false);
}
return true;
}
diff --git a/plugins/flake/pathshapes/rectangle/RectangleShape.h b/plugins/flake/pathshapes/rectangle/RectangleShape.h
index 08c828c2b2..0264b8a9bc 100644
--- a/plugins/flake/pathshapes/rectangle/RectangleShape.h
+++ b/plugins/flake/pathshapes/rectangle/RectangleShape.h
@@ -1,97 +1,90 @@
/* This file is part of the KDE project
Copyright (C) 2006-2007 Thorsten Zachmann <zachmann@kde.org>
Copyright (C) 2006-2007 Jan Hambrecht <jaham@gmx.net>
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 KORECTANGLESHAPE_H
#define KORECTANGLESHAPE_H
#include "KoParameterShape.h"
#include <SvgShape.h>
#define RectangleShapeId "RectangleShape"
/**
* The RectangleShape is a shape that represents a rectangle.
* The rectangle can have rounded corners, with different corner
* radii in x- and y-direction.
*/
class RectangleShape : public KoParameterShape, public SvgShape
{
public:
RectangleShape();
~RectangleShape() override;
KoShape* cloneShape() const override;
/// Returns the corner radius in x-direction
qreal cornerRadiusX() const;
/**
* Sets the corner radius in x-direction.
*
* The corner x-radius is a percent value (a number between 0 and 100)
* of the half size of the rectangles width.
*
* @param radius the new corner radius in x-direction
*/
void setCornerRadiusX(qreal radius);
/// Returns the corner radius in y-direction
qreal cornerRadiusY() const;
/**
* Sets the corner radius in y-direction.
*
* The corner y-radius is a percent value (a number between 0 and 100)
* of the half size of the rectangles height.
*
* @param radius the new corner radius in y-direction
*/
void setCornerRadiusY(qreal radius);
-
- /// reimplemented
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
-
- /// reimplemented
- void saveOdf(KoShapeSavingContext &context) const override;
-
/// reimplemented
QString pathShapeId() const override;
/// reimplemented from SvgShape
bool saveSvg(SvgSavingContext &context) override;
/// reimplemented from SvgShape
bool loadSvg(const KoXmlElement &element, SvgLoadingContext &context) override;
protected:
RectangleShape(const RectangleShape &rhs);
void moveHandleAction(int handleId, const QPointF &point, Qt::KeyboardModifiers modifiers = Qt::NoModifier) override;
void updatePath(const QSizeF &size) override;
void createPoints(int requiredPointCount);
void updateHandles();
private:
qreal m_cornerRadiusX; ///< in percent of half of the rectangle width (a number between 0 and 100)
qreal m_cornerRadiusY; ///< in percent of half of the rectangle height (a number between 0 and 100)
};
#endif /* KORECTANGLESHAPE_H */
diff --git a/plugins/flake/pathshapes/spiral/SpiralShape.cpp b/plugins/flake/pathshapes/spiral/SpiralShape.cpp
index a6b11ba06b..5232e0ec90 100644
--- a/plugins/flake/pathshapes/spiral/SpiralShape.cpp
+++ b/plugins/flake/pathshapes/spiral/SpiralShape.cpp
@@ -1,317 +1,303 @@
/* This file is part of the KDE project
Copyright (C) 2007 Rob Buis <buis@kde.org>
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 "SpiralShape.h"
#include <KoParameterShape_p.h>
#include <KoPathPoint.h>
#include <KoShapeSavingContext.h>
#include <KoXmlReader.h>
#include <KoXmlWriter.h>
#include <KoXmlNS.h>
#include <math.h>
#include "kis_assert.h"
SpiralShape::SpiralShape()
: m_fade(.9)
, m_kindAngle(M_PI)
, m_radii(100.0, 100.0)
, m_type(Curve)
, m_clockwise(true)
{
//m_handles.push_back(QPointF(50, 0));
//m_handles.push_back(QPointF(50, 50));
//m_handles.push_back(QPointF(0, 50));
createPath(QSizeF(m_radii.x(), m_radii.y()));
}
SpiralShape::SpiralShape(const SpiralShape &rhs)
: KoParameterShape(rhs),
m_fade(rhs.m_fade),
m_kindAngle(rhs.m_kindAngle),
m_center(rhs.m_center),
m_radii(rhs.m_radii),
m_type(rhs.m_type),
m_clockwise(rhs.m_clockwise)
{
Q_FOREACH(KoPathPoint *point, rhs.m_points) {
KIS_ASSERT_RECOVER(point) { continue; }
m_points << new KoPathPoint(*point, this);
}
}
SpiralShape::~SpiralShape()
{
}
KoShape *SpiralShape::cloneShape() const
{
return new SpiralShape(*this);
}
-void SpiralShape::saveOdf(KoShapeSavingContext &context) const
-{
- // TODO?
- KoPathShape::saveOdf(context);
-}
-
-bool SpiralShape::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &/*context*/)
-{
- Q_UNUSED(element);
-
- // TODO?
- return true;
-}
-
void SpiralShape::setSize(const QSizeF &newSize)
{
QTransform matrix(resizeMatrix(newSize));
m_center = matrix.map(m_center);
m_radii = matrix.map(m_radii);
KoParameterShape::setSize(newSize);
}
QPointF SpiralShape::normalize()
{
QPointF offset(KoParameterShape::normalize());
QTransform matrix;
matrix.translate(-offset.x(), -offset.y());
m_center = matrix.map(m_center);
return offset;
}
void SpiralShape::moveHandleAction(int handleId, const QPointF &point, Qt::KeyboardModifiers modifiers)
{
Q_UNUSED(handleId);
Q_UNUSED(point);
Q_UNUSED(modifiers);
#if 0
QPointF p(point);
QPointF diff(m_center - point);
diff.setX(-diff.x());
qreal angle = 0;
if (diff.x() == 0) {
angle = (diff.y() < 0 ? 270 : 90) * M_PI / 180.0;
} else {
diff.setY(diff.y() * m_radii.x() / m_radii.y());
angle = atan(diff.y() / diff.x());
if (angle < 0) {
angle = M_PI + angle;
}
if (diff.y() < 0) {
angle += M_PI;
}
}
switch (handleId) {
case 0:
p = QPointF(m_center + QPointF(cos(angle) * m_radii.x(), -sin(angle) * m_radii.y()));
m_handles[handleId] = p;
updateKindHandle();
break;
case 1:
p = QPointF(m_center + QPointF(cos(angle) * m_radii.x(), -sin(angle) * m_radii.y()));
m_handles[handleId] = p;
updateKindHandle();
break;
case 2: {
QList<QPointF> kindHandlePositions;
kindHandlePositions.push_back(QPointF(m_center + QPointF(cos(m_kindAngle) * m_radii.x(), -sin(m_kindAngle) * m_radii.y())));
kindHandlePositions.push_back(m_center);
kindHandlePositions.push_back((m_handles[0] + m_handles[1]) / 2.0);
QPointF diff = m_center * 2.0;
int handlePos = 0;
for (int i = 0; i < kindHandlePositions.size(); ++i) {
QPointF pointDiff(p - kindHandlePositions[i]);
if (i == 0 || qAbs(pointDiff.x()) + qAbs(pointDiff.y()) < qAbs(diff.x()) + qAbs(diff.y())) {
diff = pointDiff;
handlePos = i;
}
}
m_handles[handleId] = kindHandlePositions[handlePos];
m_type = SpiralType(handlePos);
} break;
}
#endif
}
void SpiralShape::updatePath(const QSizeF &size)
{
createPath(size);
normalize();
#if 0
Q_UNUSED(size);
QPointF startpoint(m_handles[0]);
QPointF curvePoints[12];
int pointCnt = arcToCurve(m_radii.x(), m_radii.y(), m_startAngle, sweepAngle(), startpoint, curvePoints);
int cp = 0;
m_points[cp]->setPoint(startpoint);
m_points[cp]->unsetProperty(KoPathPoint::HasControlPoint1);
for (int i = 0; i < pointCnt; i += 3) {
m_points[cp]->setControlPoint2(curvePoints[i]);
m_points[++cp]->setControlPoint1(curvePoints[i + 1]);
m_points[cp]->setPoint(curvePoints[i + 2]);
m_points[cp]->unsetProperty(KoPathPoint::HasControlPoint2);
}
if (m_type == Curve) {
m_points[++cp]->setPoint(m_center);
m_points[cp]->unsetProperty(KoPathPoint::HasControlPoint1);
m_points[cp]->unsetProperty(KoPathPoint::HasControlPoint2);
} else if (m_type == Line && m_startAngle == m_endAngle) {
m_points[0]->setControlPoint1(m_points[cp]->controlPoint1());
m_points[0]->setPoint(m_points[cp]->point());
--cp;
}
d->m_subpaths[0]->clear();
for (int i = 0; i <= cp; ++i) {
if (i < cp || (m_type == Line && m_startAngle != m_endAngle)) {
m_points[i]->unsetProperty(KoPathPoint::CloseSubpath);
} else {
m_points[i]->setProperty(KoPathPoint::CloseSubpath);
}
d->m_subpaths[0]->push_back(m_points[i]);
}
#endif
}
void SpiralShape::createPath(const QSizeF &size)
{
Q_UNUSED(size);
clear();
QPointF center = QPointF(m_radii.x() / 2.0, m_radii.y() / 2.0);
//moveTo(QPointF(size.width(), m_radii.y()));
qreal adv_ang = (m_clockwise ? -1.0 : 1.0) * M_PI_2;
// radius of first segment is non-faded radius:
qreal m_radius = m_radii.x() / 2.0;
qreal r = m_radius;
QPointF oldP(center.x(), (m_clockwise ? -1.0 : 1.0) * m_radius + center.y());
QPointF newP;
QPointF newCenter(center);
moveTo(oldP);
uint m_segments = 10;
//m_handles[0] = oldP;
for (uint i = 0; i < m_segments; ++i) {
newP.setX(r * cos(adv_ang * (i + 2)) + newCenter.x());
newP.setY(r * sin(adv_ang * (i + 2)) + newCenter.y());
if (m_type == Curve) {
qreal rx = qAbs(oldP.x() - newP.x());
qreal ry = qAbs(oldP.y() - newP.y());
if (m_clockwise) {
arcTo(rx, ry, ((i + 1) % 4) * 90, 90);
} else {
arcTo(rx, ry, 360 - ((i + 1) % 4) * 90, -90);
}
} else {
lineTo(newP);
}
newCenter += (newP - newCenter) * (1.0 - m_fade);
oldP = newP;
r *= m_fade;
}
//m_handles[1] = QPointF(center.x(), (m_clockwise ? -1.0 : 1.0) * m_radius + center.y());
m_points = *subpaths()[0];
notifyPointsChanged();
}
void SpiralShape::updateKindHandle()
{
/*
m_kindAngle = (m_startAngle + m_endAngle) * M_PI / 360.0;
if (m_startAngle > m_endAngle)
{
m_kindAngle += M_PI;
}
switch (m_type)
{
case Curve:
m_handles[2] = m_center + QPointF(cos(m_kindAngle) * m_radii.x(), -sin(m_kindAngle) * m_radii.y());
break;
case Line:
m_handles[2] = m_center;
break;
}
*/
}
void SpiralShape::updateAngleHandles()
{
// qreal startRadian = m_startAngle * M_PI / 180.0;
// qreal endRadian = m_endAngle * M_PI / 180.0;
// m_handles[0] = m_center + QPointF(cos(startRadian) * m_radii.x(), -sin(startRadian) * m_radii.y());
// m_handles[1] = m_center + QPointF(cos(endRadian) * m_radii.x(), -sin(endRadian) * m_radii.y());
}
void SpiralShape::setType(SpiralType type)
{
m_type = type;
updateKindHandle();
updatePath(size());
}
SpiralShape::SpiralType SpiralShape::type() const
{
return m_type;
}
void SpiralShape::setFade(qreal fade)
{
m_fade = fade;
updateKindHandle();
//updateAngleHandles();
updatePath(size());
}
qreal SpiralShape::fade() const
{
return m_fade;
}
bool SpiralShape::clockWise() const
{
return m_clockwise;
}
void SpiralShape::setClockWise(bool clockWise)
{
m_clockwise = clockWise;
updateKindHandle();
//updateAngleHandles();
updatePath(size());
}
QString SpiralShape::pathShapeId() const
{
return SpiralShapeId;
}
diff --git a/plugins/flake/pathshapes/spiral/SpiralShape.h b/plugins/flake/pathshapes/spiral/SpiralShape.h
index d58d6c6245..b6d30a7705 100644
--- a/plugins/flake/pathshapes/spiral/SpiralShape.h
+++ b/plugins/flake/pathshapes/spiral/SpiralShape.h
@@ -1,105 +1,100 @@
/* This file is part of the KDE project
Copyright (C) 2007 Rob Buis <buis@kde.org>
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 KOSPIRALSHAPE_H
#define KOSPIRALSHAPE_H
#include "KoParameterShape.h"
#define SpiralShapeId "SpiralShape"
/**
* This class adds support for the spiral
* shape.
*/
class SpiralShape : public KoParameterShape
{
public:
/// the possible spiral types
enum SpiralType {
Curve = 0, ///< spiral uses curves
Line = 1 ///< spiral uses lines
};
SpiralShape();
~SpiralShape() override;
KoShape* cloneShape() const override;
void setSize(const QSizeF &newSize) override;
QPointF normalize() override;
/**
* Sets the type of the spiral.
* @param type the new spiral type
*/
void setType(SpiralType type);
/// Returns the actual spiral type
SpiralType type() const;
/**
* Sets the fade parameter of the spiral.
* @param angle the new start angle in degree
*/
void setFade(qreal fade);
/// Returns the actual fade parameter
qreal fade() const;
bool clockWise() const;
void setClockWise(bool clockwise);
/// reimplemented
QString pathShapeId() const override;
protected:
SpiralShape(const SpiralShape &rhs);
- // reimplemented
- void saveOdf(KoShapeSavingContext &context) const override;
- // reimplemented
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
-
void moveHandleAction(int handleId, const QPointF &point, Qt::KeyboardModifiers modifiers = Qt::NoModifier) override;
void updatePath(const QSizeF &size) override;
void createPath(const QSizeF &size);
private:
void updateKindHandle();
void updateAngleHandles();
// fade parameter
qreal m_fade;
// angle for modifying the kind in radiant
qreal m_kindAngle;
// the center of the spiral
QPointF m_center;
// the radii of the spiral
QPointF m_radii;
// the actual spiral type
SpiralType m_type;
//
bool m_clockwise;
KoSubpath m_points;
};
#endif /* KOSPIRALSHAPE_H */
diff --git a/plugins/flake/pathshapes/star/StarShape.cpp b/plugins/flake/pathshapes/star/StarShape.cpp
index 4d43f0b80f..5a44043d46 100644
--- a/plugins/flake/pathshapes/star/StarShape.cpp
+++ b/plugins/flake/pathshapes/star/StarShape.cpp
@@ -1,457 +1,303 @@
/* This file is part of the KDE project
Copyright (C) 2006-2009 Jan Hambrecht <jaham@gmx.net>
Copyright (C) 2009 Thomas Zander <zander@kde.org>
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 "StarShape.h"
#include <KoParameterShape_p.h>
#include <KoPathPoint.h>
#include <KoShapeLoadingContext.h>
#include <KoShapeSavingContext.h>
#include <KoXmlReader.h>
#include <KoXmlNS.h>
#include <KoXmlWriter.h>
#include <QStringList>
#include <math.h>
StarShape::StarShape()
: m_cornerCount(5)
, m_zoomX(1.0)
, m_zoomY(1.0)
, m_convex(false)
{
m_radius[base] = 25.0;
m_radius[tip] = 50.0;
m_angles[base] = m_angles[tip] = defaultAngleRadian();
m_roundness[base] = m_roundness[tip] = 0.0f;
m_center = QPointF(50, 50);
updatePath(QSize(100, 100));
}
StarShape::StarShape(const StarShape &rhs)
: KoParameterShape(rhs),
m_cornerCount(rhs.m_cornerCount),
m_radius(rhs.m_radius),
m_angles(rhs.m_angles),
m_zoomX(rhs.m_zoomX),
m_zoomY(rhs.m_zoomY),
m_roundness(rhs.m_roundness),
m_center(rhs.m_center),
m_convex(rhs.m_convex)
{
}
StarShape::~StarShape()
{
}
KoShape *StarShape::cloneShape() const
{
return new StarShape(*this);
}
void StarShape::setCornerCount(uint cornerCount)
{
if (cornerCount >= 3) {
double oldDefaultAngle = defaultAngleRadian();
m_cornerCount = cornerCount;
double newDefaultAngle = defaultAngleRadian();
m_angles[base] += newDefaultAngle - oldDefaultAngle;
m_angles[tip] += newDefaultAngle - oldDefaultAngle;
updatePath(QSize());
}
}
uint StarShape::cornerCount() const
{
return m_cornerCount;
}
void StarShape::setBaseRadius(qreal baseRadius)
{
m_radius[base] = fabs(baseRadius);
updatePath(QSize());
}
qreal StarShape::baseRadius() const
{
return m_radius[base];
}
void StarShape::setTipRadius(qreal tipRadius)
{
m_radius[tip] = fabs(tipRadius);
updatePath(QSize());
}
qreal StarShape::tipRadius() const
{
return m_radius[tip];
}
void StarShape::setBaseRoundness(qreal baseRoundness)
{
m_roundness[base] = baseRoundness;
updatePath(QSize());
}
void StarShape::setTipRoundness(qreal tipRoundness)
{
m_roundness[tip] = tipRoundness;
updatePath(QSize());
}
void StarShape::setConvex(bool convex)
{
m_convex = convex;
updatePath(QSize());
}
bool StarShape::convex() const
{
return m_convex;
}
QPointF StarShape::starCenter() const
{
return m_center;
}
void StarShape::moveHandleAction(int handleId, const QPointF &point, Qt::KeyboardModifiers modifiers)
{
if (modifiers & Qt::ShiftModifier) {
QPointF handle = handles()[handleId];
QPointF tangentVector = point - handle;
qreal distance = sqrt(tangentVector.x() * tangentVector.x() + tangentVector.y() * tangentVector.y());
QPointF radialVector = handle - m_center;
// cross product to determine in which direction the user is dragging
qreal moveDirection = radialVector.x() * tangentVector.y() - radialVector.y() * tangentVector.x();
// make the roundness stick to zero if distance is under a certain value
float snapDistance = 3.0;
if (distance >= 0.0) {
distance = distance < snapDistance ? 0.0 : distance - snapDistance;
} else {
distance = distance > -snapDistance ? 0.0 : distance + snapDistance;
}
// control changes roundness on both handles, else only the actual handle roundness is changed
if (modifiers & Qt::ControlModifier) {
m_roundness[handleId] = moveDirection < 0.0f ? distance : -distance;
} else {
m_roundness[base] = m_roundness[tip] = moveDirection < 0.0f ? distance : -distance;
}
} else {
QPointF distVector = point - m_center;
// unapply scaling
distVector.rx() /= m_zoomX;
distVector.ry() /= m_zoomY;
m_radius[handleId] = sqrt(distVector.x() * distVector.x() + distVector.y() * distVector.y());
qreal angle = atan2(distVector.y(), distVector.x());
if (angle < 0.0) {
angle += 2.0 * M_PI;
}
qreal diffAngle = angle - m_angles[handleId];
qreal radianStep = M_PI / static_cast<qreal>(m_cornerCount);
if (handleId == tip) {
m_angles[tip] += diffAngle - radianStep;
m_angles[base] += diffAngle - radianStep;
} else {
// control make the base point move freely
if (modifiers & Qt::ControlModifier) {
m_angles[base] += diffAngle - 2 * radianStep;
} else {
m_angles[base] = m_angles[tip];
}
}
}
}
void StarShape::updatePath(const QSizeF &size)
{
Q_UNUSED(size);
qreal radianStep = M_PI / static_cast<qreal>(m_cornerCount);
createPoints(m_convex ? m_cornerCount : 2 * m_cornerCount);
KoSubpath &points = *subpaths()[0];
uint index = 0;
for (uint i = 0; i < 2 * m_cornerCount; ++i) {
uint cornerType = i % 2;
if (cornerType == base && m_convex) {
continue;
}
qreal radian = static_cast<qreal>((i + 1) * radianStep) + m_angles[cornerType];
QPointF cornerPoint = QPointF(m_zoomX * m_radius[cornerType] * cos(radian), m_zoomY * m_radius[cornerType] * sin(radian));
points[index]->setPoint(m_center + cornerPoint);
points[index]->unsetProperty(KoPathPoint::StopSubpath);
points[index]->unsetProperty(KoPathPoint::CloseSubpath);
if (m_roundness[cornerType] > 1e-10 || m_roundness[cornerType] < -1e-10) {
// normalized cross product to compute tangential vector for handle point
QPointF tangentVector(cornerPoint.y() / m_radius[cornerType], -cornerPoint.x() / m_radius[cornerType]);
points[index]->setControlPoint2(points[index]->point() - m_roundness[cornerType] * tangentVector);
points[index]->setControlPoint1(points[index]->point() + m_roundness[cornerType] * tangentVector);
} else {
points[index]->removeControlPoint1();
points[index]->removeControlPoint2();
}
index++;
}
// first path starts and closes path
points[0]->setProperty(KoPathPoint::StartSubpath);
points[0]->setProperty(KoPathPoint::CloseSubpath);
// last point stops and closes path
points.last()->setProperty(KoPathPoint::StopSubpath);
points.last()->setProperty(KoPathPoint::CloseSubpath);
normalize();
QList<QPointF> handles;
handles.push_back(points.at(tip)->point());
if (!m_convex) {
handles.push_back(points.at(base)->point());
}
setHandles(handles);
m_center = computeCenter();
}
void StarShape::createPoints(int requiredPointCount)
{
if (subpaths().count() != 1) {
clear();
subpaths().append(new KoSubpath());
}
int currentPointCount = subpaths()[0]->count();
if (currentPointCount > requiredPointCount) {
for (int i = 0; i < currentPointCount - requiredPointCount; ++i) {
delete subpaths()[0]->front();
subpaths()[0]->pop_front();
}
} else if (requiredPointCount > currentPointCount) {
for (int i = 0; i < requiredPointCount - currentPointCount; ++i) {
subpaths()[0]->append(new KoPathPoint(this, QPointF()));
}
}
notifyPointsChanged();
}
void StarShape::setSize(const QSizeF &newSize)
{
QTransform matrix(resizeMatrix(newSize));
m_zoomX *= matrix.m11();
m_zoomY *= matrix.m22();
// this transforms the handles
KoParameterShape::setSize(newSize);
m_center = computeCenter();
}
QPointF StarShape::computeCenter() const
{
KoSubpath &points = *subpaths()[0];
QPointF center(0, 0);
for (uint i = 0; i < m_cornerCount; ++i) {
if (m_convex) {
center += points[i]->point();
} else {
center += points[2 * i]->point();
}
}
if (m_cornerCount > 0) {
return center / static_cast<qreal>(m_cornerCount);
}
return center;
}
-bool StarShape::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- bool loadAsCustomShape = false;
-
- if (element.localName() == "custom-shape") {
- QString drawEngine = element.attributeNS(KoXmlNS::draw, "engine", "");
- if (drawEngine != "calligra:star") {
- return false;
- }
- loadAsCustomShape = true;
- } else if (element.localName() != "regular-polygon") {
- return false;
- }
-
- m_radius[tip] = 50;
- m_center = QPointF(50, 50);
-
- if (!loadAsCustomShape) {
- QString corners = element.attributeNS(KoXmlNS::draw, "corners", "");
- if (!corners.isEmpty()) {
- m_cornerCount = corners.toUInt();
- // initialize default angles of tip and base
- m_angles[base] = m_angles[tip] = defaultAngleRadian();
- }
-
- m_convex = (element.attributeNS(KoXmlNS::draw, "concave", "false") == "false");
-
- if (m_convex) {
- m_radius[base] = m_radius[tip];
- } else {
- // sharpness is radius of ellipse on which inner polygon points are located
- // 0% means all polygon points are on a single ellipse
- // 100% means inner points are located at polygon center point
- QString sharpness = element.attributeNS(KoXmlNS::draw, "sharpness", "");
- if (!sharpness.isEmpty() && sharpness.right(1) == "%") {
- float percent = sharpness.left(sharpness.length() - 1).toFloat();
- m_radius[base] = m_radius[tip] * (100 - percent) / 100;
- }
- }
- } else {
- QString drawData = element.attributeNS(KoXmlNS::draw, "data");
- if (drawData.isEmpty()) {
- return false;
- }
-
- QStringList properties = drawData.split(';');
- if (properties.count() == 0) {
- return false;
- }
-
- foreach (const QString &property, properties) {
- QStringList pair = property.split(':');
- if (pair.count() != 2) {
- continue;
- }
- if (pair[0] == "corners") {
- m_cornerCount = pair[1].toInt();
- } else if (pair[0] == "concave") {
- m_convex = (pair[1] == "false");
- } else if (pair[0] == "baseRoundness") {
- m_roundness[base] = pair[1].toDouble();
- } else if (pair[0] == "tipRoundness") {
- m_roundness[tip] = pair[1].toDouble();
- } else if (pair[0] == "baseAngle") {
- m_angles[base] = pair[1].toDouble();
- } else if (pair[0] == "tipAngle") {
- m_angles[tip] = pair[1].toDouble();
- } else if (pair[0] == "sharpness") {
- float percent = pair[1].left(pair[1].length() - 1).toFloat();
- m_radius[base] = m_radius[tip] * (100 - percent) / 100;
- }
- }
-
- if (m_convex) {
- m_radius[base] = m_radius[tip];
- }
- }
-
- updatePath(QSizeF());
-
- // reset transformation
- setTransformation(QTransform());
-
- loadOdfAttributes(element, context, OdfAllAttributes);
- loadText(element, context);
-
- return true;
-}
-
-void StarShape::saveOdf(KoShapeSavingContext &context) const
-{
- if (isParametricShape()) {
- double defaultAngle = defaultAngleRadian();
- bool hasRoundness = m_roundness[tip] != 0.0f || m_roundness[base] != 0.0f;
- bool hasAngleOffset = m_angles[base] != defaultAngle || m_angles[tip] != defaultAngle;
- if (hasRoundness || hasAngleOffset) {
- // draw:regular-polygon has no means of saving roundness
- // so we save as a custom shape with a specific draw:engine
- context.xmlWriter().startElement("draw:custom-shape");
- saveOdfAttributes(context, OdfAllAttributes);
-
- // now write the special shape data
- context.xmlWriter().addAttribute("draw:engine", "calligra:star");
- // create the data attribute
- QString drawData = QString("corners:%1;").arg(m_cornerCount);
- drawData += m_convex ? "concave:false;" : "concave:true;";
- if (!m_convex) {
- // sharpness is radius of ellipse on which inner polygon points are located
- // 0% means all polygon points are on a single ellipse
- // 100% means inner points are located at polygon center point
- qreal percent = (m_radius[tip] - m_radius[base]) / m_radius[tip] * 100.0;
- drawData += QString("sharpness:%1%;").arg(percent);
- }
- if (m_roundness[base] != 0.0f) {
- drawData += QString("baseRoundness:%1;").arg(m_roundness[base]);
- }
- if (m_roundness[tip] != 0.0f) {
- drawData += QString("tipRoundness:%1;").arg(m_roundness[tip]);
- }
- drawData += QString("baseAngle:%1;").arg(m_angles[base]);
- drawData += QString("tipAngle:%1;").arg(m_angles[tip]);
-
- context.xmlWriter().addAttribute("draw:data", drawData);
-
- saveOdfCommonChildElements(context);
- saveText(context);
-
- // write a enhanced geometry element for compatibility with other applications
- context.xmlWriter().startElement("draw:enhanced-geometry");
- context.xmlWriter().addAttribute("draw:enhanced-path", toString(transformation()));
- context.xmlWriter().endElement(); // draw:enhanced-geometry
-
- context.xmlWriter().endElement(); // draw:custom-shape
- } else {
- context.xmlWriter().startElement("draw:regular-polygon");
- saveOdfAttributes(context, OdfAllAttributes);
- context.xmlWriter().addAttribute("draw:corners", m_cornerCount);
- context.xmlWriter().addAttribute("draw:concave", m_convex ? "false" : "true");
- if (!m_convex) {
- // sharpness is radius of ellipse on which inner polygon points are located
- // 0% means all polygon points are on a single ellipse
- // 100% means inner points are located at polygon center point
- qreal percent = (m_radius[tip] - m_radius[base]) / m_radius[tip] * 100.0;
- context.xmlWriter().addAttribute("draw:sharpness", QString("%1%").arg(percent));
- }
- saveOdfCommonChildElements(context);
- saveText(context);
- context.xmlWriter().endElement();
- }
- } else {
- KoPathShape::saveOdf(context);
- }
-}
-
QString StarShape::pathShapeId() const
{
return StarShapeId;
}
double StarShape::defaultAngleRadian() const
{
qreal radianStep = M_PI / static_cast<qreal>(m_cornerCount);
return M_PI_2 - 2 * radianStep;
}
diff --git a/plugins/flake/pathshapes/star/StarShape.h b/plugins/flake/pathshapes/star/StarShape.h
index a6740aca9d..eccacb617d 100644
--- a/plugins/flake/pathshapes/star/StarShape.h
+++ b/plugins/flake/pathshapes/star/StarShape.h
@@ -1,150 +1,146 @@
/* This file is part of the KDE project
Copyright (C) 2006-2008 Jan Hambrecht <jaham@gmx.net>
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 KOSTARSHAPE_H
#define KOSTARSHAPE_H
#include <array>
#include <KoParameterShape.h>
#define StarShapeId "StarShape"
/**
* The star shape is a shape that can represent a star or
* a regular polygon. There a some properties which can
* be changed to control the appearance of the shape
* like the number of corners, the inner/outer radius
* and the corner roundness.
*/
class StarShape : public KoParameterShape
{
public:
StarShape();
~StarShape() override;
KoShape* cloneShape() const override;
/**
* Sets the number of corners.
*
* The minimum accepted number of corners is 3.
* If the star is set to be convex (like a regular polygon),
* the corner count equals the number of polygon points.
* For a real star it represents the number of legs the star has.
*
* @param cornerCount the new number of corners
*/
void setCornerCount(uint cornerCount);
/// Returns the number of corners
uint cornerCount() const;
/**
* Sets the radius of the base points.
* The base radius has no meaning if the star is set convex.
* @param baseRadius the new base radius
*/
void setBaseRadius(qreal baseRadius);
/// Returns the base radius
qreal baseRadius() const;
/**
* Sets the radius of the tip points.
* @param tipRadius the new tip radius
*/
void setTipRadius(qreal tipRadius);
/// Returns the tip radius
qreal tipRadius() const;
/**
* Sets the roundness at the base points.
*
* A roundness value of zero disables the roundness.
*
* @param baseRoundness the new base roundness
*/
void setBaseRoundness(qreal baseRoundness);
/**
* Sets the roundness at the tip points.
*
* A roundness value of zero disables the roundness.
*
* @param tipRoundness the new base roundness
*/
void setTipRoundness(qreal tipRoundness);
/**
* Sets the star to be convex, looking like a polygon.
* @param convex if true makes shape behave like regular polygon
*/
void setConvex(bool convex);
/// Returns if the star represents a regular polygon.
bool convex() const;
/**
* Returns the star center point in shape coordinates.
*
* The star center is the weight center of the star and not necessarily
* coincident with the shape center point.
*/
QPointF starCenter() const;
/// reimplemented
void setSize(const QSizeF &newSize) override;
/// reimplemented
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
- /// reimplemented
- void saveOdf(KoShapeSavingContext &context) const override;
- /// reimplemented
QString pathShapeId() const override;
protected:
StarShape(const StarShape &rhs);
void moveHandleAction(int handleId, const QPointF &point, Qt::KeyboardModifiers modifiers = Qt::NoModifier) override;
void updatePath(const QSizeF &size) override;
/// recreates the path points when the corner count or convexity changes
void createPoints(int requiredPointCount);
private:
/// Computes the star center point from the inner points
QPointF computeCenter() const;
/// Returns the default offset angle in radian
double defaultAngleRadian() const;
/// the handle types
enum Handles { tip = 0, base = 1 };
uint m_cornerCount; ///< number of corners
std::array<qreal, 2> m_radius; ///< the different radii
std::array<qreal, 2> m_angles; ///< the offset angles
qreal m_zoomX; ///< scaling in x
qreal m_zoomY; ///< scaling in y
std::array<qreal, 2> m_roundness; ///< the roundness at the handles
QPointF m_center; ///< the star center point
bool m_convex; ///< controls if the star is convex
};
#endif /* KOSTARSHAPE_H */
diff --git a/plugins/flake/textshape/CMakeLists.txt b/plugins/flake/textshape/CMakeLists.txt
deleted file mode 100644
index 0f37e71d71..0000000000
--- a/plugins/flake/textshape/CMakeLists.txt
+++ /dev/null
@@ -1,140 +0,0 @@
-project( textPlugin)
-
-
-if (${Qt5_VERSION} VERSION_GREATER "5.8.0" )
- remove_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50900)
-elseif(${Qt5_VERSION} VERSION_GREATER "5.7.0" )
- remove_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50800)
-elseif(${Qt5_VERSION} VERSION_GREATER "5.6.0" )
- remove_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50700)
-else()
- remove_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50600)
-endif()
-
-add_definitions(
- -DQT_DISABLE_DEPRECATED_BEFORE=0
-)
-
-add_subdirectory( textlayout )
-add_subdirectory( kotext )
-
-
-
-set ( textshape_SRCS
- TextPlugin.cpp
- TextShape.cpp
- TextShapeFactory.cpp
- TextTool.cpp
- TextEditingPluginContainer.cpp
- TextToolFactory.cpp
- ShrinkToFitShapeContainer.cpp
- SimpleRootAreaProvider.cpp
-
- FontSizeAction.cpp
- FontFamilyAction.cpp
-
- dialogs/StylesCombo.cpp
- dialogs/StylesComboPreview.cpp
- dialogs/DockerStylesComboModel.cpp
- dialogs/SimpleCharacterWidget.cpp
- dialogs/SimpleParagraphWidget.cpp
- dialogs/SimpleTableWidget.cpp
- dialogs/SimpleInsertWidget.cpp
- dialogs/ParagraphLayout.cpp
- dialogs/ParagraphIndentSpacing.cpp
- dialogs/ParagraphDecorations.cpp
- dialogs/ParagraphBulletsNumbers.cpp
- dialogs/ParagraphSettingsDialog.cpp
- dialogs/ParagraphDropCaps.cpp
- dialogs/ListsSpinBox.cpp
- dialogs/StylesModel.cpp
- dialogs/StylesManagerModel.cpp
- dialogs/StylesSortFilterProxyModel.cpp
- dialogs/AbstractStylesModel.cpp
- dialogs/StylesFilteredModelBase.cpp
- dialogs/ValidParentStylesProxyModel.cpp
- dialogs/StylesDelegate.cpp
- dialogs/StyleManager.cpp
- dialogs/StyleManagerDialog.cpp
- dialogs/ParagraphGeneral.cpp
- dialogs/CharacterGeneral.cpp
- dialogs/CharacterHighlighting.cpp
- dialogs/InsertCharacter.cpp
- dialogs/FontDia.cpp
- dialogs/FontDecorations.cpp
- dialogs/LanguageTab.cpp
- dialogs/FormattingPreview.cpp
- dialogs/StyleManagerWelcome.cpp
- dialogs/TableDialog.cpp
- dialogs/QuickTableButton.cpp
- dialogs/FormattingButton.cpp
- dialogs/ChangeConfigureDialog.cpp
- dialogs/AcceptRejectChangeDialog.cpp
- dialogs/TrackedChangeModel.cpp
- dialogs/TrackedChangeManager.cpp
- dialogs/BibliographyConfigureDialog.cpp
- dialogs/TableOfContentsConfigure.cpp
- dialogs/TableOfContentsStyleConfigure.cpp
- dialogs/TableOfContentsStyleModel.cpp
- dialogs/TableOfContentsStyleDelegate.cpp
- dialogs/TableOfContentsPreview.cpp
- dialogs/TableOfContentsEntryDelegate.cpp
- dialogs/TableOfContentsEntryModel.cpp
- dialogs/TableOfContentsTemplate.cpp
- dialogs/BibliographyTemplate.cpp
- dialogs/BibliographyPreview.cpp
- dialogs/ListLevelChooser.cpp
- dialogs/SectionFormatDialog.cpp
- dialogs/SectionsSplitDialog.cpp
-
- commands/ChangeListLevelCommand.cpp
- commands/ShowChangesCommand.cpp
- commands/AcceptChangeCommand.cpp
- commands/RejectChangeCommand.cpp
- commands/AutoResizeCommand.cpp
-)
-
-ki18n_wrap_ui(textshape_SRCS
- dialogs/SimpleCharacterWidget.ui
- dialogs/SimpleParagraphWidget.ui
- dialogs/SimpleTableWidget.ui
- dialogs/SimpleInsertWidget.ui
- dialogs/ParagraphLayout.ui
- dialogs/ParagraphIndentSpacing.ui
- dialogs/ParagraphDecorations.ui
- dialogs/ParagraphBulletsNumbers.ui
- dialogs/ParagraphDropCaps.ui
- dialogs/StyleManager.ui
- dialogs/CharacterGeneral.ui
- dialogs/CharacterHighlighting.ui
- dialogs/StyleManagerWelcome.ui
- dialogs/TableDialog.ui
- dialogs/BibliographyConfigureDialog.ui
- dialogs/TableOfContentsConfigure.ui
- dialogs/TableOfContentsStyleConfigure.ui
-
-
- dialogs/FontDecorations.ui
- dialogs/LanguageTab.ui
- dialogs/ChangeConfigureDialog.ui
- dialogs/AcceptRejectChangeDialog.ui
- dialogs/TrackedChangeManager.ui
- dialogs/SectionFormatDialog.ui
- dialogs/SectionsSplitDialog.ui
-
-)
-
-qt5_add_resources(textshape_SRCS textshape.qrc)
-
-
-add_library(krita_shape_text MODULE ${textshape_SRCS})
-
-target_link_libraries(krita_shape_text kritatext kritatextlayout kritawidgetutils kritawidgets Qt5::Network KF5::Completion KF5::ItemViews KF5::WidgetsAddons
-)
-
-if( SHOULD_BUILD_FEATURE_RDF )
- target_link_libraries(krita_shape_text ${SOPRANO_LIBRARIES})
-endif()
-
-
-install(TARGETS krita_shape_text DESTINATION ${KRITA_PLUGIN_INSTALL_DIR})
diff --git a/plugins/flake/textshape/FontFamilyAction.cpp b/plugins/flake/textshape/FontFamilyAction.cpp
deleted file mode 100644
index 58f267ceba..0000000000
--- a/plugins/flake/textshape/FontFamilyAction.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/* This file is part of the KDE libraries
- Copyright (C) 1999 Reginald Stadlbauer <reggie@kde.org>
- (C) 1999 Simon Hausmann <hausmann@kde.org>
- (C) 2000 Nicolas Hadacek <haadcek@kde.org>
- (C) 2000 Kurt Granroth <granroth@kde.org>
- (C) 2000 Michael Koch <koch@kde.org>
- (C) 2001 Holger Freyther <freyther@kde.org>
- (C) 2002 Ellis Whitehead <ellis@kde.org>
- (C) 2002 Joseph Wenninger <jowenn@kde.org>
- (C) 2003 Andras Mantia <amantia@kde.org>
- (C) 2005-2006 Hamish Rodda <rodda@kde.org>
- (C) 2007 Clarence Dang <dang@kde.org>
- (C) 2014 Dan Leinir Turthra Jensen <admin@leinir.dk>
-
- 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.
-*/
-
-// This is a minorly modified version of the KFontAction class. It exists
-// entirely because there's a hang bug on windows at the moment.
-
-#include "FontFamilyAction.h"
-
-#include <QToolBar>
-
-#include <QDebug>
-#include <QIcon>
-#include <klocalizedstring.h>
-#include <kfontchooser.h>
-#include <QFontComboBox>
-
-class KoFontFamilyAction::KoFontFamilyActionPrivate
-{
-public:
- KoFontFamilyActionPrivate(KoFontFamilyAction *parent)
- : q(parent)
- , settingFont(0)
- {
- }
-
- void _ko_slotFontChanged(const QFont &font)
- {
- qDebug() << "QFontComboBox - slotFontChanged("
- << font.family() << ") settingFont=" << settingFont;
- if (settingFont) {
- return;
- }
-
- q->setFont(font.family());
- q->triggered(font.family());
-
- qDebug() << "\tslotFontChanged done";
- }
-
- KoFontFamilyAction *q;
- int settingFont;
-};
-
-KoFontFamilyAction::KoFontFamilyAction(uint fontListCriteria, QObject *parent)
- : KSelectAction(parent)
- , d(new KoFontFamilyActionPrivate(this))
-{
- QStringList list;
- KFontChooser::getFontList(list, fontListCriteria);
- KSelectAction::setItems(list);
- setEditable(true);
-}
-
-KoFontFamilyAction::KoFontFamilyAction(QObject *parent)
- : KSelectAction(parent)
- , d(new KoFontFamilyActionPrivate(this))
-{
- QStringList list;
- KFontChooser::getFontList(list, 0);
- KSelectAction::setItems(list);
- setEditable(true);
-}
-
-KoFontFamilyAction::KoFontFamilyAction(const QString &text, QObject *parent)
- : KSelectAction(text, parent)
- , d(new KoFontFamilyActionPrivate(this))
-{
- QStringList list;
- KFontChooser::getFontList(list, 0);
- KSelectAction::setItems(list);
- setEditable(true);
-}
-
-KoFontFamilyAction::KoFontFamilyAction(const QIcon &icon, const QString &text, QObject *parent)
- : KSelectAction(icon, text, parent)
- , d(new KoFontFamilyActionPrivate(this))
-{
- QStringList list;
- KFontChooser::getFontList(list, 0);
- KSelectAction::setItems(list);
- setEditable(true);
-}
-
-KoFontFamilyAction::~KoFontFamilyAction()
-{
- delete d;
-}
-
-QString KoFontFamilyAction::font() const
-{
- return currentText();
-}
-
-QWidget *KoFontFamilyAction::createWidget(QWidget *parent)
-{
- qDebug() << "KoFontFamilyAction::createWidget()";
-// silence unclear warning from original kfontaction.acpp
-// #ifdef __GNUC__
-// #warning FIXME: items need to be converted
-// #endif
- // This is the visual element on the screen. This method overrides
- // the KSelectAction one, preventing KSelectAction from creating its
- // regular KComboBox.
- QFontComboBox *cb = new QFontComboBox(parent);
- //cb->setFontList(items());
-
- qDebug() << "\tset=" << font();
- // Do this before connecting the signal so that nothing will fire.
- cb->setCurrentFont(QFont(font().toLower()));
- qDebug() << "\tspit back=" << cb->currentFont().family();
-
- connect(cb, SIGNAL(currentFontChanged(QFont)), SLOT(_ko_slotFontChanged(QFont)));
- cb->setMinimumWidth(cb->sizeHint().width());
- return cb;
-}
-
-/*
- * Maintenance note: Keep in sync with KFontComboBox::setCurrentFont()
- */
-void KoFontFamilyAction::setFont(const QString &family)
-{
- qDebug() << "KoFontFamilyAction::setFont(" << family << ")";
-
- // Suppress triggered(QString) signal and prevent recursive call to ourself.
- d->settingFont++;
-
- Q_FOREACH (QWidget *w, createdWidgets()) {
- QFontComboBox *cb = qobject_cast<QFontComboBox *>(w);
- qDebug() << "\tw=" << w << "cb=" << cb;
-
- if (!cb) {
- continue;
- }
-
- cb->setCurrentFont(QFont(family.toLower()));
- qDebug() << "\t\tw spit back=" << cb->currentFont().family();
- }
-
- d->settingFont--;
-
- qDebug() << "\tcalling setCurrentAction()";
-
- QString lowerName = family.toLower();
- if (setCurrentAction(lowerName, Qt::CaseInsensitive)) {
- return;
- }
-
- int i = lowerName.indexOf(" [");
- if (i > -1) {
- lowerName = lowerName.left(i);
- i = 0;
- if (setCurrentAction(lowerName, Qt::CaseInsensitive)) {
- return;
- }
- }
-
- lowerName += " [";
- if (setCurrentAction(lowerName, Qt::CaseInsensitive)) {
- return;
- }
-
- // TODO: Inconsistent state if KFontComboBox::setCurrentFont() succeeded
- // but setCurrentAction() did not and vice-versa.
- qDebug() << "Font not found " << family.toLower();
-}
-
-// have to include this because of Q_PRIVATE_SLOT
-#include "moc_FontFamilyAction.cpp"
diff --git a/plugins/flake/textshape/FontFamilyAction.h b/plugins/flake/textshape/FontFamilyAction.h
deleted file mode 100644
index b6440611f3..0000000000
--- a/plugins/flake/textshape/FontFamilyAction.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* This file is part of the KDE libraries
- Copyright (C) 1999 Reginald Stadlbauer <reggie@kde.org>
- (C) 1999 Simon Hausmann <hausmann@kde.org>
- (C) 2000 Nicolas Hadacek <haadcek@kde.org>
- (C) 2000 Kurt Granroth <granroth@kde.org>
- (C) 2000 Michael Koch <koch@kde.org>
- (C) 2001 Holger Freyther <freyther@kde.org>
- (C) 2002 Ellis Whitehead <ellis@kde.org>
- (C) 2003 Andras Mantia <amantia@kde.org>
- (C) 2005-2006 Hamish Rodda <rodda@kde.org>
- (C) 2014 Dan Leinir Turthra Jensen
-
- 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.
-*/
-
-// This is a minorly modified version of the KFontAction class. It exists
-// entirely because there's a hang bug on windows at the moment.
-
-#ifndef KOFONTACTION_H
-#define KOFONTACTION_H
-
-#include <kselectaction.h>
-
-class QIcon;
-
-/**
- * An action to select a font family.
- * On a toolbar this will show a combobox with all the fonts on the system.
- */
-class KoFontFamilyAction : public KSelectAction
-{
- Q_OBJECT
- Q_PROPERTY(QString font READ font WRITE setFont)
-
-public:
- KoFontFamilyAction(uint fontListCriteria, QObject *parent);
- explicit KoFontFamilyAction(QObject *parent);
- KoFontFamilyAction(const QString &text, QObject *parent);
- KoFontFamilyAction(const QIcon &icon, const QString &text, QObject *parent);
- ~KoFontFamilyAction() override;
-
- QString font() const;
-
- void setFont(const QString &family);
-
- QWidget *createWidget(QWidget *parent) override;
-
-private:
- class KoFontFamilyActionPrivate;
- KoFontFamilyActionPrivate *const d;
-
- Q_PRIVATE_SLOT(d, void _ko_slotFontChanged(const QFont &))
-};
-
-#endif
diff --git a/plugins/flake/textshape/FontSizeAction.cpp b/plugins/flake/textshape/FontSizeAction.cpp
deleted file mode 100644
index 740f3c616d..0000000000
--- a/plugins/flake/textshape/FontSizeAction.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-/* This file is part of the KDE libraries
- Copyright (C) 1999 Reginald Stadlbauer <reggie@kde.org>
- (C) 1999 Simon Hausmann <hausmann@kde.org>
- (C) 2000 Nicolas Hadacek <haadcek@kde.org>
- (C) 2000 Kurt Granroth <granroth@kde.org>
- (C) 2000 Michael Koch <koch@kde.org>
- (C) 2001 Holger Freyther <freyther@kde.org>
- (C) 2002 Ellis Whitehead <ellis@kde.org>
- (C) 2002 Joseph Wenninger <jowenn@kde.org>
- (C) 2003 Andras Mantia <amantia@kde.org>
- (C) 2005-2006 Hamish Rodda <rodda@kde.org>
-
- 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 <QFontDatabase>
-#include <QToolBar>
-#include <QToolButton>
-
-#include <QDebug>
-#include <klocalizedstring.h>
-#include <QIcon>
-
-#include "FontSizeAction.h"
-
-QString format(qreal v)
-{
- static const QString f("%1");
- static const QString e;
- static const QRegExp r("\\.?0+$");
- return f.arg(v, 0, 'f').replace(r, e);
-}
-
-class FontSizeAction::Private
-{
-public:
- Private(FontSizeAction *parent)
- : q(parent)
- {
- }
-
- void init();
-
- FontSizeAction *q;
-};
-
-// BEGIN FontSizeAction
-FontSizeAction::FontSizeAction(QObject *parent)
- : KSelectAction(parent)
- , d(new Private(this))
-{
- d->init();
-}
-
-FontSizeAction::FontSizeAction(const QString &text, QObject *parent)
- : KSelectAction(text, parent)
- , d(new Private(this))
-{
- d->init();
-}
-
-FontSizeAction::FontSizeAction(const QIcon &icon, const QString &text, QObject *parent)
- : KSelectAction(icon, text, parent)
- , d(new Private(this))
-{
- d->init();
-}
-
-FontSizeAction::~FontSizeAction()
-{
- delete d;
-}
-
-void FontSizeAction::Private::init()
-{
- q->setEditable(true);
- QFontDatabase fontDB;
- const QList<int> sizes = fontDB.standardSizes();
- QStringList lst;
- for (QList<int>::ConstIterator it = sizes.begin(); it != sizes.end(); ++it) {
- lst.append(format(*it));
- }
- q->setItems(lst);
-}
-
-void FontSizeAction::setFontSize(qreal size)
-{
- if (size == fontSize()) {
- const QString test = format(size);
- Q_FOREACH (QAction *action, actions()) {
- if (action->text() == test) {
- setCurrentAction(action);
- return;
- }
- }
- }
-
- if (size < 1) {
- qWarning() << "FontSizeAction: Size " << size << " is out of range";
- return;
- }
-
- QAction *a = action(format(size));
- if (!a) {
- // Insert at the correct position in the list (to keep sorting)
- QList<qreal> lst;
- // Convert to list of qreals
- QStringListIterator itemsIt(items());
- QStringList debug_lst = items();
-
- while (itemsIt.hasNext()) {
- lst.append(itemsIt.next().toDouble());
- }
- //add the new size
- lst.append(size);
-
- //remove actions
- clear();
-
- // Sort the list
- std::sort(lst.begin(), lst.end());
- Q_FOREACH (qreal it, lst) {
- QAction *const action = addAction(format(it));
- if (it == size) {
- setCurrentAction(action);
- }
- }
-
- } else {
- setCurrentAction(a);
- }
-}
-
-qreal FontSizeAction::fontSize() const
-{
- return currentText().toDouble();
-}
-
-void FontSizeAction::actionTriggered(QAction *action)
-{
- emit fontSizeChanged(action->text().toDouble());
- KSelectAction::actionTriggered(action);
-}
diff --git a/plugins/flake/textshape/FontSizeAction.h b/plugins/flake/textshape/FontSizeAction.h
deleted file mode 100644
index 6511e3f294..0000000000
--- a/plugins/flake/textshape/FontSizeAction.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 1999 Reginald Stadlbauer <reggie@kde.org>
- (C) 1999 Simon Hausmann <hausmann@kde.org>
- (C) 2000 Nicolas Hadacek <haadcek@kde.org>
- (C) 2000 Kurt Granroth <granroth@kde.org>
- (C) 2000 Michael Koch <koch@kde.org>
- (C) 2001 Holger Freyther <freyther@kde.org>
- (C) 2002 Ellis Whitehead <ellis@kde.org>
- (C) 2003 Andras Mantia <amantia@kde.org>
- (C) 2005-2006 Hamish Rodda <rodda@kde.org>
- *
- * 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 FONTSIZEACTION_H
-#define FONTSIZEACTION_H
-
-#include <kselectaction.h>
-
-class QIcon;
-
-/**
- * An action to allow changing of the font size.
- * This action will be shown as a combobox on a toolbar with a proper set of font sizes.
- *
- * NOTE: We do not use KFontSizeAction because it does not support font size
- * values of type qreal.
- */
-class FontSizeAction : public KSelectAction
-{
- Q_OBJECT
- Q_PROPERTY(qreal fontSize READ fontSize WRITE setFontSize)
-
-public:
- explicit FontSizeAction(QObject *parent);
- FontSizeAction(const QString &text, QObject *parent);
- FontSizeAction(const QIcon &icon, const QString &text, QObject *parent);
-
- ~FontSizeAction() override;
-
- qreal fontSize() const;
-
- void setFontSize(qreal size);
-
-Q_SIGNALS:
- void fontSizeChanged(qreal);
-
-protected Q_SLOTS:
- /**
- * This function is called whenever an action from the selections is triggered.
- */
- void actionTriggered(QAction *action) override;
-
-private:
- class Private;
- Private *const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/ShrinkToFitShapeContainer.cpp b/plugins/flake/textshape/ShrinkToFitShapeContainer.cpp
deleted file mode 100644
index 3148323b8d..0000000000
--- a/plugins/flake/textshape/ShrinkToFitShapeContainer.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2010 Sebastian Sauer <sebsauer@kdab.com>
- *
- * 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 "ShrinkToFitShapeContainer.h"
-
-#include <KoShapeSavingContext.h>
-#include <KoTextLayoutRootArea.h>
-
-ShrinkToFitShapeContainer::ShrinkToFitShapeContainer(KoShape *childShape, KoDocumentResourceManager *documentResources)
- : KoShapeContainer()
- , d(new Private(childShape))
-{
- Q_UNUSED(documentResources);
-
- setPosition(childShape->position());
- setSize(childShape->size());
- setZIndex(childShape->zIndex());
- setRunThrough(childShape->runThrough());
- rotate(childShape->rotation());
- //setTransformation(childShape->transformation());
-
- if (childShape->parent()) {
- childShape->parent()->addShape(this);
- childShape->setParent(0);
- }
-
- childShape->setPosition(QPointF(0.0, 0.0)); // since its relative to my position, this won't move it
- childShape->setSelectable(false); // our ShrinkToFitShapeContainer will handle that from now on
-
- setModel(new ShrinkToFitShapeContainerModel(this));
- addShape(childShape);
-
- QSet<KoShape *> delegates;
- delegates << childShape;
- setToolDelegates(delegates);
-
- KoTextShapeData *data = dynamic_cast<KoTextShapeData *>(childShape->userData());
- Q_ASSERT(data);
- KoTextDocumentLayout *lay = qobject_cast<KoTextDocumentLayout *>(data->document()->documentLayout());
- Q_ASSERT(lay);
- QObject::connect(lay, SIGNAL(finishedLayout()), static_cast<ShrinkToFitShapeContainerModel *>(model()), SLOT(finishedLayout()));
-}
-
-ShrinkToFitShapeContainer::~ShrinkToFitShapeContainer()
-{
-}
-
-void ShrinkToFitShapeContainer::paintComponent(QPainter &painter, KoShapePaintingContext &) const
-{
- Q_UNUSED(painter);
- //painter.fillRect(converter.documentToView(QRectF(QPointF(0,0),size())), QBrush(QColor("#ffcccc"))); // for testing
-}
-
-bool ShrinkToFitShapeContainer::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- Q_UNUSED(element);
- Q_UNUSED(context);
- return true;
-}
-
-void ShrinkToFitShapeContainer::saveOdf(KoShapeSavingContext &context) const
-{
- d->childShape->saveOdf(context);
-}
-
-ShrinkToFitShapeContainer *ShrinkToFitShapeContainer::wrapShape(KoShape *shape, KoDocumentResourceManager *documentResourceManager)
-{
- Q_ASSERT(dynamic_cast<KoTextShapeData *>(shape->userData()));
- Q_ASSERT(qobject_cast<KoTextDocumentLayout *>(dynamic_cast<KoTextShapeData *>(shape->userData())->document()->documentLayout()));
-
- return new ShrinkToFitShapeContainer(shape, documentResourceManager);
-}
-
-void ShrinkToFitShapeContainer::tryWrapShape(KoShape *shape, const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- KoTextShapeData *data = dynamic_cast<KoTextShapeData *>(shape->userData());
- if (!data || data->resizeMethod() != KoTextShapeData::ShrinkToFitResize) {
- return;
- }
-
- KoShapeContainer *oldParent = shape->parent();
- ShrinkToFitShapeContainer *tos = wrapShape(shape, context.documentResourceManager());
- if (!tos->loadOdf(element, context)) {
- shape->setParent(oldParent);
- delete tos;
- }
-}
-
-void ShrinkToFitShapeContainer::unwrapShape(KoShape *shape)
-{
- Q_ASSERT(shape->parent() == this);
-
- removeShape(shape);
- shape->setParent(parent());
-
- QSet<KoShape *> delegates = toolDelegates();
- delegates.remove(shape);
- setToolDelegates(delegates);
-
- shape->setPosition(position());
- shape->setSize(size());
- shape->rotate(rotation());
- shape->setSelectable(true);
-}
-
-ShrinkToFitShapeContainerModel::ShrinkToFitShapeContainerModel(ShrinkToFitShapeContainer *q)
- : q(q)
- , m_scale(1.0)
- , m_dirty(10)
- , m_maybeUpdate(false)
-{
-}
-
-void ShrinkToFitShapeContainerModel::finishedLayout()
-{
- m_maybeUpdate = true;
- containerChanged(q, KoShape::SizeChanged);
- m_maybeUpdate = false;
-}
-
-void ShrinkToFitShapeContainerModel::containerChanged(KoShapeContainer *container, KoShape::ChangeType type)
-{
- Q_ASSERT(container == q); Q_UNUSED(container);
- if (type == KoShape::SizeChanged) {
- KoTextShapeData *data = dynamic_cast<KoTextShapeData *>(q->d->childShape->userData());
- Q_ASSERT(data);
- KoTextLayoutRootArea *rootArea = data->rootArea();
- Q_ASSERT(rootArea);
-
- QSizeF shapeSize = q->size();
- QSizeF documentSize = rootArea->boundingRect().size();
- if (m_maybeUpdate && shapeSize == m_shapeSize && documentSize == m_documentSize) {
- m_dirty = 0;
- return; // nothing to update
- }
-
- m_shapeSize = shapeSize;
- m_documentSize = documentSize;
-
- if (documentSize.width() > 0.0 && documentSize.height() > 0.0) {
- if (m_dirty || !m_maybeUpdate) {
- qreal scaleX = qMin<qreal>(1.0, shapeSize.width() / documentSize.width());
- qreal scaleY = qMin<qreal>(1.0, shapeSize.height() / documentSize.height());
- m_scale = (scaleX + scaleY) / 2.0 * 0.95;
- if (m_maybeUpdate && m_dirty) {
- --m_dirty;
- }
- }
- } else {
- m_scale = 1.0;
- m_dirty = 1;
- }
-
- QSizeF newSize(shapeSize.width() / m_scale, shapeSize.height() / m_scale);
- q->d->childShape->setSize(newSize);
-
- QTransform m;
- m.scale(m_scale, m_scale);
- q->d->childShape->setTransformation(m);
- }
-}
-
-bool ShrinkToFitShapeContainerModel::inheritsTransform(const KoShape *child) const
-{
- Q_ASSERT(child == q->d->childShape); Q_UNUSED(child);
- return true;
-}
-
-bool ShrinkToFitShapeContainerModel::isClipped(const KoShape *child) const
-{
- Q_ASSERT(child == q->d->childShape); Q_UNUSED(child);
- return false;
-}
diff --git a/plugins/flake/textshape/ShrinkToFitShapeContainer.h b/plugins/flake/textshape/ShrinkToFitShapeContainer.h
deleted file mode 100644
index a3f7771e21..0000000000
--- a/plugins/flake/textshape/ShrinkToFitShapeContainer.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2010 Sebastian Sauer <sebsauer@kdab.com>
- *
- * 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 SHRINKTOFITSHAPECONTAINER_H
-#define SHRINKTOFITSHAPECONTAINER_H
-
-#include <KoShape.h>
-#include <KoShapeContainer.h>
-#include <SimpleShapeContainerModel.h>
-#include <KoXmlNS.h>
-#include <KoXmlReader.h>
-#include <KoOdfLoadingContext.h>
-#include <KoTextShapeData.h>
-#include <QObject>
-#include <QPainter>
-
-#include <KoShapeContainer_p.h>
-#include <KoTextDocumentLayout.h>
-#include <KoShapeLoadingContext.h>
-#include <KoDocumentResourceManager.h>
-
-/**
- * Container that is used to wrap a shape and shrink a text-shape to fit the content.
- */
-class ShrinkToFitShapeContainer : public KoShapeContainer
-{
-public:
- explicit ShrinkToFitShapeContainer(KoShape *childShape, KoDocumentResourceManager *documentResources = 0);
- ~ShrinkToFitShapeContainer() override;
-
- // reimplemented
- void paintComponent(QPainter &painter, KoShapePaintingContext &paintcontext) const override;
- // reimplemented
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
- // reimplemented
- void saveOdf(KoShapeSavingContext &context) const override;
-
- /**
- * Factory function to create and return a ShrinkToFitShapeContainer instance that wraps the \a shape with it.
- */
- static ShrinkToFitShapeContainer *wrapShape(KoShape *shape, KoDocumentResourceManager *documentResourceManager = 0);
-
- /**
- * Try to load text-on-shape from \a element and wrap \a shape with it.
- */
- static void tryWrapShape(KoShape *shape, const KoXmlElement &element, KoShapeLoadingContext &context);
-
- /**
- * Undo the wrapping done in the \a wrapShape method.
- */
- void unwrapShape(KoShape *shape);
-
-private:
- friend class ShrinkToFitShapeContainerModel;
- class Private;
- QSharedDataPointer<Private> d;
-};
-
-/**
- * \internal d-pointer class for the \a ShrinkToFitShapeContainer class.
- */
-class ShrinkToFitShapeContainer::Private : public QSharedData
-{
-public:
- explicit Private(KoShape *childShape) : childShape(childShape) {}
- virtual ~Private() = default;
- KoShape *childShape; // the original shape not owned by us
-};
-
-/**
- * The container-model class implements \a KoShapeContainerModel for the \a ShrinkToFitShapeContainer to
- * to stuff once our container changes.
- */
-class ShrinkToFitShapeContainerModel : public QObject, public SimpleShapeContainerModel
-{
- Q_OBJECT
- friend class ShrinkToFitShapeContainer;
-public:
- ShrinkToFitShapeContainerModel(ShrinkToFitShapeContainer *q);
-
- // reimplemented
- void containerChanged(KoShapeContainer *container, KoShape::ChangeType type) override;
- // reimplemented
- bool inheritsTransform(const KoShape *child) const override;
- // reimplemented
- bool isClipped(const KoShape *child) const override;
-
-private Q_SLOTS:
- void finishedLayout();
-
-private:
- ShrinkToFitShapeContainer *q;
- qreal m_scale;
- QSizeF m_shapeSize, m_documentSize;
- int m_dirty;
- bool m_maybeUpdate;
-};
-
-#endif
diff --git a/plugins/flake/textshape/SimpleRootAreaProvider.cpp b/plugins/flake/textshape/SimpleRootAreaProvider.cpp
deleted file mode 100644
index 51e38f546f..0000000000
--- a/plugins/flake/textshape/SimpleRootAreaProvider.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 C. Boemann <cbo@boemann.dk>
- *
- * 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 "SimpleRootAreaProvider.h"
-
-#include "TextShape.h"
-
-#include <KoBorder.h>
-#include <KoTextLayoutRootArea.h>
-#include <KoTextLayoutObstruction.h>
-
-SimpleRootAreaProvider::SimpleRootAreaProvider(KoTextShapeData *data, TextShape *textshape)
- : m_textShape(textshape)
- , m_area(0)
- , m_textShapeData(data)
- , m_fixAutogrow(false)
-
-{
-}
-
-KoTextLayoutRootArea *SimpleRootAreaProvider::provide(KoTextDocumentLayout *documentLayout, const RootAreaConstraint &, int requestedPosition, bool *isNewRootArea)
-{
- if (m_area == 0) {
- *isNewRootArea = true;
- m_area = new KoTextLayoutRootArea(documentLayout);
- m_area->setAssociatedShape(m_textShape);
- m_textShapeData->setRootArea(m_area);
-
- return m_area;
- }
- if (requestedPosition == 0) {
- *isNewRootArea = false;
- return m_area;
- }
- return 0;
-}
-
-void SimpleRootAreaProvider::releaseAllAfter(KoTextLayoutRootArea *afterThis)
-{
- Q_UNUSED(afterThis);
-}
-
-void SimpleRootAreaProvider::doPostLayout(KoTextLayoutRootArea *rootArea, bool isNewRootArea)
-{
- Q_UNUSED(isNewRootArea);
-
- m_textShape->update();
-
- QSizeF newSize = m_textShape->size()
- - QSizeF(m_textShapeData->leftPadding() + m_textShapeData->rightPadding(),
- m_textShapeData->topPadding() + m_textShapeData->bottomPadding());
-
- KoBorder *border = m_textShape->border();
-
- if (border) {
- newSize -= QSizeF(border->borderWidth(KoBorder::LeftBorder) + border->borderWidth(KoBorder::RightBorder), border->borderWidth(KoBorder::TopBorder) + border->borderWidth(KoBorder::BottomBorder));
- }
-
- if (m_textShapeData->verticalAlignment() & Qt::AlignBottom) {
- // Do nothing
- }
- if (m_textShapeData->verticalAlignment() & Qt::AlignVCenter) {
- // Do nothing
- }
- if (m_textShapeData->resizeMethod() == KoTextShapeData::AutoGrowWidthAndHeight
- || m_textShapeData->resizeMethod() == KoTextShapeData::AutoGrowHeight) {
- qreal height = rootArea->bottom() - rootArea->top();
- if (height > newSize.height()) {
- newSize.setHeight(height);
- }
- if (m_textShape->shapeId() == "AnnotationTextShapeID") {
- if (height < newSize.height()) {
- newSize.setHeight(rootArea->bottom() - rootArea->top());
- }
- }
- }
- if (m_textShapeData->resizeMethod() == KoTextShapeData::AutoGrowWidthAndHeight
- || m_textShapeData->resizeMethod() == KoTextShapeData::AutoGrowWidth) {
- qreal width = rootArea->right() - rootArea->left();
- if (width > newSize.width()) {
- newSize.setWidth(rootArea->right() - rootArea->left());
- }
- }
-
- qreal newBottom = rootArea->top() + newSize.height();
- KoFlake::AnchorPosition sizeAnchor = KoFlake::TopLeft;
-
- if (m_textShapeData->verticalAlignment() & Qt::AlignBottom) {
- if (true /*FIXME test no page based shapes interfering*/) {
- rootArea->setVerticalAlignOffset(newBottom - rootArea->bottom());
- sizeAnchor = KoFlake::BottomLeft;
- }
- }
- if (m_textShapeData->verticalAlignment() & Qt::AlignVCenter) {
- if (true /*FIXME test no page based shapes interfering*/) {
- rootArea->setVerticalAlignOffset((newBottom - rootArea->bottom()) / 2);
- sizeAnchor = KoFlake::Center;
- }
- }
- newSize += QSizeF(m_textShapeData->leftPadding() + m_textShapeData->rightPadding(),
- m_textShapeData->topPadding() + m_textShapeData->bottomPadding());
- if (border) {
- newSize += QSizeF(border->borderWidth(KoBorder::LeftBorder) + border->borderWidth(KoBorder::RightBorder), border->borderWidth(KoBorder::TopBorder) + border->borderWidth(KoBorder::BottomBorder));
- }
-
- if (newSize != m_textShape->size()) {
- // OO grows to both sides so when to small the initial layouting needs
- // to keep that into account.
- if (m_fixAutogrow) {
- m_fixAutogrow = false;
- QSizeF tmpSize = m_textShape->size();
- tmpSize.setWidth(newSize.width());
- QPointF centerpos = rootArea->associatedShape()->absolutePosition(KoFlake::Center);
- m_textShape->setSize(tmpSize);
- m_textShape->setAbsolutePosition(centerpos, KoFlake::Center);
- centerpos = rootArea->associatedShape()->absolutePosition(sizeAnchor);
- m_textShape->setSize(newSize);
- m_textShape->setAbsolutePosition(centerpos, sizeAnchor);
- }
- m_textShape->setSize(newSize);
- }
-
- m_textShape->update();
-}
-
-void SimpleRootAreaProvider::updateAll()
-{
- if (m_area && m_area->associatedShape()) {
- m_area->associatedShape()->update();
- }
-}
-
-QRectF SimpleRootAreaProvider::suggestRect(KoTextLayoutRootArea *rootArea)
-{
- //Come up with a rect, but actually we don't need the height, as we set it to infinite below
- // Still better keep it for completeness sake
- QRectF rect(QPointF(), m_textShape->size());
- rect.adjust(m_textShapeData->leftPadding(), m_textShapeData->topPadding(), -m_textShapeData->rightPadding(), - m_textShapeData->bottomPadding());
-
- KoBorder *border = m_textShape->border();
- if (border) {
- rect.adjust(border->borderWidth(KoBorder::LeftBorder), border->borderWidth(KoBorder::TopBorder),
- -border->borderWidth(KoBorder::RightBorder), - border->borderWidth(KoBorder::BottomBorder));
- }
-
- // In simple cases we always set height way too high so that we have no breaking
- // If the shape grows afterwards or not is handled in doPostLayout()
- rect.setHeight(1E6);
-
- if (m_textShapeData->resizeMethod() == KoTextShapeData::AutoGrowWidthAndHeight
- || m_textShapeData->resizeMethod() == KoTextShapeData::AutoGrowWidth) {
- rootArea->setNoWrap(1E6);
- }
-
- // Make sure the size is not negative due to padding and border with
- // This can happen on vertical lines containing text on shape.
- if (rect.width() < 0) {
- rect.setWidth(0);
- }
- return rect;
-}
-
-QList<KoTextLayoutObstruction *> SimpleRootAreaProvider::relevantObstructions(KoTextLayoutRootArea *rootArea)
-{
- Q_UNUSED(rootArea);
-
- QList<KoTextLayoutObstruction *> obstructions;
- /*
- m_textShape->boundingRect();
- QList<KoShape *> shapes;
- shapes = manager->shapesAt(canvasRect):
- */
- return obstructions;
-}
diff --git a/plugins/flake/textshape/SimpleRootAreaProvider.h b/plugins/flake/textshape/SimpleRootAreaProvider.h
deleted file mode 100644
index ca8f79b941..0000000000
--- a/plugins/flake/textshape/SimpleRootAreaProvider.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 C. Boemann <cbo@boemann.dk>
- *
- * 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 SIMPLEROOTAREAPROVIDER_H
-#define SIMPLEROOTAREAPROVIDER_H
-
-#include "KoTextLayoutRootAreaProvider.h"
-
-class TextShape;
-class KoTextShapeData;
-
-class SimpleRootAreaProvider : public KoTextLayoutRootAreaProvider
-{
-public:
- SimpleRootAreaProvider(KoTextShapeData *data, TextShape *textshape);
-
- /// reimplemented
- KoTextLayoutRootArea *provide(KoTextDocumentLayout *documentLayout, const RootAreaConstraint &constraints, int requestedPosition, bool *isNewRootArea) override;
-
- void releaseAllAfter(KoTextLayoutRootArea *afterThis) override;
-
- void doPostLayout(KoTextLayoutRootArea *rootArea, bool isNewRootArea) override;
-
- void updateAll() override;
-
- QRectF suggestRect(KoTextLayoutRootArea *rootArea) override;
-
- QList<KoTextLayoutObstruction *> relevantObstructions(KoTextLayoutRootArea *rootArea) override;
-
- TextShape *m_textShape;
-
- KoTextLayoutRootArea *m_area;
- KoTextShapeData *m_textShapeData;
- bool m_fixAutogrow;
-};
-
-#endif
diff --git a/plugins/flake/textshape/TextChange.cpp b/plugins/flake/textshape/TextChange.cpp
deleted file mode 100644
index 6559041261..0000000000
--- a/plugins/flake/textshape/TextChange.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 "TextChange.h"
-
-TextChange::TextChange()
- : m_formerPosition(0)
- , m_position(0)
- , m_previous(0)
- , m_next(0)
-{
-}
-
-int TextChange::length() const
-{
- return m_after.length() - m_before.length();
-}
-
-int TextChange::formerPosition() const
-{
- return m_formerPosition;
-}
-
-int TextChange::position() const
-{
- return m_position;
-}
-
-int TextChange::formerLength() const
-{
- // TODO
- return -1;
-}
-
-void TextChange::setPosition(int pos)
-{
- m_position = pos;
- m_formerPosition = pos;
-}
-
-void TextChange::setOldText(const QString &old)
-{
- m_before = old;
-}
-
-void TextChange::setNewText(const QString &current)
-{
- m_after = current;
-}
-
-void TextChange::setPrevious(TextChange *item)
-{
- m_previous = item;
-}
-
-void TextChange::setNext(TextChange *item)
-{
- m_next = item;
-}
-
-void TextChange::move(int length)
-{
- m_position += length;
- if (m_next) {
- m_next->move(length);
- }
-}
-
-void TextChange::insertBefore(TextChange *node)
-{
- move(node->length());
- node->setPrevious(previous());
- node->setNext(this);
- setPrevious(node);
- if (node->previous()) {
- node->previous()->setNext(node);
- }
-}
-
-void TextChange::insertAfter(TextChange *node)
-{
- node->setPrevious(this);
- node->setNext(next());
- setNext(node);
- if (node->next()) {
- node->next()->setPrevious(node);
- }
-}
-
-void TextChange::merge(TextChange *other)
-{
- // make sure the start of 'other' is within this change instance
- Q_ASSERT(other->position() >= position() && other->position() <= position() + length());
-
- /// this only does very simple merging for now.
- m_after.insert(other->position() - m_position, other->after());
-}
-
diff --git a/plugins/flake/textshape/TextChange.h b/plugins/flake/textshape/TextChange.h
deleted file mode 100644
index 93b559f680..0000000000
--- a/plugins/flake/textshape/TextChange.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 TEXTCHANGE_H
-#define TEXTCHANGE_H
-
-#include <QString>
-
-class TextChange
-{
-public:
- TextChange();
- int formerLength() const;
- int length() const;
- int formerPosition() const;
- int position() const;
-
- TextChange *next()
- {
- return m_next;
- }
- const TextChange *next() const
- {
- return m_next;
- }
- TextChange *previous()
- {
- return m_previous;
- }
- const TextChange *previous() const
- {
- return m_previous;
- }
-
- QString before() const
- {
- return m_before;
- }
- QString after() const
- {
- return m_after;
- }
-
- void setPosition(int pos);
- void setOldText(const QString &old);
- void setNewText(const QString &current);
- void setPrevious(TextChange *item);
- void setNext(TextChange *item);
- void move(int length);
-
- void insertBefore(TextChange *node);
- void insertAfter(TextChange *node);
-
- void merge(TextChange *other);
-
-private:
- QString m_before, m_after;
- int m_formerPosition, m_position;
- TextChange *m_previous, *m_next;
-};
-
-#endif
diff --git a/plugins/flake/textshape/TextChanges.cpp b/plugins/flake/textshape/TextChanges.cpp
deleted file mode 100644
index 01d7f1af9d..0000000000
--- a/plugins/flake/textshape/TextChanges.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 "TextChanges.h"
-#include "TextChange.h"
-
-TextChanges::TextChanges()
- : m_root(0)
-{
-}
-
-TextChanges::~TextChanges()
-{
- TextChange *change = m_root;
- while (change) {
- TextChange *prev = change;
- change = change->next();
- delete prev;
- }
- m_root = 0;
-}
-
-void TextChanges::inserted(int position, const QString &text)
-{
- changed(position, QString(), text);
-}
-
-void TextChanges::changed(int position, const QString &former, const QString &latter)
-{
- TextChange *change = new TextChange();
- change->setPosition(position);
- change->setNewText(latter);
- change->setOldText(former);
- if (m_root == 0) {
- m_root = change;
- return;
- }
-
- TextChange *cursor = m_root;
- while (cursor->next()) {
- if (cursor->position() + cursor->length() >= position) {
- break;
- }
- cursor = cursor->next();
- }
- Q_ASSERT(cursor);
- if (cursor->position() > position) { // insert new one before.
- cursor->insertBefore(change);
- if (cursor == m_root) {
- m_root = change;
- }
- } else if (position >= cursor->position() && position <= cursor->position() + cursor->length()) {//merge
- cursor->merge(change);
- delete change;
- } else { // insert new one after.
- cursor->insertAfter(change);
- if (change->next()) {
- change->next()->move(change->length());
- }
- }
-}
-
-bool TextChanges::hasText(int position, int length) const
-{
- Q_UNUSED(position);
- Q_UNUSED(length);
- return false;
-}
-
-QMap<int, const TextChange *> TextChanges::changes() const
-{
- QMap<int, const TextChange *> result;
- return result;
-}
diff --git a/plugins/flake/textshape/TextChanges.h b/plugins/flake/textshape/TextChanges.h
deleted file mode 100644
index 9e04c64a1d..0000000000
--- a/plugins/flake/textshape/TextChanges.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 TextChanges_H
-#define TextChanges_H
-
-#include <QMap>
-
-class TextChange;
-class QString;
-
-class TextChanges
-{
-public:
- TextChanges();
- ~TextChanges();
- void inserted(int position, const QString &text);
- void changed(int position, const QString &former, const QString &latter);
-
- /// return true if the current text and formatting for the parameter section is already in our database
- bool hasText(int position, int length) const;
-
- const TextChange *first() const
- {
- return m_root;
- }
- QMap<int, const TextChange *> changes() const;
-
-private:
- QMap<int, TextChange *> m_index;
- TextChange *m_root;
-};
-
-#endif
diff --git a/plugins/flake/textshape/TextDocumentStructureModel.cpp b/plugins/flake/textshape/TextDocumentStructureModel.cpp
deleted file mode 100644
index e0329f478a..0000000000
--- a/plugins/flake/textshape/TextDocumentStructureModel.cpp
+++ /dev/null
@@ -1,295 +0,0 @@
-/* This file is part of the Calligra project, made within the KDE community.
- *
- * Copyright (C) 2013 Friedrich W. H. Kossebau <friedrich@kogmbh.com>
- *
- * 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 <TextDocumentStructureModel.h>
-
-// KDE
-#include <QDebug>
-// Qt
-#include <QTextDocument>
-#include <QTextFrame>
-#include <QTextBlock>
-#include <QTextCursor>
-
-NodeData NodeData::fromBlock(int blockNumber)
-{
- NodeData nodeData;
- nodeData.type = Block;
- nodeData.blockNumber = blockNumber;
- return nodeData;
-}
-
-NodeData NodeData::fromFrame(QTextFrame *frame)
-{
- NodeData nodeData;
- nodeData.type = Frame;
- nodeData.frame = frame;
- return nodeData;
-}
-
-TextDocumentStructureModel::TextDocumentStructureModel(QObject *parent)
- : QAbstractItemModel(parent)
-{
- connect(this, SIGNAL(modelReset()), SLOT(onModelReset()));
-}
-
-TextDocumentStructureModel::~TextDocumentStructureModel()
-{
-}
-
-int TextDocumentStructureModel::columnCount(const QModelIndex &index) const
-{
- Q_UNUSED(index);
-
- return endColumn;
-}
-
-int TextDocumentStructureModel::rowCount(const QModelIndex &index) const
-{
- qDebug() << "-------------------------- index:" << index << m_textDocument;
- if (!m_textDocument) {
- return 0;
- }
-
- if (!index.isValid()) {
- // one root frame
- return 1;
- }
-
- Q_ASSERT(index.internalId() < uint(m_nodeDataTable.count()));
-
- const NodeData &nodeData = m_nodeDataTable.at(index.internalId());
-
- if (nodeData.type == NodeData::Frame) {
- QTextFrame *frame = nodeData.frame;
-
- // count frames and blocks
- int count = 0;
- for (QTextFrame::iterator iterator = frame->begin(); !iterator.atEnd(); ++iterator) {
- ++count;
- }
- return count;
- }
-
- // should be a block then, no childs for now
- return 0;
-}
-
-QVariant TextDocumentStructureModel::data(const QModelIndex &index, int role) const
-{
- if (!m_textDocument || ! index.isValid()) {
- return QVariant();
- }
-
- Q_ASSERT(index.internalId() < uint(m_nodeDataTable.count()));
-
- const NodeData &nodeData = m_nodeDataTable.at(index.internalId());
-
- switch (role) {
- case Qt::DisplayRole: {
- if (nodeData.type == NodeData::Frame) {
- QTextFrame *frame = nodeData.frame;
- return QLatin1String(frame->metaObject()->className());
- }
- // else should be a block
- return QLatin1String("Block");
- }
- }
-
- return QVariant();
-}
-
-QModelIndex TextDocumentStructureModel::parent(const QModelIndex &index) const
-{
- qDebug() << "-------------------------- index:" << index << m_textDocument;
- if (!m_textDocument || ! index.isValid()) {
- return QModelIndex();
- }
-
- Q_ASSERT(index.internalId() < uint(m_nodeDataTable.count()));
-
- const NodeData &nodeData = m_nodeDataTable.at(index.internalId());
-
- QTextFrame *parentFrame;
- if (nodeData.type == NodeData::Frame) {
- parentFrame = nodeData.frame->parentFrame();
- } else {
- QTextBlock block = m_textDocument->findBlockByNumber(nodeData.blockNumber);
- Q_ASSERT(block.isValid());
- // QTextBlock's API has no option to query the parentframe, so get it via a cursor
- QTextCursor cursor(block);
- parentFrame = cursor.currentFrame();
- }
-
- if (!parentFrame) {
- return QModelIndex();
- }
-
- QTextFrame *grandParentFrame = parentFrame->parentFrame();
- // parent is root frame?
- if (!grandParentFrame) {
- Q_ASSERT(parentFrame == m_textDocument->rootFrame());
- return createIndex(0, 0, static_cast<quintptr>(0));
- }
-
- // find position of parentFrame
- bool posFound = false;
- int row = 0;
- for (QTextFrame::iterator iterator = grandParentFrame->begin(); !iterator.atEnd(); ++iterator) {
- if (iterator.currentFrame() == parentFrame) {
- posFound = true;
- break;
- }
- ++row;
- }
- Q_ASSERT(posFound); Q_UNUSED(posFound);
- return createIndex(row, 0, frameIndex(parentFrame));
-}
-
-QModelIndex TextDocumentStructureModel::index(int row, int column, const QModelIndex &parentIndex) const
-{
- qDebug() << "-------------------------- row:" << row << "column:" << column << "index:" << parentIndex << m_textDocument;
- if (!m_textDocument) {
- return QModelIndex();
- }
-
- if (!parentIndex.isValid()) {
- return createIndex(row, column, static_cast<quintptr>(0));
- }
-
- Q_ASSERT(parentIndex.internalId() < uint(m_nodeDataTable.count()));
-
- const NodeData &nodeData = m_nodeDataTable.at(parentIndex.internalId());
- // can be only frame for now
- Q_ASSERT(nodeData.type == NodeData::Frame);
-
- QTextFrame *parentFrame = nodeData.frame;
- int index = -1;
- int count = 0;
- for (QTextFrame::iterator iterator = parentFrame->begin(); !iterator.atEnd(); ++iterator) {
- if (count == row) {
- QTextFrame *frame = iterator.currentFrame();
- if (frame) {
- index = frameIndex(frame);
- break;
- } else {
- QTextBlock block = iterator.currentBlock();
- if (block.isValid()) {
- index = blockIndex(block);
- break;
- }
- }
- }
- ++count;
- }
-
- Q_ASSERT(index != -1);
- return createIndex(row, column, index);
-}
-
-bool TextDocumentStructureModel::hasChildren(const QModelIndex &parentIndex) const
-{
- qDebug() << "-------------------------- parentIndex:" << parentIndex << m_textDocument;
- if (!m_textDocument) {
- return false;
- }
- // there is one root children
- if (!parentIndex.isValid()) {
- return true;
- }
-
- Q_ASSERT(parentIndex.internalId() < uint(m_nodeDataTable.count()));
-
- const NodeData &nodeData = m_nodeDataTable.at(parentIndex.internalId());
-
- if (nodeData.type == NodeData::Frame) {
- return (! nodeData.frame->begin().atEnd());
- }
- // no children with a block
- return false;
-}
-
-void TextDocumentStructureModel::setTextDocument(QTextDocument *textDocument)
-{
- if (m_textDocument) {
- m_textDocument->disconnect(this);
- }
-
- m_textDocument = textDocument;
-
- if (m_textDocument) {
- connect(m_textDocument, SIGNAL(contentsChanged()), SLOT(onContentsChanged()));
- }
-
- reset();
-}
-
-int TextDocumentStructureModel::blockIndex(const QTextBlock &block) const
-{
- int index;
-
- const int blockNumber = block.blockNumber();
- QHash<int, int>::ConstIterator it = m_blockNumberTable.constFind(blockNumber);
- if (it == m_blockNumberTable.constEnd()) {
- index = m_nodeDataTable.count();
- m_blockNumberTable.insert(blockNumber, index);
- m_nodeDataTable.append(NodeData::fromBlock(blockNumber));
- } else {
- index = it.value();
- }
-
- return index;
-}
-
-int TextDocumentStructureModel::frameIndex(QTextFrame *frame) const
-{
- int index;
-
- QHash<QTextFrame *, int>::ConstIterator it = m_frameTable.constFind(frame);
- if (it == m_frameTable.constEnd()) {
- index = m_nodeDataTable.count();
- m_frameTable.insert(frame, index);
- m_nodeDataTable.append(NodeData::fromFrame(frame));
- } else {
- index = it.value();
- }
-
- return index;
-}
-
-void TextDocumentStructureModel::onContentsChanged()
-{
- reset();
-}
-
-void TextDocumentStructureModel::onModelReset()
-{
- qDebug() << "-------------------------- " << m_textDocument;
- m_nodeDataTable.clear();
- m_blockNumberTable.clear();
- m_frameTable.clear();
-
- // prefill table with root node
- if (m_textDocument) {
- QTextFrame *rootFrame = m_textDocument->rootFrame();
- m_frameTable.insert(rootFrame, 0);
- m_nodeDataTable.append(NodeData::fromFrame(rootFrame));
- }
-}
diff --git a/plugins/flake/textshape/TextDocumentStructureModel.h b/plugins/flake/textshape/TextDocumentStructureModel.h
deleted file mode 100644
index 37fecbff96..0000000000
--- a/plugins/flake/textshape/TextDocumentStructureModel.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* This file is part of the Calligra project, made within the KDE community.
- *
- * Copyright (C) 2013 Friedrich W. H. Kossebau <friedrich@kogmbh.com>
- *
- * 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 TEXTDOCUMENTSTRUCTUREMODEL_H
-#define TEXTDOCUMENTSTRUCTUREMODEL_H
-
-#include <QAbstractItemModel>
-#include <QVector>
-#include <QHash>
-#include <QPointer>
-
-class QTextDocument;
-class QTextFrame;
-class QTextBlock;
-
-struct NodeData {
- enum Type {Frame, Block};
-
- Type type;
- union {
- QTextFrame *frame;
- int blockNumber;
- };
- static NodeData fromFrame(QTextFrame *frame);
- static NodeData fromBlock(int blockNumber);
-};
-
-class TextDocumentStructureModel : public QAbstractItemModel
-{
- Q_OBJECT
-
- enum Columns {
- nameColumn = 0,
- endColumn
- };
-
-public:
- explicit TextDocumentStructureModel(QObject *parent = 0);
- virtual ~TextDocumentStructureModel();
-
-public: // QAbstractItemModel API
- virtual QModelIndex index(int row, int column, const QModelIndex &parentIndex) const;
- virtual QModelIndex parent(const QModelIndex &index) const;
- virtual int rowCount(const QModelIndex &index) const;
- virtual int columnCount(const QModelIndex &index) const;
- virtual QVariant data(const QModelIndex &index, int role) const;
- virtual bool hasChildren(const QModelIndex &parent) const;
-
-public:
- void setTextDocument(QTextDocument *textDocument);
-
-private Q_SLOTS:
- void onContentsChanged();
- void onModelReset();
-
-private:
- int blockIndex(const QTextBlock &block) const;
- int frameIndex(QTextFrame *frame) const;
-
-private:
- QPointer<QTextDocument> m_textDocument;
-
- mutable QVector<NodeData> m_nodeDataTable;
- mutable QHash<int, int> m_blockNumberTable;
- mutable QHash<QTextFrame *, int> m_frameTable;
-};
-
-#endif // TEXTDOCUMENTSTRUCTUREMODEL_H
diff --git a/plugins/flake/textshape/TextEditingPluginContainer.cpp b/plugins/flake/textshape/TextEditingPluginContainer.cpp
deleted file mode 100644
index f8a7429887..0000000000
--- a/plugins/flake/textshape/TextEditingPluginContainer.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2010 Thomas Zander <zander@kde.org>
- *
- * 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 "TextEditingPluginContainer.h"
-#include "TextTool.h"
-#include <KoTextEditingRegistry.h>
-#include <KoTextEditingPlugin.h>
-
-#include <QDebug>
-
-TextEditingPluginContainer::TextEditingPluginContainer(QObject *parent)
- : QObject(parent)
-{
- foreach (const QString &key, KoTextEditingRegistry::instance()->keys()) {
- KoTextEditingFactory *factory = KoTextEditingRegistry::instance()->value(key);
- Q_ASSERT(factory);
- if (m_textEditingPlugins.contains(factory->id())) {
- qWarning() << "Duplicate id for textEditingPlugin, ignoring one! (" << factory->id() << ")";
- continue;
- }
- KoTextEditingPlugin *plugin = factory->create();
- if (plugin) {
- m_textEditingPlugins.insert(factory->id(), plugin);
- }
- }
-}
-
-TextEditingPluginContainer::~TextEditingPluginContainer()
-{
- qDeleteAll(m_textEditingPlugins);
- m_textEditingPlugins.clear();
-}
-
-KoTextEditingPlugin *TextEditingPluginContainer::spellcheck() const
-{
- return plugin("spellcheck");
-}
diff --git a/plugins/flake/textshape/TextEditingPluginContainer.h b/plugins/flake/textshape/TextEditingPluginContainer.h
deleted file mode 100644
index 1f83252549..0000000000
--- a/plugins/flake/textshape/TextEditingPluginContainer.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2010 Thomas Zander <zander@kde.org>
- *
- * 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 TEXTEDITINGPLUGINCONTAINER_H
-#define TEXTEDITINGPLUGINCONTAINER_H
-
-#include <QObject>
-#include <QHash>
-#include <QString>
-#include <QVariant>
-
-class KoTextEditingPlugin;
-
-/// This class holds on to the text editing plugins.
-/// the goal of this class is to have one plugin instance per calligra-document
-/// instead of one per tool.
-class TextEditingPluginContainer : public QObject
-{
- Q_OBJECT
-public:
- enum ResourceManagerId {
- ResourceId = 345681743
- };
-
- explicit TextEditingPluginContainer(QObject *parent = 0);
- ~TextEditingPluginContainer() override;
-
- KoTextEditingPlugin *spellcheck() const;
-
- KoTextEditingPlugin *plugin(const QString &pluginId) const
- {
- if (m_textEditingPlugins.contains(pluginId)) {
- return m_textEditingPlugins.value(pluginId);
- }
- return 0;
- }
-
- QList<KoTextEditingPlugin *> values() const
- {
- return m_textEditingPlugins.values();
- }
-
-private:
- QHash<QString, KoTextEditingPlugin *> m_textEditingPlugins;
-};
-
-Q_DECLARE_METATYPE(TextEditingPluginContainer *)
-
-#endif
diff --git a/plugins/flake/textshape/TextPlugin.cpp b/plugins/flake/textshape/TextPlugin.cpp
deleted file mode 100644
index b77f545b37..0000000000
--- a/plugins/flake/textshape/TextPlugin.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006 Thomas Zander <zander@kde.org>
- *
- * 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 "TextPlugin.h"
-#include "TextToolFactory.h"
-#ifdef CREATE_TEXTDOCUMENT_INSPECTOR
-#include "TextDocumentInspectionPlugin.h"
-#endif
-#include "TextShapeFactory.h"
-
-#include <KoShapeRegistry.h>
-#include <KoDockRegistry.h>
-#include <KoToolRegistry.h>
-
-#include <kpluginfactory.h>
-
-#ifdef CREATE_TEXTDOCUMENT_INSPECTOR
-K_PLUGIN_FACTORY_WITH_JSON(TextPluginFactory, "calligra_shape_text.json", registerPlugin<TextPlugin>(); registerPlugin<TextDocumentInspectionPlugin>(QLatin1String("TextDocumentInspection"));)
-#else
-K_PLUGIN_FACTORY_WITH_JSON(TextPluginFactory, "calligra_shape_text.json", registerPlugin<TextPlugin>();)
-#endif
-
-TextPlugin::TextPlugin(QObject *parent, const QVariantList &)
- : QObject(parent)
-{
- //KoToolRegistry::instance()->add(new TextToolFactory());
- KoShapeRegistry::instance()->add(new TextShapeFactory());
-}
-
-#include <TextPlugin.moc>
diff --git a/plugins/flake/textshape/TextPlugin.h b/plugins/flake/textshape/TextPlugin.h
deleted file mode 100644
index fb5ce1b3ad..0000000000
--- a/plugins/flake/textshape/TextPlugin.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006 Thomas Zander <zander@kde.org>
- *
- * 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 TEXTPLUGIN_H
-#define TEXTPLUGIN_H
-
-#include <QObject>
-#include <QVariantList>
-
-class TextPlugin : public QObject
-{
- Q_OBJECT
-
-public:
- TextPlugin(QObject *parent, const QVariantList &);
- ~TextPlugin() override {}
-};
-#endif
diff --git a/plugins/flake/textshape/TextShape.cpp b/plugins/flake/textshape/TextShape.cpp
deleted file mode 100644
index c8ae74d958..0000000000
--- a/plugins/flake/textshape/TextShape.cpp
+++ /dev/null
@@ -1,473 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008-2010 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Pierre Stirnweiss \pierre.stirnweiss_calligra@gadz.org>
- * Copyright (C) 2010 KO GmbH <cbo@kogmbh.com>
- *
- * 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 "TextShape.h"
-#include "ShrinkToFitShapeContainer.h"
-#include <KoTextSharedLoadingData.h>
-#include "SimpleRootAreaProvider.h"
-
-#include <KoTextLayoutRootArea.h>
-#include <KoTextEditor.h>
-
-#include <KoCanvasBase.h>
-#include <KoCanvasResourceProvider.h>
-#include <KoChangeTracker.h>
-#include <KoInlineTextObjectManager.h>
-#include <KoTextRangeManager.h>
-#include <KoOdfLoadingContext.h>
-#include <KoOdfWorkaround.h>
-#include <KoParagraphStyle.h>
-#include <KoPostscriptPaintDevice.h>
-#include <KoSelection.h>
-#include <KoShapeLoadingContext.h>
-#include <KoShapeBackground.h>
-#include <KoShapePaintingContext.h>
-#include <KoShapeSavingContext.h>
-#include <KoText.h>
-#include <KoTextDocument.h>
-#include <KoTextDocumentLayout.h>
-#include <KoTextPage.h>
-#include <KoTextShapeContainerModel.h>
-#include <KoPageProvider.h>
-#include <KoXmlWriter.h>
-#include <KoXmlReader.h>
-#include <KoXmlNS.h>
-#include <KoStyleStack.h>
-
-#include <QAbstractTextDocumentLayout>
-#include <QApplication>
-#include <QFont>
-#include <QPainter>
-#include <QPainterPath>
-#include <QPen>
-#include <QTextLayout>
-
-#include <QDebug>
-
-#include <KoShapeContainer_p.h>
-#include "kis_painting_tweaks.h"
-
-TextShape::TextShape(KoInlineTextObjectManager *inlineTextObjectManager, KoTextRangeManager *textRangeManager)
- : KoShapeContainer(new KoTextShapeContainerModel())
- , KoFrameShape(KoXmlNS::draw, "text-box")
- , m_pageProvider(0)
- , m_imageCollection(0)
- , m_clip(true)
-{
- setShapeId(TextShape_SHAPEID);
- m_textShapeData = new KoTextShapeData();
- setUserData(m_textShapeData);
- SimpleRootAreaProvider *provider = new SimpleRootAreaProvider(m_textShapeData, this);
-
- KoTextDocument(m_textShapeData->document()).setInlineTextObjectManager(inlineTextObjectManager);
- KoTextDocument(m_textShapeData->document()).setTextRangeManager(textRangeManager);
-
- m_layout = new KoTextDocumentLayout(m_textShapeData->document(), provider);
- m_textShapeData->document()->setDocumentLayout(m_layout);
-
- /// FIXME: collision detection was dropped in Krita
- /// due to performance reasons
- // setCollisionDetection(true);
-
- QObject::connect(m_layout, SIGNAL(layoutIsDirty()), m_layout, SLOT(scheduleLayout()));
-}
-
-TextShape::TextShape(const TextShape &rhs)
- : KoShapeContainer(rhs)
- , KoFrameShape(rhs)
- , m_textShapeData(dynamic_cast<KoTextShapeData*>(rhs.m_textShapeData->clone()))
- , m_pageProvider(0)
- , m_imageCollection(0)
- , m_clip(rhs.m_clip)
-{
- /// TODO: we need to clone the model
- KoTextShapeContainerModel *origModel = dynamic_cast<KoTextShapeContainerModel *>(rhs.model());
- if (origModel) {
- setModel(new KoTextShapeContainerModel());
- }
- // XXX: ?
- //reinterpret_cast<KoShapeContainerPrivate*>(rhs.d_ptr)->model = new KoTextShapeContainerModel();
-
- setShapeId(TextShape_SHAPEID);
- setUserData(m_textShapeData);
-
- SimpleRootAreaProvider *provider = new SimpleRootAreaProvider(m_textShapeData, this);
- m_layout = new KoTextDocumentLayout(m_textShapeData->document(), provider);
- m_textShapeData->document()->setDocumentLayout(m_layout);
-
- /// FIXME: collision detection was dropped in Krita
- /// due to performance reasons
- // setCollisionDetection(true);
-
- QObject::connect(m_layout, SIGNAL(layoutIsDirty()), m_layout, SLOT(scheduleLayout()));
-
- updateDocumentData();
- m_layout->scheduleLayout();
-}
-
-
-TextShape::~TextShape()
-{
-}
-
-KoShape *TextShape::cloneShape() const
-{
- return new TextShape(*this);
-}
-
-void TextShape::paintComponent(QPainter &painter,
- KoShapePaintingContext &paintContext) const
-{
- painter.save();
- KoBorder *border = this->border();
-
- if (border) {
- const QRectF borderRect = QRectF(QPointF(0, 0), size());
- border->paint(painter, borderRect, KoBorder::PaintInsideLine);
- } else if (paintContext.showTextShapeOutlines) {
- // No need to paint the outlines if there is a real border.
- if (qAbs(rotation()) > 1) {
- painter.setRenderHint(QPainter::Antialiasing);
- }
-
- // disabled, due to refactoring out of \p converter
-// QPen pen(QColor(210, 210, 210)); // use cosmetic pen
-// QPointF onePixel = converter.viewToDocument(QPointF(1.0, 1.0));
-// QRectF rect(QPointF(0.0, 0.0), size() - QSizeF(onePixel.x(), onePixel.y()));
-// painter.setPen(pen);
-// painter.drawRect(rect);
- }
- painter.restore();
-
- if (m_textShapeData->isDirty()) { // not layouted yet.
- return;
- }
-
- QTextDocument *doc = m_textShapeData->document();
- Q_ASSERT(doc);
- KoTextDocumentLayout *lay = qobject_cast<KoTextDocumentLayout *>(doc->documentLayout());
- Q_ASSERT(lay);
- lay->showInlineObjectVisualization(paintContext.showInlineObjectVisualization);
-
- if (background()) {
- QPainterPath p;
- p.addRect(QRectF(QPointF(), size()));
- background()->paint(painter, paintContext, p);
- }
-
- // this enables to use the same shapes on different pages showing different page numbers
- if (m_pageProvider) {
- KoTextPage *page = m_pageProvider->page(this);
- if (page) {
- // this is used to not trigger repaints if layout during the painting is done
- if (!m_textShapeData->rootArea()->page() || page->pageNumber() != m_textShapeData->rootArea()->page()->pageNumber()) {
- m_textShapeData->rootArea()->setPage(page); // takes over ownership of the page
- } else {
- delete page;
- }
- }
- }
-
- KoTextDocumentLayout::PaintContext pc;
-
- QAbstractTextDocumentLayout::Selection selection;
- KoTextEditor *textEditor = KoTextDocument(m_textShapeData->document()).textEditor();
- selection.cursor = *(textEditor->cursor());
- QPalette palette = pc.textContext.palette;
- selection.format.setBackground(palette.brush(QPalette::Highlight));
- selection.format.setForeground(palette.brush(QPalette::HighlightedText));
- pc.textContext.selections.append(selection);
-
- pc.textContext.selections += KoTextDocument(doc).selections();
- pc.imageCollection = m_imageCollection;
- pc.showFormattingCharacters = paintContext.showFormattingCharacters;
- pc.showTableBorders = paintContext.showTableBorders;
- pc.showSectionBounds = paintContext.showSectionBounds;
- pc.showSpellChecking = paintContext.showSpellChecking;
- pc.showSelections = paintContext.showSelections;
-
- // When clipping the painter we need to make sure not to cutoff cosmetic pens which
- // may used to draw e.g. table-borders for user convenience when on screen (but not
- // on e.g. printing). Such cosmetic pens are special cause they will always have the
- // same pen-width (1 pixel) independent of zoom-factor or painter transformations and
- // are not taken into account in any border-calculations.
- QRectF clipRect = outlineRect();
- qreal cosmeticPenX = 1 * 72. / painter.device()->logicalDpiX();
- qreal cosmeticPenY = 1 * 72. / painter.device()->logicalDpiY();
- painter.setClipRect(clipRect.adjusted(-cosmeticPenX, -cosmeticPenY, cosmeticPenX, cosmeticPenY), Qt::IntersectClip);
-
- painter.save();
- painter.translate(0, -m_textShapeData->documentOffset());
- m_textShapeData->rootArea()->paint(&painter, pc); // only need to draw ourselves
- painter.restore();
-
-}
-
-QPointF TextShape::convertScreenPos(const QPointF &point) const
-{
- QPointF p = absoluteTransformation().inverted().map(point);
- return p + QPointF(0.0, m_textShapeData->documentOffset());
-}
-
-QPainterPath TextShape::outline() const
-{
- QPainterPath path;
- path.addRect(QRectF(QPointF(0, 0), size()));
- return path;
-}
-
-QRectF TextShape::outlineRect() const
-{
- if (m_textShapeData->rootArea()) {
- QRectF rect = m_textShapeData->rootArea()->boundingRect();
- rect.moveTop(rect.top() - m_textShapeData->rootArea()->top());
- if (m_clip) {
- rect.setHeight(size().height());
- }
- return rect | QRectF(QPointF(0, 0), size());
- }
- return QRectF(QPointF(0, 0), size());
-}
-
-void TextShape::shapeChanged(ChangeType type, KoShape *shape)
-{
- Q_UNUSED(shape);
- KoShapeContainer::shapeChanged(type, shape);
- if (type == PositionChanged || type == SizeChanged /* || type == CollisionDetected*/) {
- m_textShapeData->setDirty();
- }
-}
-
-void TextShape::saveOdf(KoShapeSavingContext &context) const
-{
- KoXmlWriter &writer = context.xmlWriter();
-
- QString textHeight = additionalAttribute("fo:min-height");
- const_cast<TextShape *>(this)->removeAdditionalAttribute("fo:min-height");
- writer.startElement("draw:frame");
- // if the TextShape is wrapped in a shrink to fit container we need to save the geometry of the container as
- // the geometry of the shape might have been changed.
- if (ShrinkToFitShapeContainer *stf = dynamic_cast<ShrinkToFitShapeContainer *>(this->parent())) {
- stf->saveOdfAttributes(context, OdfSize | OdfPosition | OdfTransformation);
- saveOdfAttributes(context, OdfAdditionalAttributes | OdfMandatories | OdfCommonChildElements);
- } else {
- saveOdfAttributes(context, OdfAllAttributes);
- }
-
- writer.startElement("draw:text-box");
- if (!textHeight.isEmpty()) {
- writer.addAttribute("fo:min-height", textHeight);
- }
- KoTextDocumentLayout *lay = qobject_cast<KoTextDocumentLayout *>(m_textShapeData->document()->documentLayout());
- int index = -1;
- if (lay) {
- int i = 0;
- foreach (KoShape *shape, lay->shapes()) {
- if (shape == this) {
- index = i;
- } else if (index >= 0) {
- writer.addAttribute("draw:chain-next-name", shape->name());
- break;
- }
- ++i;
- }
- }
- const bool saveMyText = index == 0; // only save the text once.
-
- m_textShapeData->saveOdf(context, 0, 0, saveMyText ? -1 : 0);
- writer.endElement(); // draw:text-box
- saveOdfCommonChildElements(context);
- writer.endElement(); // draw:frame
-}
-
-QString TextShape::saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const
-{
- Qt::Alignment vAlign(m_textShapeData->verticalAlignment());
- QString verticalAlign = "top";
- if (vAlign == Qt::AlignBottom) {
- verticalAlign = "bottom";
- } else if (vAlign == Qt::AlignVCenter) {
- verticalAlign = "middle";
- }
- style.addProperty("draw:textarea-vertical-align", verticalAlign);
-
- KoTextShapeData::ResizeMethod resize = m_textShapeData->resizeMethod();
- if (resize == KoTextShapeData::AutoGrowWidth || resize == KoTextShapeData::AutoGrowWidthAndHeight) {
- style.addProperty("draw:auto-grow-width", "true");
- }
- if (resize != KoTextShapeData::AutoGrowHeight && resize != KoTextShapeData::AutoGrowWidthAndHeight) {
- style.addProperty("draw:auto-grow-height", "false");
- }
- if (resize == KoTextShapeData::ShrinkToFitResize) {
- style.addProperty("draw:fit-to-size", "true");
- }
-
- m_textShapeData->saveStyle(style, context);
-
- return KoShape::saveStyle(style, context);
-}
-
-void TextShape::loadStyle(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- KoShape::loadStyle(element, context);
- KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
- styleStack.setTypeProperties("graphic");
-
- QString verticalAlign(styleStack.property(KoXmlNS::draw, "textarea-vertical-align"));
- Qt::Alignment alignment(Qt::AlignTop);
- if (verticalAlign == "bottom") {
- alignment = Qt::AlignBottom;
- } else if (verticalAlign == "justify") {
- // not yet supported
- alignment = Qt::AlignVCenter;
- } else if (verticalAlign == "middle") {
- alignment = Qt::AlignVCenter;
- }
-
- m_textShapeData->setVerticalAlignment(alignment);
-
- const QString fitToSize = styleStack.property(KoXmlNS::draw, "fit-to-size");
- KoTextShapeData::ResizeMethod resize = KoTextShapeData::NoResize;
- if (fitToSize == "true" || fitToSize == "shrink-to-fit") { // second is buggy value from impress
- resize = KoTextShapeData::ShrinkToFitResize;
- } else {
- // An explicit svg:width or svg:height defined do change the default value (means those value
- // used if not explicit defined otherwise) for auto-grow-height and auto-grow-height. So
- // they are mutable exclusive.
- // It is not clear (means we did not test and took care of it) what happens if both are
- // defined and are in conflict with each other or how the fit-to-size is related to this.
-
- QString autoGrowWidth = styleStack.property(KoXmlNS::draw, "auto-grow-width");
- if (autoGrowWidth.isEmpty()) {
- autoGrowWidth = element.hasAttributeNS(KoXmlNS::svg, "width") ? "false" : "true";
- }
-
- QString autoGrowHeight = styleStack.property(KoXmlNS::draw, "auto-grow-height");
- if (autoGrowHeight.isEmpty()) {
- autoGrowHeight = element.hasAttributeNS(KoXmlNS::svg, "height") ? "false" : "true";
- }
-
- if (autoGrowWidth == "true") {
- resize = autoGrowHeight == "true" ? KoTextShapeData::AutoGrowWidthAndHeight : KoTextShapeData::AutoGrowWidth;
- } else if (autoGrowHeight == "true") {
- resize = KoTextShapeData::AutoGrowHeight;
- }
- }
-
- m_textShapeData->setResizeMethod(resize);
-}
-
-bool TextShape::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- m_textShapeData->document()->setUndoRedoEnabled(false);
- loadOdfAttributes(element, context, OdfAllAttributes);
-
- // this cannot be done in loadStyle as that fills the style stack incorrectly and therefore
- // it results in wrong data being loaded.
- m_textShapeData->loadStyle(element, context);
-
-#ifndef NWORKAROUND_ODF_BUGS
- KoTextShapeData::ResizeMethod method = m_textShapeData->resizeMethod();
- if (KoOdfWorkaround::fixAutoGrow(method, context)) {
- KoTextDocumentLayout *lay = qobject_cast<KoTextDocumentLayout *>(m_textShapeData->document()->documentLayout());
- Q_ASSERT(lay);
- if (lay) {
- SimpleRootAreaProvider *provider = dynamic_cast<SimpleRootAreaProvider *>(lay->provider());
- if (provider) {
- provider->m_fixAutogrow = true;
- }
- }
- }
-#endif
-
- bool answer = loadOdfFrame(element, context);
- m_textShapeData->document()->setUndoRedoEnabled(true);
- return answer;
-}
-
-bool TextShape::loadOdfFrame(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- // If the loadOdfFrame from the base class for draw:text-box fails, check
- // for table:table, because that is a legal child of draw:frame in ODF 1.2.
- if (!KoFrameShape::loadOdfFrame(element, context)) {
- const KoXmlElement &possibleTableElement(KoXml::namedItemNS(element, KoXmlNS::table, "table"));
- if (possibleTableElement.isNull()) {
- return false;
- } else {
- return loadOdfFrameElement(possibleTableElement, context);
- }
- }
-
- return true;
-}
-
-bool TextShape::loadOdfFrameElement(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- bool ok = m_textShapeData->loadOdf(element, context, 0, this);
- if (ok) {
- ShrinkToFitShapeContainer::tryWrapShape(this, element, context);
- }
- return ok;
-}
-
-void TextShape::update() const
-{
- KoShapeContainer::update();
-}
-
-void TextShape::updateAbsolute(const QRectF &shape) const
-{
- // this is done to avoid updates which are called during the paint event and not needed.
- //if (!m_paintRegion.contains(shape.toRect())) {
- //KoShape::update(shape);
- //}
-
- // FIXME: just a hack to remove outdated call from the deprecated shape
- KoShape::updateAbsolute(shape);
-}
-
-void TextShape::waitUntilReady(bool asynchronous) const
-{
- Q_UNUSED(asynchronous);
- KoTextDocumentLayout *lay = qobject_cast<KoTextDocumentLayout *>(m_textShapeData->document()->documentLayout());
- Q_ASSERT(lay);
- if (m_textShapeData->isDirty()) {
- // Do a simple layout-call which will make sure to relayout till things are done. If more
- // layouts are scheduled then we don't need to wait for them here but can just continue.
- lay->layout();
- }
-}
-
-KoImageCollection *TextShape::imageCollection()
-{
- return m_imageCollection;
-}
-
-void TextShape::updateDocumentData()
-{
- if (m_layout) {
- KoTextDocument document(m_textShapeData->document());
- m_layout->setStyleManager(document.styleManager());
- m_layout->setInlineTextObjectManager(document.inlineTextObjectManager());
- m_layout->setTextRangeManager(document.textRangeManager());
- m_layout->setChangeTracker(document.changeTracker());
- }
-}
diff --git a/plugins/flake/textshape/TextShape.h b/plugins/flake/textshape/TextShape.h
deleted file mode 100644
index 7d850e8279..0000000000
--- a/plugins/flake/textshape/TextShape.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Pierre Stirnweiss \pierre.stirnweiss_calligra@gadz.org>
- * Copyright (C) 2010 KO GmbH <cbo@kogmbh.com>
- *
- * 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 KOTEXTSHAPE_H
-#define KOTEXTSHAPE_H
-
-#include <KoShapeContainer.h>
-#include <KoFrameShape.h>
-#include <KoTextShapeData.h>
-#include <KoTextDocument.h>
-
-#include <QTextDocument>
-#include <QPainter>
-
-#define TextShape_SHAPEID "TextShapeID"
-
-class KoInlineTextObjectManager;
-class KoTextRangeManager;
-class KoPageProvider;
-class KoImageCollection;
-class KoTextDocument;
-class TextShape;
-class KoTextDocumentLayout;
-class KoParagraphStyle;
-
-/**
- * A text shape.
- * The Text shape is capable of drawing structured text.
- * @see KoTextShapeData
- */
-class TextShape : public KoShapeContainer, public KoFrameShape
-{
-public:
- TextShape(KoInlineTextObjectManager *inlineTextObjectManager, KoTextRangeManager *textRangeManager);
- ~TextShape() override;
-
- KoShape* cloneShape() const override;
-
- /// reimplemented
- void paintComponent(QPainter &painter, KoShapePaintingContext &paintcontext) const override;
- /// reimplemented
- void waitUntilReady(bool asynchronous) const override;
-
- /// helper method.
- QPointF convertScreenPos(const QPointF &point) const;
-
- /// reimplemented
- QPainterPath outline() const override;
-
- /// reimplemented
- QRectF outlineRect() const override;
-
- ///reimplemented
- ChildZOrderPolicy childZOrderPolicy() override
- {
- return KoShape::ChildZPassThrough;
- }
-
- /// set the image collection which is needed to draw bullet from images
- void setImageCollection(KoImageCollection *collection)
- {
- m_imageCollection = collection;
- }
-
- KoImageCollection *imageCollection();
-
- /**
- * From KoShape reimplemented method to load the TextShape from ODF.
- *
- * This method redirects the call to the KoTextShapeData::loadOdf() method which
- * in turn will call the KoTextLoader::loadBody() method that reads the element
- * into a QTextCursor.
- *
- * @param context the KoShapeLoadingContext used for loading.
- * @param element element which represents the shape in odf.
- * @return false if loading failed.
- */
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
-
- /**
- * From KoShape reimplemented method to store the TextShape data as ODF.
- *
- * @param context the KoShapeSavingContext used for saving.
- */
- void saveOdf(KoShapeSavingContext &context) const override;
-
- KoTextShapeData *textShapeData()
- {
- return m_textShapeData;
- }
-
- void updateDocumentData();
-
- void update() const override;
- void updateAbsolute(const QRectF &shape) const override;
-
- // required for kpresenter hack
- void setPageProvider(KoPageProvider *provider)
- {
- m_pageProvider = provider;
- }
-
- /// reimplemented
- bool loadOdfFrame(const KoXmlElement &element, KoShapeLoadingContext &context) override;
-
-protected:
- bool loadOdfFrameElement(const KoXmlElement &element, KoShapeLoadingContext &context) override;
-
- /// reimplemented
- void loadStyle(const KoXmlElement &element, KoShapeLoadingContext &context) override;
-
- /// reimplemented
- QString saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const override;
-
- TextShape(const TextShape &rhs);
-
-private:
- void shapeChanged(ChangeType type, KoShape *shape = 0) override;
-
- KoTextShapeData *m_textShapeData;
- KoPageProvider *m_pageProvider;
- KoImageCollection *m_imageCollection;
- bool m_clip;
- KoTextDocumentLayout *m_layout;
-};
-
-#endif
diff --git a/plugins/flake/textshape/TextShapeFactory.cpp b/plugins/flake/textshape/TextShapeFactory.cpp
deleted file mode 100644
index 5451d0a0f3..0000000000
--- a/plugins/flake/textshape/TextShapeFactory.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2007,2009,2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 "TextShapeFactory.h"
-#include "TextShape.h"
-
-#include <KoProperties.h>
-#include <KoShape.h>
-#include <KoTextDocument.h>
-#include <KoTextShapeData.h>
-#include <KoXmlNS.h>
-#include <KoStyleManager.h>
-#include <KoDocumentResourceManager.h>
-#include <KoInlineTextObjectManager.h>
-#include <KoTextRangeManager.h>
-#include <changetracker/KoChangeTracker.h>
-#include <KoImageCollection.h>
-#include <KoShapeLoadingContext.h>
-
-#include <KoIcon.h>
-
-#include <klocalizedstring.h>
-#include <kundo2stack.h>
-#include <QTextCursor>
-
-TextShapeFactory::TextShapeFactory()
- : KoShapeFactoryBase(TextShape_SHAPEID, i18n("Text"))
-{
- setToolTip(i18n("A shape that shows text"));
- QList<QPair<QString, QStringList> > odfElements;
- odfElements.append(QPair<QString, QStringList>(KoXmlNS::draw, QStringList("text-box")));
- odfElements.append(QPair<QString, QStringList>(KoXmlNS::table, QStringList("table")));
- setXmlElements(odfElements);
- setLoadingPriority(1);
-
- KoShapeTemplate t;
- t.name = i18n("Text");
- t.iconName = koIconName("x-shape-text");
- t.toolTip = i18n("Text Shape");
- KoProperties *props = new KoProperties();
- t.properties = props;
- props->setProperty("demo", true);
- addTemplate(t);
-}
-
-KoShape *TextShapeFactory::createDefaultShape(KoDocumentResourceManager *documentResources) const
-{
- KoInlineTextObjectManager *manager = 0;
- KoTextRangeManager *locationManager = 0;
- if (documentResources && documentResources->hasResource(KoText::InlineTextObjectManager)) {
- QVariant variant = documentResources->resource(KoText::InlineTextObjectManager);
- if (variant.isValid()) {
- manager = variant.value<KoInlineTextObjectManager *>();
- }
- }
- if (documentResources && documentResources->hasResource(KoText::TextRangeManager)) {
- QVariant variant = documentResources->resource(KoText::TextRangeManager);
- if (variant.isValid()) {
- locationManager = variant.value<KoTextRangeManager *>();
- }
- }
- if (!manager) {
- manager = new KoInlineTextObjectManager();
- }
- if (!locationManager) {
- locationManager = new KoTextRangeManager();
- }
- TextShape *text = new TextShape(manager, locationManager);
- if (documentResources) {
- KoTextDocument document(text->textShapeData()->document());
-
- if (documentResources->hasResource(KoText::StyleManager)) {
- KoStyleManager *styleManager = documentResources->resource(KoText::StyleManager).value<KoStyleManager *>();
- document.setStyleManager(styleManager);
- }
-
- // this is needed so the shape can reinitialize itself with the stylemanager
- text->textShapeData()->setDocument(text->textShapeData()->document());
-
- document.setUndoStack(documentResources->undoStack());
-
- if (documentResources->hasResource(KoText::PageProvider)) {
- KoPageProvider *pp = static_cast<KoPageProvider *>(documentResources->resource(KoText::PageProvider).value<void *>());
- text->setPageProvider(pp);
- }
- if (documentResources->hasResource(KoText::ChangeTracker)) {
- KoChangeTracker *changeTracker = documentResources->resource(KoText::ChangeTracker).value<KoChangeTracker *>();
- document.setChangeTracker(changeTracker);
- }
-
- document.setShapeController(documentResources->globalShapeController());
-
- //update the resources of the document
- text->updateDocumentData();
-
- text->setImageCollection(documentResources->imageCollection());
- }
-
- return text;
-}
-
-KoShape *TextShapeFactory::createShape(const KoProperties */*params*/, KoDocumentResourceManager *documentResources) const
-{
- TextShape *shape = static_cast<TextShape *>(createDefaultShape(documentResources));
- shape->textShapeData()->document()->setUndoRedoEnabled(false);
- shape->setSize(QSizeF(300, 200));
- /*
- QString text("text");
- if (params->contains(text)) {
- KoTextShapeData *shapeData = qobject_cast<KoTextShapeData*>(shape->userData());
- }
- */
- if (documentResources) {
- shape->setImageCollection(documentResources->imageCollection());
- }
- shape->textShapeData()->document()->setUndoRedoEnabled(true);
- return shape;
-}
-
-bool TextShapeFactory::supports(const KoXmlElement &e, KoShapeLoadingContext &context) const
-{
- Q_UNUSED(context);
- return (e.localName() == "text-box" && e.namespaceURI() == KoXmlNS::draw) ||
- (e.localName() == "table" && e.namespaceURI() == KoXmlNS::table);
-}
-
-void TextShapeFactory::newDocumentResourceManager(KoDocumentResourceManager *manager) const
-{
- QVariant variant;
- variant.setValue<KoInlineTextObjectManager *>(new KoInlineTextObjectManager(manager));
- manager->setResource(KoText::InlineTextObjectManager, variant);
-
- variant.setValue<KoTextRangeManager *>(new KoTextRangeManager());
- manager->setResource(KoText::TextRangeManager, variant);
-
- if (!manager->hasResource(KoDocumentResourceManager::UndoStack)) {
-// qWarning() << "No KUndo2Stack found in the document resource manager, creating a new one";
- manager->setUndoStack(new KUndo2Stack(manager));
- }
- if (!manager->hasResource(KoText::StyleManager)) {
- variant.setValue(new KoStyleManager(manager));
- manager->setResource(KoText::StyleManager, variant);
- }
- if (!manager->imageCollection()) {
- manager->setImageCollection(new KoImageCollection(manager));
- }
-}
diff --git a/plugins/flake/textshape/TextShapeFactory.h b/plugins/flake/textshape/TextShapeFactory.h
deleted file mode 100644
index 60f750e41d..0000000000
--- a/plugins/flake/textshape/TextShapeFactory.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006, 2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 TEXTSHAPEFACTORY_H
-#define TEXTSHAPEFACTORY_H
-
-#include <KoShapeFactoryBase.h>
-
-class KoShape;
-
-class TextShapeFactory : public KoShapeFactoryBase
-{
-public:
- /// constructor
- TextShapeFactory();
- ~TextShapeFactory() override {}
-
- KoShape *createShape(const KoProperties *params, KoDocumentResourceManager *documentResources = 0) const override;
- KoShape *createDefaultShape(KoDocumentResourceManager *documentResources = 0) const override;
- bool supports(const KoXmlElement &e, KoShapeLoadingContext &context) const override;
-
- void newDocumentResourceManager(KoDocumentResourceManager *manager) const override;
-};
-
-#endif
diff --git a/plugins/flake/textshape/TextTool.cpp b/plugins/flake/textshape/TextTool.cpp
deleted file mode 100644
index 090ab74eda..0000000000
--- a/plugins/flake/textshape/TextTool.cpp
+++ /dev/null
@@ -1,3140 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2008, 2012 Pierre Stirnweiss <pstirnweiss@googlemail.org>
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2011 Mojtaba Shahi Senobari <mojtaba.shahi3000@gmail.com>
- * Copyright (C) 2014 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 "TextTool.h"
-
-#include "TextEditingPluginContainer.h"
-#include "dialogs/SimpleCharacterWidget.h"
-#include "dialogs/SimpleParagraphWidget.h"
-#include "dialogs/SimpleTableWidget.h"
-#include "dialogs/SimpleInsertWidget.h"
-#include "dialogs/ParagraphSettingsDialog.h"
-#include "dialogs/StyleManagerDialog.h"
-#include "dialogs/InsertCharacter.h"
-#include "dialogs/FontDia.h"
-#include "dialogs/TableDialog.h"
-#include "dialogs/SectionFormatDialog.h"
-#include "dialogs/SectionsSplitDialog.h"
-#include "commands/AutoResizeCommand.h"
-#include "commands/ChangeListLevelCommand.h"
-#include "FontSizeAction.h"
-#include "FontFamilyAction.h"
-
-#include <KoOdf.h>
-#include <KoCanvasBase.h>
-#include <KoShapeController.h>
-#include <KoCanvasController.h>
-#include <KoCanvasResourceProvider.h>
-#include <KoSelection.h>
-#include <KoShapeManager.h>
-#include <KoSelectedShapesProxy.h>
-#include <KoPointerEvent.h>
-#include <KoColor.h>
-#include <KoColorBackground.h>
-#include <KoColorPopupAction.h>
-#include <KoTextDocumentLayout.h>
-#include <KoParagraphStyle.h>
-#include <KoToolSelection.h>
-#include <KoTextEditingPlugin.h>
-#include <KoTextEditingRegistry.h>
-#include <KoInlineTextObjectManager.h>
-#include <KoTextRangeManager.h>
-#include <KoStyleManager.h>
-#include <KoTextOdfSaveHelper.h>
-#include <KoTextDrag.h>
-#include <KoTextDocument.h>
-#include <KoTextEditor.h>
-#include <KoChangeTracker.h>
-#include <KoChangeTrackerElement.h>
-#include <KoInlineNote.h>
-#include <KoBookmark.h>
-#include <KoBookmarkManager.h>
-#include <KoListLevelProperties.h>
-#include <KoTextLayoutRootArea.h>
-//#include <ResizeTableCommand.h>
-#include <KoIcon.h>
-#include <KoViewConverter.h>
-#include <KoShapeFactoryBase.h>
-#include "kis_action_registry.h"
-
-#include <QDebug>
-#include <kstandardshortcut.h>
-#include <kactionmenu.h>
-#include <kstandardaction.h>
-#include <ksharedconfig.h>
-
-#include <QDesktopServices>
-#include <QMenu>
-#include <QMenuBar>
-#include <QAction>
-#include <QTextTable>
-#include <QTextList>
-#include <QTabWidget>
-#include <QTextDocumentFragment>
-#include <QToolTip>
-#include <KisSignalMapper.h>
-#include <QLinearGradient>
-#include <QBitmap>
-#include <QDrag>
-#include <QDragLeaveEvent>
-#include <QDragMoveEvent>
-#include <QDropEvent>
-#include <QMimeData>
-
-#include "KoShapeControllerBase.h"
-#include <KoAnnotation.h>
-#include <KoShapeRegistry.h>
-#include <kuser.h>
-
-#include <KoDocumentRdfBase.h>
-
-class TextToolSelection : public KoToolSelection
-{
-public:
-
- TextToolSelection(QWeakPointer<KoTextEditor> editor)
- : KoToolSelection(0)
- , m_editor(editor)
- {
- }
-
- bool hasSelection() override
- {
- if (!m_editor.isNull()) {
- return m_editor.data()->hasSelection();
- }
- return false;
- }
-
- QWeakPointer<KoTextEditor> m_editor;
-};
-
-static bool hit(const QKeySequence &input, KStandardShortcut::StandardShortcut shortcut)
-{
- foreach (const QKeySequence &ks, KStandardShortcut::shortcut(shortcut)) {
- if (input == ks) {
- return true;
- }
- }
- return false;
-}
-
-TextTool::TextTool(KoCanvasBase *canvas)
- : KoToolBase(canvas)
- , m_textShape(0)
- , m_textShapeData(0)
- , m_changeTracker(0)
- , m_allowActions(true)
- , m_allowAddUndoCommand(true)
- , m_allowResourceManagerUpdates(true)
- , m_prevCursorPosition(-1)
- , m_caretTimer(this)
- , m_caretTimerState(true)
- , m_currentCommand(0)
- , m_currentCommandHasChildren(false)
- , m_specialCharacterDocker(0)
- , m_textTyping(false)
- , m_textDeleting(false)
- , m_editTipTimer(this)
- , m_delayedEnsureVisible(false)
- , m_toolSelection(0)
- , m_tableDraggedOnce(false)
- , m_tablePenMode(false)
- , m_lastImMicroFocus(QRectF(0, 0, 0, 0))
- , m_drag(0)
-{
- setTextMode(true);
-
- createActions();
-
- m_unit = canvas->resourceManager()->unitResource(KoCanvasResourceProvider::Unit);
-
- foreach (KoTextEditingPlugin *plugin, textEditingPluginContainer()->values()) {
- connect(plugin, SIGNAL(startMacro(QString)),
- this, SLOT(startMacro(QString)));
- connect(plugin, SIGNAL(stopMacro()), this, SLOT(stopMacro()));
- QHash<QString, QAction *> actions = plugin->actions();
- QHash<QString, QAction *>::iterator i = actions.begin();
- while (i != actions.end()) {
-// addAction(i.key(), i.value());
- ++i;
- }
- }
-
- m_contextMenu.reset(new QMenu());
-
- // setup the context list.
- KisSignalMapper *signalMapper = new KisSignalMapper(this);
- connect(signalMapper, SIGNAL(mapped(QString)), this, SLOT(startTextEditingPlugin(QString)));
- m_contextMenu->addAction(this->action("format_font"));
- foreach (const QString &key, KoTextEditingRegistry::instance()->keys()) {
- KoTextEditingFactory *factory = KoTextEditingRegistry::instance()->value(key);
- if (factory->showInMenu()) {
- QAction *a = new QAction(factory->title(), this);
- connect(a, SIGNAL(triggered()), signalMapper, SLOT(map()));
- signalMapper->setMapping(a, factory->id());
- m_contextMenu->addAction(a);
-// addAction(QString("apply_%1").arg(factory->id()), a);
- }
- }
-
- connect(canvas->selectedShapesProxy(), SIGNAL(selectionChanged()), this, SLOT(shapeAddedToCanvas()));
-
- m_caretTimer.setInterval(500);
- connect(&m_caretTimer, SIGNAL(timeout()), this, SLOT(blinkCaret()));
-
- m_editTipTimer.setInterval(500);
- m_editTipTimer.setSingleShot(true);
- connect(&m_editTipTimer, SIGNAL(timeout()), this, SLOT(showEditTip()));
-}
-
-void TextTool::createActions()
-{
- bool useAdvancedText = !(canvas()->resourceManager()->intResource(KoCanvasResourceProvider::ApplicationSpeciality)
- & KoCanvasResourceProvider::NoAdvancedText);
-
- KisActionRegistry *actionRegistry = KisActionRegistry::instance();
-
- // FIXME: find new icons for these
- m_actionConfigureSection = actionRegistry->makeQAction("configure_section", this);
-// addAction("configure_section", m_actionConfigureSection);
- connect(m_actionConfigureSection, SIGNAL(triggered(bool)), this, SLOT(configureSection()));
-
- m_actionInsertSection = actionRegistry->makeQAction("insert_section", this);
-// addAction("insert_section", m_actionInsertSection);
- connect(m_actionInsertSection, SIGNAL(triggered(bool)), this, SLOT(insertNewSection()));
-
- m_actionSplitSections = actionRegistry->makeQAction("split_sections", this);
-// addAction("split_sections", m_actionSplitSections);
- connect(m_actionSplitSections, SIGNAL(triggered(bool)), this, SLOT(splitSections()));
-
- m_actionPasteAsText = actionRegistry->makeQAction("edit_paste_text", this);
-// addAction("edit_paste_text", m_actionPasteAsText);
- connect(m_actionPasteAsText, SIGNAL(triggered(bool)), this, SLOT(pasteAsText()));
-
- m_actionFormatBold = actionRegistry->makeQAction("format_bold", this);
-// addAction("format_bold", m_actionFormatBold);
- m_actionFormatBold->setCheckable(true);
- connect(m_actionFormatBold, SIGNAL(triggered(bool)), this, SLOT(bold(bool)));
-
- m_actionFormatItalic = actionRegistry->makeQAction("format_italic", this);
- m_actionFormatItalic->setCheckable(true);
-// addAction("format_italic", m_actionFormatItalic);
- connect(m_actionFormatItalic, SIGNAL(triggered(bool)), this, SLOT(italic(bool)));
-
- m_actionFormatUnderline = actionRegistry->makeQAction("format_underline", this);
- m_actionFormatUnderline->setCheckable(true);
-// addAction("format_underline", m_actionFormatUnderline);
- connect(m_actionFormatUnderline, SIGNAL(triggered(bool)), this, SLOT(underline(bool)));
-
- m_actionFormatStrikeOut = actionRegistry->makeQAction("format_strike", this);
- m_actionFormatStrikeOut->setCheckable(true);
-// addAction("format_strike", m_actionFormatStrikeOut);
- connect(m_actionFormatStrikeOut, SIGNAL(triggered(bool)), this, SLOT(strikeOut(bool)));
-
- QActionGroup *alignmentGroup = new QActionGroup(this);
- m_actionAlignLeft = actionRegistry->makeQAction("format_alignleft", this);
- m_actionAlignLeft->setCheckable(true);
- alignmentGroup->addAction(m_actionAlignLeft);
-// addAction("format_alignleft", m_actionAlignLeft);
- connect(m_actionAlignLeft, SIGNAL(triggered(bool)), this, SLOT(alignLeft()));
-
- m_actionAlignRight = actionRegistry->makeQAction("format_alignright", this);
- m_actionAlignRight->setCheckable(true);
- alignmentGroup->addAction(m_actionAlignRight);
-// addAction("format_alignright", m_actionAlignRight);
- connect(m_actionAlignRight, SIGNAL(triggered(bool)), this, SLOT(alignRight()));
-
- m_actionAlignCenter = actionRegistry->makeQAction("format_aligncenter", this);
- m_actionAlignCenter->setCheckable(true);
-// addAction("format_aligncenter", m_actionAlignCenter);
-
- alignmentGroup->addAction(m_actionAlignCenter);
- connect(m_actionAlignCenter, SIGNAL(triggered(bool)), this, SLOT(alignCenter()));
-
- m_actionAlignBlock = actionRegistry->makeQAction("format_alignblock", this);
- m_actionAlignBlock->setCheckable(true);
- alignmentGroup->addAction(m_actionAlignBlock);
-// addAction("format_alignblock", m_actionAlignBlock);
- connect(m_actionAlignBlock, SIGNAL(triggered(bool)), this, SLOT(alignBlock()));
-
- m_actionChangeDirection = actionRegistry->makeQAction("change_text_direction", this);
- m_actionChangeDirection->setCheckable(true);
-// addAction("change_text_direction", m_actionChangeDirection);
- connect(m_actionChangeDirection, SIGNAL(triggered()), this, SLOT(textDirectionChanged()));
-
- m_actionFormatSuper = actionRegistry->makeQAction("format_super", this);
- m_actionFormatSuper->setCheckable(true);
-// addAction("format_super", m_actionFormatSuper);
- connect(m_actionFormatSuper, SIGNAL(triggered(bool)), this, SLOT(superScript(bool)));
-
- m_actionFormatSub = actionRegistry->makeQAction("format_sub", this);
- m_actionFormatSub->setCheckable(true);
-// addAction("format_sub", m_actionFormatSub);
- connect(m_actionFormatSub, SIGNAL(triggered(bool)), this, SLOT(subScript(bool)));
-
- // TODO: check these rtl-things work properly
- m_actionFormatIncreaseIndent = actionRegistry->makeQAction("format_increaseindent", this);
-// addAction("format_increaseindent", m_actionFormatIncreaseIndent);
- connect(m_actionFormatIncreaseIndent, SIGNAL(triggered()), this, SLOT(increaseIndent()));
-
- m_actionFormatDecreaseIndent = actionRegistry->makeQAction("format_decreaseindent", this);
-// addAction("format_decreaseindent", m_actionFormatDecreaseIndent);
- connect(m_actionFormatDecreaseIndent, SIGNAL(triggered()), this, SLOT(decreaseIndent()));
-
- const char *const increaseIndentActionIconName =
- QApplication::isRightToLeft() ? koIconNameCStr("format-indent-less") : koIconNameCStr("format-indent-more");
- m_actionFormatIncreaseIndent->setIcon(koIcon(increaseIndentActionIconName));
-
- const char *const decreaseIndentActionIconName =
- QApplication::isRightToLeft() ? koIconNameCStr("format_decreaseindent") : koIconNameCStr("format-indent-less");
- m_actionFormatIncreaseIndent->setIcon(koIcon(decreaseIndentActionIconName));
-
- QAction *action = actionRegistry->makeQAction("format_bulletlist", this);
-// addAction("format_bulletlist", action);
-
- action = actionRegistry->makeQAction("format_numberlist", this);
-// addAction("format_numberlist", action);
-
- action = actionRegistry->makeQAction("fontsizeup", this);
-// addAction("fontsizeup", action);
- connect(action, SIGNAL(triggered()), this, SLOT(increaseFontSize()));
-
- action = actionRegistry->makeQAction("fontsizedown", this);
-// addAction("fontsizedown", action);
- connect(action, SIGNAL(triggered()), this, SLOT(decreaseFontSize()));
-
- m_actionFormatFontFamily = new KoFontFamilyAction(this);
- m_actionFormatFontFamily->setText(i18n("Font Family"));
-// addAction("format_fontfamily", m_actionFormatFontFamily);
- connect(m_actionFormatFontFamily, SIGNAL(triggered(QString)),
- this, SLOT(setFontFamily(QString)));
-
- m_variableMenu = new KActionMenu(i18n("Variable"), this);
-// addAction("insert_variable", m_variableMenu);
-
- // ------------------- Actions with a key binding and no GUI item
- action = actionRegistry->makeQAction("nonbreaking_space", this);
-// addAction("nonbreaking_space", action);
- connect(action, SIGNAL(triggered()), this, SLOT(nonbreakingSpace()));
-
- action = actionRegistry->makeQAction("nonbreaking_hyphen", this);
-// addAction("nonbreaking_hyphen", action);
- connect(action, SIGNAL(triggered()), this, SLOT(nonbreakingHyphen()));
-
- action = actionRegistry->makeQAction("insert_index", this);
-// addAction("insert_index", action);
- connect(action, SIGNAL(triggered()), this, SLOT(insertIndexMarker()));
-
- action = actionRegistry->makeQAction("soft_hyphen", this);
- // TODO: double check this one works, conflicts with "zoom out"
-// addAction("soft_hyphen", action);
- connect(action, SIGNAL(triggered()), this, SLOT(softHyphen()));
-
- if (useAdvancedText) {
- action = actionRegistry->makeQAction("line_break", this);
-// addAction("line_break", action);
- connect(action, SIGNAL(triggered()), this, SLOT(lineBreak()));
-
- action = actionRegistry->makeQAction("insert_framebreak", this);
-// addAction("insert_framebreak", action);
- connect(action, SIGNAL(triggered()), this, SLOT(insertFrameBreak()));
- }
-
- action = actionRegistry->makeQAction("format_font", this);
-// addAction("format_font", action);
- connect(action, SIGNAL(triggered()), this, SLOT(selectFont()));
-
- m_actionFormatFontSize = new FontSizeAction(i18n("Font Size"), this);
-// addAction("format_fontsize", m_actionFormatFontSize);
- connect(m_actionFormatFontSize, SIGNAL(fontSizeChanged(qreal)), this, SLOT(setFontSize(qreal)));
-
- m_actionFormatTextColor = new KoColorPopupAction(this);
-// addAction("format_textcolor", m_actionFormatTextColor);
- connect(m_actionFormatTextColor, SIGNAL(colorChanged(KoColor)), this, SLOT(setTextColor(KoColor)));
-
- m_actionFormatBackgroundColor = new KoColorPopupAction(this);
-// addAction("format_backgroundcolor", m_actionFormatBackgroundColor);
- connect(m_actionFormatBackgroundColor, SIGNAL(colorChanged(KoColor)), this, SLOT(setBackgroundColor(KoColor)));
-
- m_growWidthAction = actionRegistry->makeQAction("grow_to_fit_width", this);
-// addAction("grow_to_fit_width", m_growWidthAction);
- connect(m_growWidthAction, SIGNAL(triggered(bool)), this, SLOT(setGrowWidthToFit(bool)));
-
- m_growHeightAction = actionRegistry->makeQAction("grow_to_fit_height", this);
-// addAction("grow_to_fit_height", m_growHeightAction);
- connect(m_growHeightAction, SIGNAL(triggered(bool)), this, SLOT(setGrowHeightToFit(bool)));
-
- m_shrinkToFitAction = actionRegistry->makeQAction("shrink_to_fit", this);
-// addAction("shrink_to_fit", m_shrinkToFitAction);
- connect(m_shrinkToFitAction, SIGNAL(triggered(bool)), this, SLOT(setShrinkToFit(bool)));
-
- if (useAdvancedText) {
- action = actionRegistry->makeQAction("insert_table", this);
-// addAction("insert_table", action);
- connect(action, SIGNAL(triggered()), this, SLOT(insertTable()));
-
- action = actionRegistry->makeQAction("insert_tablerow_above", this);
-// addAction("insert_tablerow_above", action);
- connect(action, SIGNAL(triggered(bool)), this, SLOT(insertTableRowAbove()));
-
- action = actionRegistry->makeQAction("insert_tablerow_below", this);
-// addAction("insert_tablerow_below", action);
- connect(action, SIGNAL(triggered(bool)), this, SLOT(insertTableRowBelow()));
-
- action = actionRegistry->makeQAction("insert_tablecolumn_left", this);
-// addAction("insert_tablecolumn_left", action);
- connect(action, SIGNAL(triggered(bool)), this, SLOT(insertTableColumnLeft()));
-
- action = actionRegistry->makeQAction("insert_tablecolumn_right", this);
-// addAction("insert_tablecolumn_right", action);
- connect(action, SIGNAL(triggered(bool)), this, SLOT(insertTableColumnRight()));
-
- action = actionRegistry->makeQAction("delete_tablecolumn", this);
-// addAction("delete_tablecolumn", action);
- connect(action, SIGNAL(triggered(bool)), this, SLOT(deleteTableColumn()));
-
- action = actionRegistry->makeQAction("delete_tablerow", this);
-// addAction("delete_tablerow", action);
- connect(action, SIGNAL(triggered(bool)), this, SLOT(deleteTableRow()));
-
- action = actionRegistry->makeQAction("merge_tablecells", this);
-// addAction("merge_tablecells", action);
- connect(action, SIGNAL(triggered(bool)), this, SLOT(mergeTableCells()));
-
- action = actionRegistry->makeQAction("split_tablecells", this);
-// addAction("split_tablecells", action);
- connect(action, SIGNAL(triggered(bool)), this, SLOT(splitTableCells()));
-
- action = actionRegistry->makeQAction("activate_borderpainter", this);
-// addAction("activate_borderpainter", action);
- }
-
- action = actionRegistry->makeQAction("format_paragraph", this);
-// addAction("format_paragraph", action);
- connect(action, SIGNAL(triggered()), this, SLOT(formatParagraph()));
-
- action = actionRegistry->makeQAction("format_stylist", this);
-// addAction("format_stylist", action);
- connect(action, SIGNAL(triggered()), this, SLOT(showStyleManager()));
-
- action = KStandardAction::selectAll(this, SLOT(selectAll()), this);
-// addAction("edit_select_all", action);
-
- action = actionRegistry->makeQAction("insert_specialchar", this);
-// addAction("insert_specialchar", action);
- connect(action, SIGNAL(triggered()), this, SLOT(insertSpecialCharacter()));
-
- action = actionRegistry->makeQAction("repaint", this);
-// addAction("repaint", action);
- connect(action, SIGNAL(triggered()), this, SLOT(relayoutContent()));
-
- action = actionRegistry->makeQAction("insert_annotation", this);
-// addAction("insert_annotation", action);
- connect(action, SIGNAL(triggered()), this, SLOT(insertAnnotation()));
-
-#ifndef NDEBUG
- action = actionRegistry->makeQAction("detailed_debug_paragraphs", this);
-// addAction("detailed_debug_paragraphs", action);
- connect(action, SIGNAL(triggered()), this, SLOT(debugTextDocument()));
- action = actionRegistry->makeQAction("detailed_debug_styles", this);
-// addAction("detailed_debug_styles", action);
- connect(action, SIGNAL(triggered()), this, SLOT(debugTextStyles()));
-#endif
-}
-
-#ifndef NDEBUG
-#include "tests/MockShapes.h"
-#include <kundo2stack.h>
-#include <KisMimeDatabase.h>
-
-TextTool::TextTool(MockCanvas *canvas) // constructor for our unit tests;
- : KoToolBase(canvas),
- m_textShape(0),
- m_textShapeData(0),
- m_changeTracker(0),
- m_allowActions(true),
- m_allowAddUndoCommand(true),
- m_allowResourceManagerUpdates(true),
- m_prevCursorPosition(-1),
- m_caretTimer(this),
- m_caretTimerState(true),
- m_currentCommand(0),
- m_currentCommandHasChildren(false),
- m_specialCharacterDocker(0),
- m_textEditingPlugins(0)
- , m_editTipTimer(this)
- , m_delayedEnsureVisible(false)
- , m_tableDraggedOnce(false)
- , m_tablePenMode(false)
-{
- // we could init some vars here, but we probably don't have to
- QLocale::setDefault(QLocale("en"));
- QTextDocument *document = new QTextDocument(); // this document is leaked
-
- KoInlineTextObjectManager *inlineManager = new KoInlineTextObjectManager();
- KoTextDocument(document).setInlineTextObjectManager(inlineManager);
-
- KoTextRangeManager *locationManager = new KoTextRangeManager();
- KoTextDocument(document).setTextRangeManager(locationManager);
-
- m_textEditor = new KoTextEditor(document);
- KoTextDocument(document).setTextEditor(m_textEditor.data());
- m_toolSelection = new TextToolSelection(m_textEditor);
-
- m_changeTracker = new KoChangeTracker();
- KoTextDocument(document).setChangeTracker(m_changeTracker);
-
- KoTextDocument(document).setUndoStack(new KUndo2Stack());
-}
-#endif
-
-TextTool::~TextTool()
-{
- delete m_toolSelection;
-
- KIS_SAFE_ASSERT_RECOVER (!m_currentCommand) {
- delete m_currentCommand;
- }
-}
-
-void TextTool::showEditTip()
-{
- if (!m_textShapeData || m_editTipPointedAt.position == -1) {
- return;
- }
-
- QTextCursor c(m_textShapeData->document());
- c.setPosition(m_editTipPointedAt.position);
- QString text = "<p align=center style=\'white-space:pre\' >";
- int toolTipWidth = 0;
-
- if (m_changeTracker && m_changeTracker->containsInlineChanges(c.charFormat())
- && m_changeTracker->displayChanges()) {
- KoChangeTrackerElement *element = m_changeTracker->elementById(c.charFormat().property(KoCharacterStyle::ChangeTrackerId).toInt());
- if (element->isEnabled()) {
- QString changeType;
- if (element->getChangeType() == KoGenChange::InsertChange) {
- changeType = i18n("Insertion");
- } else if (element->getChangeType() == KoGenChange::DeleteChange) {
- changeType = i18n("Deletion");
- } else {
- changeType = i18n("Formatting");
- }
-
- text += "<b>" + changeType + "</b><br/>";
-
- QString date = element->getDate();
- //Remove the T which separates the Data and Time.
- date[10] = QLatin1Char(' ');
- date = element->getCreator() + QLatin1Char(' ') + date;
- text += date + "</p>";
-
- toolTipWidth = QFontMetrics(QToolTip::font()).boundingRect(date).width();
- }
- }
-
- if (m_editTipPointedAt.bookmark || !m_editTipPointedAt.externalHRef.isEmpty()) {
- QString help = i18n("Ctrl+click to go to link ");
- help += m_editTipPointedAt.externalHRef;
- text += help + "</p>";
- toolTipWidth = QFontMetrics(QToolTip::font()).boundingRect(help).width();
- }
-
- if (m_editTipPointedAt.note) {
- QString help = i18n("Ctrl+click to go to the note ");
- text += help + "</p>";
- toolTipWidth = QFontMetrics(QToolTip::font()).boundingRect(help).width();
- }
-
- if (m_editTipPointedAt.noteReference > 0) {
- QString help = i18n("Ctrl+click to go to the note reference");
- text += help + "</p>";
- toolTipWidth = QFontMetrics(QToolTip::font()).boundingRect(help).width();
- }
-
- QToolTip::hideText();
-
- if (toolTipWidth) {
- QRect keepRect(m_editTipPos - QPoint(3, 3), QSize(6, 6));
- QToolTip::showText(m_editTipPos - QPoint(toolTipWidth / 2, 0), text, canvas()->canvasWidget(), keepRect);
- }
-
-}
-
-void TextTool::blinkCaret()
-{
- if (!(canvas()->canvasWidget() && canvas()->canvasWidget()->hasFocus())) {
- m_caretTimer.stop();
- m_caretTimerState = false; // not visible.
- } else {
- m_caretTimerState = !m_caretTimerState;
- }
- repaintCaret();
-}
-
-void TextTool::relayoutContent()
-{
- KoTextDocumentLayout *lay = qobject_cast<KoTextDocumentLayout *>(m_textShapeData->document()->documentLayout());
- Q_ASSERT(lay);
- foreach (KoTextLayoutRootArea *rootArea, lay->rootAreas()) {
- rootArea->setDirty();
- }
- lay->emitLayoutIsDirty();
-}
-
-void TextTool::paint(QPainter &painter, const KoViewConverter &converter)
-{
- if (m_textEditor.isNull()) {
- return;
- }
- if (canvas()
- && (canvas()->canvasWidget() && canvas()->canvasWidget()->hasFocus())
- && !m_caretTimer.isActive()) { // make sure we blink
- m_caretTimer.start();
- m_caretTimerState = true;
- }
- if (!m_caretTimerState) {
- m_caretTimer.setInterval(500); // we set it lower during typing, so set it back to normal
- }
-
- if (!m_textShapeData) {
- return;
- }
- if (m_textShapeData->isDirty()) {
- return;
- }
-
- qreal zoomX, zoomY;
- converter.zoom(&zoomX, &zoomY);
-
- painter.save();
- QTransform shapeMatrix = m_textShape->absoluteTransformation();
- shapeMatrix.scale(zoomX, zoomY);
- shapeMatrix.translate(0, -m_textShapeData->documentOffset());
-
- // Possibly draw table dragging visual cues
- const qreal boxHeight = 20;
- if (m_tableDragInfo.tableHit == KoPointedAt::ColumnDivider) {
- QPointF anchorPos = m_tableDragInfo.tableDividerPos - QPointF(m_dx, 0.0);
- if (m_tableDragInfo.tableColumnDivider > 0) {
- //let's draw left
- qreal w = m_tableDragInfo.tableLeadSize - m_dx;
- QRectF rect(anchorPos - QPointF(w, 0.0), QSizeF(w, 0.0));
- QRectF drawRect(shapeMatrix.map(rect.topLeft()), shapeMatrix.map(rect.bottomRight()));
- drawRect.setHeight(boxHeight);
- drawRect.moveTop(drawRect.top() - 1.5 * boxHeight);
- QString label = m_unit.toUserStringValue(w);
- int labelWidth = QFontMetrics(QToolTip::font()).boundingRect(label).width();
- painter.fillRect(drawRect, QColor(64, 255, 64, 196));
- painter.setPen(QColor(0, 0, 0, 196));
- if (labelWidth + 10 < drawRect.width()) {
- QPointF centerLeft(drawRect.left(), drawRect.center().y());
- QPointF centerRight(drawRect.right(), drawRect.center().y());
- painter.drawLine(centerLeft, drawRect.center() - QPointF(labelWidth / 2 + 5, 0.0));
- painter.drawLine(centerLeft, centerLeft + QPointF(7, -5));
- painter.drawLine(centerLeft, centerLeft + QPointF(7, 5));
- painter.drawLine(drawRect.center() + QPointF(labelWidth / 2 + 5, 0.0), centerRight);
- painter.drawLine(centerRight, centerRight + QPointF(-7, -5));
- painter.drawLine(centerRight, centerRight + QPointF(-7, 5));
- painter.drawText(drawRect, Qt::AlignCenter, label);
- }
- }
- if (m_tableDragInfo.tableColumnDivider < m_tableDragInfo.table->columns()) {
- //let's draw right
- qreal w = m_tableDragInfo.tableTrailSize + m_dx;
- QRectF rect(anchorPos, QSizeF(w, 0.0));
- QRectF drawRect(shapeMatrix.map(rect.topLeft()), shapeMatrix.map(rect.bottomRight()));
- drawRect.setHeight(boxHeight);
- drawRect.moveTop(drawRect.top() - 1.5 * boxHeight);
- QString label;
- int labelWidth;
- if (m_tableDragWithShift) {
- label = i18n("follows along");
- labelWidth = QFontMetrics(QToolTip::font()).boundingRect(label).width();
- drawRect.setWidth(2 * labelWidth);
- QLinearGradient g(drawRect.topLeft(), drawRect.topRight());
- g.setColorAt(0.6, QColor(255, 64, 64, 196));
- g.setColorAt(1.0, QColor(255, 64, 64, 0));
- QBrush brush(g);
- painter.fillRect(drawRect, brush);
- } else {
- label = m_unit.toUserStringValue(w);
- labelWidth = QFontMetrics(QToolTip::font()).boundingRect(label).width();
- drawRect.setHeight(boxHeight);
- painter.fillRect(drawRect, QColor(64, 255, 64, 196));
- }
- painter.setPen(QColor(0, 0, 0, 196));
- if (labelWidth + 10 < drawRect.width()) {
- QPointF centerLeft(drawRect.left(), drawRect.center().y());
- QPointF centerRight(drawRect.right(), drawRect.center().y());
- painter.drawLine(centerLeft, drawRect.center() - QPointF(labelWidth / 2 + 5, 0.0));
- painter.drawLine(centerLeft, centerLeft + QPointF(7, -5));
- painter.drawLine(centerLeft, centerLeft + QPointF(7, 5));
- if (!m_tableDragWithShift) {
- painter.drawLine(drawRect.center() + QPointF(labelWidth / 2 + 5, 0.0), centerRight);
- painter.drawLine(centerRight, centerRight + QPointF(-7, -5));
- painter.drawLine(centerRight, centerRight + QPointF(-7, 5));
- }
- painter.drawText(drawRect, Qt::AlignCenter, label);
- }
- if (!m_tableDragWithShift) {
- // let's draw a helper text too
- label = i18n("Press shift to not resize this");
- labelWidth = QFontMetrics(QToolTip::font()).boundingRect(label).width();
- labelWidth += 10;
- //if (labelWidth < drawRect.width())
- {
- drawRect.moveTop(drawRect.top() + boxHeight);
- drawRect.moveLeft(drawRect.left() + (drawRect.width() - labelWidth) / 2);
- drawRect.setWidth(labelWidth);
- painter.fillRect(drawRect, QColor(64, 255, 64, 196));
- painter.drawText(drawRect, Qt::AlignCenter, label);
- }
- }
- }
- }
- // Possibly draw table dragging visual cues
- if (m_tableDragInfo.tableHit == KoPointedAt::RowDivider) {
- QPointF anchorPos = m_tableDragInfo.tableDividerPos - QPointF(0.0, m_dy);
- if (m_tableDragInfo.tableRowDivider > 0) {
- qreal h = m_tableDragInfo.tableLeadSize - m_dy;
- QRectF rect(anchorPos - QPointF(0.0, h), QSizeF(0.0, h));
- QRectF drawRect(shapeMatrix.map(rect.topLeft()), shapeMatrix.map(rect.bottomRight()));
- drawRect.setWidth(boxHeight);
- drawRect.moveLeft(drawRect.left() - 1.5 * boxHeight);
- QString label = m_unit.toUserStringValue(h);
- QRectF labelRect = QFontMetrics(QToolTip::font()).boundingRect(label);
- labelRect.setHeight(boxHeight);
- labelRect.setWidth(labelRect.width() + 10);
- labelRect.moveTopLeft(drawRect.center() - QPointF(labelRect.width(), labelRect.height()) / 2);
- painter.fillRect(drawRect, QColor(64, 255, 64, 196));
- painter.fillRect(labelRect, QColor(64, 255, 64, 196));
- painter.setPen(QColor(0, 0, 0, 196));
- if (labelRect.height() + 10 < drawRect.height()) {
- QPointF centerTop(drawRect.center().x(), drawRect.top());
- QPointF centerBottom(drawRect.center().x(), drawRect.bottom());
- painter.drawLine(centerTop, drawRect.center() - QPointF(0.0, labelRect.height() / 2 + 5));
- painter.drawLine(centerTop, centerTop + QPointF(-5, 7));
- painter.drawLine(centerTop, centerTop + QPointF(5, 7));
- painter.drawLine(drawRect.center() + QPointF(0.0, labelRect.height() / 2 + 5), centerBottom);
- painter.drawLine(centerBottom, centerBottom + QPointF(-5, -7));
- painter.drawLine(centerBottom, centerBottom + QPointF(5, -7));
- }
- painter.drawText(labelRect, Qt::AlignCenter, label);
- }
- }
- if (m_caretTimerState) {
- // Lets draw the caret ourselves, as the Qt method doesn't take cursor
- // charFormat into consideration.
- QTextBlock block = m_textEditor.data()->block();
- if (block.isValid()) {
- int posInParag = m_textEditor.data()->position() - block.position();
- if (posInParag <= block.layout()->preeditAreaPosition()) {
- posInParag += block.layout()->preeditAreaText().length();
- }
-
- QTextLine tl = block.layout()->lineForTextPosition(m_textEditor.data()->position() - block.position());
- if (tl.isValid()) {
- painter.setRenderHint(QPainter::Antialiasing, false);
- QRectF rect = caretRect(m_textEditor.data()->cursor());
- QPointF baselinePoint;
- if (tl.ascent() > 0) {
- QFontMetricsF fm(m_textEditor.data()->charFormat().font(), painter.device());
- rect.setY(rect.y() + tl.ascent() - qMin(tl.ascent(), fm.ascent()));
- rect.setHeight(qMin(tl.ascent(), fm.ascent()) + qMin(tl.descent(), fm.descent()));
- baselinePoint = QPoint(rect.x(), rect.y() + tl.ascent());
- } else {
- //line only filled with characters-without-size (eg anchors)
- // layout will make sure line has height of block font
- QFontMetricsF fm(block.charFormat().font(), painter.device());
- rect.setHeight(fm.ascent() + fm.descent());
- baselinePoint = QPoint(rect.x(), rect.y() + fm.ascent());
- }
- QRectF drawRect(shapeMatrix.map(rect.topLeft()), shapeMatrix.map(rect.bottomLeft()));
- drawRect.setWidth(2);
- painter.setCompositionMode(QPainter::RasterOp_SourceXorDestination);
- if (m_textEditor.data()->isEditProtected(true)) {
- QRectF circleRect(shapeMatrix.map(baselinePoint), QSizeF(14, 14));
- circleRect.translate(-6.5, -6.5);
- QPen pen(QColor(16, 255, 255));
- pen.setWidthF(2.0);
- painter.setPen(pen);
- painter.setRenderHint(QPainter::Antialiasing, true);
- painter.drawEllipse(circleRect);
- painter.drawLine(circleRect.topLeft() + QPointF(4.5, 4.5),
- circleRect.bottomRight() - QPointF(4.5, 4.5));
- } else {
- painter.fillRect(drawRect, QColor(128, 255, 128));
- }
- }
- }
- }
-
- painter.restore();
-}
-
-void TextTool::updateSelectedShape(const QPointF &point, bool noDocumentChange)
-{
- QRectF area(point, QSizeF(1, 1));
- if (m_textEditor.data()->hasSelection()) {
- repaintSelection();
- } else {
- repaintCaret();
- }
- QList<KoShape *> sortedShapes = canvas()->shapeManager()->shapesAt(area, true);
- std::sort(sortedShapes.begin(), sortedShapes.end(), KoShape::compareShapeZIndex);
- for (int count = sortedShapes.count() - 1; count >= 0; count--) {
- KoShape *shape = sortedShapes.at(count);
-
- if (shape->isContentProtected()) {
- continue;
- }
- TextShape *textShape = dynamic_cast<TextShape *>(shape);
- if (textShape) {
- if (textShape != m_textShape) {
- if (static_cast<KoTextShapeData *>(textShape->userData())->document() != m_textShapeData->document()) {
- //we should only change to another document if allowed
- if (noDocumentChange) {
- return;
- }
-
- // if we change to another textdocument we need to remove selection in old document
- // or it would continue to be painted etc
-
- m_textEditor.data()->setPosition(m_textEditor.data()->position());
- }
- m_textShape = textShape;
-
- setShapeData(static_cast<KoTextShapeData *>(m_textShape->userData()));
-
- // This is how we inform the rulers of the active range
- // For now we will not consider table cells, but just give the shape dimensions
- QVariant v;
- QRectF rect(QPoint(), m_textShape->size());
- rect = m_textShape->absoluteTransformation().mapRect(rect);
- v.setValue(rect);
- canvas()->resourceManager()->setResource(KoCanvasResourceProvider::ActiveRange, v);
- }
- return;
- }
- }
-}
-
-void TextTool::mousePressEvent(KoPointerEvent *event)
-{
- if (m_textEditor.isNull()) {
- return;
- }
-
- // request the software keyboard, if any
- if (event->button() == Qt::LeftButton && qApp->autoSipEnabled()) {
- QStyle::RequestSoftwareInputPanel behavior = QStyle::RequestSoftwareInputPanel(qApp->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel));
- // the two following bools just make it all a lot easier to read in the following if()
- // basically, we require a widget for this to work (passing 0 to QApplication::sendEvent
- // crashes) and there are three tests any one of which can be true to trigger the event
- const bool hasWidget = canvas()->canvasWidget();
- if ((behavior == QStyle::RSIP_OnMouseClick && hasWidget) ||
- (hasWidget && canvas()->canvasWidget()->hasFocus())) {
- QEvent event(QEvent::RequestSoftwareInputPanel);
- if (hasWidget) {
- QApplication::sendEvent(canvas()->canvasWidget(), &event);
- }
- }
- }
-
- bool shiftPressed = event->modifiers() & Qt::ShiftModifier;
-
- updateSelectedShape(event->point, shiftPressed);
-
- KoSelection *selection = canvas()->selectedShapesProxy()->selection();
- if (m_textShape && !selection->isSelected(m_textShape) && m_textShape->isSelectable()) {
- selection->deselectAll();
- selection->select(m_textShape);
- }
-
- KoPointedAt pointedAt = hitTest(event->point);
- m_tableDraggedOnce = false;
- m_clickWithinSelection = false;
- if (pointedAt.position != -1) {
- m_tablePenMode = false;
-
- if ((event->button() == Qt::LeftButton) && !shiftPressed && m_textEditor.data()->hasSelection() && m_textEditor.data()->isWithinSelection(pointedAt.position)) {
- m_clickWithinSelection = true;
- m_draggingOrigin = event->pos(); //we store the pixel pos
- } else if (!(event->button() == Qt::RightButton && m_textEditor.data()->hasSelection() && m_textEditor.data()->isWithinSelection(pointedAt.position))) {
- m_textEditor.data()->setPosition(pointedAt.position, shiftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor);
- useCursor(Qt::IBeamCursor);
- }
- m_tableDragInfo.tableHit = KoPointedAt::None;
- if (m_caretTimer.isActive()) { // make the caret not blink, (blinks again after first draw)
- m_caretTimer.stop();
- m_caretTimer.setInterval(50);
- m_caretTimer.start();
- m_caretTimerState = true; // turn caret instantly on on click
- }
- } else {
- if (event->button() == Qt::RightButton) {
- m_tablePenMode = false;
- KoTextEditingPlugin *plugin = textEditingPluginContainer()->spellcheck();
- if (plugin) {
- plugin->setCurrentCursorPosition(m_textShapeData->document(), -1);
- }
-
- event->ignore();
- } else if (m_tablePenMode) {
- m_textEditor.data()->beginEditBlock(kundo2_i18n("Change Border Formatting"));
- if (pointedAt.tableHit == KoPointedAt::ColumnDivider) {
- if (pointedAt.tableColumnDivider < pointedAt.table->columns()) {
- m_textEditor.data()->setTableBorderData(pointedAt.table,
- pointedAt.tableRowDivider, pointedAt.tableColumnDivider,
- KoBorder::LeftBorder, m_tablePenBorderData);
- }
- if (pointedAt.tableColumnDivider > 0) {
- m_textEditor.data()->setTableBorderData(pointedAt.table,
- pointedAt.tableRowDivider, pointedAt.tableColumnDivider - 1,
- KoBorder::RightBorder, m_tablePenBorderData);
- }
- } else if (pointedAt.tableHit == KoPointedAt::RowDivider) {
- if (pointedAt.tableRowDivider < pointedAt.table->rows()) {
- m_textEditor.data()->setTableBorderData(pointedAt.table,
- pointedAt.tableRowDivider, pointedAt.tableColumnDivider,
- KoBorder::TopBorder, m_tablePenBorderData);
- }
- if (pointedAt.tableRowDivider > 0) {
- m_textEditor.data()->setTableBorderData(pointedAt.table,
- pointedAt.tableRowDivider - 1, pointedAt.tableColumnDivider,
- KoBorder::BottomBorder, m_tablePenBorderData);
- }
- }
- m_textEditor.data()->endEditBlock();
- } else {
- m_tableDragInfo = pointedAt;
- m_tablePenMode = false;
- }
- return;
- }
- if (shiftPressed) { // altered selection.
- repaintSelection();
- } else {
- repaintCaret();
- }
-
- updateSelectionHandler();
- updateStyleManager();
-
- updateActions();
-
- //activate context-menu for spelling-suggestions
- if (event->button() == Qt::RightButton) {
- KoTextEditingPlugin *plugin = textEditingPluginContainer()->spellcheck();
- if (plugin) {
- plugin->setCurrentCursorPosition(m_textShapeData->document(), m_textEditor.data()->position());
- }
-
- event->ignore();
- }
-
- if (event->button() == Qt::MidButton) { // Paste
- const QMimeData *data = QApplication::clipboard()->mimeData(QClipboard::Selection);
-
- // on windows we do not have data if we try to paste this selection
- if (data) {
- m_prevCursorPosition = m_textEditor.data()->position();
- m_textEditor.data()->paste(canvas(), data, canvas()->resourceManager());
- editingPluginEvents();
- }
- }
-}
-
-void TextTool::setShapeData(KoTextShapeData *data)
-{
- bool docChanged = !data || !m_textShapeData || m_textShapeData->document() != data->document();
- if (m_textShapeData) {
- disconnect(m_textShapeData, SIGNAL(destroyed(QObject*)), this, SLOT(shapeDataRemoved()));
- }
- m_textShapeData = data;
- if (!m_textShapeData) {
- return;
- }
- connect(m_textShapeData, SIGNAL(destroyed(QObject*)), this, SLOT(shapeDataRemoved()));
- if (docChanged) {
- if (!m_textEditor.isNull()) {
- disconnect(m_textEditor.data(), SIGNAL(textFormatChanged()), this, SLOT(updateActions()));
- }
- m_textEditor = KoTextDocument(m_textShapeData->document()).textEditor();
- Q_ASSERT(m_textEditor.data());
- if (!m_toolSelection) {
- m_toolSelection = new TextToolSelection(m_textEditor.data());
- } else {
- m_toolSelection->m_editor = m_textEditor.data();
- }
-
- m_variableMenu->menu()->clear();
- KoTextDocument document(m_textShapeData->document());
- foreach (QAction *action, document.inlineTextObjectManager()->createInsertVariableActions(canvas())) {
- m_variableMenu->addAction(action);
- connect(action, SIGNAL(triggered()), this, SLOT(returnFocusToCanvas()));
- }
-
- connect(m_textEditor.data(), SIGNAL(textFormatChanged()), this, SLOT(updateActions()));
- updateActions();
- }
-}
-
-void TextTool::updateSelectionHandler()
-{
- if (m_textEditor) {
- emit selectionChanged(m_textEditor.data()->hasSelection());
- if (m_textEditor.data()->hasSelection()) {
- QClipboard *clipboard = QApplication::clipboard();
- if (clipboard->supportsSelection()) {
- clipboard->setText(m_textEditor.data()->selectedText(), QClipboard::Selection);
- }
- }
- }
-
- KoCanvasResourceProvider *p = canvas()->resourceManager();
- m_allowResourceManagerUpdates = false;
- if (m_textEditor && m_textShapeData) {
- p->setResource(KoText::CurrentTextPosition, m_textEditor.data()->position());
- p->setResource(KoText::CurrentTextAnchor, m_textEditor.data()->anchor());
- QVariant variant;
- variant.setValue<void *>(m_textShapeData->document());
- p->setResource(KoText::CurrentTextDocument, variant);
- } else {
- p->clearResource(KoText::CurrentTextPosition);
- p->clearResource(KoText::CurrentTextAnchor);
- p->clearResource(KoText::CurrentTextDocument);
- }
- m_allowResourceManagerUpdates = true;
-}
-
-QMimeData *TextTool::generateMimeData() const
-{
- if (!m_textShapeData || m_textEditor.isNull() || !m_textEditor.data()->hasSelection()) {
- return 0;
- }
- int from = m_textEditor.data()->position();
- int to = m_textEditor.data()->anchor();
- KoTextOdfSaveHelper saveHelper(m_textShapeData->document(), from, to);
- KoTextDrag drag;
-
-#ifdef SHOULD_BUILD_RDF
- KoDocumentResourceManager *rm = 0;
- if (canvas()->shapeController()) {
- rm = canvas()->shapeController()->resourceManager();
- }
-
- if (rm && rm->hasResource(KoText::DocumentRdf)) {
- KoDocumentRdfBase *rdf = qobject_cast<KoDocumentRdfBase *>(rm->resource(KoText::DocumentRdf).value<QObject *>());
- if (rdf) {
- saveHelper.setRdfModel(rdf->model());
- }
- }
-#endif
- drag.setOdf(KoOdf::mimeType(KoOdf::Text), saveHelper);
- QTextDocumentFragment fragment = m_textEditor.data()->selection();
- drag.setData("text/html", fragment.toHtml("utf-8").toUtf8());
- drag.setData("text/plain", fragment.toPlainText().toUtf8());
-
- return drag.takeMimeData();
-}
-
-TextEditingPluginContainer *TextTool::textEditingPluginContainer()
-{
- m_textEditingPlugins = canvas()->resourceManager()->
- resource(TextEditingPluginContainer::ResourceId).value<TextEditingPluginContainer *>();
-
- if (m_textEditingPlugins == 0) {
- m_textEditingPlugins = new TextEditingPluginContainer(canvas()->resourceManager());
- QVariant variant;
- variant.setValue(m_textEditingPlugins.data());
- canvas()->resourceManager()->setResource(TextEditingPluginContainer::ResourceId, variant);
-
- foreach (KoTextEditingPlugin *plugin, m_textEditingPlugins->values()) {
- connect(plugin, SIGNAL(startMacro(QString)),
- this, SLOT(startMacro(QString)));
- connect(plugin, SIGNAL(stopMacro()), this, SLOT(stopMacro()));
- QHash<QString, QAction *> actions = plugin->actions();
- QHash<QString, QAction *>::iterator i = actions.begin();
- while (i != actions.end()) {
-// addAction(i.key(), i.value());
- ++i;
- }
- }
-
- }
- return m_textEditingPlugins;
-}
-
-void TextTool::copy() const
-{
- QMimeData *mimeData = generateMimeData();
- if (mimeData) {
- QApplication::clipboard()->setMimeData(mimeData);
- }
-}
-
-void TextTool::deleteSelection()
-{
- m_textEditor.data()->deleteChar();
- editingPluginEvents();
-}
-
-bool TextTool::paste()
-{
- const QMimeData *data = QApplication::clipboard()->mimeData(QClipboard::Clipboard);
-
- // on windows we do not have data if we try to paste the selection
- if (!data) {
- return false;
- }
-
- // since this is not paste-as-text we will not paste in urls, but instead let KoToolProxy solve it
- if (data->hasUrls()) {
- return false;
- }
-
- if (data->hasFormat(KoOdf::mimeType(KoOdf::Text))
- || data->hasText()) {
- m_prevCursorPosition = m_textEditor.data()->position();
- m_textEditor.data()->paste(canvas(), data);
- editingPluginEvents();
- return true;
- }
-
- return false;
-}
-
-void TextTool::cut()
-{
- if (m_textEditor.data()->hasSelection()) {
- copy();
- KUndo2Command *topCmd = m_textEditor.data()->beginEditBlock(kundo2_i18n("Cut"));
- m_textEditor.data()->deleteChar(false, topCmd);
- m_textEditor.data()->endEditBlock();
- }
-}
-
-void TextTool::dragMoveEvent(QDragMoveEvent *event, const QPointF &point)
-{
- if (event->mimeData()->hasFormat(KoOdf::mimeType(KoOdf::Text))
- || event->mimeData()->hasFormat(KoOdf::mimeType(KoOdf::OpenOfficeClipboard))
- || event->mimeData()->hasText()) {
- if (m_drag) {
- event->setDropAction(Qt::MoveAction);
- event->accept();
- } else if (event->proposedAction() == Qt::CopyAction) {
- event->acceptProposedAction();
- } else {
- event->ignore();
- return;
- }
- KoPointedAt pointedAt = hitTest(point);
-
- if (pointedAt.position == -1) {
- event->ignore();
- }
- if (m_caretTimer.isActive()) { // make the caret not blink, (blinks again after first draw)
- m_caretTimer.stop();
- m_caretTimer.setInterval(50);
- m_caretTimer.start();
- m_caretTimerState = true; // turn caret instantly on on click
- }
-
- if (m_preDragSelection.cursor.isNull()) {
- repaintSelection();
-
- m_preDragSelection.cursor = QTextCursor(*m_textEditor.data()->cursor());
-
- if (m_drag) {
- // Make a selection that looks like the current cursor selection
- // so we can move the real carent around freely
- QVector< QAbstractTextDocumentLayout::Selection > sels = KoTextDocument(m_textShapeData->document()).selections();
-
- m_preDragSelection.format = QTextCharFormat();
- m_preDragSelection.format.setBackground(qApp->palette().brush(QPalette::Highlight));
- m_preDragSelection.format.setForeground(qApp->palette().brush(QPalette::HighlightedText));
- sels.append(m_preDragSelection);
- KoTextDocument(m_textShapeData->document()).setSelections(sels);
- } // else we wantt the selection ot disappaear
- }
- repaintCaret(); // will erase caret
- m_textEditor.data()->setPosition(pointedAt.position);
- repaintCaret(); // will paint caret in new spot
-
- // Selection has visually not appeared at a new spot so no need to repaint it
- }
-}
-
-void TextTool::dragLeaveEvent(QDragLeaveEvent *event)
-{
- if (m_drag) {
- // restore the old selections
- QVector< QAbstractTextDocumentLayout::Selection > sels = KoTextDocument(m_textShapeData->document()).selections();
- sels.pop_back();
- KoTextDocument(m_textShapeData->document()).setSelections(sels);
- }
-
- repaintCaret(); // will erase caret in old spot
- m_textEditor.data()->setPosition(m_preDragSelection.cursor.anchor());
- m_textEditor.data()->setPosition(m_preDragSelection.cursor.position(), QTextCursor::KeepAnchor);
- repaintCaret(); // will paint caret in new spot
-
- if (!m_drag) {
- repaintSelection(); // will paint selection again
- }
-
- // mark that we now are back to normal selection
- m_preDragSelection.cursor = QTextCursor();
- event->accept();
-}
-
-void TextTool::dropEvent(QDropEvent *event, const QPointF &)
-{
- if (m_drag) {
- // restore the old selections
- QVector< QAbstractTextDocumentLayout::Selection > sels = KoTextDocument(m_textShapeData->document()).selections();
- sels.pop_back();
- KoTextDocument(m_textShapeData->document()).setSelections(sels);
- }
-
- QTextCursor insertCursor(*m_textEditor.data()->cursor());
-
- m_textEditor.data()->setPosition(m_preDragSelection.cursor.anchor());
- m_textEditor.data()->setPosition(m_preDragSelection.cursor.position(), QTextCursor::KeepAnchor);
- repaintSelection(); // will erase the selection in new spot
- if (m_drag) {
- m_textEditor.data()->deleteChar();
- }
- m_prevCursorPosition = insertCursor.position();
- m_textEditor.data()->setPosition(m_prevCursorPosition);
- m_textEditor.data()->paste(canvas(), event->mimeData());
- m_textEditor.data()->setPosition(m_prevCursorPosition);
- //since the paste made insertCursor we can now use that for the end position
- m_textEditor.data()->setPosition(insertCursor.position(), QTextCursor::KeepAnchor);
-
- // mark that we no are back to normal selection
- m_preDragSelection.cursor = QTextCursor();
- event->accept();
-}
-
-KoPointedAt TextTool::hitTest(const QPointF &point) const
-{
- if (!m_textShape || !m_textShapeData) {
- return KoPointedAt();
- }
- QPointF p = m_textShape->convertScreenPos(point);
- KoTextLayoutRootArea *rootArea = m_textShapeData->rootArea();
- return rootArea ? rootArea->hitTest(p, Qt::FuzzyHit) : KoPointedAt();
-}
-
-void TextTool::mouseDoubleClickEvent(KoPointerEvent *event)
-{
- if (canvas()->shapeManager()->shapeAt(event->point) != m_textShape) {
- event->ignore(); // allow the event to be used by another
- return;
- }
-
- if (event->modifiers() & Qt::ShiftModifier) {
- // When whift is pressed we behave as a single press
- return mousePressEvent(event);
- }
-
- m_textEditor.data()->select(QTextCursor::WordUnderCursor);
-
- m_clickWithinSelection = false;
-
- repaintSelection();
- updateSelectionHandler();
-}
-
-void TextTool::mouseTripleClickEvent(KoPointerEvent *event)
-{
- if (canvas()->shapeManager()->shapeAt(event->point) != m_textShape) {
- event->ignore(); // allow the event to be used by another
- return;
- }
-
- if (event->modifiers() & Qt::ShiftModifier) {
- // When whift is pressed we behave as a single press
- return mousePressEvent(event);
- }
-
- m_textEditor.data()->clearSelection();
- m_textEditor.data()->movePosition(QTextCursor::StartOfBlock);
- m_textEditor.data()->movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
-
- m_clickWithinSelection = false;
-
- repaintSelection();
- updateSelectionHandler();
-}
-
-void TextTool::mouseMoveEvent(KoPointerEvent *event)
-{
- m_editTipPos = event->globalPos();
-
- if (event->buttons()) {
- updateSelectedShape(event->point, true);
- }
-
- m_editTipTimer.stop();
-
- if (QToolTip::isVisible()) {
- QToolTip::hideText();
- }
-
- KoPointedAt pointedAt = hitTest(event->point);
-
- if (event->buttons() == Qt::NoButton) {
- if (m_tablePenMode) {
- if (pointedAt.tableHit == KoPointedAt::ColumnDivider || pointedAt.tableHit == KoPointedAt::RowDivider) {
- useTableBorderCursor();
- } else {
- useCursor(Qt::IBeamCursor);
- }
- // do nothing else
- return;
- }
-
- if (!m_textShapeData || pointedAt.position < 0) {
- if (pointedAt.tableHit == KoPointedAt::ColumnDivider) {
- useCursor(Qt::SplitHCursor);
- m_draggingOrigin = event->point;
- } else if (pointedAt.tableHit == KoPointedAt::RowDivider) {
- if (pointedAt.tableRowDivider > 0) {
- useCursor(Qt::SplitVCursor);
- m_draggingOrigin = event->point;
- } else {
- useCursor(Qt::IBeamCursor);
- }
- } else {
- useCursor(Qt::IBeamCursor);
- }
- return;
- }
-
- QTextCursor mouseOver(m_textShapeData->document());
- mouseOver.setPosition(pointedAt.position);
-
- if (m_changeTracker && m_changeTracker->containsInlineChanges(mouseOver.charFormat())) {
- m_editTipPointedAt = pointedAt;
- if (QToolTip::isVisible()) {
- QTimer::singleShot(0, this, SLOT(showEditTip()));
- } else {
- m_editTipTimer.start();
- }
- }
-
- if ((pointedAt.bookmark || !pointedAt.externalHRef.isEmpty()) || pointedAt.note || (pointedAt.noteReference > 0)) {
- if (event->modifiers() & Qt::ControlModifier) {
- useCursor(Qt::PointingHandCursor);
- }
- m_editTipPointedAt = pointedAt;
- if (QToolTip::isVisible()) {
- QTimer::singleShot(0, this, SLOT(showEditTip()));
- } else {
- m_editTipTimer.start();
- }
- return;
- }
-
- // check if mouse pointer is over shape with hyperlink
- KoShape *selectedShape = canvas()->shapeManager()->shapeAt(event->point);
- if (selectedShape != 0 && selectedShape != m_textShape && selectedShape->hyperLink().size() != 0) {
- useCursor(Qt::PointingHandCursor);
- return;
- }
-
- useCursor(Qt::IBeamCursor);
-
- // Set Arrow Cursor when mouse is on top of annotation shape.
- if (selectedShape) {
- if (selectedShape->shapeId() == "AnnotationTextShapeID") {
- QPointF point(event->point);
- if (point.y() <= (selectedShape->position().y() + 25)) {
- useCursor(Qt::ArrowCursor);
- }
- }
- }
-
- return;
- } else {
- if (m_tableDragInfo.tableHit == KoPointedAt::ColumnDivider) {
- m_tableDragWithShift = event->modifiers() & Qt::ShiftModifier;
- if (m_tableDraggedOnce) {
- canvas()->shapeController()->resourceManager()->undoStack()->undo();
- }
- KUndo2Command *topCmd = m_textEditor.data()->beginEditBlock(kundo2_i18n("Adjust Column Width"));
- m_dx = m_draggingOrigin.x() - event->point.x();
- if (m_tableDragInfo.tableColumnDivider < m_tableDragInfo.table->columns()
- && m_tableDragInfo.tableTrailSize + m_dx < 0) {
- m_dx = -m_tableDragInfo.tableTrailSize;
- }
- if (m_tableDragInfo.tableColumnDivider > 0) {
- if (m_tableDragInfo.tableLeadSize - m_dx < 0) {
- m_dx = m_tableDragInfo.tableLeadSize;
- }
- m_textEditor.data()->adjustTableColumnWidth(m_tableDragInfo.table,
- m_tableDragInfo.tableColumnDivider - 1,
- m_tableDragInfo.tableLeadSize - m_dx, topCmd);
- } else {
- m_textEditor.data()->adjustTableWidth(m_tableDragInfo.table, -m_dx, 0.0);
- }
- if (m_tableDragInfo.tableColumnDivider < m_tableDragInfo.table->columns()) {
- if (!m_tableDragWithShift) {
- m_textEditor.data()->adjustTableColumnWidth(m_tableDragInfo.table,
- m_tableDragInfo.tableColumnDivider,
- m_tableDragInfo.tableTrailSize + m_dx, topCmd);
- }
- } else {
- m_tableDragWithShift = true; // act like shift pressed
- }
- if (m_tableDragWithShift) {
- m_textEditor.data()->adjustTableWidth(m_tableDragInfo.table, 0.0, m_dx);
- }
- m_textEditor.data()->endEditBlock();
- m_tableDragInfo.tableDividerPos.setY(m_textShape->convertScreenPos(event->point).y());
- if (m_tableDraggedOnce) {
- //we need to redraw like this so we update outside the textshape too
- if (canvas()->canvasWidget()) {
- canvas()->canvasWidget()->update();
- }
- }
- m_tableDraggedOnce = true;
- } else if (m_tableDragInfo.tableHit == KoPointedAt::RowDivider) {
- if (m_tableDraggedOnce) {
- canvas()->shapeController()->resourceManager()->undoStack()->undo();
- }
- if (m_tableDragInfo.tableRowDivider > 0) {
- KUndo2Command *topCmd = m_textEditor.data()->beginEditBlock(kundo2_i18n("Adjust Row Height"));
- m_dy = m_draggingOrigin.y() - event->point.y();
-
- if (m_tableDragInfo.tableLeadSize - m_dy < 0) {
- m_dy = m_tableDragInfo.tableLeadSize;
- }
-
- m_textEditor.data()->adjustTableRowHeight(m_tableDragInfo.table,
- m_tableDragInfo.tableRowDivider - 1,
- m_tableDragInfo.tableLeadSize - m_dy, topCmd);
-
- m_textEditor.data()->endEditBlock();
-
- m_tableDragInfo.tableDividerPos.setX(m_textShape->convertScreenPos(event->point).x());
- if (m_tableDraggedOnce) {
- //we need to redraw like this so we update outside the textshape too
- if (canvas()->canvasWidget()) {
- canvas()->canvasWidget()->update();
- }
- }
- m_tableDraggedOnce = true;
- }
-
- } else if (m_tablePenMode) {
- // do nothing
- } else if (m_clickWithinSelection) {
- if (!m_drag && (event->pos() - m_draggingOrigin).manhattanLength()
- >= QApplication::startDragDistance()) {
- QMimeData *mimeData = generateMimeData();
- if (mimeData) {
- m_drag = new QDrag(canvas()->canvasWidget());
- m_drag->setMimeData(mimeData);
-
- m_drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::CopyAction);
-
- m_drag = 0;
- }
- }
- } else {
- useCursor(Qt::IBeamCursor);
- if (pointedAt.position == m_textEditor.data()->position()) {
- return;
- }
- if (pointedAt.position >= 0) {
- if (m_textEditor.data()->hasSelection()) {
- repaintSelection(); // will erase selection
- } else {
- repaintCaret();
- }
-
- m_textEditor.data()->setPosition(pointedAt.position, QTextCursor::KeepAnchor);
-
- if (m_textEditor.data()->hasSelection()) {
- repaintSelection();
- } else {
- repaintCaret();
- }
- }
- }
-
- updateSelectionHandler();
- }
-}
-
-void TextTool::mouseReleaseEvent(KoPointerEvent *event)
-{
- event->ignore();
- editingPluginEvents();
-
- m_tableDragInfo.tableHit = KoPointedAt::None;
- if (m_tableDraggedOnce) {
- m_tableDraggedOnce = false;
- //we need to redraw like this so we update outside the textshape too
- if (canvas()->canvasWidget()) {
- canvas()->canvasWidget()->update();
- }
- }
-
- if (!m_textShapeData) {
- return;
- }
-
- // check if mouse pointer is not over some shape with hyperlink
- KoShape *selectedShape = canvas()->shapeManager()->shapeAt(event->point);
- if (selectedShape != 0 && selectedShape != m_textShape && selectedShape->hyperLink().size() != 0) {
- QString url = selectedShape->hyperLink();
- runUrl(event, url);
- return;
- }
-
- KoPointedAt pointedAt = hitTest(event->point);
-
- if (m_clickWithinSelection && !m_drag) {
- if (m_caretTimer.isActive()) { // make the caret not blink, (blinks again after first draw)
- m_caretTimer.stop();
- m_caretTimer.setInterval(50);
- m_caretTimer.start();
- m_caretTimerState = true; // turn caret instantly on on click
- }
- repaintCaret(); // will erase caret
- repaintSelection(); // will erase selection
- m_textEditor.data()->setPosition(pointedAt.position);
- repaintCaret(); // will paint caret in new spot
- }
-
- // Is there an anchor here ?
- if ((event->modifiers() & Qt::ControlModifier) && !m_textEditor.data()->hasSelection()) {
- if (pointedAt.bookmark) {
- m_textEditor.data()->setPosition(pointedAt.bookmark->rangeStart());
- ensureCursorVisible();
- event->accept();
- return;
- }
- if (pointedAt.note) {
- m_textEditor.data()->setPosition(pointedAt.note->textFrame()->firstPosition());
- ensureCursorVisible();
- event->accept();
- return;
- }
- if (pointedAt.noteReference > 0) {
- m_textEditor.data()->setPosition(pointedAt.noteReference);
- ensureCursorVisible();
- event->accept();
- return;
- }
- if (!pointedAt.externalHRef.isEmpty()) {
- runUrl(event, pointedAt.externalHRef);
- }
- }
-}
-
-void TextTool::keyPressEvent(QKeyEvent *event)
-{
- int destinationPosition = -1; // for those cases where the moveOperation is not relevant;
- QTextCursor::MoveOperation moveOperation = QTextCursor::NoMove;
- KoTextEditor *textEditor = m_textEditor.data();
- m_tablePenMode = false; // keypress always stops the table (border) pen mode
- Q_ASSERT(textEditor);
- if (event->key() == Qt::Key_Backspace) {
- if (!textEditor->hasSelection() && textEditor->block().textList()
- && (textEditor->position() == textEditor->block().position())
- && !(m_changeTracker && m_changeTracker->recordChanges())) {
- if (!textEditor->blockFormat().boolProperty(KoParagraphStyle::UnnumberedListItem)) {
- // backspace at beginning of numbered list item, makes it unnumbered
- textEditor->toggleListNumbering(false);
- } else {
- KoListLevelProperties llp;
- llp.setStyle(KoListStyle::None);
- llp.setLevel(0);
- // backspace on numbered, empty parag, removes numbering.
- textEditor->setListProperties(llp);
- }
- } else if (textEditor->position() > 0 || textEditor->hasSelection()) {
- if (!textEditor->hasSelection() && event->modifiers() & Qt::ControlModifier) { // delete prev word.
- textEditor->movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor);
- }
- textEditor->deletePreviousChar();
-
- editingPluginEvents();
- }
- } else if ((event->key() == Qt::Key_Tab)
- && ((!textEditor->hasSelection() && (textEditor->position() == textEditor->block().position())) || (textEditor->block().document()->findBlock(textEditor->anchor()) != textEditor->block().document()->findBlock(textEditor->position()))) && textEditor->block().textList()) {
- ChangeListLevelCommand::CommandType type = ChangeListLevelCommand::IncreaseLevel;
- ChangeListLevelCommand *cll = new ChangeListLevelCommand(*textEditor->cursor(), type, 1);
- textEditor->addCommand(cll);
- editingPluginEvents();
- } else if ((event->key() == Qt::Key_Backtab)
- && ((!textEditor->hasSelection() && (textEditor->position() == textEditor->block().position())) || (textEditor->block().document()->findBlock(textEditor->anchor()) != textEditor->block().document()->findBlock(textEditor->position()))) && textEditor->block().textList() && !(m_changeTracker && m_changeTracker->recordChanges())) {
- ChangeListLevelCommand::CommandType type = ChangeListLevelCommand::DecreaseLevel;
- ChangeListLevelCommand *cll = new ChangeListLevelCommand(*textEditor->cursor(), type, 1);
- textEditor->addCommand(cll);
- editingPluginEvents();
- } else if (event->key() == Qt::Key_Delete) {
- if (!textEditor->hasSelection() && event->modifiers() & Qt::ControlModifier) {// delete next word.
- textEditor->movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor);
- }
- // the event only gets through when the Del is not used in the app
- // if the app forwards Del then deleteSelection is used
- textEditor->deleteChar();
- editingPluginEvents();
- } else if ((event->key() == Qt::Key_Left) && (event->modifiers() & Qt::ControlModifier) == 0) {
- moveOperation = QTextCursor::Left;
- } else if ((event->key() == Qt::Key_Right) && (event->modifiers() & Qt::ControlModifier) == 0) {
- moveOperation = QTextCursor::Right;
- } else if ((event->key() == Qt::Key_Up) && (event->modifiers() & Qt::ControlModifier) == 0) {
- moveOperation = QTextCursor::Up;
- } else if ((event->key() == Qt::Key_Down) && (event->modifiers() & Qt::ControlModifier) == 0) {
- moveOperation = QTextCursor::Down;
- } else {
- // check for shortcuts.
- QKeySequence item(event->key() | ((Qt::ControlModifier | Qt::AltModifier) & event->modifiers()));
- if (hit(item, KStandardShortcut::Begin))
- // Goto beginning of the document. Default: Ctrl-Home
- {
- destinationPosition = 0;
- } else if (hit(item, KStandardShortcut::End)) {
- // Goto end of the document. Default: Ctrl-End
- if (m_textShapeData) {
- QTextBlock last = m_textShapeData->document()->lastBlock();
- destinationPosition = last.position() + last.length() - 1;
- }
- } else if (hit(item, KStandardShortcut::Prior)) { // page up
- // Scroll up one page. Default: Prior
- event->ignore(); // let app level actions handle it
- return;
- } else if (hit(item, KStandardShortcut::Next)) {
- // Scroll down one page. Default: Next
- event->ignore(); // let app level actions handle it
- return;
- } else if (hit(item, KStandardShortcut::BeginningOfLine))
- // Goto beginning of current line. Default: Home
- {
- moveOperation = QTextCursor::StartOfLine;
- } else if (hit(item, KStandardShortcut::EndOfLine))
- // Goto end of current line. Default: End
- {
- moveOperation = QTextCursor::EndOfLine;
- } else if (hit(item, KStandardShortcut::BackwardWord)) {
- moveOperation = QTextCursor::WordLeft;
- } else if (hit(item, KStandardShortcut::ForwardWord)) {
- moveOperation = QTextCursor::WordRight;
- }
-#ifdef Q_OS_MACOS
- // Don't reject "alt" key, it may be used for typing text on Mac OS
- else if ((event->modifiers() & Qt::ControlModifier) || event->text().length() == 0) {
-#else
- else if ((event->modifiers() & (Qt::ControlModifier | Qt::AltModifier)) || event->text().length() == 0) {
-#endif
- event->ignore();
- return;
- } else if ((event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return)) {
- m_prevCursorPosition = textEditor->position();
- textEditor->newLine();
- updateActions();
- editingPluginEvents();
- } else if ((event->key() == Qt::Key_Tab || !(event->text().length() == 1 && !event->text().at(0).isPrint()))) { // insert the text
- m_prevCursorPosition = textEditor->position();
- startingSimpleEdit(); //signal editing plugins that this is a simple edit
- textEditor->insertText(event->text());
- editingPluginEvents();
- }
- }
- if (moveOperation != QTextCursor::NoMove || destinationPosition != -1) {
- useCursor(Qt::BlankCursor);
- bool shiftPressed = event->modifiers() & Qt::ShiftModifier;
- if (textEditor->hasSelection()) {
- repaintSelection(); // will erase selection
- } else {
- repaintCaret();
- }
- QTextBlockFormat format = textEditor->blockFormat();
-
- KoText::Direction dir = static_cast<KoText::Direction>(format.intProperty(KoParagraphStyle::TextProgressionDirection));
- bool isRtl;
- if (dir == KoText::AutoDirection) {
- isRtl = textEditor->block().text().isRightToLeft();
- } else {
- isRtl = dir == KoText::RightLeftTopBottom;
- }
-
- if (isRtl) { // if RTL toggle direction of cursor movement.
- switch (moveOperation) {
- case QTextCursor::Left: moveOperation = QTextCursor::Right; break;
- case QTextCursor::Right: moveOperation = QTextCursor::Left; break;
- case QTextCursor::WordRight: moveOperation = QTextCursor::WordLeft; break;
- case QTextCursor::WordLeft: moveOperation = QTextCursor::WordRight; break;
- default: break;
- }
- }
- int prevPosition = textEditor->position();
- if (moveOperation != QTextCursor::NoMove)
- textEditor->movePosition(moveOperation,
- shiftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor);
- else
- textEditor->setPosition(destinationPosition,
- shiftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor);
- if (moveOperation == QTextCursor::Down && prevPosition == textEditor->position()) {
- // change behavior a little big from Qt; at the bottom of the doc we go to the end of the doc
- textEditor->movePosition(QTextCursor::End,
- shiftPressed ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor);
- }
- if (shiftPressed) { // altered selection.
- repaintSelection();
- } else {
- repaintCaret();
- }
- updateActions();
- editingPluginEvents();
- }
- if (m_caretTimer.isActive()) { // make the caret not blink but decide on the action if its visible or not.
- m_caretTimer.stop();
- m_caretTimer.setInterval(50);
- m_caretTimer.start();
- m_caretTimerState = true; // turn caret on while typing
- }
- if (moveOperation != QTextCursor::NoMove)
- // this difference in handling is need to prevent leaving a trail of old cursors onscreen
- {
- ensureCursorVisible();
- } else {
- m_delayedEnsureVisible = true;
- }
- updateActions();
- updateSelectionHandler();
-}
-
-QVariant TextTool::inputMethodQuery(Qt::InputMethodQuery query, const KoViewConverter &converter) const
-{
- KoTextEditor *textEditor = m_textEditor.data();
- if (!textEditor || !m_textShapeData) {
- return QVariant();
- }
-
- switch (query) {
- case Qt::ImMicroFocus: {
- // The rectangle covering the area of the input cursor in widget coordinates.
- QRectF rect = caretRect(textEditor->cursor());
- rect.moveTop(rect.top() - m_textShapeData->documentOffset());
- QTransform shapeMatrix = m_textShape->absoluteTransformation();
- qreal zoomX, zoomY;
- converter.zoom(&zoomX, &zoomY);
- shapeMatrix.scale(zoomX, zoomY);
- rect = shapeMatrix.mapRect(rect);
- return rect.toRect();
- }
- case Qt::ImFont:
- // The currently used font for text input.
- return textEditor->charFormat().font();
- case Qt::ImCursorPosition:
- // The logical position of the cursor within the text surrounding the input area (see ImSurroundingText).
- return textEditor->position() - textEditor->block().position();
- case Qt::ImSurroundingText:
- // The plain text around the input area, for example the current paragraph.
- return textEditor->block().text();
- case Qt::ImCurrentSelection:
- // The currently selected text.
- return textEditor->selectedText();
- default:
- ; // Qt 4.6 adds ImMaximumTextLength and ImAnchorPosition
- }
- return QVariant();
-}
-
-void TextTool::inputMethodEvent(QInputMethodEvent *event)
-{
- KoTextEditor *textEditor = m_textEditor.data();
- if (textEditor == 0) {
- return;
- }
- if (event->replacementLength() > 0) {
- textEditor->setPosition(textEditor->position() + event->replacementStart());
- for (int i = event->replacementLength(); i > 0; --i) {
- textEditor->deleteChar();
- }
- }
- if (!event->commitString().isEmpty()) {
- QKeyEvent ke(QEvent::KeyPress, -1, 0, event->commitString());
- keyPressEvent(&ke);
- // The cursor may reside in a different block before vs. after keyPressEvent.
- QTextBlock block = textEditor->block();
- QTextLayout *layout = block.layout();
- Q_ASSERT(layout);
- layout->setPreeditArea(-1, QString());
- } else {
- QTextBlock block = textEditor->block();
- QTextLayout *layout = block.layout();
- Q_ASSERT(layout);
- layout->setPreeditArea(textEditor->position() - block.position(), event->preeditString());
- const_cast<QTextDocument *>(textEditor->document())->markContentsDirty(textEditor->position(), event->preeditString().length());
- }
- event->accept();
-}
-
-void TextTool::ensureCursorVisible(bool moveView)
-{
- KoTextEditor *textEditor = m_textEditor.data();
- if (!textEditor || !m_textShapeData) {
- return;
- }
-
- bool upToDate;
- QRectF cRect = caretRect(textEditor->cursor(), &upToDate);
-
- KoTextDocumentLayout *lay = qobject_cast<KoTextDocumentLayout *>(m_textShapeData->document()->documentLayout());
- Q_ASSERT(lay);
- KoTextLayoutRootArea *rootArea = lay->rootAreaForPoint(cRect.center());
- if (rootArea && rootArea->associatedShape() && m_textShapeData->rootArea() != rootArea) {
- // If we have changed root area we need to update m_textShape and m_textShapeData
- m_textShape = static_cast<TextShape *>(rootArea->associatedShape());
- Q_ASSERT(m_textShape);
- disconnect(m_textShapeData, SIGNAL(destroyed(QObject*)), this, SLOT(shapeDataRemoved()));
- m_textShapeData = static_cast<KoTextShapeData *>(m_textShape->userData());
- Q_ASSERT(m_textShapeData);
- connect(m_textShapeData, SIGNAL(destroyed(QObject*)), this, SLOT(shapeDataRemoved()));
- }
-
- if (!moveView) {
- return;
- }
-
- if (!upToDate) { // paragraph is not yet layouted.
- // The number one usecase for this is when the user pressed enter.
- // try to do it on next caret blink
- m_delayedEnsureVisible = true;
- return; // we shouldn't move to an obsolete position
- }
- cRect.moveTop(cRect.top() - m_textShapeData->documentOffset());
- canvas()->ensureVisible(m_textShape->absoluteTransformation().mapRect(cRect));
-}
-
-void TextTool::keyReleaseEvent(QKeyEvent *event)
-{
- event->accept();
-}
-
-void TextTool::updateActions()
-{
- bool notInAnnotation = true; // no annotation shape anymore!
- KoTextEditor *textEditor = m_textEditor.data();
- if (textEditor == 0) {
- return;
- }
- m_allowActions = false;
-
- //Update the characterStyle related GUI elements
- QTextCharFormat cf = textEditor->charFormat();
- m_actionFormatBold->setChecked(cf.fontWeight() > QFont::Normal);
- m_actionFormatItalic->setChecked(cf.fontItalic());
- m_actionFormatUnderline->setChecked(cf.intProperty(KoCharacterStyle::UnderlineType) != KoCharacterStyle::NoLineType);
- m_actionFormatStrikeOut->setChecked(cf.intProperty(KoCharacterStyle::StrikeOutType) != KoCharacterStyle::NoLineType);
- bool super = false, sub = false;
- switch (cf.verticalAlignment()) {
- case QTextCharFormat::AlignSuperScript:
- super = true;
- break;
- case QTextCharFormat::AlignSubScript:
- sub = true;
- break;
- default:;
- }
- m_actionFormatSuper->setChecked(super);
- m_actionFormatSub->setChecked(sub);
- m_actionFormatFontSize->setFontSize(cf.font().pointSizeF());
- m_actionFormatFontFamily->setFont(cf.font().family());
-
- KoTextShapeData::ResizeMethod resizemethod = KoTextShapeData::AutoResize;
- if (m_textShapeData) {
- resizemethod = m_textShapeData->resizeMethod();
- }
- m_shrinkToFitAction->setEnabled(resizemethod != KoTextShapeData::AutoResize && notInAnnotation);
- m_shrinkToFitAction->setChecked(resizemethod == KoTextShapeData::ShrinkToFitResize);
-
- m_growWidthAction->setEnabled(resizemethod != KoTextShapeData::AutoResize && notInAnnotation);
- m_growWidthAction->setChecked(resizemethod == KoTextShapeData::AutoGrowWidth || resizemethod == KoTextShapeData::AutoGrowWidthAndHeight);
-
- m_growHeightAction->setEnabled(resizemethod != KoTextShapeData::AutoResize && notInAnnotation);
- m_growHeightAction->setChecked(resizemethod == KoTextShapeData::AutoGrowHeight || resizemethod == KoTextShapeData::AutoGrowWidthAndHeight);
-
- //update paragraphStyle GUI element
- QTextBlockFormat bf = textEditor->blockFormat();
-
- if (bf.hasProperty(KoParagraphStyle::TextProgressionDirection)) {
- switch (bf.intProperty(KoParagraphStyle::TextProgressionDirection)) {
- case KoText::RightLeftTopBottom:
- m_actionChangeDirection->setChecked(true);
- break;
- case KoText::LeftRightTopBottom:
- default:
- m_actionChangeDirection->setChecked(false);
- break;
- }
- } else {
- m_actionChangeDirection->setChecked(textEditor->block().text().isRightToLeft());
- }
- if (bf.alignment() == Qt::AlignLeading || bf.alignment() == Qt::AlignTrailing) {
- bool revert = (textEditor->block().layout()->textOption().textDirection() == Qt::RightToLeft);
- if ((bf.alignment() == Qt::AlignLeading) ^ revert) {
- m_actionAlignLeft->setChecked(true);
- } else {
- m_actionAlignRight->setChecked(true);
- }
- } else if (bf.alignment() == Qt::AlignHCenter) {
- m_actionAlignCenter->setChecked(true);
- }
- if (bf.alignment() == Qt::AlignJustify) {
- m_actionAlignBlock->setChecked(true);
- } else if (bf.alignment() == (Qt::AlignLeft | Qt::AlignAbsolute)) {
- m_actionAlignLeft->setChecked(true);
- } else if (bf.alignment() == (Qt::AlignRight | Qt::AlignAbsolute)) {
- m_actionAlignRight->setChecked(true);
- }
-
- if (textEditor->block().textList()) {
- QTextListFormat listFormat = textEditor->block().textList()->format();
- if (listFormat.intProperty(KoListStyle::Level) > 1) {
- m_actionFormatDecreaseIndent->setEnabled(true);
- } else {
- m_actionFormatDecreaseIndent->setEnabled(false);
- }
-
- if (listFormat.intProperty(KoListStyle::Level) < 10) {
- m_actionFormatIncreaseIndent->setEnabled(true);
- } else {
- m_actionFormatIncreaseIndent->setEnabled(false);
- }
- } else {
- m_actionFormatDecreaseIndent->setEnabled(textEditor->blockFormat().leftMargin() > 0.);
- }
-
- m_allowActions = true;
-
- bool useAdvancedText = !(canvas()->resourceManager()->intResource(KoCanvasResourceProvider::ApplicationSpeciality)
- & KoCanvasResourceProvider::NoAdvancedText);
- if (useAdvancedText) {
- action("insert_table")->setEnabled(notInAnnotation);
-
- bool hasTable = textEditor->currentTable();
- action("insert_tablerow_above")->setEnabled(hasTable && notInAnnotation);
- action("insert_tablerow_below")->setEnabled(hasTable && notInAnnotation);
- action("insert_tablecolumn_left")->setEnabled(hasTable && notInAnnotation);
- action("insert_tablecolumn_right")->setEnabled(hasTable && notInAnnotation);
- action("delete_tablerow")->setEnabled(hasTable && notInAnnotation);
- action("delete_tablecolumn")->setEnabled(hasTable && notInAnnotation);
- action("merge_tablecells")->setEnabled(hasTable && notInAnnotation);
- action("split_tablecells")->setEnabled(hasTable && notInAnnotation);
- action("activate_borderpainter")->setEnabled(hasTable && notInAnnotation);
- }
- action("insert_annotation")->setEnabled(notInAnnotation);
-
- ///TODO if selection contains several different format
- emit blockChanged(textEditor->block());
- emit charFormatChanged(cf, textEditor->blockCharFormat());
- emit blockFormatChanged(bf);
-}
-
-QMenu *TextTool::popupActionsMenu()
-{
- return m_contextMenu.data();
-}
-
-void TextTool::updateStyleManager()
-{
- if (!m_textShapeData) {
- return;
- }
- KoStyleManager *styleManager = KoTextDocument(m_textShapeData->document()).styleManager();
- emit styleManagerChanged(styleManager);
-
- //TODO move this to its own method
- m_changeTracker = KoTextDocument(m_textShapeData->document()).changeTracker();
-}
-
-void TextTool::activate(ToolActivation activation, const QSet<KoShape *> &shapes)
-{
- KoToolBase::activate(activation, shapes);
-
- m_caretTimer.start();
- m_caretTimerState = true;
- foreach (KoShape *shape, shapes) {
- m_textShape = dynamic_cast<TextShape *>(shape);
- if (m_textShape) {
- break;
- }
- }
- if (!m_textShape) { // none found
- emit done();
- // This is how we inform the rulers of the active range
- // No shape means no active range
- canvas()->resourceManager()->setResource(KoCanvasResourceProvider::ActiveRange, QVariant(QRectF()));
- return;
- }
-
- // This is how we inform the rulers of the active range
- // For now we will not consider table cells, but just give the shape dimensions
- QVariant v;
- QRectF rect(QPoint(), m_textShape->size());
- rect = m_textShape->absoluteTransformation().mapRect(rect);
- v.setValue(rect);
- canvas()->resourceManager()->setResource(KoCanvasResourceProvider::ActiveRange, v);
- if ((!m_oldTextEditor.isNull()) && m_oldTextEditor.data()->document() != static_cast<KoTextShapeData *>(m_textShape->userData())->document()) {
- m_oldTextEditor.data()->setPosition(m_oldTextEditor.data()->position());
- //we need to redraw like this so we update the old textshape wherever it may be
- if (canvas()->canvasWidget()) {
- canvas()->canvasWidget()->update();
- }
- }
- setShapeData(static_cast<KoTextShapeData *>(m_textShape->userData()));
- useCursor(Qt::IBeamCursor);
-
- updateStyleManager();
- repaintSelection();
- updateSelectionHandler();
- updateActions();
- if (m_specialCharacterDocker) {
- m_specialCharacterDocker->setEnabled(true);
- }
-}
-
-void TextTool::deactivate()
-{
- m_caretTimer.stop();
- m_caretTimerState = false;
- repaintCaret();
- m_textShape = 0;
-
- // This is how we inform the rulers of the active range
- // No shape means no active range
- canvas()->resourceManager()->setResource(KoCanvasResourceProvider::ActiveRange, QVariant(QRectF()));
-
- m_oldTextEditor = m_textEditor;
- setShapeData(0);
-
- updateSelectionHandler();
- if (m_specialCharacterDocker) {
- m_specialCharacterDocker->setEnabled(false);
- m_specialCharacterDocker->setVisible(false);
- }
-
- KoToolBase::deactivate();
-}
-
-void TextTool::repaintDecorations()
-{
- if (m_textShapeData) {
- repaintSelection();
- }
-}
-
-void TextTool::repaintCaret()
-{
- KoTextEditor *textEditor = m_textEditor.data();
- if (!textEditor || !m_textShapeData) {
- return;
- }
-
- KoTextDocumentLayout *lay = qobject_cast<KoTextDocumentLayout *>(m_textShapeData->document()->documentLayout());
- Q_ASSERT(lay); Q_UNUSED(lay);
-
- // If we have changed root area we need to update m_textShape and m_textShapeData
- if (m_delayedEnsureVisible) {
- m_delayedEnsureVisible = false;
- ensureCursorVisible();
- return;
- }
-
- ensureCursorVisible(false); // ensures the various vars are updated
-
- bool upToDate;
- QRectF repaintRect = caretRect(textEditor->cursor(), &upToDate);
- repaintRect.moveTop(repaintRect.top() - m_textShapeData->documentOffset());
- if (repaintRect.isValid()) {
- repaintRect = m_textShape->absoluteTransformation().mapRect(repaintRect);
-
- // Make sure there is enough space to show an icon
- QRectF iconSize = canvas()->viewConverter()->viewToDocument(QRect(0, 0, 18, 18));
- repaintRect.setX(repaintRect.x() - iconSize.width() / 2);
- repaintRect.setRight(repaintRect.right() + iconSize.width() / 2);
- repaintRect.setTop(repaintRect.y() - iconSize.height() / 2);
- repaintRect.setBottom(repaintRect.bottom() + iconSize.height() / 2);
- canvas()->updateCanvas(repaintRect);
- }
-}
-
-void TextTool::repaintSelection()
-{
- KoTextEditor *textEditor = m_textEditor.data();
- if (textEditor == 0) {
- return;
- }
- QTextCursor cursor = *textEditor->cursor();
-
- QList<TextShape *> shapes;
- KoTextDocumentLayout *lay = qobject_cast<KoTextDocumentLayout *>(textEditor->document()->documentLayout());
- Q_ASSERT(lay);
- foreach (KoShape *shape, lay->shapes()) {
- TextShape *textShape = dynamic_cast<TextShape *>(shape);
- if (textShape == 0) { // when the shape is being deleted its no longer a TextShape but a KoShape
- continue;
- }
-
- //Q_ASSERT(!shapes.contains(textShape));
- if (!shapes.contains(textShape)) {
- shapes.append(textShape);
- }
- }
-
- // loop over all shapes that contain the text and update per shape.
- QRectF repaintRect = textRect(cursor);
- foreach (TextShape *ts, shapes) {
- QRectF rect = repaintRect;
- rect.moveTop(rect.y() - ts->textShapeData()->documentOffset());
- rect = ts->absoluteTransformation().mapRect(rect);
- QRectF r = ts->boundingRect().intersected(rect);
- canvas()->updateCanvas(r);
- }
-}
-
-QRectF TextTool::caretRect(QTextCursor *cursor, bool *upToDate) const
-{
- QTextCursor tmpCursor(*cursor);
- tmpCursor.setPosition(cursor->position()); // looses the anchor
-
- QRectF rect = textRect(tmpCursor);
- if (rect.size() == QSizeF(0, 0)) {
- if (upToDate) {
- *upToDate = false;
- }
- rect = m_lastImMicroFocus; // prevent block changed but layout not done
- } else {
- if (upToDate) {
- *upToDate = true;
- }
- m_lastImMicroFocus = rect;
- }
- return rect;
-}
-
-QRectF TextTool::textRect(QTextCursor &cursor) const
-{
- if (!m_textShapeData) {
- return QRectF();
- }
- KoTextEditor *textEditor = m_textEditor.data();
- KoTextDocumentLayout *lay = qobject_cast<KoTextDocumentLayout *>(textEditor->document()->documentLayout());
- return lay->selectionBoundingBox(cursor);
-}
-
-KoToolSelection *TextTool::selection()
-{
- return m_toolSelection;
-}
-
-QList<QPointer<QWidget> > TextTool::createOptionWidgets()
-{
- QList<QPointer<QWidget> > widgets;
- SimpleCharacterWidget *scw = new SimpleCharacterWidget(this, 0);
- SimpleParagraphWidget *spw = new SimpleParagraphWidget(this, 0);
- if (m_textEditor.data()) {
-// connect(m_textEditor.data(), SIGNAL(paragraphStyleApplied(KoParagraphStyle*)), spw, SLOT(slotParagraphStyleApplied(KoParagraphStyle*)));
-// connect(m_textEditor.data(), SIGNAL(characterStyleApplied(KoCharacterStyle*)), scw, SLOT(slotCharacterStyleApplied(KoCharacterStyle*)));
- //initialise the char- and par- widgets with the current block and formats.
- scw->setCurrentBlockFormat(m_textEditor.data()->blockFormat());
- scw->setCurrentFormat(m_textEditor.data()->charFormat(), m_textEditor.data()-> blockCharFormat());
- spw->setCurrentBlock(m_textEditor.data()->block());
- spw->setCurrentFormat(m_textEditor.data()->blockFormat());
- }
- SimpleTableWidget *stw = new SimpleTableWidget(this, 0);
- SimpleInsertWidget *siw = new SimpleInsertWidget(this, 0);
-
- /* We do not use these for now. Let's see if they become useful at a certain point in time. If not, we can remove the whole chain (SimpleCharWidget, SimpleParWidget, DockerStyleComboModel)
- if (m_textShapeData && KoTextDocument(m_textShapeData->document()).styleManager()) {
- scw->setInitialUsedStyles(KoTextDocument(m_textShapeData->document()).styleManager()->usedCharacterStyles());
- spw->setInitialUsedStyles(KoTextDocument(m_textShapeData->document()).styleManager()->usedParagraphStyles());
- }
- */
- // Connect to/with simple character widget (docker)
- connect(this, SIGNAL(styleManagerChanged(KoStyleManager*)), scw, SLOT(setStyleManager(KoStyleManager*)));
- connect(this, SIGNAL(charFormatChanged(QTextCharFormat,QTextCharFormat)), scw, SLOT(setCurrentFormat(QTextCharFormat,QTextCharFormat)));
- connect(this, SIGNAL(blockFormatChanged(QTextBlockFormat)), scw, SLOT(setCurrentBlockFormat(QTextBlockFormat)));
- connect(scw, SIGNAL(doneWithFocus()), this, SLOT(returnFocusToCanvas()));
- connect(scw, SIGNAL(characterStyleSelected(KoCharacterStyle*)), this, SLOT(setStyle(KoCharacterStyle*)));
- connect(scw, SIGNAL(newStyleRequested(QString)), this, SLOT(createStyleFromCurrentCharFormat(QString)));
- connect(scw, SIGNAL(showStyleManager(int)), this, SLOT(showStyleManager(int)));
-
- // Connect to/with simple paragraph widget (docker)
- connect(this, SIGNAL(styleManagerChanged(KoStyleManager*)), spw, SLOT(setStyleManager(KoStyleManager*)));
- connect(this, SIGNAL(blockChanged(QTextBlock)), spw, SLOT(setCurrentBlock(QTextBlock)));
- connect(this, SIGNAL(blockFormatChanged(QTextBlockFormat)), spw, SLOT(setCurrentFormat(QTextBlockFormat)));
- connect(spw, SIGNAL(doneWithFocus()), this, SLOT(returnFocusToCanvas()));
- connect(spw, SIGNAL(paragraphStyleSelected(KoParagraphStyle*)), this, SLOT(setStyle(KoParagraphStyle*)));
- connect(spw, SIGNAL(newStyleRequested(QString)), this, SLOT(createStyleFromCurrentBlockFormat(QString)));
- connect(spw, SIGNAL(showStyleManager(int)), this, SLOT(showStyleManager(int)));
-
- // Connect to/with simple table widget (docker)
- connect(this, SIGNAL(styleManagerChanged(KoStyleManager*)), stw, SLOT(setStyleManager(KoStyleManager*)));
- connect(stw, SIGNAL(doneWithFocus()), this, SLOT(returnFocusToCanvas()));
- connect(stw, SIGNAL(tableBorderDataUpdated(KoBorder::BorderData)), this, SLOT(setTableBorderData(KoBorder::BorderData)));
-
- // Connect to/with simple insert widget (docker)
- connect(siw, SIGNAL(doneWithFocus()), this, SLOT(returnFocusToCanvas()));
- connect(siw, SIGNAL(insertTableQuick(int,int)), this, SLOT(insertTableQuick(int,int)));
-
- updateStyleManager();
- if (m_textShape) {
- updateActions();
- }
- scw->setWindowTitle(i18n("Character"));
- widgets.append(scw);
- spw->setWindowTitle(i18n("Paragraph"));
- widgets.append(spw);
-
- bool useAdvancedText = !(canvas()->resourceManager()->intResource(KoCanvasResourceProvider::ApplicationSpeciality)
- & KoCanvasResourceProvider::NoAdvancedText);
- if (useAdvancedText) {
- stw->setWindowTitle(i18n("Table"));
- widgets.append(stw);
- siw->setWindowTitle(i18n("Insert"));
- widgets.append(siw);
- }
- return widgets;
-}
-
-void TextTool::returnFocusToCanvas()
-{
- canvas()->canvasWidget()->setFocus();
-}
-
-void TextTool::startEditing(KUndo2Command *command)
-{
- m_currentCommand = command;
- m_currentCommandHasChildren = true;
-}
-
-void TextTool::stopEditing()
-{
- m_currentCommand = 0;
- m_currentCommandHasChildren = false;
-}
-
-void TextTool::insertNewSection()
-{
- KoTextEditor *textEditor = m_textEditor.data();
- if (!textEditor) {
- return;
- }
-
- textEditor->newSection();
-}
-
-void TextTool::configureSection()
-{
- KoTextEditor *textEditor = m_textEditor.data();
- if (!textEditor) {
- return;
- }
-
- SectionFormatDialog *dia = new SectionFormatDialog(0, m_textEditor.data());
- dia->exec();
- delete dia;
-
- returnFocusToCanvas();
- updateActions();
-}
-
-void TextTool::splitSections()
-{
- KoTextEditor *textEditor = m_textEditor.data();
- if (!textEditor) {
- return;
- }
-
- SectionsSplitDialog *dia = new SectionsSplitDialog(0, m_textEditor.data());
- dia->exec();
- delete dia;
-
- returnFocusToCanvas();
- updateActions();
-}
-
-void TextTool::pasteAsText()
-{
- KoTextEditor *textEditor = m_textEditor.data();
- if (!textEditor) {
- return;
- }
-
- const QMimeData *data = QApplication::clipboard()->mimeData(QClipboard::Clipboard);
- // on windows we do not have data if we try to paste this selection
- if (!data) {
- return;
- }
-
- if (data->hasFormat(KoOdf::mimeType(KoOdf::Text))
- || data->hasText()) {
- m_prevCursorPosition = m_textEditor.data()->position();
- m_textEditor.data()->paste(canvas(), data, true);
- editingPluginEvents();
- }
-}
-
-void TextTool::bold(bool bold)
-{
- m_textEditor.data()->bold(bold);
-}
-
-void TextTool::italic(bool italic)
-{
- m_textEditor.data()->italic(italic);
-}
-
-void TextTool::underline(bool underline)
-{
- m_textEditor.data()->underline(underline);
-}
-
-void TextTool::strikeOut(bool strikeOut)
-{
- m_textEditor.data()->strikeOut(strikeOut);
-}
-
-void TextTool::nonbreakingSpace()
-{
- if (!m_allowActions || !m_textEditor.data()) {
- return;
- }
- m_textEditor.data()->insertText(QString(QChar(Qt::Key_nobreakspace)));
-}
-
-void TextTool::nonbreakingHyphen()
-{
- if (!m_allowActions || !m_textEditor.data()) {
- return;
- }
- m_textEditor.data()->insertText(QString(QChar(0x2013)));
-}
-
-void TextTool::softHyphen()
-{
- if (!m_allowActions || !m_textEditor.data()) {
- return;
- }
- m_textEditor.data()->insertText(QString(QChar(Qt::Key_hyphen)));
-}
-
-void TextTool::lineBreak()
-{
- if (!m_allowActions || !m_textEditor.data()) {
- return;
- }
- m_textEditor.data()->insertText(QString(QChar(0x2028)));
-}
-
-void TextTool::alignLeft()
-{
- if (!m_allowActions || !m_textEditor.data()) {
- return;
- }
- m_textEditor.data()->setHorizontalTextAlignment(Qt::AlignLeft | Qt::AlignAbsolute);
-}
-
-void TextTool::alignRight()
-{
- if (!m_allowActions || !m_textEditor.data()) {
- return;
- }
- m_textEditor.data()->setHorizontalTextAlignment(Qt::AlignRight | Qt::AlignAbsolute);
-}
-
-void TextTool::alignCenter()
-{
- if (!m_allowActions || !m_textEditor.data()) {
- return;
- }
- m_textEditor.data()->setHorizontalTextAlignment(Qt::AlignHCenter);
-}
-
-void TextTool::alignBlock()
-{
- if (!m_allowActions || !m_textEditor.data()) {
- return;
- }
- m_textEditor.data()->setHorizontalTextAlignment(Qt::AlignJustify);
-}
-
-void TextTool::superScript(bool on)
-{
- if (!m_allowActions || !m_textEditor.data()) {
- return;
- }
- if (on) {
- m_actionFormatSub->setChecked(false);
- }
- m_textEditor.data()->setVerticalTextAlignment(on ? Qt::AlignTop : Qt::AlignVCenter);
-}
-
-void TextTool::subScript(bool on)
-{
- if (!m_allowActions || !m_textEditor.data()) {
- return;
- }
- if (on) {
- m_actionFormatSuper->setChecked(false);
- }
- m_textEditor.data()->setVerticalTextAlignment(on ? Qt::AlignBottom : Qt::AlignVCenter);
-}
-
-void TextTool::increaseIndent()
-{
- if (!m_allowActions || !m_textEditor.data()) {
- return;
- }
- if (m_textEditor.data()->block().textList()) {
- ChangeListLevelCommand::CommandType type = ChangeListLevelCommand::IncreaseLevel;
- ChangeListLevelCommand *cll = new ChangeListLevelCommand(*(m_textEditor.data()->cursor()), type, 1);
- m_textEditor.data()->addCommand(cll);
- editingPluginEvents();
- } else {
- m_textEditor.data()->increaseIndent();
- }
- updateActions();
-}
-
-void TextTool::decreaseIndent()
-{
- if (!m_allowActions || !m_textEditor.data()) {
- return;
- }
- if (m_textEditor.data()->block().textList()) {
- ChangeListLevelCommand::CommandType type = ChangeListLevelCommand::DecreaseLevel;
- ChangeListLevelCommand *cll = new ChangeListLevelCommand(*(m_textEditor.data()->cursor()), type, 1);
- m_textEditor.data()->addCommand(cll);
- editingPluginEvents();
- } else {
- m_textEditor.data()->decreaseIndent();
- }
- updateActions();
-}
-
-void TextTool::decreaseFontSize()
-{
- if (!m_allowActions || !m_textEditor.data()) {
- return;
- }
- m_textEditor.data()->decreaseFontSize();
-}
-
-void TextTool::increaseFontSize()
-{
- if (!m_allowActions || !m_textEditor.data()) {
- return;
- }
- m_textEditor.data()->increaseFontSize();
-}
-
-void TextTool::setFontFamily(const QString &font)
-{
- if (!m_allowActions || !m_textEditor.data()) {
- return;
- }
- m_textEditor.data()->setFontFamily(font);
-}
-
-void TextTool::setFontSize(qreal size)
-{
- if (!m_allowActions || !m_textEditor.data() || m_textEditor.isNull()) {
- return;
- }
- m_textEditor.data()->setFontSize(size);
-}
-
-void TextTool::insertIndexMarker()
-{
- // TODO handle result when we figure out how to report errors from a tool.
- m_textEditor.data()->insertIndexMarker();
-}
-
-void TextTool::insertFrameBreak()
-{
- m_textEditor.data()->insertFrameBreak();
-
- ensureCursorVisible();
- m_delayedEnsureVisible = true;
-}
-
-void TextTool::setStyle(KoCharacterStyle *style)
-{
- KoCharacterStyle *charStyle = style;
- //if the given KoCharacterStyle is null, set the KoParagraphStyle character properties
- if (!charStyle) {
- charStyle = static_cast<KoCharacterStyle *>(KoTextDocument(m_textShapeData->document()).styleManager()->paragraphStyle(m_textEditor.data()->blockFormat().intProperty(KoParagraphStyle::StyleId)));
- }
- if (charStyle) {
- m_textEditor.data()->setStyle(charStyle);
- updateActions();
- }
-}
-
-void TextTool::setStyle(KoParagraphStyle *style)
-{
- m_textEditor.data()->setStyle(style);
- updateActions();
-}
-
-void TextTool::insertTable()
-{
- TableDialog *dia = new TableDialog(0);
- if (dia->exec() == TableDialog::Accepted) {
- m_textEditor.data()->insertTable(dia->rows(), dia->columns());
- }
- delete dia;
-
- updateActions();
-}
-
-void TextTool::insertTableQuick(int rows, int columns)
-{
- m_textEditor.data()->insertTable(rows, columns);
- updateActions();
-}
-
-void TextTool::insertTableRowAbove()
-{
- m_textEditor.data()->insertTableRowAbove();
-}
-
-void TextTool::insertTableRowBelow()
-{
- m_textEditor.data()->insertTableRowBelow();
-}
-
-void TextTool::insertTableColumnLeft()
-{
- m_textEditor.data()->insertTableColumnLeft();
-}
-
-void TextTool::insertTableColumnRight()
-{
- m_textEditor.data()->insertTableColumnRight();
-}
-
-void TextTool::deleteTableColumn()
-{
- m_textEditor.data()->deleteTableColumn();
-}
-
-void TextTool::deleteTableRow()
-{
- m_textEditor.data()->deleteTableRow();
-}
-
-void TextTool::mergeTableCells()
-{
- m_textEditor.data()->mergeTableCells();
-}
-
-void TextTool::splitTableCells()
-{
- m_textEditor.data()->splitTableCells();
-}
-
-void TextTool::useTableBorderCursor()
-{
- static const unsigned char data[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x68, 0x00,
- 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0xfd, 0x00,
- 0x00, 0x80, 0x7e, 0x00, 0x00, 0x40, 0x3f, 0x00, 0x00, 0xa0, 0x1f, 0x00,
- 0x00, 0xd0, 0x0f, 0x00, 0x00, 0xe8, 0x07, 0x00, 0x00, 0xf4, 0x03, 0x00,
- 0x00, 0xe4, 0x01, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x80, 0x41, 0x00, 0x00,
- 0x40, 0x32, 0x00, 0x00, 0xa0, 0x0f, 0x00, 0x00, 0xd0, 0x0f, 0x00, 0x00,
- 0xd0, 0x0f, 0x00, 0x00, 0xe8, 0x07, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00,
- 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
-
- QBitmap result(32, 32);
- result.fill(Qt::color0);
- QPainter painter(&result);
- painter.drawPixmap(0, 0, QBitmap::fromData(QSize(25, 23), data));
- QBitmap brushMask = result.createHeuristicMask(false);
-
- useCursor(QCursor(result, brushMask, 1, 21));
-}
-
-void TextTool::setTableBorderData(const KoBorder::BorderData &data)
-{
- m_tablePenMode = true;
- m_tablePenBorderData = data;
-}
-
-void TextTool::formatParagraph()
-{
- ParagraphSettingsDialog *dia = new ParagraphSettingsDialog(this, m_textEditor.data());
- dia->setUnit(canvas()->unit());
- dia->setImageCollection(m_textShape->imageCollection());
- dia->exec();
- delete dia;
- returnFocusToCanvas();
-}
-
-void TextTool::testSlot(bool on)
-{
- qDebug() << "signal received. bool:" << on;
-}
-
-void TextTool::selectAll()
-{
- KoTextEditor *textEditor = m_textEditor.data();
- if (!textEditor || !m_textShapeData) {
- return;
- }
- const int selectionLength = qAbs(textEditor->position() - textEditor->anchor());
- textEditor->movePosition(QTextCursor::End);
- textEditor->setPosition(0, QTextCursor::KeepAnchor);
- repaintSelection();
- if (selectionLength != qAbs(textEditor->position() - textEditor->anchor())) { // it actually changed
- emit selectionChanged(true);
- }
-}
-
-void TextTool::startMacro(const QString &title)
-{
- if (title != i18n("Key Press") && title != i18n("Autocorrection")) { //dirty hack while waiting for refactor of text editing
- m_textTyping = false;
- } else {
- m_textTyping = true;
- }
-
- if (title != i18n("Delete") && title != i18n("Autocorrection")) { //same dirty hack as above
- m_textDeleting = false;
- } else {
- m_textDeleting = true;
- }
-
- if (m_currentCommand) {
- return;
- }
-
- class MacroCommand : public KUndo2Command
- {
- public:
- MacroCommand(const KUndo2MagicString &title) : KUndo2Command(title), m_first(true) {}
- void redo() override
- {
- if (!m_first) {
- KUndo2Command::redo();
- }
- m_first = false;
- }
- bool mergeWith(const KUndo2Command *) override
- {
- return false;
- }
- bool m_first;
- };
-
- /**
- * FIXME: The messages generated by the Text Tool might not be
- * properly translated, since we don't control it in
- * type-safe way.
- *
- * The title is already translated string, we just don't
- * have any type control over it.
- */
- KUndo2MagicString title_workaround = kundo2_noi18n(title);
- m_currentCommand = new MacroCommand(title_workaround);
- m_currentCommandHasChildren = false;
-}
-
-void TextTool::stopMacro()
-{
- if (!m_currentCommand) {
- return;
- }
- if (!m_currentCommandHasChildren) {
- delete m_currentCommand;
- }
- m_currentCommand = 0;
-}
-
-void TextTool::showStyleManager(int styleId)
-{
- if (!m_textShapeData) {
- return;
- }
- KoStyleManager *styleManager = KoTextDocument(m_textShapeData->document()).styleManager();
- Q_ASSERT(styleManager);
- if (!styleManager) {
- return; //don't crash
- }
- StyleManagerDialog *dia = new StyleManagerDialog(canvas()->canvasWidget());
- dia->setStyleManager(styleManager);
- dia->setUnit(canvas()->unit());
-
- KoParagraphStyle *paragraphStyle = styleManager->paragraphStyle(styleId);
- if (paragraphStyle) {
- dia->setParagraphStyle(paragraphStyle);
- }
- KoCharacterStyle *characterStyle = styleManager->characterStyle(styleId);
- if (characterStyle) {
- dia->setCharacterStyle(characterStyle);
- }
- dia->show();
-}
-
-void TextTool::startTextEditingPlugin(const QString &pluginId)
-{
- KoTextEditingPlugin *plugin = textEditingPluginContainer()->plugin(pluginId);
- if (plugin) {
- if (m_textEditor.data()->hasSelection()) {
- plugin->checkSection(m_textShapeData->document(), m_textEditor.data()->selectionStart(), m_textEditor.data()->selectionEnd());
- } else {
- plugin->finishedWord(m_textShapeData->document(), m_textEditor.data()->position());
- }
- }
-}
-
-void TextTool::canvasResourceChanged(int key, const QVariant &var)
-{
- if (m_textEditor.isNull()) {
- return;
- }
- if (!m_textShapeData) {
- return;
- }
- if (m_allowResourceManagerUpdates == false) {
- return;
- }
- if (key == KoText::CurrentTextPosition) {
- repaintSelection();
- m_textEditor.data()->setPosition(var.toInt());
- ensureCursorVisible();
- } else if (key == KoText::CurrentTextAnchor) {
- repaintSelection();
- int pos = m_textEditor.data()->position();
- m_textEditor.data()->setPosition(var.toInt());
- m_textEditor.data()->setPosition(pos, QTextCursor::KeepAnchor);
- } else if (key == KoCanvasResourceProvider::Unit) {
- m_unit = var.value<KoUnit>();
- } else {
- return;
- }
-
- repaintSelection();
-}
-
-void TextTool::insertSpecialCharacter()
-{
- if (m_specialCharacterDocker == 0) {
- m_specialCharacterDocker = new InsertCharacter(canvas()->canvasWidget());
- connect(m_specialCharacterDocker, SIGNAL(insertCharacter(QString)),
- this, SLOT(insertString(QString)));
- }
-
- m_specialCharacterDocker->show();
-}
-
-void TextTool::insertString(const QString &string)
-{
- m_textEditor.data()->insertText(string);
- returnFocusToCanvas();
-}
-
-void TextTool::selectFont()
-{
- FontDia *fontDlg = new FontDia(m_textEditor.data());
- fontDlg->exec();
- delete fontDlg;
- returnFocusToCanvas();
-}
-
-void TextTool::shapeAddedToCanvas()
-{
- qDebug();
- if (m_textShape) {
- KoSelection *selection = canvas()->selectedShapesProxy()->selection();
- KoShape *shape = selection->firstSelectedShape();
- if (shape != m_textShape && canvas()->shapeManager()->shapes().contains(m_textShape)) {
- // this situation applies when someone, not us, changed the selection by selecting another
- // text shape. Possibly by adding one.
- // Deselect the new shape again, so we can keep editing what we were already editing
- selection->select(m_textShape);
- selection->deselect(shape);
- }
- }
-}
-
-void TextTool::shapeDataRemoved()
-{
- m_textShapeData = 0;
- m_textShape = 0;
- if (!m_textEditor.isNull() && !m_textEditor.data()->cursor()->isNull()) {
- const QTextDocument *doc = m_textEditor.data()->document();
- Q_ASSERT(doc);
- KoTextDocumentLayout *lay = qobject_cast<KoTextDocumentLayout *>(doc->documentLayout());
- if (!lay || lay->shapes().isEmpty()) {
- emit done();
- return;
- }
- m_textShape = static_cast<TextShape *>(lay->shapes().first());
- m_textShapeData = static_cast<KoTextShapeData *>(m_textShape->userData());
- connect(m_textShapeData, SIGNAL(destroyed(QObject*)), this, SLOT(shapeDataRemoved()));
- }
-}
-
-void TextTool::createStyleFromCurrentBlockFormat(const QString &name)
-{
- KoTextDocument document(m_textShapeData->document());
- KoStyleManager *styleManager = document.styleManager();
- KoParagraphStyle *paragraphStyle = new KoParagraphStyle(m_textEditor.data()->blockFormat(), m_textEditor.data()->charFormat());
- paragraphStyle->setName(name);
- styleManager->add(paragraphStyle);
- m_textEditor.data()->setStyle(paragraphStyle);
- emit charFormatChanged(m_textEditor.data()->charFormat(), m_textEditor.data()->blockCharFormat());
- emit blockFormatChanged(m_textEditor.data()->blockFormat());
-}
-
-void TextTool::createStyleFromCurrentCharFormat(const QString &name)
-{
- KoCharacterStyle blankStyle;
- KoTextDocument document(m_textShapeData->document());
- KoStyleManager *styleManager = document.styleManager();
- KoCharacterStyle *originalCharStyle = styleManager->characterStyle(m_textEditor.data()->charFormat().intProperty(KoCharacterStyle::StyleId));
- KoCharacterStyle *autoStyle;
- if (!originalCharStyle) {
- originalCharStyle = &blankStyle;
- autoStyle = originalCharStyle->autoStyle(m_textEditor.data()->charFormat(), m_textEditor.data()->blockCharFormat());
- autoStyle->setParentStyle(0);
- } else {
- autoStyle = originalCharStyle->autoStyle(m_textEditor.data()->charFormat(), m_textEditor.data()->blockCharFormat());
- }
- autoStyle->setName(name);
- styleManager->add(autoStyle);
- m_textEditor.data()->setStyle(autoStyle);
- emit charFormatChanged(m_textEditor.data()->charFormat(), m_textEditor.data()->blockCharFormat());
-}
-
-// ---------- editing plugins methods.
-void TextTool::editingPluginEvents()
-{
- if (m_prevCursorPosition == -1 || m_prevCursorPosition == m_textEditor.data()->position()) {
- qDebug() << "m_prevCursorPosition=" << m_prevCursorPosition << "m_textEditor.data()->position()=" << m_textEditor.data()->position();
- return;
- }
-
- QTextBlock block = m_textEditor.data()->block();
- if (!block.contains(m_prevCursorPosition)) {
- qDebug() << "m_prevCursorPosition=" << m_prevCursorPosition;
- finishedWord();
- finishedParagraph();
- m_prevCursorPosition = -1;
- } else {
- int from = m_prevCursorPosition;
- int to = m_textEditor.data()->position();
- if (from > to) {
- std::swap(from, to);
- }
- QString section = block.text().mid(from - block.position(), to - from);
- qDebug() << "from=" << from << "to=" << to;
- if (section.contains(' ')) {
- finishedWord();
- m_prevCursorPosition = -1;
- }
- }
-}
-
-void TextTool::finishedWord()
-{
- if (m_textShapeData && textEditingPluginContainer()) {
- foreach (KoTextEditingPlugin *plugin, textEditingPluginContainer()->values()) {
- plugin->finishedWord(m_textShapeData->document(), m_prevCursorPosition);
- }
- }
-}
-
-void TextTool::finishedParagraph()
-{
- if (m_textShapeData && textEditingPluginContainer()) {
- foreach (KoTextEditingPlugin *plugin, textEditingPluginContainer()->values()) {
- plugin->finishedParagraph(m_textShapeData->document(), m_prevCursorPosition);
- }
- }
-}
-
-void TextTool::startingSimpleEdit()
-{
- if (m_textShapeData && textEditingPluginContainer()) {
- foreach (KoTextEditingPlugin *plugin, textEditingPluginContainer()->values()) {
- plugin->startingSimpleEdit(m_textShapeData->document(), m_prevCursorPosition);
- }
- }
-
-}
-
-void TextTool::setTextColor(const KoColor &color)
-{
- m_textEditor.data()->setTextColor(color.toQColor());
-}
-
-void TextTool::setBackgroundColor(const KoColor &color)
-{
- m_textEditor.data()->setTextBackgroundColor(color.toQColor());
-}
-
-void TextTool::setGrowWidthToFit(bool enabled)
-{
- m_textEditor.data()->addCommand(new AutoResizeCommand(m_textShapeData, KoTextShapeData::AutoGrowWidth, enabled));
- updateActions();
-}
-
-void TextTool::setGrowHeightToFit(bool enabled)
-{
- m_textEditor.data()->addCommand(new AutoResizeCommand(m_textShapeData, KoTextShapeData::AutoGrowHeight, enabled));
- updateActions();
-}
-
-void TextTool::setShrinkToFit(bool enabled)
-{
- m_textEditor.data()->addCommand(new AutoResizeCommand(m_textShapeData, KoTextShapeData::ShrinkToFitResize, enabled));
- updateActions();
-}
-
-void TextTool::runUrl(KoPointerEvent *event, QString &url)
-{
- QUrl _url = QUrl::fromUserInput(url);
- if (!_url.isLocalFile()) {
- QDesktopServices::openUrl(_url);
- }
- event->accept();
-}
-
-void TextTool::debugTextDocument()
-{
-#ifndef NDEBUG
- if (!m_textShapeData) {
- return;
- }
- const int CHARSPERLINE = 80; // TODO Make configurable using ENV var?
- const int CHARPOSITION = 278301935;
- KoTextDocument document(m_textShapeData->document());
- KoStyleManager *styleManager = document.styleManager();
- KoInlineTextObjectManager *inlineManager = document.inlineTextObjectManager();
-
- QTextBlock block = m_textShapeData->document()->begin();
- for (; block.isValid(); block = block.next()) {
- QVariant var = block.blockFormat().property(KoParagraphStyle::StyleId);
- if (!var.isNull()) {
- KoParagraphStyle *ps = styleManager->paragraphStyle(var.toInt());
- qDebug() << "--- Paragraph Style:" << (ps ? ps->name() : QString()) << var.toInt();
- }
- var = block.charFormat().property(KoCharacterStyle::StyleId);
- if (!var.isNull()) {
- KoCharacterStyle *cs = styleManager->characterStyle(var.toInt());
- qDebug() << "--- Character Style:" << (cs ? cs->name() : QString()) << var.toInt();
- }
- int lastPrintedChar = -1;
- QTextBlock::iterator it;
- QString fragmentText;
- QList<QTextCharFormat> inlineCharacters;
- for (it = block.begin(); !it.atEnd(); ++it) {
- QTextFragment fragment = it.fragment();
- if (!fragment.isValid()) {
- continue;
- }
- QTextCharFormat fmt = fragment.charFormat();
- qDebug() << "changeId: " << fmt.property(KoCharacterStyle::ChangeTrackerId);
- const int fragmentStart = fragment.position() - block.position();
- for (int i = fragmentStart; i < fragmentStart + fragment.length(); i += CHARSPERLINE) {
- if (lastPrintedChar == fragmentStart - 1) {
- fragmentText += '|';
- }
- if (lastPrintedChar < fragmentStart || i > fragmentStart) {
- QString debug = block.text().mid(lastPrintedChar, CHARSPERLINE);
- lastPrintedChar += CHARSPERLINE;
- if (lastPrintedChar > block.length()) {
- debug += "\\n";
- }
- qDebug() << debug;
- }
- var = fmt.property(KoCharacterStyle::StyleId);
- QString charStyleLong, charStyleShort;
- if (!var.isNull()) { // named style
- charStyleShort = QString::number(var.toInt());
- KoCharacterStyle *cs = styleManager->characterStyle(var.toInt());
- if (cs) {
- charStyleLong = cs->name();
- }
- }
- if (inlineManager && fmt.hasProperty(KoCharacterStyle::InlineInstanceId)) {
- QTextCharFormat inlineFmt = fmt;
- inlineFmt.setProperty(CHARPOSITION, fragmentStart);
- inlineCharacters << inlineFmt;
- }
-
- if (fragment.length() > charStyleLong.length()) {
- fragmentText += charStyleLong;
- } else if (fragment.length() > charStyleShort.length()) {
- fragmentText += charStyleShort;
- } else if (fragment.length() >= 2) {
- fragmentText += QChar(8230); // ellipses
- }
-
- int rest = fragmentStart - (lastPrintedChar - CHARSPERLINE) + fragment.length() - fragmentText.length();
- rest = qMin(rest, CHARSPERLINE - fragmentText.length());
- if (rest >= 2) {
- fragmentText = QString("%1%2").arg(fragmentText).arg(' ', rest);
- }
- if (rest >= 0) {
- fragmentText += '|';
- }
- if (fragmentText.length() >= CHARSPERLINE) {
- qDebug() << fragmentText;
- fragmentText.clear();
- }
- }
- }
- if (!fragmentText.isEmpty()) {
- qDebug() << fragmentText;
- } else if (block.length() == 1) { // no actual tet
- qDebug() << "\\n";
- }
- foreach (const QTextCharFormat &cf, inlineCharacters) {
- KoInlineObject *object = inlineManager->inlineTextObject(cf);
- qDebug() << "At pos:" << cf.intProperty(CHARPOSITION) << object;
- // qDebug() << "-> id:" << cf.intProperty(577297549);
- }
- QTextList *list = block.textList();
- if (list) {
- if (list->format().hasProperty(KoListStyle::StyleId)) {
- KoListStyle *ls = styleManager->listStyle(list->format().intProperty(KoListStyle::StyleId));
- qDebug() << " List style applied:" << ls->styleId() << ls->name();
- } else {
- qDebug() << " +- is a list..." << list;
- }
- }
- }
-#endif
-}
-
-void TextTool::debugTextStyles()
-{
-#ifndef NDEBUG
- if (!m_textShapeData) {
- return;
- }
- KoTextDocument document(m_textShapeData->document());
- KoStyleManager *styleManager = document.styleManager();
-
- QSet<int> seenStyles;
-
- foreach (KoParagraphStyle *style, styleManager->paragraphStyles()) {
- qDebug() << style->styleId() << style->name() << (styleManager->defaultParagraphStyle() == style ? "[Default]" : "");
- KoListStyle *ls = style->listStyle();
- if (ls) { // optional ;)
- qDebug() << " +- ListStyle: " << ls->styleId() << ls->name()
- << (ls == styleManager->defaultListStyle() ? "[Default]" : "");
- foreach (int level, ls->listLevels()) {
- KoListLevelProperties llp = ls->levelProperties(level);
- qDebug() << " | level" << llp.level() << " style (enum):" << llp.style();
- if (llp.bulletCharacter().unicode() != 0) {
- qDebug() << " | bullet" << llp.bulletCharacter();
- }
- }
- seenStyles << ls->styleId();
- }
- }
-
- bool first = true;
- foreach (KoCharacterStyle *style, styleManager->characterStyles()) {
- if (seenStyles.contains(style->styleId())) {
- continue;
- }
- if (first) {
- qDebug() << "--- Character styles ---";
- first = false;
- }
- qDebug() << style->styleId() << style->name();
- qDebug() << style->font();
- }
-
- first = true;
- foreach (KoListStyle *style, styleManager->listStyles()) {
- if (seenStyles.contains(style->styleId())) {
- continue;
- }
- if (first) {
- qDebug() << "--- List styles ---";
- first = false;
- }
- qDebug() << style->styleId() << style->name()
- << (style == styleManager->defaultListStyle() ? "[Default]" : "");
- }
-#endif
-}
-
-void TextTool::textDirectionChanged()
-{
- if (!m_allowActions || !m_textEditor.data()) {
- return;
- }
-
- QTextBlockFormat blockFormat;
- if (m_actionChangeDirection->isChecked()) {
- blockFormat.setProperty(KoParagraphStyle::TextProgressionDirection, KoText::RightLeftTopBottom);
- } else {
- blockFormat.setProperty(KoParagraphStyle::TextProgressionDirection, KoText::LeftRightTopBottom);
- }
- m_textEditor.data()->mergeBlockFormat(blockFormat);
-}
-
-void TextTool::setListLevel(int level)
-{
- if (level < 1 || level > 10) {
- return;
- }
-
- KoTextEditor *textEditor = m_textEditor.data();
- if (textEditor->block().textList()) {
- ChangeListLevelCommand::CommandType type = ChangeListLevelCommand::SetLevel;
- ChangeListLevelCommand *cll = new ChangeListLevelCommand(*textEditor->cursor(), type, level);
- textEditor->addCommand(cll);
- editingPluginEvents();
- }
-}
-
-void TextTool::insertAnnotation()
-{
- // no annotations anymore, sorry :(
-}
diff --git a/plugins/flake/textshape/TextTool.h b/plugins/flake/textshape/TextTool.h
deleted file mode 100644
index 7995d853eb..0000000000
--- a/plugins/flake/textshape/TextTool.h
+++ /dev/null
@@ -1,427 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2011 Mojtaba Shahi Senobari <mojtaba.shahi3000@gmail.com>
- * Copyright (C) 2008, 2012 Pierre Stirnweiss <pstirnweiss@googlemail.org>
- * Copyright (C) 2014 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 KOTEXTTOOL_H
-#define KOTEXTTOOL_H
-
-#include "TextShape.h"
-#include "KoPointedAt.h"
-
-#include <KoToolBase.h>
-#include <KoTextCommandBase.h>
-#include <KoUnit.h>
-#include <KoBorder.h>
-
-#include <QClipboard>
-#include <QHash>
-#include <QTextBlock>
-#include <QTextCursor>
-#include <QTimer>
-#include <QWeakPointer>
-#include <QRectF>
-#include <QPointer>
-
-#include <TextEditingPluginContainer.h>
-
-class InsertCharacter;
-class KoChangeTracker;
-class KoCharacterStyle;
-class KoColor;
-class KoColorPopupAction;
-class KoParagraphStyle;
-class KoStyleManager;
-class KoTextEditor;
-class UndoTextCommand;
-
-class QAction;
-class KActionMenu;
-class KoFontFamilyAction;
-class FontSizeAction;
-
-class KUndo2Command;
-
-class QDrag;
-class QMimeData;
-class QMenu;
-
-class MockCanvas;
-class TextToolSelection;
-
-/**
- * This is the tool for the text-shape (which is a flake-based plugin).
- */
-class TextTool : public KoToolBase, public KoUndoableTool
-{
- Q_OBJECT
-public:
- explicit TextTool(KoCanvasBase *canvas);
-#ifndef NDEBUG
- explicit TextTool(MockCanvas *canvas);
-#endif
- ~TextTool() override;
-
- /// reimplemented from superclass
- void paint(QPainter &painter, const KoViewConverter &converter) override;
-
- /// reimplemented from superclass
- void mousePressEvent(KoPointerEvent *event) override;
- /// reimplemented from superclass
- void mouseDoubleClickEvent(KoPointerEvent *event) override;
- /// reimplemented from superclass
- void mouseTripleClickEvent(KoPointerEvent *event) override;
- /// reimplemented from superclass
- void mouseMoveEvent(KoPointerEvent *event) override;
- /// reimplemented from superclass
- void mouseReleaseEvent(KoPointerEvent *event) override;
- /// reimplemented from superclass
- void keyPressEvent(QKeyEvent *event) override;
- /// reimplemented from superclass
- void keyReleaseEvent(QKeyEvent *event) override;
- /// reimplemented from superclass
- void activate(ToolActivation activation, const QSet<KoShape *> &shapes) override;
- /// reimplemented from superclass
- void deactivate() override;
- /// reimplemented from superclass
- void copy() const override;
-
- /// reimplemented from KoUndoableTool
- void setAddUndoCommandAllowed(bool allowed) override
- {
- m_allowAddUndoCommand = allowed;
- }
-
- ///reimplemented
- void deleteSelection() override;
- /// reimplemented from superclass
- void cut() override;
- /// reimplemented from superclass
- bool paste() override;
- /// reimplemented from superclass
- void dragMoveEvent(QDragMoveEvent *event, const QPointF &point) override;
- /// reimplemented from superclass
- void dragLeaveEvent(QDragLeaveEvent *event) override;
- /// reimplemented from superclass
- void dropEvent(QDropEvent *event, const QPointF &point) override;
-
- /// reimplemented from superclass
- void repaintDecorations() override;
-
- /// reimplemented from superclass
- KoToolSelection *selection() override;
- /// reimplemented from superclass
- QList<QPointer<QWidget> > createOptionWidgets() override;
-
- /// reimplemented from superclass
- QVariant inputMethodQuery(Qt::InputMethodQuery query, const KoViewConverter &converter) const override;
- /// reimplemented from superclass
- void inputMethodEvent(QInputMethodEvent *event) override;
-
- /// The following two methods allow an undo/redo command to tell the tool, it will modify the QTextDocument and wants to be parent of the undo/redo commands resulting from these changes.
-
- void startEditing(KUndo2Command *command);
-
- void stopEditing();
-
- void setShapeData(KoTextShapeData *data);
-
- QRectF caretRect(QTextCursor *cursor, bool *upToDate = 0) const;
-
- QRectF textRect(QTextCursor &cursor) const;
-
-protected:
- virtual void createActions();
- TextShape *textShape()
- {
- return m_textShape;
- }
-
- friend class SimpleParagraphWidget;
- friend class ParagraphSettingsDialog;
-
- KoTextEditor *textEditor()
- {
- return m_textEditor.data();
- }
-
-public Q_SLOTS:
- /// Insert comment to document.
- void insertAnnotation();
- /// start the textedit-plugin.
- void startTextEditingPlugin(const QString &pluginId);
- /// reimplemented from KoToolBase
- void canvasResourceChanged(int key, const QVariant &res) override;
-
-Q_SIGNALS:
- /// emitted every time a different styleManager is set.
- void styleManagerChanged(KoStyleManager *manager);
- /// emitted every time a caret move leads to a different character format being under the caret
- void charFormatChanged(const QTextCharFormat &format, const QTextCharFormat &refBlockCharFormat);
- /// emitted every time a caret move leads to a different paragraph format being under the caret
- void blockFormatChanged(const QTextBlockFormat &format);
- /// emitted every time a caret move leads to a different paragraph format being under the caret
- void blockChanged(const QTextBlock &block);
-
-private Q_SLOTS:
- /// inserts new paragraph and includes it into the new section
- void insertNewSection();
- /// configures params of the current section
- void configureSection();
- /// inserts paragraph between sections bounds
- void splitSections();
- /// paste text from the clipboard without formatting
- void pasteAsText();
- /// make the selected text bold or not
- void bold(bool);
- /// make the selected text italic or not
- void italic(bool);
- /// underline of the selected text
- void underline(bool underline);
- /// strikethrough of the selected text
- void strikeOut(bool strikeOut);
- /// insert a non breaking space at the caret position
- void nonbreakingSpace();
- /// insert a non breaking hyphen at the caret position
- void nonbreakingHyphen();
- /// insert a soft hyphen at the caret position
- void softHyphen();
- /// insert a linebreak at the caret position
- void lineBreak();
- /// force the remainder of the text into the next page
- void insertFrameBreak();
- /// align all of the selected text left
- void alignLeft();
- /// align all of the selected text right
- void alignRight();
- /// align all of the selected text centered
- void alignCenter();
- /// align all of the selected text block-justified
- void alignBlock();
- /// make the selected text switch to be super-script
- void superScript(bool);
- /// make the selected text switch to be sub-script
- void subScript(bool);
- /// move the paragraph indent of the selected text to be less (left on LtR text)
- void decreaseIndent();
- /// move the paragraph indent of the selected text to be more (right on LtR text)
- void increaseIndent();
- /// Increase the font size. This will preserve eventual difference in font size within the selection.
- void increaseFontSize();
- /// Decrease font size. See above.
- void decreaseFontSize();
- /// Set font family
- void setFontFamily(const QString &);
- /// Set Font size
- void setFontSize(qreal size);
- /// see KoTextEditor::insertIndexMarker
- void insertIndexMarker();
- /// shows a dialog to insert a table
- void insertTable();
- /// insert a table of given dimensions
- void insertTableQuick(int rows, int columns);
- /// insert a row above
- void insertTableRowAbove();
- /// insert a row below
- void insertTableRowBelow();
- /// insert a column left
- void insertTableColumnLeft();
- /// insert a column right
- void insertTableColumnRight();
- /// delete a column
- void deleteTableColumn();
- /// delete a row
- void deleteTableRow();
- /// merge table cells
- void mergeTableCells();
- /// split previous merged table cells
- void splitTableCells();
- /// format the table border (enter table pen mode)
- void setTableBorderData(const KoBorder::BorderData &data);
- /// shows a dialog to alter the paragraph properties
- void formatParagraph();
- /// select all text in the current document.
- void selectAll();
- /// show the style manager
- void showStyleManager(int styleId = -1);
- /// change color of a selected text
- void setTextColor(const KoColor &color);
- /// change background color of a selected text
- void setBackgroundColor(const KoColor &color);
- /// Enable or disable grow-width-to-fit-text.
- void setGrowWidthToFit(bool enabled);
- /// Enable or disable grow-height-to-fit-text.
- void setGrowHeightToFit(bool enabled);
- /// Enable or disable shrink-to-fit-text.
- void setShrinkToFit(bool enabled);
- /// set Paragraph style of current selection. Existing style will be completely overridden.
- void setStyle(KoParagraphStyle *style);
- /// set the characterStyle of the current selection. see above.
- void setStyle(KoCharacterStyle *style);
- /// set the level of current selected list
- void setListLevel(int level);
-
- /// slot to call when a series of commands is started that together need to become 1 undo action.
- void startMacro(const QString &title);
- /// slot to call when a series of commands has ended that together should be 1 undo action.
- void stopMacro();
-
- /// show the insert special character docker.
- void insertSpecialCharacter();
- /// insert string
- void insertString(const QString &string);
-
- /// returns the focus to canvas when styles are selected in the optionDocker
- void returnFocusToCanvas();
-
- void selectFont();
- void shapeAddedToCanvas();
-
- void blinkCaret();
- void relayoutContent();
-
- // called when the m_textShapeData has been deleted.
- void shapeDataRemoved();
-
- //Show tooltip with editing info
- void showEditTip();
-
- /// print debug about the details of the text document
- void debugTextDocument();
- /// print debug about the details of the styles on the current text document
- void debugTextStyles();
-
- void ensureCursorVisible(bool moveView = true);
-
- void createStyleFromCurrentBlockFormat(const QString &name);
- void createStyleFromCurrentCharFormat(const QString &name);
-
- void testSlot(bool);
-
- /// change block text direction
- void textDirectionChanged();
-
- void updateActions();
-
- QMenu* popupActionsMenu() override;
-
-private:
- void repaintCaret();
- void repaintSelection();
- KoPointedAt hitTest(const QPointF &point) const;
- void updateStyleManager();
- void updateSelectedShape(const QPointF &point, bool noDocumentChange);
- void updateSelectionHandler();
- void editingPluginEvents();
- void finishedWord();
- void finishedParagraph();
- void startingSimpleEdit();
- void runUrl(KoPointerEvent *event, QString &url);
- void useTableBorderCursor();
-
- QMimeData *generateMimeData() const;
-
- TextEditingPluginContainer *textEditingPluginContainer();
-
-private:
- friend class UndoTextCommand;
- friend class ChangeTracker;
- friend class TextCutCommand;
- friend class ShowChangesCommand;
-
- TextShape *m_textShape; // where caret of m_textEditor currently is
- KoTextShapeData *m_textShapeData; // where caret of m_textEditor currently is
- QWeakPointer<KoTextEditor> m_textEditor;
- QWeakPointer<KoTextEditor> m_oldTextEditor;
- KoChangeTracker *m_changeTracker;
- KoUnit m_unit;
- bool m_allowActions;
- bool m_allowAddUndoCommand;
- bool m_allowResourceManagerUpdates;
- int m_prevCursorPosition; /// used by editingPluginEvents
- int m_prevMouseSelectionStart, m_prevMouseSelectionEnd;
-
- QTimer m_caretTimer;
- bool m_caretTimerState;
- QAction *m_actionPasteAsText;
- QAction *m_actionFormatBold;
- QAction *m_actionFormatItalic;
- QAction *m_actionFormatUnderline;
- QAction *m_actionFormatStrikeOut;
- QAction *m_actionAlignLeft;
- QAction *m_actionAlignRight;
- QAction *m_actionAlignCenter;
- QAction *m_actionAlignBlock;
- QAction *m_actionFormatSuper;
- QAction *m_actionFormatSub;
- QAction *m_actionFormatIncreaseIndent;
- QAction *m_actionFormatDecreaseIndent;
- QAction *m_growWidthAction;
- QAction *m_growHeightAction;
- QAction *m_shrinkToFitAction;
- QAction *m_actionChangeDirection;
- QAction *m_actionInsertSection;
- QAction *m_actionConfigureSection;
- QAction *m_actionSplitSections;
- KActionMenu *m_variableMenu;
-
- FontSizeAction *m_actionFormatFontSize;
- KoFontFamilyAction *m_actionFormatFontFamily;
- KoColorPopupAction *m_actionFormatTextColor;
- KoColorPopupAction *m_actionFormatBackgroundColor;
-
- KUndo2Command *m_currentCommand; //this command will be the direct parent of undoCommands generated as the result of QTextDocument changes
-
- bool m_currentCommandHasChildren;
-
- InsertCharacter *m_specialCharacterDocker;
-
- QPointer<TextEditingPluginContainer> m_textEditingPlugins;
-
- bool m_textTyping;
- bool m_textDeleting;
-
- QTimer m_editTipTimer;
- KoPointedAt m_editTipPointedAt;
- QPoint m_editTipPos;
-
- bool m_delayedEnsureVisible;
- TextToolSelection *m_toolSelection;
-
- KoPointedAt m_tableDragInfo;
- bool m_tableDraggedOnce;
- bool m_tableDragWithShift;
- QPointF m_draggingOrigin;
- qreal m_dx;
- qreal m_dy;
- bool m_tablePenMode;
- KoBorder::BorderData m_tablePenBorderData;
- mutable QRectF m_lastImMicroFocus;
-
- bool m_clickWithinSelection;
- QDrag *m_drag;
- QAbstractTextDocumentLayout::Selection m_preDragSelection;
-
- QScopedPointer<QMenu> m_contextMenu;
-};
-
-#endif
diff --git a/plugins/flake/textshape/TextToolFactory.cpp b/plugins/flake/textshape/TextToolFactory.cpp
deleted file mode 100644
index eebc537f5f..0000000000
--- a/plugins/flake/textshape/TextToolFactory.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006 Thomas Zander <zander@kde.org>
- *
- * 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 "TextToolFactory.h"
-#include "TextTool.h"
-#include "TextShape.h"
-
-#include <KoIcon.h>
-#include <klocalizedstring.h>
-
-TextToolFactory::TextToolFactory()
- : KoToolFactoryBase("TextTool")
-{
- setToolTip(i18n("Text editing"));
- setSection(dynamicToolType() + ",calligrawords,calligraauthor");
- setIconName(koIconNameCStr("tool-text"));
- setPriority(2);
- setActivationShapeId(TextShape_SHAPEID);
-}
-
-TextToolFactory::~TextToolFactory()
-{
-}
-
-KoToolBase *TextToolFactory::createTool(KoCanvasBase *canvas)
-{
- return new TextTool(canvas);
-}
diff --git a/plugins/flake/textshape/TextToolFactory.h b/plugins/flake/textshape/TextToolFactory.h
deleted file mode 100644
index fff7d2ba93..0000000000
--- a/plugins/flake/textshape/TextToolFactory.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006 Thomas Zander <zander@kde.org>
- *
- * 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 KOTEXTTOOLFACTORY_H
-#define KOTEXTTOOLFACTORY_H
-
-#include <KoToolFactoryBase.h>
-
-class TextToolFactory : public KoToolFactoryBase
-{
-public:
- TextToolFactory();
- ~TextToolFactory() override;
-
- KoToolBase *createTool(KoCanvasBase *canvas) override;
-};
-
-#endif
diff --git a/plugins/flake/textshape/calligra_shape_text.json b/plugins/flake/textshape/calligra_shape_text.json
deleted file mode 100644
index 8a2cb2f9d1..0000000000
--- a/plugins/flake/textshape/calligra_shape_text.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "Id": "Text Shape",
- "Type": "Service",
- "X-Flake-MinVersion": "28",
- "X-Flake-PluginVersion": "28",
- "X-KDE-Library": "krita_shape_text",
- "X-KDE-PluginInfo-Name": "textshape",
- "X-KDE-ServiceTypes": [
- "Krita/Flake"
- ]
-}
diff --git a/plugins/flake/textshape/commands/AcceptChangeCommand.cpp b/plugins/flake/textshape/commands/AcceptChangeCommand.cpp
deleted file mode 100644
index a2d355194e..0000000000
--- a/plugins/flake/textshape/commands/AcceptChangeCommand.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/* This file is part of the KDE project
-* Copyright (C) 2010 Pierre Stirnweiss \pstirnweiss@googlemail.com>
- *
- * 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 "AcceptChangeCommand.h"
-
-#include <KoGenChange.h>
-#include <KoTextDocument.h>
-
-#include <changetracker/KoChangeTracker.h>
-#include <changetracker/KoChangeTrackerElement.h>
-#include <styles/KoCharacterStyle.h>
-
-#include <klocalizedstring.h>
-
-#include <QPair>
-#include <QStack>
-#include <QTextBlock>
-#include <QTextCharFormat>
-#include <QTextCursor>
-#include <QTextDocument>
-#include <QTextFragment>
-
-AcceptChangeCommand::AcceptChangeCommand(int changeId, const QList<QPair<int, int> > &changeRanges, QTextDocument *document, KUndo2Command *parent)
- : KoTextCommandBase(parent)
- , m_first(true)
- , m_changeId(changeId)
- , m_changeRanges(changeRanges)
- , m_document(document)
-{
- setText(kundo2_i18n("Accept change"));
-
- m_changeTracker = KoTextDocument(m_document).changeTracker();
-}
-
-AcceptChangeCommand::~AcceptChangeCommand()
-{
-}
-
-void AcceptChangeCommand::redo()
-{
- if (m_first) {
- m_first = false;
- QTextCursor cursor(m_document);
- if (m_changeTracker->elementById(m_changeId)->getChangeType() != KoGenChange::DeleteChange) {
- QList<QPair<int, int> >::const_iterator it;
- for (it = m_changeRanges.constBegin(); it != m_changeRanges.constEnd(); ++it) {
- cursor.setPosition((*it).first);
- cursor.setPosition((*it).second, QTextCursor::KeepAnchor);
- QTextCharFormat format = cursor.charFormat();
- int changeId = format.property(KoCharacterStyle::ChangeTrackerId).toInt();
- if (changeId == m_changeId) {
- if (int parentChangeId = m_changeTracker->parent(m_changeId)) {
- format.setProperty(KoCharacterStyle::ChangeTrackerId, parentChangeId);
- } else {
- format.clearProperty(KoCharacterStyle::ChangeTrackerId);
- }
- cursor.setCharFormat(format);
- }
- }
- } else {
- QList<QPair<int, int> >::const_iterator it;
- QStack<QPair<int, int> > deleteRanges;
- for (it = m_changeRanges.constBegin(); it != m_changeRanges.constEnd(); ++it) {
- deleteRanges.push(QPair<int, int>((*it).first, (*it).second));
- }
- while (!deleteRanges.isEmpty()) {
- QPair<int, int> range = deleteRanges.pop();
- cursor.setPosition(range.first);
- cursor.setPosition(range.second, QTextCursor::KeepAnchor);
- cursor.deleteChar();
- }
- }
- m_changeTracker->acceptRejectChange(m_changeId, true);
- } else {
- m_changeTracker->acceptRejectChange(m_changeId, true);
- KoTextCommandBase::redo();
- UndoRedoFinalizer finalizer(this);
- }
- emit acceptRejectChange();
-}
-
-void AcceptChangeCommand::undo()
-{
- m_changeTracker->acceptRejectChange(m_changeId, false);
- KoTextCommandBase::undo();
- UndoRedoFinalizer finalizer(this);
- emit acceptRejectChange();
-}
diff --git a/plugins/flake/textshape/commands/AcceptChangeCommand.h b/plugins/flake/textshape/commands/AcceptChangeCommand.h
deleted file mode 100644
index 86fc865bc2..0000000000
--- a/plugins/flake/textshape/commands/AcceptChangeCommand.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* This file is part of the KDE project
-* Copyright (C) 2010 Pierre Stirnweiss \pstirnweiss@googlemail.com>
- *
- * 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 ACCEPTCHANGECOMMAND_H
-#define ACCEPTCHANGECOMMAND_H
-
-#include <KoTextCommandBase.h>
-
-#include <QPair>
-
-class KoChangeTracker;
-
-class QTextDocument;
-
-class AcceptChangeCommand : public QObject, public KoTextCommandBase
-{
- Q_OBJECT
-public:
- AcceptChangeCommand(int changeId, const QList<QPair<int, int> > &changeRanges, QTextDocument *document, KUndo2Command *parent = 0);
- ~AcceptChangeCommand() override;
-
- void redo() override;
- void undo() override;
-
-Q_SIGNALS:
- void acceptRejectChange();
-
-private:
- bool m_first;
- int m_changeId;
- QList<QPair<int, int> > m_changeRanges;
- QTextDocument *m_document;
- KoChangeTracker *m_changeTracker;
-};
-
-#endif // ACCEPTCHANGECOMMAND_H
diff --git a/plugins/flake/textshape/commands/AutoResizeCommand.cpp b/plugins/flake/textshape/commands/AutoResizeCommand.cpp
deleted file mode 100644
index 85d872c6fe..0000000000
--- a/plugins/flake/textshape/commands/AutoResizeCommand.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * This file is part of the KDE project
- * Copyright (C) 2010 Sebastian Sauer <sebsauer@kdab.com>
- *
- * 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 "AutoResizeCommand.h"
-#include "TextShape.h"
-
-#include <klocalizedstring.h>
-
-AutoResizeCommand::AutoResizeCommand(KoTextShapeData *shapeData, KoTextShapeData::ResizeMethod resizeMethod, bool enabled)
- : KUndo2Command()
- , m_shapeData(shapeData)
- , m_resizeMethod(resizeMethod)
- , m_enabled(enabled)
- , m_first(true)
- , m_prevResizeMethod(KoTextShapeData::NoResize)
-{
- Q_ASSERT(m_shapeData);
- const QString s = m_enabled ? i18nc("Enable Shrink To Fit", "Enable") : i18nc("Disable Shrink To Fit", "Disable");
- switch (m_resizeMethod) {
- case KoTextShapeData::AutoGrowWidth:
- setText(kundo2_i18nc("Enable/Disable Grow To Fit Width", "%1 Grow To Fit Width", s));
- break;
- case KoTextShapeData::AutoGrowHeight:
- setText(kundo2_i18nc("Enable/Disable Grow To Fit Height", "%1 Grow To Fit Height", s));
- break;
- case KoTextShapeData::ShrinkToFitResize:
- setText(kundo2_i18nc("Enable/Disable Shrink To Fit", "%1 Shrink To Fit", s));
- break;
- default:
- Q_ASSERT_X(false, __FUNCTION__, QString("The resize-method '%1' is unsupported by this command").arg(resizeMethod).toUtf8());
- break;
- }
-}
-
-void AutoResizeCommand::undo()
-{
- m_shapeData->setResizeMethod(m_prevResizeMethod);
-}
-
-void AutoResizeCommand::redo()
-{
- if (m_first) {
- m_first = false;
- m_prevResizeMethod = m_shapeData->resizeMethod();
- }
- KoTextShapeData::ResizeMethod resize = m_enabled ? m_resizeMethod : KoTextShapeData::NoResize;
- if (m_resizeMethod == KoTextShapeData::AutoGrowWidth || m_resizeMethod == KoTextShapeData::AutoGrowHeight) {
- if (m_enabled) {
- if ((m_shapeData->resizeMethod() == KoTextShapeData::AutoGrowWidth || m_shapeData->resizeMethod() == KoTextShapeData::AutoGrowHeight) && m_resizeMethod != m_shapeData->resizeMethod()) {
- resize = KoTextShapeData::AutoGrowWidthAndHeight;
- }
- } else {
- if (m_shapeData->resizeMethod() == KoTextShapeData::AutoGrowWidthAndHeight) {
- resize = m_resizeMethod == KoTextShapeData::AutoGrowWidth ? KoTextShapeData::AutoGrowHeight : KoTextShapeData::AutoGrowWidth;
- }
- }
- }
- m_shapeData->setResizeMethod(resize);
-}
diff --git a/plugins/flake/textshape/commands/AutoResizeCommand.h b/plugins/flake/textshape/commands/AutoResizeCommand.h
deleted file mode 100644
index a1fc1ef4c2..0000000000
--- a/plugins/flake/textshape/commands/AutoResizeCommand.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * This file is part of the KDE project
- * Copyright (C) 2010 Sebastian Sauer <sebsauer@kdab.com>
- *
- * 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 AUTORESIZECOMMAND_H
-#define AUTORESIZECOMMAND_H
-
-#include <kundo2command.h>
-#include <QPointer>
-#include <TextTool.h>
-#include <KoTextDocumentLayout.h>
-
-class TextShape;
-
-class AutoResizeCommand : public KUndo2Command
-{
-public:
- AutoResizeCommand(KoTextShapeData *shapeData, KoTextShapeData::ResizeMethod resizeMethod, bool enable);
-
- void undo() override;
- void redo() override;
-
-private:
- KoTextShapeData *m_shapeData;
- KoTextShapeData::ResizeMethod m_resizeMethod;
- bool m_enabled;
- bool m_first;
- KoTextShapeData::ResizeMethod m_prevResizeMethod;
-};
-
-#endif // TEXTCUTCOMMAND_H
diff --git a/plugins/flake/textshape/commands/ChangeListLevelCommand.cpp b/plugins/flake/textshape/commands/ChangeListLevelCommand.cpp
deleted file mode 100644
index b74e956006..0000000000
--- a/plugins/flake/textshape/commands/ChangeListLevelCommand.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- *
- * 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 "ChangeListLevelCommand.h"
-
-#include <KoParagraphStyle.h>
-#include <KoTextBlockData.h>
-#include <KoTextDocument.h>
-#include <KoList.h>
-#include "TextTool.h"
-#include <KoListLevelProperties.h>
-#include <klocalizedstring.h>
-#include <QDebug>
-
-#include <QTextCursor>
-#include <QHash>
-#include <QList>
-
-#define MARGIN_DEFAULT 18 // we consider it the default value
-
-ChangeListLevelCommand::ChangeListLevelCommand(const QTextCursor &cursor, ChangeListLevelCommand::CommandType type, int coef, KUndo2Command *parent)
- : KoTextCommandBase(parent)
- , m_type(type)
- , m_coefficient(coef)
- , m_first(true)
-{
- setText(kundo2_i18n("Change List Level"));
-
- int selectionStart = qMin(cursor.anchor(), cursor.position());
- int selectionEnd = qMax(cursor.anchor(), cursor.position());
-
- QTextBlock block = cursor.block().document()->findBlock(selectionStart);
-
- bool oneOf = (selectionStart == selectionEnd); //ensures the block containing the cursor is selected in that case
-
- while (block.isValid() && ((block.position() < selectionEnd) || oneOf)) {
- m_blocks.append(block);
- if (block.textList()) {
- m_lists.insert(m_blocks.size() - 1, KoTextDocument(block.document()).list(block.textList()));
- Q_ASSERT(m_lists.value(m_blocks.size() - 1));
- m_levels.insert(m_blocks.size() - 1, effectiveLevel(m_lists.value(m_blocks.size() - 1)->level(block)));
- }
- oneOf = false;
- block = block.next();
- }
-}
-
-ChangeListLevelCommand::~ChangeListLevelCommand()
-{
-}
-
-int ChangeListLevelCommand::effectiveLevel(int level)
-{
- int result = -1;
- if (m_type == IncreaseLevel) {
- result = level + m_coefficient;
- } else if (m_type == DecreaseLevel) {
- result = level - m_coefficient;
- } else if (m_type == SetLevel) {
- result = m_coefficient;
- }
- result = qMax(1, qMin(10, result));
- return result;
-}
-
-void ChangeListLevelCommand::redo()
-{
- if (!m_first) {
- KoTextCommandBase::redo();
- UndoRedoFinalizer finalizer(this);
- for (int i = 0; i < m_blocks.size(); ++i) {
- m_lists.value(i)->updateStoredList(m_blocks.at(i));
- QTextBlock currentBlock(m_blocks.at(i));
- KoTextBlockData userData(currentBlock);
- userData.setCounterWidth(-1.0);
- }
- } else {
- for (int i = 0; i < m_blocks.size() && m_lists.value(i); ++i) {
- if (!m_lists.value(i)->style()->hasLevelProperties(m_levels.value(i))) {
- KoListLevelProperties llp = m_lists.value(i)->style()->levelProperties(m_levels.value(i));
- if (llp.alignmentMode() == false) {
- //old list mode, see KoListLevelProperties::alignmentMode() documentation
- llp.setIndent((m_levels.value(i) - 1) * 20); //TODO make this configurable
- } else {
- llp.setTabStopPosition(MARGIN_DEFAULT * (m_levels.value(i) + 1));
- llp.setMargin(MARGIN_DEFAULT * (m_levels.value(i) + 1));
- llp.setTextIndent(- MARGIN_DEFAULT);
- }
- llp.setDisplayLevel(llp.displayLevel() + m_coefficient);
- llp.setLevel(m_levels.value(i));
-
- m_lists.value(i)->style()->setLevelProperties(llp);
- }
- m_lists.value(i)->add(m_blocks.at(i), m_levels.value(i));
- }
- }
- m_first = false;
-}
-
-void ChangeListLevelCommand::undo()
-{
- KoTextCommandBase::undo();
- UndoRedoFinalizer finalizer(this);
- for (int i = 0; i < m_blocks.size(); ++i) {
- if (m_blocks.at(i).textList()) {
- m_lists.value(i)->updateStoredList(m_blocks.at(i));
- }
-
- QTextBlock currentBlock(m_blocks.at(i));
- KoTextBlockData userData(currentBlock);
- userData.setCounterWidth(-1.0);
- }
-}
-
-bool ChangeListLevelCommand::mergeWith(const KUndo2Command *)
-{
- return false;
-}
diff --git a/plugins/flake/textshape/commands/ChangeListLevelCommand.h b/plugins/flake/textshape/commands/ChangeListLevelCommand.h
deleted file mode 100644
index b4b0a8c09e..0000000000
--- a/plugins/flake/textshape/commands/ChangeListLevelCommand.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- *
- * 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 CHANGELISTLEVELCOMMAND
-#define CHANGELISTLEVELCOMMAND
-
-#include "KoTextCommandBase.h"
-
-#include <QTextBlock>
-#include <QList>
-#include <QHash>
-
-class KoList;
-
-/**
- * This command is used the change level of a list-item.
- */
-class ChangeListLevelCommand : public KoTextCommandBase
-{
-public:
- enum CommandType {
- IncreaseLevel,
- DecreaseLevel,
- SetLevel
- };
-
- /**
- * Change the list property of 'block'.
- * @param block the paragraph to change the list property of
- * @param coef indicates by how many levels the list item should be displaced
- * @param parent the parent undo command for macro functionality
- */
- ChangeListLevelCommand(const QTextCursor &cursor, CommandType type, int coef, KUndo2Command *parent = 0);
-
- ~ChangeListLevelCommand() override;
-
- /// redo the command
- void redo() override;
- /// revert the actions done in redo
- void undo() override;
-
- /// reimplemented from KUndo2Command
- int id() const override
- {
- return 58450689;
- }
- /// reimplemented from KUndo2Command
- bool mergeWith(const KUndo2Command *other) override;
-
-private:
- int effectiveLevel(int level);
-
- CommandType m_type;
- int m_coefficient;
-
- QList<QTextBlock> m_blocks;
- QHash<int, KoList *> m_lists;
- QHash<int, int> m_levels;
-
- bool m_first;
-};
-
-#endif
diff --git a/plugins/flake/textshape/commands/RejectChangeCommand.cpp b/plugins/flake/textshape/commands/RejectChangeCommand.cpp
deleted file mode 100644
index 1e418b52b6..0000000000
--- a/plugins/flake/textshape/commands/RejectChangeCommand.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/* This file is part of the KDE project
-* Copyright (C) 2010 Pierre Stirnweiss \pstirnweiss@googlemail.com>
- *
- * 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 "RejectChangeCommand.h"
-
-#include <KoGenChange.h>
-#include <KoInlineTextObjectManager.h>
-#include <KoTextDocument.h>
-#include <KoTextDocumentLayout.h>
-
-#include <changetracker/KoChangeTracker.h>
-#include <changetracker/KoChangeTrackerElement.h>
-#include <styles/KoCharacterStyle.h>
-
-#include <klocalizedstring.h>
-
-#include <QPair>
-#include <QStack>
-#include <QTextBlock>
-#include <QTextCharFormat>
-#include <QTextCursor>
-#include <QTextDocument>
-#include <QTextFragment>
-
-RejectChangeCommand::RejectChangeCommand(int changeId, const QList<QPair<int, int> > &changeRanges, QTextDocument *document, KUndo2Command *parent)
- : KoTextCommandBase(parent)
- , m_first(true)
- , m_changeId(changeId)
- , m_changeRanges(changeRanges)
- , m_document(document)
-{
- setText(kundo2_i18n("Reject change"));
-
- m_changeTracker = KoTextDocument(m_document).changeTracker();
- m_layout = dynamic_cast<KoTextDocumentLayout *>(document->documentLayout());
-}
-
-RejectChangeCommand::~RejectChangeCommand()
-{
-}
-
-void RejectChangeCommand::redo()
-{
- if (m_first) {
- m_first = false;
- QTextCursor cursor(m_document);
- if (m_changeTracker->elementById(m_changeId)->getChangeType() == KoGenChange::InsertChange) {
- QList<QPair<int, int> >::const_iterator it;
- QStack<QPair<int, int> > deleteRanges;
- for (it = m_changeRanges.constBegin(); it != m_changeRanges.constEnd(); ++it) {
- deleteRanges.push(QPair<int, int>((*it).first, (*it).second));
- }
- while (!deleteRanges.isEmpty()) {
- QPair<int, int> range = deleteRanges.pop();
- cursor.setPosition(range.first);
- cursor.setPosition(range.second, QTextCursor::KeepAnchor);
- cursor.deleteChar();
- }
- } else if (m_changeTracker->elementById(m_changeId)->getChangeType() == KoGenChange::FormatChange) {
- QList<QPair<int, int> >::const_iterator it;
- for (it = m_changeRanges.constBegin(); it != m_changeRanges.constEnd(); ++it) {
- cursor.setPosition((*it).first);
- cursor.setPosition((*it).second, QTextCursor::KeepAnchor);
- int changeId = cursor.charFormat().property(KoCharacterStyle::ChangeTrackerId).toInt();
- QTextCharFormat format = m_changeTracker->elementById(m_changeId)->getPrevFormat().toCharFormat();
- if (changeId == m_changeId) {
- if (int parentChangeId = m_changeTracker->parent(m_changeId)) {
- format.setProperty(KoCharacterStyle::ChangeTrackerId, parentChangeId);
- } else {
- format.clearProperty(KoCharacterStyle::ChangeTrackerId);
- }
- cursor.setCharFormat(format);
- }
- }
- } else if (m_changeTracker->elementById(m_changeId)->getChangeType() == KoGenChange::DeleteChange) {
- QList<QPair<int, int> >::const_iterator it;
- QStack<QPair<int, int> > deleteRanges;
- for (it = m_changeRanges.constBegin(); it != m_changeRanges.constEnd(); ++it) {
- cursor.setPosition((*it).first);
- cursor.setPosition((*it).second, QTextCursor::KeepAnchor);
- deleteRanges.push(QPair<int, int>((*it).first, (*it).second));
- }
- while (!deleteRanges.isEmpty()) {
- QPair<int, int> range = deleteRanges.pop();
- cursor.setPosition(range.first);
- cursor.setPosition(range.second, QTextCursor::KeepAnchor);
- QTextCharFormat format = cursor.charFormat();
- format.clearProperty(KoCharacterStyle::ChangeTrackerId);
- cursor.setCharFormat(format);
- }
- }
- m_changeTracker->acceptRejectChange(m_changeId, true);
- } else {
- m_changeTracker->acceptRejectChange(m_changeId, true);
- KoTextCommandBase::redo();
- UndoRedoFinalizer finalizer(this);
- }
- emit acceptRejectChange();
-}
-
-void RejectChangeCommand::undo()
-{
- m_changeTracker->acceptRejectChange(m_changeId, false);
- KoTextCommandBase::undo();
- UndoRedoFinalizer finalizer(this);
- emit acceptRejectChange();
-}
diff --git a/plugins/flake/textshape/commands/RejectChangeCommand.h b/plugins/flake/textshape/commands/RejectChangeCommand.h
deleted file mode 100644
index 5b8a6bb3a6..0000000000
--- a/plugins/flake/textshape/commands/RejectChangeCommand.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* This file is part of the KDE project
-* Copyright (C) 2010 Pierre Stirnweiss \pstirnweiss@googlemail.com>
- *
- * 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 REJECTCHANGECOMMAND_H
-#define REJECTCHANGECOMMAND_H
-
-#include <KoTextCommandBase.h>
-
-#include <QPair>
-
-class KoChangeTracker;
-class KoTextDocumentLayout;
-
-class QTextDocument;
-
-class RejectChangeCommand : public QObject, public KoTextCommandBase
-{
- Q_OBJECT
-public:
- RejectChangeCommand(int changeId, const QList<QPair<int, int> > &changeRanges, QTextDocument *document, KUndo2Command *parent = 0);
- ~RejectChangeCommand() override;
-
- void redo() override;
- void undo() override;
-
-Q_SIGNALS:
- void acceptRejectChange();
-
-private:
- bool m_first;
- int m_changeId;
- QList<QPair<int, int> > m_changeRanges;
- QTextDocument *m_document;
- KoChangeTracker *m_changeTracker;
- KoTextDocumentLayout *m_layout;
-};
-
-#endif // REJECTCHANGECOMMAND_H
diff --git a/plugins/flake/textshape/commands/ShowChangesCommand.cpp b/plugins/flake/textshape/commands/ShowChangesCommand.cpp
deleted file mode 100644
index 4159f20a95..0000000000
--- a/plugins/flake/textshape/commands/ShowChangesCommand.cpp
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * This file is part of the KDE project
- * Copyright (C) 2009 Ganesh Paramasivam <ganesh@crystalfab.com>
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- *
- * 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 <iostream>
-#include "ShowChangesCommand.h"
-
-#include <KoChangeTracker.h>
-#include <KoChangeTrackerElement.h>
-#include <KoCharacterStyle.h>
-#include <KoTextDocument.h>
-#include <KoTextDocumentLayout.h>
-#include <KoTextEditor.h>
-#include <KoShapeAnchor.h>
-#include <KoInlineTextObjectManager.h>
-#include <KoCanvasBase.h>
-#include <KoShapeController.h>
-#include <KoShapeContainer.h>
-
-#include <klocalizedstring.h>
-
-#include <QTextDocument>
-#include <QtAlgorithms>
-#include <QList>
-
-ShowChangesCommand::ShowChangesCommand(bool showChanges, QTextDocument *document, KoCanvasBase *canvas, KUndo2Command *parent)
- : KoTextCommandBase(parent)
- , m_document(document)
- , m_first(true)
- , m_showChanges(showChanges)
- , m_canvas(canvas)
-{
- Q_ASSERT(document);
- m_changeTracker = KoTextDocument(m_document).changeTracker();
- m_textEditor = KoTextDocument(m_document).textEditor();
- if (showChanges) {
- setText(kundo2_i18n("Show Changes"));
- } else {
- setText(kundo2_i18n("Hide Changes"));
- }
-}
-
-void ShowChangesCommand::undo()
-{
- KoTextCommandBase::undo();
- UndoRedoFinalizer finalizer(this);
- foreach (KUndo2Command *shapeCommand, m_shapeCommands) {
- shapeCommand->undo();
- }
- emit toggledShowChange(!m_showChanges);
- enableDisableStates(!m_showChanges);
-}
-
-void ShowChangesCommand::redo()
-{
- if (!m_first) {
- KoTextCommandBase::redo();
- UndoRedoFinalizer finalizer(this);
- foreach (KUndo2Command *shapeCommand, m_shapeCommands) {
- shapeCommand->redo();
- }
- emit toggledShowChange(m_showChanges);
- enableDisableStates(m_showChanges);
- } else {
- m_first = false;
- enableDisableChanges();
- }
-}
-
-void ShowChangesCommand::enableDisableChanges()
-{
- if (m_changeTracker) {
- enableDisableStates(m_showChanges);
-
- if (m_showChanges) {
- insertDeletedChanges();
- } else {
- removeDeletedChanges();
- }
-#if 0
- TODO
- KoTextDocumentLayout *lay = qobject_cast<KoTextDocumentLayout *>(m_document->documentLayout());
- if (lay) {
- lay->scheduleLayout();
- }
-#endif
- }
-}
-
-void ShowChangesCommand::enableDisableStates(bool showChanges)
-{
- m_changeTracker->setDisplayChanges(showChanges);
-
- QTextCharFormat format = m_textEditor->charFormat();
- format.clearProperty(KoCharacterStyle::ChangeTrackerId);
- m_textEditor->setCharFormat(format);
-}
-
-void ShowChangesCommand::insertDeletedChanges()
-{
- QVector<KoChangeTrackerElement *> elementVector;
- KoTextDocument(m_textEditor->document()).changeTracker()->getDeletedChanges(elementVector);
- std::sort(elementVector.begin(), elementVector.end());
-}
-
-void ShowChangesCommand::checkAndAddAnchoredShapes(int position, int length)
-{
- KoInlineTextObjectManager *inlineObjectManager
- = KoTextDocument(m_document).inlineTextObjectManager();
- Q_ASSERT(inlineObjectManager);
-
- QTextCursor cursor = m_textEditor->document()->find(QString(QChar::ObjectReplacementCharacter), position);
- while (!cursor.isNull() && cursor.position() < position + length) {
- QTextCharFormat fmt = cursor.charFormat();
- KoInlineObject *object = inlineObjectManager->inlineTextObject(fmt);
- Q_ASSERT(object);
- Q_UNUSED(object);
- /* FIXME
- KoTextAnchor *anchor = dynamic_cast<KoTextAnchor *>(object);
- if (!anchor) {
- continue;
- }
- */
-#if 0
- // TODO -- since March 2010...
- KoTextDocumentLayout *lay = qobject_cast<KoTextDocumentLayout *>(m_document->documentLayout());
-
- KoShapeContainer *container = dynamic_cast<KoShapeContainer *>(lay->shapeForPosition(i));
-
- // a very ugly hack. Since this class is going away soon, it should be okay
- if (!container) {
- container = dynamic_cast<KoShapeContainer *>((lay->shapes()).at(0));
- }
-
- if (container) {
- container->addShape(anchor->shape());
- KUndo2Command *shapeCommand = m_canvas->shapeController()->addShapeDirect(anchor->shape());
- shapeCommand->redo();
- m_shapeCommands.push_front(shapeCommand);
- }
-#endif
- cursor = m_textEditor->document()->find(QString(QChar::ObjectReplacementCharacter), position);
- }
-}
-
-void ShowChangesCommand::removeDeletedChanges()
-{
- QVector<KoChangeTrackerElement *> elementVector;
- m_changeTracker->getDeletedChanges(elementVector);
- std::sort(elementVector.begin(), elementVector.end());
-}
-
-void ShowChangesCommand::checkAndRemoveAnchoredShapes(int position, int length)
-{
- KoInlineTextObjectManager *inlineObjectManager
- = KoTextDocument(m_document).inlineTextObjectManager();
- Q_ASSERT(inlineObjectManager);
-
- QTextCursor cursor = m_textEditor->document()->find(QString(QChar::ObjectReplacementCharacter), position);
- while (!cursor.isNull() && cursor.position() < position + length) {
- QTextCharFormat fmt = cursor.charFormat();
- KoInlineObject *object = inlineObjectManager->inlineTextObject(fmt);
- Q_ASSERT(object);
- Q_UNUSED(object);
- /* FIXME
- KoTextAnchor *anchor = dynamic_cast<KoTextAnchor *>(object);
- if (!anchor)
- continue;
-
- KUndo2Command *shapeCommand = m_canvas->shapeController()->removeShape(anchor->shape());
- shapeCommand->redo();
- m_shapeCommands.push_front(shapeCommand);
- */
- }
-}
-
-ShowChangesCommand::~ShowChangesCommand()
-{
-}
diff --git a/plugins/flake/textshape/commands/ShowChangesCommand.h b/plugins/flake/textshape/commands/ShowChangesCommand.h
deleted file mode 100644
index dc46add039..0000000000
--- a/plugins/flake/textshape/commands/ShowChangesCommand.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2009 Ganesh Paramasivam <ganesh@crystalfab.com>
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- *
- * 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 SHOWCHANGECOMMAND_H
-#define SHOWCHANGECOMMAND_H
-
-#include "KoTextCommandBase.h"
-
-#include <QObject>
-#include <QPointer>
-#include <QList>
-
-#include <KoCanvasBase.h>
-
-class KoChangeTracker;
-class KoTextEditor;
-
-
-class QTextDocument;
-
-class ShowChangesCommand : public QObject, public KoTextCommandBase
-{
- Q_OBJECT
-public:
-
- ShowChangesCommand(bool showChanges, QTextDocument *document, KoCanvasBase *canvas, KUndo2Command *parent = 0);
- ~ShowChangesCommand() override;
-
- void undo() override;
- void redo() override;
-
-Q_SIGNALS:
- void toggledShowChange(bool on);
-
-private:
- void enableDisableChanges();
- void enableDisableStates(bool showChanges);
- void insertDeletedChanges();
- void checkAndAddAnchoredShapes(int position, int length);
- void removeDeletedChanges();
- void checkAndRemoveAnchoredShapes(int position, int length);
-
- QTextDocument *m_document;
- KoChangeTracker *m_changeTracker;
- KoTextEditor *m_textEditor;
- bool m_first;
- bool m_showChanges;
- QPointer<KoCanvasBase> m_canvas;
-
- QList<KUndo2Command *> m_shapeCommands;
-};
-
-#endif // SHOWCHANGECOMMAND_H
diff --git a/plugins/flake/textshape/dialogs/AbstractStylesModel.cpp b/plugins/flake/textshape/dialogs/AbstractStylesModel.cpp
deleted file mode 100644
index a449478ffc..0000000000
--- a/plugins/flake/textshape/dialogs/AbstractStylesModel.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2012 Pierre Stirnweiss <pstirnweiss@googlemail.org>
- *
- * 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 "AbstractStylesModel.h"
-
-AbstractStylesModel::AbstractStylesModel(QObject *parent)
- : QAbstractItemModel(parent)
- , m_styleThumbnailer(0)
-{
-}
diff --git a/plugins/flake/textshape/dialogs/AbstractStylesModel.h b/plugins/flake/textshape/dialogs/AbstractStylesModel.h
deleted file mode 100644
index 8f3f6794f4..0000000000
--- a/plugins/flake/textshape/dialogs/AbstractStylesModel.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2012 Pierre Stirnweiss <pstirnweiss@googlemail.org>
- *
- * 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 ABSTRACTSTYLESMODEL_H
-#define ABSTRACTSTYLESMODEL_H
-
-#include <QAbstractItemModel>
-#include <QSize>
-
-class KoStyleThumbnailer;
-
-class KoCharacterStyle;
-
-class QImage;
-
-/** This class is used to provide widgets (like the @class StylesCombo) the styles available to the document being worked on.
- *
- * This is an abstract class supposed to be inherited only. DO NOT instantiate this class directly.
- *
- * On top of the standard QAbstractItemModel methods to re-implement, there are 3 specific methods which need to be re-implemented in order to be used with the styles widgets:
- * - setStyleThumbnailer: a @class KoStyleThumbnailer is used to layout/draw a preview of the style
- * - indexOf: for a given character or paragraph style, returns the corresponding QModelIndex
- * - stylePreview: returns a QImage, preview of the given style (given as row number in the list model)
- *
- * Following assumptions are made:
- * - the AbstractStylesModel derived model is a flat list of items (this also means that "parent" QModelIndexes are always invalid)
- * - the AbstractStylesModel derived model has only one column
- * - there is no header in the AbstractStylesModel derived model
-*/
-
-class AbstractStylesModel : public QAbstractItemModel
-{
- Q_OBJECT
-public:
- enum Type {
- CharacterStyle,
- ParagraphStyle
- };
-
- enum AdditionalRoles {
- CharacterStylePointer = Qt::UserRole + 1,
- ParagraphStylePointer,
- isModifiedStyle,
- isTitleRole,
- TitleString
- };
-
- explicit AbstractStylesModel(QObject *parent = 0);
-
- /** Re-implement from QAbstractItemModel.
- *
- * No methods are reimplemented there. Subclasses need to reimplement all of QAbstractItemModel's virtual methods.
- *
- */
-
- /** Specific methods of the AbstractStylesModel */
-
- /** Sets the @class KoStyleThumbnailer of the model. It is required that a @param thumbnailer is set before using the model. */
- virtual void setStyleThumbnailer(KoStyleThumbnailer *thumbnailer) = 0;
-
- /** Return a @class QModelIndex for the specified @param style.
- * @param style may be either a character or paragraph style.
- */
- virtual QModelIndex indexOf(const KoCharacterStyle *style) const = 0;
-
- /** Returns a QImage which is a preview of the style specified by @param row of the given @param size.
- * If size isn't specified, the default size of the given @class KoStyleThumbnailer is used.
- */
- virtual QImage stylePreview(int row, const QSize &size = QSize()) = 0;
-// virtual QImage stylePreview(QModelIndex &index, const QSize &size = QSize()) = 0;
-
- /** Returns the type of styles in the model */
- virtual AbstractStylesModel::Type stylesType() const = 0;
-
-protected:
- KoStyleThumbnailer *m_styleThumbnailer;
- Type m_modelType;
-};
-
-#endif // ABSTRACTSTYLESMODEL_H
diff --git a/plugins/flake/textshape/dialogs/AcceptRejectChangeDialog.cpp b/plugins/flake/textshape/dialogs/AcceptRejectChangeDialog.cpp
deleted file mode 100644
index 945ddfbbe1..0000000000
--- a/plugins/flake/textshape/dialogs/AcceptRejectChangeDialog.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Ganesh Paramasivam <ganesh@crystalfab.com>
- *
- * 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 "AcceptRejectChangeDialog.h"
-#include <KoChangeTracker.h>
-#include <KoChangeTrackerElement.h>
-
-AcceptRejectChangeDialog::AcceptRejectChangeDialog(KoChangeTracker *changeTracker, int changeId)
-{
- ui.setupUi(this);
- ui.authorNameLineEdit->setText(changeTracker->elementById(changeId)->getCreator());
- ui.dateLineEdit->setText(changeTracker->elementById(changeId)->getDate());
- KoGenChange::Type changeType = changeTracker->elementById(changeId)->getChangeType();
-
- if (changeType == KoGenChange::InsertChange) {
- ui.changeTypeLineEdit->setText(QString("Insertion"));
- } else if (changeType == KoGenChange::FormatChange) {
- ui.changeTypeLineEdit->setText(QString("Formatting"));
- } else {
- ui.changeTypeLineEdit->setText(QString("Deletion"));
- }
-
- connect(ui.acceptButton, SIGNAL(released()), this, SLOT(changeAccepted()));
- connect(ui.rejectButton, SIGNAL(released()), this, SLOT(changeRejected()));
- connect(ui.cancelButton, SIGNAL(released()), this, SLOT(dialogCancelled()));
-
-}
-
-AcceptRejectChangeDialog::~AcceptRejectChangeDialog()
-{
-}
-
-void AcceptRejectChangeDialog::changeAccepted()
-{
- this->done(AcceptRejectChangeDialog::eChangeAccepted);
-}
-
-void AcceptRejectChangeDialog::changeRejected()
-{
- this->done(AcceptRejectChangeDialog::eChangeRejected);
-}
-
-void AcceptRejectChangeDialog::dialogCancelled()
-{
- this->done(AcceptRejectChangeDialog::eDialogCancelled);
-}
diff --git a/plugins/flake/textshape/dialogs/AcceptRejectChangeDialog.h b/plugins/flake/textshape/dialogs/AcceptRejectChangeDialog.h
deleted file mode 100644
index 0ecf501d31..0000000000
--- a/plugins/flake/textshape/dialogs/AcceptRejectChangeDialog.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Ganesh Paramasivam <ganesh@crystalfab.com>
- *
- * 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 __ACCEPT_REJECT_CHANGE_DIALOG_H__
-#define __ACCEPT_REJECT_CHANGE_DIALOG_H__
-
-#include <QtGui>
-#include <ui_AcceptRejectChangeDialog.h>
-
-class KoChangeTracker;
-
-class AcceptRejectChangeDialog: public QDialog
-{
- Q_OBJECT
-
-public:
- typedef enum {
- eDialogCancelled = 0,
- eChangeAccepted,
- eChangeRejected
- } AcceptRejectResult;
-
- AcceptRejectChangeDialog(KoChangeTracker *changeTracker, int changeId);
- ~AcceptRejectChangeDialog();
-
-private:
- Ui::AcceptRejectChangeDialog ui;
-
-private Q_SLOTS:
- void changeAccepted();
- void changeRejected();
- void dialogCancelled();
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/AcceptRejectChangeDialog.ui b/plugins/flake/textshape/dialogs/AcceptRejectChangeDialog.ui
deleted file mode 100644
index 61ff82bc4a..0000000000
--- a/plugins/flake/textshape/dialogs/AcceptRejectChangeDialog.ui
+++ /dev/null
@@ -1,180 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>AcceptRejectChangeDialog</class>
- <widget class="QDialog" name="AcceptRejectChangeDialog">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>392</width>
- <height>287</height>
- </rect>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="maximumSize">
- <size>
- <width>392</width>
- <height>287</height>
- </size>
- </property>
- <property name="windowTitle">
- <string>Dialog</string>
- </property>
- <property name="sizeGripEnabled">
- <bool>false</bool>
- </property>
- <property name="modal">
- <bool>true</bool>
- </property>
- <widget class="QPushButton" name="acceptButton">
- <property name="geometry">
- <rect>
- <x>10</x>
- <y>247</y>
- <width>111</width>
- <height>31</height>
- </rect>
- </property>
- <property name="text">
- <string>Accept</string>
- </property>
- </widget>
- <widget class="QPushButton" name="rejectButton">
- <property name="geometry">
- <rect>
- <x>140</x>
- <y>247</y>
- <width>111</width>
- <height>31</height>
- </rect>
- </property>
- <property name="text">
- <string>Reject</string>
- </property>
- </widget>
- <widget class="QPushButton" name="cancelButton">
- <property name="geometry">
- <rect>
- <x>270</x>
- <y>247</y>
- <width>111</width>
- <height>31</height>
- </rect>
- </property>
- <property name="text">
- <string>Cancel</string>
- </property>
- </widget>
- <widget class="QTextEdit" name="changeLogTextEdit">
- <property name="geometry">
- <rect>
- <x>10</x>
- <y>177</y>
- <width>371</width>
- <height>61</height>
- </rect>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- <widget class="QLabel" name="label">
- <property name="geometry">
- <rect>
- <x>13</x>
- <y>153</y>
- <width>101</width>
- <height>17</height>
- </rect>
- </property>
- <property name="text">
- <string>Change Log</string>
- </property>
- </widget>
- <widget class="QLabel" name="label_2">
- <property name="geometry">
- <rect>
- <x>13</x>
- <y>27</y>
- <width>111</width>
- <height>17</height>
- </rect>
- </property>
- <property name="text">
- <string>Author</string>
- </property>
- </widget>
- <widget class="QLabel" name="label_3">
- <property name="geometry">
- <rect>
- <x>13</x>
- <y>72</y>
- <width>111</width>
- <height>17</height>
- </rect>
- </property>
- <property name="text">
- <string>Date</string>
- </property>
- </widget>
- <widget class="QLabel" name="label_4">
- <property name="geometry">
- <rect>
- <x>13</x>
- <y>116</y>
- <width>111</width>
- <height>17</height>
- </rect>
- </property>
- <property name="text">
- <string>Type</string>
- </property>
- </widget>
- <widget class="QLineEdit" name="authorNameLineEdit">
- <property name="geometry">
- <rect>
- <x>70</x>
- <y>20</y>
- <width>311</width>
- <height>31</height>
- </rect>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- <widget class="QLineEdit" name="dateLineEdit">
- <property name="geometry">
- <rect>
- <x>70</x>
- <y>65</y>
- <width>311</width>
- <height>31</height>
- </rect>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- <widget class="QLineEdit" name="changeTypeLineEdit">
- <property name="geometry">
- <rect>
- <x>70</x>
- <y>109</y>
- <width>311</width>
- <height>31</height>
- </rect>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/BibliographyConfigureDialog.cpp b/plugins/flake/textshape/dialogs/BibliographyConfigureDialog.cpp
deleted file mode 100644
index 3bad33cd62..0000000000
--- a/plugins/flake/textshape/dialogs/BibliographyConfigureDialog.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Smit Patel <smitpatel24@gmail.com>
- *
- * 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 "ui_BibliographyConfigureDialog.h"
-#include "BibliographyConfigureDialog.h"
-
-#include <KoTextDocument.h>
-#include <KoStyleManager.h>
-
-#include <QAbstractButton>
-#include <QHBoxLayout>
-#include <QComboBox>
-#include <QRadioButton>
-#include <QGroupBox>
-
-BibliographyConfigureDialog::BibliographyConfigureDialog(const QTextDocument *document, QWidget *parent)
- : QDialog(parent)
- , m_document(document)
- , m_bibConfiguration(KoTextDocument(m_document).styleManager()->bibliographyConfiguration())
-{
- dialog.setupUi(this);
- dialog.prefix->setText(m_bibConfiguration->prefix());
- dialog.suffix->setText(m_bibConfiguration->suffix());
- dialog.numberedEntries->setChecked(m_bibConfiguration->numberedEntries());
- dialog.sortAlgorithm->setCurrentIndex(
- dialog.sortAlgorithm->findText(m_bibConfiguration->sortAlgorithm(), Qt::MatchFixedString));
-
- dialog.sortByPosition->setChecked(m_bibConfiguration->sortByPosition());
-
- connect(dialog.buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(save(QAbstractButton*)));
- connect(dialog.addSortKeyButton, SIGNAL(clicked()), this, SLOT(addSortKey()));
- connect(dialog.sortByPosition, SIGNAL(clicked(bool)), this, SLOT(sortMethodChanged(bool)));
-
- dialog.sortKeyGroupBox->setDisabled(m_bibConfiguration->sortByPosition());
-
- if (m_bibConfiguration->sortKeys().isEmpty()) {
- m_bibConfiguration->setSortKeys(m_bibConfiguration->sortKeys()
- << QPair<QString, Qt::SortOrder>("identifier", Qt::AscendingOrder));
- }
-
- foreach (const SortKeyPair &key, m_bibConfiguration->sortKeys()) {
- dialog.sortKeyGroupBox->layout()->addWidget(
- new SortKeyWidget(key.first, key.second, dialog.sortKeyGroupBox));
- }
-
- show();
-}
-
-void BibliographyConfigureDialog::save(QAbstractButton *button)
-{
- if (dialog.buttonBox->standardButton(button) == dialog.buttonBox->Apply) {
-
- m_bibConfiguration->setPrefix(dialog.prefix->text());
- m_bibConfiguration->setSuffix(dialog.suffix->text());
- m_bibConfiguration->setSortAlgorithm(dialog.sortAlgorithm->currentText());
- m_bibConfiguration->setSortByPosition(dialog.sortByPosition->isChecked());
- m_bibConfiguration->setNumberedEntries(dialog.numberedEntries->isChecked());
-
- QList<SortKeyPair> sortKeys;
-
- foreach (QObject *o, dialog.sortKeyGroupBox->children()) {
- SortKeyWidget *widget = dynamic_cast<SortKeyWidget *>(o);
- if (widget) {
- sortKeys << SortKeyPair(widget->sortKey(), widget->sortOrder());
- }
- }
- m_bibConfiguration->setSortKeys(sortKeys);
-
- KoTextDocument(m_document).styleManager()->setBibliographyConfiguration(m_bibConfiguration);
- }
- emit accept();
-}
-
-void BibliographyConfigureDialog::addSortKey()
-{
- dialog.sortKeyGroupBox->layout()->addWidget(
- new SortKeyWidget("identifier", Qt::AscendingOrder, dialog.sortKeyGroupBox));
-}
-
-void BibliographyConfigureDialog::sortMethodChanged(bool sortByPosition)
-{
- m_bibConfiguration->setSortByPosition(sortByPosition);
-
- if (!sortByPosition && m_bibConfiguration->sortKeys().isEmpty()) {
- m_bibConfiguration->setSortKeys(m_bibConfiguration->sortKeys()
- << QPair<QString, Qt::SortOrder>("identifier", Qt::AscendingOrder));
- }
-}
-
-SortKeyWidget::SortKeyWidget(const QString &sortKey, Qt::SortOrder order, QWidget *parent) :
- QWidget(parent),
- m_dataFields(new QComboBox),
- m_ascButton(new QRadioButton(i18n("Ascending"))),
- m_dscButton(new QRadioButton(i18n("Descending"))),
- m_layout(new QHBoxLayout)
-{
- setLayout(m_layout);
- m_dataFields->addItems(KoOdfBibliographyConfiguration::bibDataFields);
- setSortKey(sortKey);
- setSortOrder(order);
-
- m_layout->addWidget(m_dataFields);
- m_layout->addWidget(m_ascButton);
- m_layout->addWidget(m_dscButton);
-}
-
-void SortKeyWidget::setSortKey(const QString &sortKey)
-{
- int sortKeyIndex = KoOdfBibliographyConfiguration::bibDataFields.indexOf(sortKey);
- if (sortKeyIndex != -1) {
- m_dataFields->setCurrentIndex(sortKeyIndex);
- }
-}
-
-void SortKeyWidget::setSortOrder(Qt::SortOrder order)
-{
- if (order == Qt::DescendingOrder) {
- m_dscButton->setChecked(true);
- } else {
- m_ascButton->setChecked(true);
- }
-}
-
-QString SortKeyWidget::sortKey() const
-{
- return m_dataFields->currentText();
-}
-
-Qt::SortOrder SortKeyWidget::sortOrder() const
-{
- return (m_ascButton->isChecked()) ? Qt::AscendingOrder : Qt::DescendingOrder;
-}
diff --git a/plugins/flake/textshape/dialogs/BibliographyConfigureDialog.h b/plugins/flake/textshape/dialogs/BibliographyConfigureDialog.h
deleted file mode 100644
index ba22c4a61f..0000000000
--- a/plugins/flake/textshape/dialogs/BibliographyConfigureDialog.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Smit Patel <smitpatel24@gmail.com>
- *
- * 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 BIBLIOGRAPHYCONFIGUREDIALOG_H
-#define BIBLIOGRAPHYCONFIGUREDIALOG_H
-
-#include "ui_BibliographyConfigureDialog.h"
-
-#include <QDialog>
-#include <QTextDocument>
-#include <QComboBox>
-#include <QRadioButton>
-#include <QHBoxLayout>
-
-#include "KoOdfBibliographyConfiguration.h"
-
-class BibliographyConfigureDialog : public QDialog
-{
- Q_OBJECT
-
-public:
- explicit BibliographyConfigureDialog(const QTextDocument *document, QWidget *parent = 0);
-
-public Q_SLOTS:
- void addSortKey();
- void save(QAbstractButton *);
- void sortMethodChanged(bool);
-
-private:
- Ui::BibliographyConfigureDialog dialog;
- const QTextDocument *m_document;
- KoOdfBibliographyConfiguration *m_bibConfiguration;
-};
-
-class SortKeyWidget : public QWidget
-{
- Q_OBJECT
-
-public:
- explicit SortKeyWidget(const QString &sortKey, Qt::SortOrder order, QWidget *parent);
-
- QString sortKey() const;
- Qt::SortOrder sortOrder() const;
-
- void setSortKey(const QString &sortKey);
- void setSortOrder(Qt::SortOrder order);
-
-private:
- QComboBox *m_dataFields;
- QRadioButton *m_ascButton;
- QRadioButton *m_dscButton;
- QHBoxLayout *m_layout;
-
-};
-
-#endif // BIBLIOGRAPHYCONFIGUREDIALOG_H
diff --git a/plugins/flake/textshape/dialogs/BibliographyConfigureDialog.ui b/plugins/flake/textshape/dialogs/BibliographyConfigureDialog.ui
deleted file mode 100644
index e3d8fffb1f..0000000000
--- a/plugins/flake/textshape/dialogs/BibliographyConfigureDialog.ui
+++ /dev/null
@@ -1,222 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>BibliographyConfigureDialog</class>
- <widget class="QDialog" name="BibliographyConfigureDialog">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>455</width>
- <height>340</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>Configure bibliography</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <item>
- <widget class="QGroupBox" name="groupBox">
- <property name="title">
- <string>Formatting of bibliography entries</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="0" column="0">
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QLabel" name="prefixLabel">
- <property name="text">
- <string>Prefix:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLineEdit" name="prefix">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="suffixLabel">
- <property name="text">
- <string>Suffix:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLineEdit" name="suffix">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="1" column="0">
- <widget class="QCheckBox" name="numberedEntries">
- <property name="text">
- <string>Number entries</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="groupBox_2">
- <property name="title">
- <string>Sort</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_3">
- <item>
- <widget class="QCheckBox" name="sortByPosition">
- <property name="text">
- <string>Sort by position</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="sortKeyGroupBox">
- <property name="title">
- <string>Sort keys</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout"/>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_3">
- <item>
- <widget class="QPushButton" name="addSortKeyButton">
- <property name="text">
- <string>Add sort key</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>87</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <widget class="QLabel" name="sortAlgorithmLabel">
- <property name="font">
- <font>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="text">
- <string>Sort algorithm:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QComboBox" name="sortAlgorithm">
- <item>
- <property name="text">
- <string>Alphanumeric</string>
- </property>
- </item>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="standardButtons">
- <set>QDialogButtonBox::Apply|QDialogButtonBox::Discard</set>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <tabstops>
- <tabstop>prefix</tabstop>
- <tabstop>suffix</tabstop>
- <tabstop>numberedEntries</tabstop>
- <tabstop>sortByPosition</tabstop>
- <tabstop>sortAlgorithm</tabstop>
- <tabstop>buttonBox</tabstop>
- </tabstops>
- <resources/>
- <connections>
- <connection>
- <sender>buttonBox</sender>
- <signal>accepted()</signal>
- <receiver>BibliographyConfigureDialog</receiver>
- <slot>accept()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>257</x>
- <y>330</y>
- </hint>
- <hint type="destinationlabel">
- <x>157</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>buttonBox</sender>
- <signal>rejected()</signal>
- <receiver>BibliographyConfigureDialog</receiver>
- <slot>reject()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>325</x>
- <y>330</y>
- </hint>
- <hint type="destinationlabel">
- <x>286</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>sortByPosition</sender>
- <signal>clicked(bool)</signal>
- <receiver>sortKeyGroupBox</receiver>
- <slot>setDisabled(bool)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>79</x>
- <y>191</y>
- </hint>
- <hint type="destinationlabel">
- <x>117</x>
- <y>221</y>
- </hint>
- </hints>
- </connection>
- </connections>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/BibliographyPreview.cpp b/plugins/flake/textshape/dialogs/BibliographyPreview.cpp
deleted file mode 100644
index a209877d26..0000000000
--- a/plugins/flake/textshape/dialogs/BibliographyPreview.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Smit Patel <smitpatel24@gmail.com>
- *
- * 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 "BibliographyPreview.h"
-
-#include "KoBibliographyInfo.h"
-#include "KoZoomHandler.h"
-#include "KoTextDocumentLayout.h"
-#include "TextTool.h"
-
-#include <KoInlineTextObjectManager.h>
-#include <KoParagraphStyle.h>
-#include <KoPageProvider.h>
-#include <KoShapePaintingContext.h>
-
-BibliographyPreview::BibliographyPreview(QWidget *parent)
- : QFrame(parent)
- , m_textShape(0)
- , m_pm(0)
- , m_styleManager(0)
- , m_previewPixSize(QSize(0, 0))
-{
-}
-
-BibliographyPreview::~BibliographyPreview()
-{
- deleteTextShape();
-
- if (m_pm) {
- delete m_pm;
- m_pm = 0;
- }
-}
-
-void BibliographyPreview::setStyleManager(KoStyleManager *styleManager)
-{
- m_styleManager = styleManager;
-}
-
-void BibliographyPreview::paintEvent(QPaintEvent *event)
-{
- Q_UNUSED(event);
-
- QPainter *p = new QPainter(this);
- p->save();
- p->translate(5.5, 1.5);
- p->setRenderHint(QPainter::Antialiasing);
- QRect rectang = rect();
- rectang.adjust(-4, -4, -4, -4);
-
- if (m_pm) {
- p->drawPixmap(rectang, *m_pm, m_pm->rect());
- } else {
- p->fillRect(rectang, QBrush(QColor(Qt::white)));
- }
-
- p->restore();
-
- delete p;
-}
-
-void BibliographyPreview::updatePreview(KoBibliographyInfo *newbibInfo)
-{
- QTextBlockFormat bibFormat;
- QTextDocument *bibDocument = new QTextDocument(this);
- KoTextDocument(bibDocument).setStyleManager(m_styleManager);
- KoBibliographyInfo *info = newbibInfo->clone();
-
- bibFormat.setProperty(KoParagraphStyle::BibliographyData, QVariant::fromValue<KoBibliographyInfo *>(info));
- bibFormat.setProperty(KoParagraphStyle::GeneratedDocument, QVariant::fromValue<QTextDocument *>(bibDocument));
-
- deleteTextShape();
-
- m_textShape = new TextShape(&m_itom, &m_tlm);
- if (m_previewPixSize.isEmpty()) {
- m_textShape->setSize(size());
- } else {
- m_textShape->setSize(m_previewPixSize);
- }
- QTextCursor cursor(m_textShape->textShapeData()->document());
-
- QTextCharFormat textCharFormat = cursor.blockCharFormat();
- textCharFormat.setFontPointSize(16);
- textCharFormat.setFontWeight(QFont::Bold);
-
- textCharFormat.setProperty(QTextCharFormat::ForegroundBrush, QBrush(Qt::black));
- cursor.setCharFormat(textCharFormat);
-
- cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
-
- QTextBlockFormat titleBlockFormat;
- cursor.insertBlock(titleBlockFormat, textCharFormat);
- cursor.insertText(info->m_indexTitleTemplate.text);
-
- textCharFormat.setFontPointSize(12);
- textCharFormat.setFontWeight(QFont::Normal);
- QTextBlockFormat blockFormat;
- cursor.insertBlock(blockFormat, textCharFormat);
- cursor.insertBlock(blockFormat, textCharFormat);
- cursor.insertText("CIT01: Title, Author, Organisation, URL");
-
- KoTextDocument(m_textShape->textShapeData()->document()).setStyleManager(m_styleManager);
-
- KoTextDocumentLayout *lay = dynamic_cast<KoTextDocumentLayout *>(m_textShape->textShapeData()->document()->documentLayout());
- connect(lay, SIGNAL(finishedLayout()), this, SLOT(finishedPreviewLayout()));
- if (lay) {
- lay->layout();
- }
-}
-
-void BibliographyPreview::finishedPreviewLayout()
-{
- if (m_pm) {
- delete m_pm;
- m_pm = 0;
- }
-
- if (m_previewPixSize.isEmpty()) {
- m_pm = new QPixmap(size());
- } else {
- m_pm = new QPixmap(m_previewPixSize);
- }
- m_pm->fill(Qt::white);
- m_zoomHandler.setZoom(0.9);
- m_zoomHandler.setDpi(72, 72);
- QPainter p(m_pm);
-
- if (m_textShape) {
- if (m_previewPixSize.isEmpty()) {
- m_textShape->setSize(size());
- } else {
- m_textShape->setSize(m_previewPixSize);
- }
- KoShapePaintingContext paintContext; //FIXME
- m_textShape->paintComponent(p, paintContext);
- }
- emit pixmapGenerated();
- update();
-}
-
-QPixmap BibliographyPreview::previewPixmap()
-{
- return QPixmap(*m_pm);
-}
-
-void BibliographyPreview::deleteTextShape()
-{
- if (m_textShape) {
- KoTextDocumentLayout *lay = dynamic_cast<KoTextDocumentLayout *>(m_textShape->textShapeData()->document()->documentLayout());
- if (lay) {
- lay->setContinuousLayout(false);
- lay->setBlockLayout(true);
- }
- delete m_textShape;
- m_textShape = 0;
- }
-}
-
-void BibliographyPreview::setPreviewSize(const QSize &size)
-{
- m_previewPixSize = size;
-}
diff --git a/plugins/flake/textshape/dialogs/BibliographyPreview.h b/plugins/flake/textshape/dialogs/BibliographyPreview.h
deleted file mode 100644
index 8a88249729..0000000000
--- a/plugins/flake/textshape/dialogs/BibliographyPreview.h
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef BIBLIOGRAPHYPREVIEW_H
-#define BIBLIOGRAPHYPREVIEW_H
-/* This file is part of the KDE project
- * Copyright (C) 2011 Smit Patel <smitpatel24@gmail.com>
- *
- * 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 <KoZoomHandler.h>
-#include <KoInlineTextObjectManager.h>
-#include <KoTextRangeManager.h>
-
-#include <QFrame>
-#include <QPixmap>
-
-class TextShape;
-class KoBibliographyInfo;
-class KoStyleManager;
-
-class BibliographyPreview : public QFrame
-{
- Q_OBJECT
-public:
- explicit BibliographyPreview(QWidget *parent = 0);
- ~BibliographyPreview() override;
- void setStyleManager(KoStyleManager *styleManager);
- /// sets the size of the generated preview pixmap if not set then it takes the widget's size
- void setPreviewSize(const QSize &size);
- QPixmap previewPixmap();
-
-protected:
- void paintEvent(QPaintEvent *event) override;
-
-Q_SIGNALS:
- void pixmapGenerated();
-public Q_SLOTS:
- void updatePreview(KoBibliographyInfo *info);
-
-private Q_SLOTS:
- void finishedPreviewLayout();
-
-private:
- TextShape *m_textShape;
- QPixmap *m_pm;
- KoZoomHandler m_zoomHandler;
- KoStyleManager *m_styleManager;
- KoInlineTextObjectManager m_itom;
- KoTextRangeManager m_tlm;
- QSize m_previewPixSize;
-
- void deleteTextShape();
-
-};
-
-#endif // BIBLIOGRAPHYPREVIEW_H
diff --git a/plugins/flake/textshape/dialogs/BibliographyTemplate.cpp b/plugins/flake/textshape/dialogs/BibliographyTemplate.cpp
deleted file mode 100644
index 74477790df..0000000000
--- a/plugins/flake/textshape/dialogs/BibliographyTemplate.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-
-/* This file is part of the KDE project
- * Copyright (C) 2011 Smit Patel <smitpatel24@gmail.com>
- *
- * 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 "BibliographyTemplate.h"
-
-#include <KoBibliographyInfo.h>
-#include <KoOdfBibliographyConfiguration.h>
-#include <KoStyleManager.h>
-#include <KoParagraphStyle.h>
-#include <klocalizedstring.h>
-
-BibliographyTemplate::BibliographyTemplate(KoStyleManager *manager)
- : m_manager(manager)
-{
- Q_ASSERT(manager);
-}
-
-QList<KoBibliographyInfo *> BibliographyTemplate::templates()
-{
- //if you are adding your own custom styles specifically for bibliography, add it as an unused style in KoStyleManager
- // when the bibliography is used the style will be automatically move to the usedStyle section
-
- QList<KoBibliographyInfo *> predefinedTemplates;
- return predefinedTemplates;
-}
-
-void BibliographyTemplate::moveTemplateToUsed(KoBibliographyInfo *info)
-{
- if (m_manager->unusedStyle(info->m_indexTitleTemplate.styleId)) {
- m_manager->moveToUsedStyles(info->m_indexTitleTemplate.styleId);
- }
-
- Q_FOREACH (const QString &bibType, KoOdfBibliographyConfiguration::bibTypes) {
- if (m_manager->unusedStyle(info->m_entryTemplate[bibType].styleId)) {
- m_manager->moveToUsedStyles(info->m_entryTemplate[bibType].styleId);
- }
- }
-}
diff --git a/plugins/flake/textshape/dialogs/BibliographyTemplate.h b/plugins/flake/textshape/dialogs/BibliographyTemplate.h
deleted file mode 100644
index 99ca6c4f61..0000000000
--- a/plugins/flake/textshape/dialogs/BibliographyTemplate.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Smit Patel <smitpatel24@gmail.com>
- *
- * 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 BIBLIOGRAPHYTEMPLATE_H
-#define BIBLIOGRAPHYTEMPLATE_H
-
-#include <QList>
-
-class KoBibliographyInfo;
-class KoStyleManager;
-
-class BibliographyTemplate
-{
-public:
- explicit BibliographyTemplate(KoStyleManager *manager);
-
- QList<KoBibliographyInfo *> templates();
-
- /// this method moves the styles used in info Bibliography from unused styles list to used
- void moveTemplateToUsed(KoBibliographyInfo *info);
-
-private:
- KoStyleManager *m_manager;
-};
-
-#endif // BIBLIOGRAPHYTEMPLATE_H
diff --git a/plugins/flake/textshape/dialogs/ChangeConfigureDialog.cpp b/plugins/flake/textshape/dialogs/ChangeConfigureDialog.cpp
deleted file mode 100644
index aed979da4c..0000000000
--- a/plugins/flake/textshape/dialogs/ChangeConfigureDialog.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2009 Ganesh Paramasivam <ganesh@crystalfab.com>
- *
- * 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 "ChangeConfigureDialog.h"
-#include <QColorDialog>
-#include <QPainter>
-
-ColorDisplayLabel::ColorDisplayLabel(QWidget *parent)
- : QLabel(parent)
- , labelColor(255, 255, 0)
-{
-}
-
-ColorDisplayLabel::~ColorDisplayLabel()
-{
-
-}
-
-void ColorDisplayLabel::paintEvent(QPaintEvent *event)
-{
- Q_UNUSED(event);
- QPainter painter(this);
- painter.setBrush(labelColor);
- painter.drawRect(rect().x(), rect().y(), rect().width(), rect().height());
-}
-
-const QColor &ColorDisplayLabel::color() const
-{
- return labelColor;
-}
-
-void ColorDisplayLabel::setColor(const QColor &color)
-{
- labelColor = color;
-}
-
-ChangeConfigureDialog::ChangeConfigureDialog(const QColor &insertionColor, const QColor &deletionColor, const QColor &formatChangeColor, const QString &authorName, KoChangeTracker::ChangeSaveFormat changeSaveFormat, QWidget *parent)
- : QDialog(parent)
-{
- ui.setupUi(this);
- ui.insertionColorDisplayLabel->setColor(insertionColor);
- ui.deletionColorDisplayLabel->setColor(deletionColor);
- ui.formatColorDisplayLabel->setColor(formatChangeColor);
- ui.authorNameLineEdit->setText(authorName);
- if (changeSaveFormat == KoChangeTracker::ODF_1_2) {
- ui.odf12RadioButton->setChecked(true);
- } else {
- ui.deltaXmlRadioButton->setChecked(true);
- }
- connect(ui.insertionColorButton, SIGNAL(clicked()), this, SLOT(insertionColorSelect()));
- connect(ui.deletionColorButton, SIGNAL(clicked()), this, SLOT(deletionColorSelect()));
- connect(ui.formatColorButton, SIGNAL(clicked()), this, SLOT(formatChangeColorSelect()));
- updatePreviewText();
-}
-
-const QString ChangeConfigureDialog::authorName()
-{
- return ui.authorNameLineEdit->text();
-}
-
-KoChangeTracker::ChangeSaveFormat ChangeConfigureDialog::saveFormat()
-{
- if (ui.odf12RadioButton->isChecked()) {
- return KoChangeTracker::ODF_1_2;
- } else {
- return KoChangeTracker::DELTAXML;
- }
-}
-
-const QColor &ChangeConfigureDialog::getInsertionBgColor()
-{
- return ui.insertionColorDisplayLabel->color();
-}
-
-const QColor &ChangeConfigureDialog::getDeletionBgColor()
-{
- return ui.deletionColorDisplayLabel->color();
-}
-
-const QColor &ChangeConfigureDialog::getFormatChangeBgColor()
-{
- return ui.formatColorDisplayLabel->color();
-}
-
-void ChangeConfigureDialog::insertionColorSelect()
-{
- colorSelect(eInsert);
-}
-
-void ChangeConfigureDialog::deletionColorSelect()
-{
- colorSelect(eDelete);
-}
-
-void ChangeConfigureDialog::formatChangeColorSelect()
-{
- colorSelect(eFormatChange);
-}
-
-void ChangeConfigureDialog::colorSelect(ChangeType type)
-{
- QColor selectedColor;
-
- switch (type) {
- case eInsert:
- selectedColor = QColorDialog::getColor(ui.insertionColorDisplayLabel->color(), this);
- if (selectedColor.isValid()) {
- ui.insertionColorDisplayLabel->setColor(selectedColor);
- ui.insertionColorDisplayLabel->update();
- }
- break;
- case eDelete:
- selectedColor = QColorDialog::getColor(ui.deletionColorDisplayLabel->color(), this);
- if (selectedColor.isValid()) {
- ui.deletionColorDisplayLabel->setColor(selectedColor);
- ui.deletionColorDisplayLabel->update();
- }
- break;
- case eFormatChange:
- selectedColor = QColorDialog::getColor(ui.formatColorDisplayLabel->color(), this);
- if (selectedColor.isValid()) {
- ui.formatColorDisplayLabel->setColor(selectedColor);
- ui.formatColorDisplayLabel->update();
- }
- break;
- case eChangeTypeNone:
- break;
- }
-
- updatePreviewText();
-}
-
-void ChangeConfigureDialog::updatePreviewText(void)
-{
- //update the insertion-text
- if (ui.previewTextEdit->find(i18n("This is a line of inserted text."))) {
- ui.previewTextEdit->setTextBackgroundColor(ui.insertionColorDisplayLabel->color());
- ui.previewTextEdit->moveCursor(QTextCursor::Start);
- }
-
- //update the deletion-text
- if (ui.previewTextEdit->find(i18n("This is a line of deleted text."))) {
- ui.previewTextEdit->setTextBackgroundColor(ui.deletionColorDisplayLabel->color());
- ui.previewTextEdit->moveCursor(QTextCursor::Start);
- }
-
- //update the format-change-text
- if (ui.previewTextEdit->find(i18n("This is a line of text whose format has been changed."))) {
- ui.previewTextEdit->setTextBackgroundColor(ui.formatColorDisplayLabel->color());
- ui.previewTextEdit->moveCursor(QTextCursor::Start);
- }
-}
-
-ChangeConfigureDialog::~ChangeConfigureDialog()
-{
-
-}
-
diff --git a/plugins/flake/textshape/dialogs/ChangeConfigureDialog.h b/plugins/flake/textshape/dialogs/ChangeConfigureDialog.h
deleted file mode 100644
index b3ad7d6b55..0000000000
--- a/plugins/flake/textshape/dialogs/ChangeConfigureDialog.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2009 Ganesh Paramasivam <ganesh@crystalfab.com>
- *
- * 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 __CHANGE_CONFIGURE_DIALOG_H__
-#define __CHANGE_CONFIGURE_DIALOG_H__
-
-#include <QLabel>
-#include <KoChangeTracker.h>
-
-class ColorDisplayLabel: public QLabel
-{
-public:
- explicit ColorDisplayLabel(QWidget *parent = 0);
- ~ColorDisplayLabel() override;
- void paintEvent(QPaintEvent *event) override;
- const QColor &color() const;
- void setColor(const QColor &color);
-
-private:
- QColor labelColor;
-};
-
-#include <ui_ChangeConfigureDialog.h>
-
-class ChangeConfigureDialog: public QDialog
-{
- Q_OBJECT
-
- typedef enum {
- eInsert,
- eDelete,
- eFormatChange,
- eChangeTypeNone
- } ChangeType;
-
-public:
- ChangeConfigureDialog(const QColor &insertionColor, const QColor &deletionColor, const QColor &formatChangeColor, const QString &authorName, KoChangeTracker::ChangeSaveFormat changeSaveFormat, QWidget *parent = 0);
- ~ChangeConfigureDialog() override;
-
- const QColor &getInsertionBgColor();
- const QColor &getDeletionBgColor();
- const QColor &getFormatChangeBgColor();
- const QString authorName();
- KoChangeTracker::ChangeSaveFormat saveFormat();
-
-private:
- Ui::ChangeConfigureDialog ui;
- void updatePreviewText();
- void colorSelect(ChangeType type);
-
-private Q_SLOTS:
- void insertionColorSelect();
- void deletionColorSelect();
- void formatChangeColorSelect();
-};
-#endif
diff --git a/plugins/flake/textshape/dialogs/ChangeConfigureDialog.ui b/plugins/flake/textshape/dialogs/ChangeConfigureDialog.ui
deleted file mode 100644
index c55f3f19f7..0000000000
--- a/plugins/flake/textshape/dialogs/ChangeConfigureDialog.ui
+++ /dev/null
@@ -1,332 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ChangeConfigureDialog</class>
- <widget class="QDialog" name="ChangeConfigureDialog">
- <property name="windowModality">
- <enum>Qt::WindowModal</enum>
- </property>
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>545</width>
- <height>490</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>Configure Change Tracking</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_4">
- <item row="0" column="0" colspan="3">
- <widget class="QLabel" name="label_2">
- <property name="font">
- <font>
- <pointsize>12</pointsize>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="text">
- <string>General Settings</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_3">
- <property name="text">
- <string>Saving Format</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QRadioButton" name="odf12RadioButton">
- <property name="text">
- <string>ODF 1.2</string>
- </property>
- </widget>
- </item>
- <item row="1" column="2">
- <widget class="QRadioButton" name="deltaXmlRadioButton">
- <property name="text">
- <string>DeltaXML (Experimental)</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="label_4">
- <property name="text">
- <string>Author Name</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1" colspan="2">
- <widget class="QLineEdit" name="authorNameLineEdit"/>
- </item>
- <item row="3" column="0" colspan="3">
- <widget class="QLabel" name="label">
- <property name="font">
- <font>
- <pointsize>12</pointsize>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="text">
- <string>Change Visualization Settings</string>
- </property>
- </widget>
- </item>
- <item row="4" column="0">
- <widget class="QGroupBox" name="insertionGroupBox">
- <property name="font">
- <font>
- <pointsize>9</pointsize>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="title">
- <string>Insertions</string>
- </property>
- <property name="flat">
- <bool>true</bool>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0">
- <widget class="QLabel" name="insertionColorLabel">
- <property name="font">
- <font>
- <pointsize>10</pointsize>
- <weight>50</weight>
- <bold>false</bold>
- </font>
- </property>
- <property name="text">
- <string>Background Color</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="ColorDisplayLabel" name="insertionColorDisplayLabel">
- <property name="autoFillBackground">
- <bool>false</bool>
- </property>
- <property name="lineWidth">
- <number>1</number>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="insertionColorButton">
- <property name="text">
- <string>...</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- <item row="4" column="1" rowspan="3" colspan="2">
- <widget class="QTextEdit" name="previewTextEdit">
- <property name="tabChangesFocus">
- <bool>false</bool>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- <property name="html">
- <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
-&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
-p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Bitstream Vera Sans'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:11pt; font-weight:600; text-decoration: underline;&quot;&gt;Preview&lt;/span&gt;&lt;/p&gt;
-&lt;p align=&quot;center&quot; style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:12pt; font-weight:600;&quot;&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-weight:600;&quot;&gt;Inserted Text&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;This is a line of text before the inserted text. This is a line of inserted text. This is a line after the inserted text.&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';&quot;&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-weight:600;&quot;&gt;Deleted Text&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;This is a line of text before the deleted text. This is a line of deleted text. This is a line after the deleted text.&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';&quot;&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-weight:600;&quot;&gt;Formatted Text&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;This is a line of text before the format-change text. This is a line of text whose format has been changed. This is a line of text after the format-change text.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- </widget>
- </item>
- <item row="5" column="0">
- <widget class="QGroupBox" name="deletionGroupBox">
- <property name="font">
- <font>
- <pointsize>9</pointsize>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="title">
- <string>Deletions</string>
- </property>
- <property name="flat">
- <bool>true</bool>
- </property>
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="0" column="0">
- <widget class="QLabel" name="deletionColorLabel">
- <property name="font">
- <font>
- <pointsize>10</pointsize>
- <weight>50</weight>
- <bold>false</bold>
- </font>
- </property>
- <property name="text">
- <string>Background Color</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <widget class="ColorDisplayLabel" name="deletionColorDisplayLabel">
- <property name="autoFillBackground">
- <bool>false</bool>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="deletionColorButton">
- <property name="text">
- <string>...</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- <zorder>deletionColorLabel</zorder>
- <zorder>deletionColorDisplayLabel</zorder>
- <zorder>deletionColorButton</zorder>
- <zorder>insertionGroupBox</zorder>
- <zorder>insertionGroupBox</zorder>
- </widget>
- </item>
- <item row="6" column="0">
- <widget class="QGroupBox" name="formatGroupBox">
- <property name="font">
- <font>
- <pointsize>9</pointsize>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="title">
- <string>Format Changes</string>
- </property>
- <property name="flat">
- <bool>true</bool>
- </property>
- <layout class="QGridLayout" name="gridLayout_3">
- <item row="0" column="0">
- <widget class="QLabel" name="formatColorLabel">
- <property name="font">
- <font>
- <pointsize>10</pointsize>
- <weight>50</weight>
- <bold>false</bold>
- </font>
- </property>
- <property name="text">
- <string>Background Color</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <layout class="QHBoxLayout" name="horizontalLayout_3">
- <item>
- <widget class="ColorDisplayLabel" name="formatColorDisplayLabel">
- <property name="autoFillBackground">
- <bool>false</bool>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="formatColorButton">
- <property name="text">
- <string>...</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- <item row="7" column="0" colspan="3">
- <widget class="QDialogButtonBox" name="okCancelButtonBox">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>ColorDisplayLabel</class>
- <extends>QLabel</extends>
- <header location="global">QLabel</header>
- </customwidget>
- </customwidgets>
- <tabstops>
- <tabstop>okCancelButtonBox</tabstop>
- </tabstops>
- <resources/>
- <connections>
- <connection>
- <sender>okCancelButtonBox</sender>
- <signal>accepted()</signal>
- <receiver>ChangeConfigureDialog</receiver>
- <slot>accept()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>248</x>
- <y>254</y>
- </hint>
- <hint type="destinationlabel">
- <x>157</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>okCancelButtonBox</sender>
- <signal>rejected()</signal>
- <receiver>ChangeConfigureDialog</receiver>
- <slot>reject()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>316</x>
- <y>260</y>
- </hint>
- <hint type="destinationlabel">
- <x>286</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- </connections>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/ChangeTrackingOptionsWidget.cpp b/plugins/flake/textshape/dialogs/ChangeTrackingOptionsWidget.cpp
deleted file mode 100644
index 15f3406ff1..0000000000
--- a/plugins/flake/textshape/dialogs/ChangeTrackingOptionsWidget.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Ganesh Paramasivam <ganesh@crystalfab.com>
- *
- * 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 "ChangeTrackingOptionsWidget.h"
-#include <QDebug>
-
-ChangeTrackingOptionsWidget::ChangeTrackingOptionsWidget(TextTool *tool, QWidget *parent)
- : QWidget(parent)
- , m_tool(tool)
-{
- widget.setupUi(this);
- connect(widget.recordChangesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(recordChangesChanged(int)));
- connect(widget.showChangesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(showChangesChanged(int)));
- connect(widget.configureChangeTrackingButton, SIGNAL(clicked(bool)), this, SLOT(configureSettingsPressed()));
-}
-
-void ChangeTrackingOptionsWidget::toggleShowChanges(bool isChecked)
-{
- widget.showChangesCheckBox->setChecked(isChecked);
-}
-
-void ChangeTrackingOptionsWidget::toggleRecordChanges(bool isChecked)
-{
- widget.recordChangesCheckBox->setChecked(isChecked);
-}
-
-void ChangeTrackingOptionsWidget::recordChangesChanged(int isChecked)
-{
- m_tool->toggleRecordChanges(isChecked);
- emit doneWithFocus();
-}
-
-void ChangeTrackingOptionsWidget::showChangesChanged(int isChecked)
-{
- m_tool->toggleShowChanges(isChecked);
- emit doneWithFocus();
-}
-
-void ChangeTrackingOptionsWidget::configureSettingsPressed()
-{
- m_tool->configureChangeTracking();
- emit doneWithFocus();
-}
-
diff --git a/plugins/flake/textshape/dialogs/ChangeTrackingOptionsWidget.h b/plugins/flake/textshape/dialogs/ChangeTrackingOptionsWidget.h
deleted file mode 100644
index dad8da0bf2..0000000000
--- a/plugins/flake/textshape/dialogs/ChangeTrackingOptionsWidget.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Ganesh Paramasivam <ganesh@crystalfab.com>
- *
- * 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 __CHANGE_TRACKING_OPTIONS_WIDGET_H__
-#define __CHANGE_TRACKING_OPTIONS_WIDGET_H__
-
-#include <ui_ChangeTrackingOptionsWidget.h>
-#include <TextTool.h>
-
-class ChangeTrackingOptionsWidget : public QWidget
-{
- Q_OBJECT
-public:
- explicit ChangeTrackingOptionsWidget(TextTool *tool, QWidget *parent = 0);
-
-private Q_SLOTS:
- void recordChangesChanged(int isChecked);
- void showChangesChanged(int isChecked);
- void configureSettingsPressed();
-
-public Q_SLOTS:
- void toggleShowChanges(bool on);
- void toggleRecordChanges(bool on);
-
-Q_SIGNALS:
- void doneWithFocus();
-
-private:
- Ui::ChangeTrackingOptions widget;
- TextTool *m_tool;
-};
-
-#endif
-
diff --git a/plugins/flake/textshape/dialogs/ChangeTrackingOptionsWidget.ui b/plugins/flake/textshape/dialogs/ChangeTrackingOptionsWidget.ui
deleted file mode 100644
index 5e5d005e90..0000000000
--- a/plugins/flake/textshape/dialogs/ChangeTrackingOptionsWidget.ui
+++ /dev/null
@@ -1,191 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ChangeTrackingOptions</class>
- <widget class="QWidget" name="ChangeTrackingOptions">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>303</width>
- <height>194</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>Change Tracking Options</string>
- </property>
- <widget class="QWidget" name="layoutWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>301</width>
- <height>191</height>
- </rect>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <property name="sizeConstraint">
- <enum>QLayout::SetNoConstraint</enum>
- </property>
- <item row="0" column="1">
- <spacer name="verticalSpacer_4">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>38</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="0">
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Expanding</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>48</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="2">
- <spacer name="horizontalSpacer_4">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Expanding</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>48</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="2" column="1">
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>38</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="3" column="0">
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>48</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="3" column="2">
- <spacer name="horizontalSpacer_5">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>48</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="4" column="1">
- <spacer name="verticalSpacer_2">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>38</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="5" column="0">
- <spacer name="horizontalSpacer_3">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>48</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="5" column="1">
- <widget class="QPushButton" name="configureChangeTrackingButton">
- <property name="text">
- <string>Configure Settings</string>
- </property>
- </widget>
- </item>
- <item row="5" column="2">
- <spacer name="horizontalSpacer_6">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>48</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="6" column="1">
- <spacer name="verticalSpacer_3">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>38</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="1">
- <widget class="QCheckBox" name="recordChangesCheckBox">
- <property name="text">
- <string>Record Changes</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QCheckBox" name="showChangesCheckBox">
- <property name="text">
- <string>Show Changes</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/CharacterGeneral.cpp b/plugins/flake/textshape/dialogs/CharacterGeneral.cpp
deleted file mode 100644
index e3099459ac..0000000000
--- a/plugins/flake/textshape/dialogs/CharacterGeneral.cpp
+++ /dev/null
@@ -1,204 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- * Copyright (C) 2012 Mojtaba Shahi Senobari <mojtaba.shahi3000@gmail.com>
- *
- * 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 "CharacterGeneral.h"
-#include "CharacterHighlighting.h"
-#include "LanguageTab.h"
-#include "FontDecorations.h"
-#include "FormattingPreview.h"
-
-#include "StylesCombo.h"
-#include "StylesModel.h"
-
-#include <KoParagraphStyle.h>
-#include <KoStyleThumbnailer.h>
-#include <KoStyleManager.h>
-#include <KoCharacterStyle.h>
-
-#include <QDebug>
-
-CharacterGeneral::CharacterGeneral(QWidget *parent)
- : QWidget(parent)
- , m_style(0)
- , m_styleManager(0)
- , m_thumbnail(new KoStyleThumbnailer())
- , m_paragraphStyleModel(new StylesModel(0, StylesModel::ParagraphStyle))
- , m_characterInheritedStyleModel(new StylesModel(0, StylesModel::CharacterStyle))
-{
- widget.setupUi(this);
- // we don't have next style for character styles
- widget.nextStyle->setVisible(false);
- widget.label_2->setVisible(false);
- //
-
- // paragraph style model
- widget.nextStyle->showEditIcon(false);
- widget.nextStyle->setStyleIsOriginal(true);
- m_paragraphStyleModel->setStyleThumbnailer(m_thumbnail);
- widget.nextStyle->setStylesModel(m_paragraphStyleModel);
- // inherited style model
- widget.inheritStyle->showEditIcon(false);
- widget.inheritStyle->setStyleIsOriginal(true);
- //for character General
- m_characterInheritedStyleModel->setStyleThumbnailer(m_thumbnail);
- widget.inheritStyle->setStylesModel(m_characterInheritedStyleModel);
- widget.inheritStyle->setEnabled(false);
-
- m_characterHighlighting = new CharacterHighlighting(true, this);
- connect(m_characterHighlighting, SIGNAL(charStyleChanged()), this, SIGNAL(styleChanged()));
- connect(m_characterHighlighting, SIGNAL(charStyleChanged()), this, SLOT(setPreviewCharacterStyle()));
-
- m_languageTab = new LanguageTab(true, this);
-
- widget.tabs->addTab(m_characterHighlighting, i18n("Font"));
-
- m_languageTab->setVisible(false);
-
- connect(widget.name, SIGNAL(textChanged(QString)), this, SIGNAL(nameChanged(QString)));
-}
-
-void CharacterGeneral::hideStyleName(bool hide)
-{
- if (hide) {
- disconnect(widget.name, SIGNAL(textChanged(QString)), this, SIGNAL(nameChanged(QString)));
- widget.tabs->removeTab(0);
- m_nameHidden = true;
- }
-}
-
-void CharacterGeneral::setStyle(KoCharacterStyle *style)
-{
- m_style = style;
- if (m_style == 0) {
- return;
- }
- blockSignals(true);
-
- if (!m_nameHidden) {
- widget.name->setText(style->name());
- }
-
- m_characterHighlighting->setDisplay(style);
- //m_languageTab->setDisplay(style);
-
- widget.preview->setCharacterStyle(style);
-
- if (m_styleManager) {
- KoCharacterStyle *parentStyle = style->parentStyle();
- if (parentStyle) {
- widget.inheritStyle->setCurrentIndex(m_characterInheritedStyleModel->indexOf(parentStyle).row());
- }
- }
-
- blockSignals(false);
-}
-
-void CharacterGeneral::save(KoCharacterStyle *style)
-{
- KoCharacterStyle *savingStyle;
- if (style == 0) {
- if (m_style == 0) {
- return;
- } else {
- savingStyle = m_style;
- }
- } else {
- savingStyle = style;
- }
-
- m_characterHighlighting->save(savingStyle);
- //m_languageTab->save(savingStyle);
- savingStyle->setName(widget.name->text());
-
- if (m_style == savingStyle) {
- emit styleAltered(savingStyle);
- }
-}
-
-void CharacterGeneral::switchToGeneralTab()
-{
- widget.tabs->setCurrentIndex(0);
-}
-
-void CharacterGeneral::selectName()
-{
- widget.tabs->setCurrentIndex(widget.tabs->indexOf(widget.generalTab));
- widget.name->selectAll();
- widget.name->setFocus(Qt::OtherFocusReason);
-}
-
-void CharacterGeneral::setPreviewCharacterStyle()
-{
- KoCharacterStyle *charStyle = new KoCharacterStyle();
- save(charStyle);
- if (charStyle) {
- widget.preview->setCharacterStyle(charStyle);
- }
-
- delete charStyle;
-}
-
-QString CharacterGeneral::styleName() const
-{
- return widget.name->text();
-}
-
-void CharacterGeneral::setStyleManager(KoStyleManager *sm)
-{
- if (!sm) {
- return;
- }
- m_styleManager = sm;
- m_paragraphStyleModel->setStyleManager(m_styleManager);
- m_characterInheritedStyleModel->setStyleManager(m_styleManager);
-}
-
-void CharacterGeneral::updateNextStyleCombo(KoParagraphStyle *style)
-{
- if (!style) {
- return;
- }
-
- widget.nextStyle->setCurrentIndex(m_paragraphStyleModel->indexOf(style).row());
- m_paragraphStyleModel->setCurrentParagraphStyle(style->styleId());
-}
-
-int CharacterGeneral::nextStyleId()
-{
- if (!m_styleManager) {
- return 0;
- }
- int nextStyleIndex = widget.nextStyle->currentIndex();
- QModelIndex paragraphStyleIndex = m_paragraphStyleModel->index(nextStyleIndex);
- quint64 internalId = paragraphStyleIndex.internalId();
- KoParagraphStyle *paragraphStyle = m_styleManager->paragraphStyle(internalId);
- if (paragraphStyle) {
- return paragraphStyle->styleId();
- } else {
- return 0;
- }
-}
-
-KoCharacterStyle *CharacterGeneral::style() const
-{
- return m_style;
-}
diff --git a/plugins/flake/textshape/dialogs/CharacterGeneral.h b/plugins/flake/textshape/dialogs/CharacterGeneral.h
deleted file mode 100644
index 8baeda06a0..0000000000
--- a/plugins/flake/textshape/dialogs/CharacterGeneral.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 CHARACTERGENERAL_H
-#define CHARACTERGENERAL_H
-
-#include <ui_CharacterGeneral.h>
-
-#include <QWidget>
-
-class KoCharacterStyle;
-class KoStyleManager;
-class KoStyleThumbnailer;
-class FontDecorations;
-class CharacterHighlighting;
-class LanguageTab;
-class StylesModel;
-
-class CharacterGeneral : public QWidget
-{
- Q_OBJECT
-public:
- explicit CharacterGeneral(QWidget *parent = 0);
-
- void setStyle(KoCharacterStyle *style);
- void hideStyleName(bool hide);
- bool isStyleChanged();
- QString styleName() const;
- void selectName();
- void setStyleManager(KoStyleManager *sm); // set style manager for m_paragraph style model
- void updateNextStyleCombo(KoParagraphStyle *style); // set current style in next style combo
- int nextStyleId(); //return the current style id in next style combo
-
- KoCharacterStyle *style() const;
-
-public Q_SLOTS:
- void save(KoCharacterStyle *style = 0);
-
- void switchToGeneralTab();
-
-Q_SIGNALS:
- void nameChanged(const QString &name);
- void styleAltered(const KoCharacterStyle *style); // when saving
- void styleChanged(); /// when user modifying
-
-private Q_SLOTS:
- void setPreviewCharacterStyle();
-
-protected:
- Ui::CharacterGeneral widget;
-
-private:
- bool m_nameHidden;
-
- FontDecorations *m_characterDecorations;
- CharacterHighlighting *m_characterHighlighting;
- LanguageTab *m_languageTab;
-
- KoCharacterStyle *m_style;
- KoStyleManager *m_styleManager;
- KoStyleThumbnailer *m_thumbnail;
- StylesModel *m_paragraphStyleModel;
- StylesModel *m_characterInheritedStyleModel;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/CharacterGeneral.ui b/plugins/flake/textshape/dialogs/CharacterGeneral.ui
deleted file mode 100644
index 37ddbff560..0000000000
--- a/plugins/flake/textshape/dialogs/CharacterGeneral.ui
+++ /dev/null
@@ -1,133 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>CharacterGeneral</class>
- <widget class="QWidget" name="CharacterGeneral">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>512</width>
- <height>363</height>
- </rect>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <property name="margin">
- <number>0</number>
- </property>
- <item>
- <widget class="QTabWidget" name="tabs">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
- <horstretch>99</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <widget class="QWidget" name="generalTab">
- <attribute name="title">
- <string>General</string>
- </attribute>
- <layout class="QGridLayout">
- <item row="0" column="0" colspan="2">
- <widget class="QLabel" name="label">
- <property name="text">
- <string comment="Name of the style">Name:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item row="0" column="2">
- <widget class="QLineEdit" name="name"/>
- </item>
- <item row="1" column="0" colspan="2">
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>Next style:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>nextStyle</cstring>
- </property>
- </widget>
- </item>
- <item row="1" column="2">
- <widget class="StylesCombo" name="nextStyle"/>
- </item>
- <item row="2" column="0" colspan="2">
- <widget class="QLabel" name="label_3">
- <property name="text">
- <string>Parent style:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>inheritStyle</cstring>
- </property>
- </widget>
- </item>
- <item row="2" column="2">
- <widget class="StylesCombo" name="inheritStyle"/>
- </item>
- <item row="3" column="0" colspan="3">
- <widget class="QCheckBox" name="inToc">
- <property name="text">
- <string>Include in table of contents</string>
- </property>
- </widget>
- </item>
- <item row="4" column="0">
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- </widget>
- </item>
- <item>
- <widget class="FormattingPreview" name="preview">
- <property name="minimumSize">
- <size>
- <width>500</width>
- <height>100</height>
- </size>
- </property>
- <property name="frameShape">
- <enum>QFrame::StyledPanel</enum>
- </property>
- <property name="frameShadow">
- <enum>QFrame::Raised</enum>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>FormattingPreview</class>
- <extends>QFrame</extends>
- <header>dialogs/FormattingPreview.h</header>
- <container>1</container>
- </customwidget>
- <customwidget>
- <class>StylesCombo</class>
- <extends>QComboBox</extends>
- <header>dialogs/StylesCombo.h</header>
- <container>1</container>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/CharacterHighlighting.cpp b/plugins/flake/textshape/dialogs/CharacterHighlighting.cpp
deleted file mode 100644
index d5aa949b40..0000000000
--- a/plugins/flake/textshape/dialogs/CharacterHighlighting.cpp
+++ /dev/null
@@ -1,489 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2001, 2002 Montel Laurent <lmontel@mandrakesoft.com>
- Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
- Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- Copyright (C) 2011 Mojtaba Shahi Senobari <mojtaba.shahi3000@gmail.com>
-
- 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 "CharacterHighlighting.h"
-
-#include <KoText.h>
-#include <KoCharacterStyle.h>
-#include <KoIcon.h>
-
-#include <QFontDatabase>
-#include <QStringList>
-#include <QVBoxLayout>
-#include <QMessageBox>
-#include <QTextCharFormat>
-
-enum Position {
- Normal,
- Superscript,
- Subscript,
- Custom
-};
-
-CharacterHighlighting::CharacterHighlighting(bool uniqueFormat, QWidget *parent)
- : QWidget(parent)
- , m_uniqueFormat(uniqueFormat)
-{
- widget.setupUi(this);
-
- QStringList list;
- KFontChooser::getFontList(list, KFontChooser::SmoothScalableFonts);
- m_fontChooser = new KFontChooser(this, (m_uniqueFormat) ? KFontChooser::NoDisplayFlags : KFontChooser::ShowDifferences, list, false);
- m_fontChooser->setSampleBoxVisible(false);
- widget.fontLayout->addWidget(m_fontChooser);
-
- widget.capitalizationList->addItems(capitalizationList());
- widget.underlineStyle->addItems(KoText::underlineTypeList());
- widget.underlineLineStyle->addItems(KoText::underlineStyleList());
-
- widget.positionList->addItems(fontLayoutPositionList());
-
- widget.strikethroughType->addItems(KoText::underlineTypeList()); //TODO make KoText consistent: either add strikethroughTypeList, or change from underlineTypeList to lineTypeList
- widget.strikethroughLineStyle->addItems(KoText::underlineStyleList()); //TODO idem
-
- connect(widget.underlineStyle, SIGNAL(activated(int)), this, SLOT(underlineTypeChanged(int)));
- connect(widget.underlineLineStyle, SIGNAL(activated(int)), this, SLOT(underlineStyleChanged(int)));
- connect(widget.underlineColor, SIGNAL(changed(QColor)), this, SLOT(underlineColorChanged(QColor)));
-
- connect(widget.strikethroughType, SIGNAL(activated(int)), this, SLOT(strikethroughTypeChanged(int)));
- connect(widget.strikethroughLineStyle, SIGNAL(activated(int)), this, SLOT(strikethroughStyleChanged(int)));
- connect(widget.strikethroughColor, SIGNAL(changed(QColor)), this, SLOT(strikethroughColorChanged(QColor)));
-
- connect(widget.capitalizationList, SIGNAL(activated(int)), this, SLOT(capitalisationChanged(int)));
-
- connect(widget.positionList, SIGNAL(activated(int)), this, SLOT(positionChanged(int)));
-
- connect(m_fontChooser, SIGNAL(fontSelected(QFont)), this, SIGNAL(fontChanged(QFont)));
- connect(m_fontChooser, SIGNAL(fontSelected(QFont)), this, SIGNAL(charStyleChanged()));
-
- const QIcon clearIcon = koIcon("edit-clear");
- widget.resetTextColor->setIcon(clearIcon);
- widget.resetBackground->setIcon(clearIcon);
- connect(widget.textColor, SIGNAL(changed(QColor)), this, SLOT(textColorChanged()));
- connect(widget.backgroundColor, SIGNAL(changed(QColor)), this, SLOT(backgroundColorChanged()));
- connect(widget.resetTextColor, SIGNAL(clicked()), this, SLOT(clearTextColor()));
- connect(widget.resetBackground, SIGNAL(clicked()), this, SLOT(clearBackgroundColor()));
- connect(widget.enableText, SIGNAL(toggled(bool)), this, SLOT(textToggled(bool)));
- connect(widget.enableBackground, SIGNAL(toggled(bool)), this, SLOT(backgroundToggled(bool)));
-}
-
-KoCharacterStyle::LineType CharacterHighlighting::indexToLineType(int index)
-{
- KoCharacterStyle::LineType lineType;
- switch (index) {
- case 1: lineType = KoCharacterStyle::SingleLine; break;
- case 2: lineType = KoCharacterStyle::DoubleLine; break;
- case 0:
- default:
- lineType = KoCharacterStyle::NoLineType; break;
- }
- return lineType;
-}
-
-KoCharacterStyle::LineStyle CharacterHighlighting::indexToLineStyle(int index)
-{
- KoCharacterStyle::LineStyle lineStyle;
- switch (index) {
- case 1: lineStyle = KoCharacterStyle::DashLine; break;
- case 2: lineStyle = KoCharacterStyle::DottedLine; break;
- case 3: lineStyle = KoCharacterStyle::DotDashLine; break;
- case 4: lineStyle = KoCharacterStyle::DotDotDashLine; break;
- case 5: lineStyle = KoCharacterStyle::WaveLine; break;
- case 0:
- default:
- lineStyle = KoCharacterStyle::SolidLine; break;
- }
- return lineStyle;
-}
-
-int CharacterHighlighting::lineTypeToIndex(KoCharacterStyle::LineType type)
-{
- int index;
- switch (type) {
- case KoCharacterStyle::NoLineType: index = 0; break;
- case KoCharacterStyle::SingleLine: index = 1; break;
- case KoCharacterStyle::DoubleLine: index = 2; break;
- default: index = 0; break;
- }
- return index;
-}
-
-int CharacterHighlighting::lineStyleToIndex(KoCharacterStyle::LineStyle type)
-{
- int index;
- switch (type) {
- case KoCharacterStyle::SolidLine: index = 0; break;
- case KoCharacterStyle::DashLine: index = 1; break;
- case KoCharacterStyle::DottedLine: index = 2; break;
- case KoCharacterStyle::DotDashLine: index = 3; break;
- case KoCharacterStyle::DotDotDashLine: index = 4; break;
- case KoCharacterStyle::WaveLine: index = 5; break;
- default: index = 0; break;
- }
- return index;
-}
-
-void CharacterHighlighting::capitalisationChanged(int item)
-{
- if (m_uniqueFormat || widget.capitalizationList->currentIndex() >= 0) {
- switch (item) {
- case 0:
- emit capitalizationChanged(QFont::MixedCase);
- m_mixedCaseInherited = false;
- break;
- case 1:
- emit capitalizationChanged(QFont::SmallCaps);
- m_smallCapsInherited = false;
- break;
- case 2:
- emit capitalizationChanged(QFont::AllUppercase);
- m_allUpperCaseInherited = false;
- break;
- case 3:
- emit capitalizationChanged(QFont::AllLowercase);
- m_allLowerCaseInherited = false;
- break;
- case 4:
- emit capitalizationChanged(QFont::Capitalize);
- m_capitalizInherited = false;
- break;
- }
- }
- emit charStyleChanged();
-}
-
-void CharacterHighlighting::positionChanged(int item)
-{
- Q_UNUSED(item);
- m_positionInherited = false;
- emit charStyleChanged();
-}
-
-void CharacterHighlighting::underlineTypeChanged(int item)
-{
- widget.underlineLineStyle->setEnabled(item > 0);
- widget.underlineColor->setEnabled(item > 0);
- m_underlineInherited = false;
- emit underlineChanged(indexToLineType(item), indexToLineStyle(widget.underlineLineStyle->currentIndex()), widget.underlineColor->color());
- emit charStyleChanged();
-}
-
-void CharacterHighlighting::underlineStyleChanged(int item)
-{
- if (widget.underlineStyle->currentIndex()) {
- emit underlineChanged(indexToLineType(widget.underlineStyle->currentIndex()), indexToLineStyle(item), widget.underlineColor->color());
- }
- m_underlineInherited = false;
- emit charStyleChanged();
-}
-
-void CharacterHighlighting::underlineColorChanged(QColor color)
-{
- if (widget.underlineStyle->currentIndex()) {
- emit underlineChanged(indexToLineType(widget.underlineStyle->currentIndex()), indexToLineStyle(widget.underlineLineStyle->currentIndex()), color);
- }
- m_underlineInherited = false;
- emit charStyleChanged();
-}
-
-void CharacterHighlighting::strikethroughTypeChanged(int item)
-{
- widget.strikethroughLineStyle->setEnabled(item > 0);
- widget.strikethroughColor->setEnabled(item > 0);
- m_strikeoutInherited = false;
- emit strikethroughChanged(indexToLineType(item), indexToLineStyle(widget.strikethroughLineStyle->currentIndex()), widget.strikethroughColor->color());
- emit charStyleChanged();
-}
-
-void CharacterHighlighting::strikethroughStyleChanged(int item)
-{
- if (widget.strikethroughType->currentIndex()) {
- emit strikethroughChanged(indexToLineType(widget.strikethroughType->currentIndex()), indexToLineStyle(item), widget.strikethroughColor->color());
- }
- m_strikeoutInherited = false;
- emit charStyleChanged();
-}
-
-void CharacterHighlighting::strikethroughColorChanged(QColor color)
-{
- if (widget.strikethroughType->currentIndex()) {
- emit strikethroughChanged(indexToLineType(widget.strikethroughType->currentIndex()), indexToLineStyle(widget.strikethroughLineStyle->currentIndex()), color);
- }
- m_strikeoutInherited = false;
- emit charStyleChanged();
-}
-
-void CharacterHighlighting::backgroundColorChanged()
-{
- m_backgroundColorReset = false; m_backgroundColorChanged = true;
- if (widget.enableBackground->isChecked() && widget.backgroundColor->color().isValid()) {
- emit backgroundColorChanged(widget.backgroundColor->color());
- }
- emit charStyleChanged();
-}
-
-void CharacterHighlighting::textColorChanged()
-{
- m_textColorReset = false; m_textColorChanged = true;
- if (widget.enableText->isChecked() && widget.textColor->color().isValid()) {
- emit textColorChanged(widget.textColor->color());
- }
- emit charStyleChanged();
-}
-
-void CharacterHighlighting::textToggled(bool state)
-{
- widget.textColor->setEnabled(state);
- widget.resetTextColor->setEnabled(state);
- emit charStyleChanged();
-}
-
-void CharacterHighlighting::backgroundToggled(bool state)
-{
- widget.backgroundColor->setEnabled(state);
- widget.resetBackground->setEnabled(state);
- emit charStyleChanged();
-}
-
-void CharacterHighlighting::clearTextColor()
-{
- widget.textColor->setColor(widget.textColor->defaultColor());
- m_textColorReset = true;
- emit textColorChanged(QColor(Qt::black));
- emit charStyleChanged();
-}
-
-void CharacterHighlighting::clearBackgroundColor()
-{
- widget.backgroundColor->setColor(widget.backgroundColor->defaultColor());
- m_backgroundColorReset = true;
- emit backgroundColorChanged(QColor(Qt::transparent));
- emit charStyleChanged();
-}
-
-QStringList CharacterHighlighting::capitalizationList()
-{
- QStringList lst;
- lst << i18n("Normal");
- lst << i18n("Small Caps");
- lst << i18n("Uppercase");
- lst << i18n("Lowercase");
- lst << i18n("Capitalize");
- return lst;
-}
-
-QStringList CharacterHighlighting::fontLayoutPositionList()
-{
- QStringList lst;
- lst << i18n("Normal");
- lst << i18n("Superscript");
- lst << i18n("Subscript");
- return lst;
-}
-void CharacterHighlighting::setDisplay(KoCharacterStyle *style)
-{
- if (style == 0) {
- return;
- }
-
- QFont font = style->font();
- QFontDatabase dbase;
- QStringList availableStyles = dbase.styles(font.family());
- if (font.italic() && !(availableStyles.contains(QString("Italic"))) && availableStyles.contains(QString("Oblique"))) {
- font.setStyle(QFont::StyleOblique);
- }
- m_fontChooser->setFont(font);
-
- m_positionInherited = !style->hasProperty(QTextFormat::TextVerticalAlignment);
- switch (style->verticalAlignment()) {
- case QTextCharFormat::AlignSuperScript:
- widget.positionList->setCurrentIndex(1);
- break;
- case QTextCharFormat::AlignSubScript:
- widget.positionList->setCurrentIndex(2);
- break;
- default:
- // TODO check if its custom instead.
- widget.positionList->setCurrentIndex(0);
- }
- if (!m_uniqueFormat) {
- widget.positionList->setEnabled(false);
- widget.positionList->setCurrentIndex(-1);
- }
-
- m_underlineInherited = !style->hasProperty(KoCharacterStyle::UnderlineStyle)
- && !style->hasProperty(KoCharacterStyle::UnderlineType)
- && !style->hasProperty(QTextFormat::TextUnderlineColor);
- m_strikeoutInherited = !style->hasProperty(KoCharacterStyle::StrikeOutStyle)
- && !style->hasProperty(KoCharacterStyle::StrikeOutType)
- && !style->hasProperty(KoCharacterStyle::StrikeOutColor);
- m_mixedCaseInherited = !style->hasProperty(QFont::MixedCase);
- m_smallCapsInherited = !style->hasProperty(QFont::SmallCaps);
- m_allUpperCaseInherited = !style->hasProperty(QFont::AllUppercase);
- m_allLowerCaseInherited = !style->hasProperty(QFont::AllLowercase);
- m_capitalizInherited = !style->hasProperty(QFont::Capitalize);
-
- //set the underline up
- widget.underlineStyle->setCurrentIndex(1);
- widget.underlineLineStyle->setCurrentIndex(lineStyleToIndex(style->underlineStyle()));
- if (m_uniqueFormat) {
- widget.underlineStyle->setCurrentIndex(lineTypeToIndex(style->underlineType()));
- } else {
- widget.underlineStyle->setCurrentIndex(-1);
- }
-
- underlineTypeChanged(widget.underlineStyle->currentIndex());
- widget.underlineColor->setColor(style->underlineColor());
-
- //set the strikethrough up
- widget.strikethroughType->setCurrentIndex(1);
- widget.strikethroughLineStyle->setCurrentIndex(lineStyleToIndex(style->strikeOutStyle()));
- if (m_uniqueFormat) {
- widget.strikethroughType->setCurrentIndex(lineTypeToIndex(style->strikeOutType()));
- } else {
- widget.strikethroughType->setCurrentIndex(-1);
- }
- strikethroughTypeChanged(widget.strikethroughType->currentIndex());
- widget.strikethroughColor->setColor(style->strikeOutColor());
-
- //Now set the capitalisation
- int index;
- switch (style->fontCapitalization()) {
- case QFont::MixedCase: widget.capitalizationList->setCurrentIndex(0); index = 0; break;
- case QFont::SmallCaps: widget.capitalizationList->setCurrentIndex(1); index = 1; break;
- case QFont::AllUppercase: widget.capitalizationList->setCurrentIndex(2); index = 2; break;
- case QFont::AllLowercase: widget.capitalizationList->setCurrentIndex(3); index = 3; break;
- case QFont::Capitalize: widget.capitalizationList->setCurrentIndex(4); index = 4; break;
- default:
- widget.capitalizationList->setCurrentIndex(0);
- index = 0;
- break;
- }
-
- if (m_uniqueFormat) {
- capitalisationChanged(index);
- } else {
- widget.capitalizationList->setCurrentIndex(-1);
- widget.capitalizationList->setEnabled(false);
- }
-
- //Set font decoration display
- widget.enableText->setVisible(!m_uniqueFormat);
- widget.enableText->setChecked(m_uniqueFormat);
- textToggled(m_uniqueFormat);
- widget.enableBackground->setVisible(!m_uniqueFormat);
- widget.enableBackground->setChecked(m_uniqueFormat);
- backgroundToggled(m_uniqueFormat);
-
- m_textColorChanged = false;
- m_backgroundColorChanged = false;
- m_textColorReset = ! style->hasProperty(QTextFormat::ForegroundBrush);
- if (m_textColorReset || (style->foreground().style() == Qt::NoBrush)) {
- clearTextColor();
- } else {
- widget.textColor->setColor(style->foreground().color());
- }
- m_backgroundColorReset = ! style->hasProperty(QTextFormat::BackgroundBrush);
- if (m_backgroundColorReset || (style->background().style() == Qt::NoBrush)) {
- clearBackgroundColor();
- } else {
- widget.backgroundColor->setColor(style->background().color());
- }
-}
-
-void CharacterHighlighting::save(KoCharacterStyle *style)
-{
- if (style == 0) {
- return;
- }
-
- KFontChooser::FontDiffFlags fontDiff = m_fontChooser->fontDiffFlags();
- if (m_uniqueFormat || (fontDiff & KFontChooser::FontDiffFamily)) {
- style->setFontFamily(m_fontChooser->font().family());
- }
- if (m_uniqueFormat || (fontDiff & KFontChooser::FontDiffSize)) {
- style->setFontPointSize(m_fontChooser->font().pointSize());
- }
- if (m_uniqueFormat || (fontDiff & KFontChooser::FontDiffStyle)) {
- style->setFontWeight(m_fontChooser->font().weight());
- style->setFontItalic(m_fontChooser->font().italic()); //TODO should set style instead of italic
- }
-
- if (!m_underlineInherited) {
- style->setUnderlineStyle(indexToLineStyle(widget.underlineLineStyle->currentIndex()));
- style->setUnderlineColor(widget.underlineColor->color());
- style->setUnderlineType(indexToLineType(widget.underlineStyle->currentIndex()));
- if (widget.underlineStyle->currentIndex() == 0) {
- style->setUnderlineStyle(KoCharacterStyle::NoLineStyle);
- }
- }
-
- if (!m_strikeoutInherited) {
- style->setStrikeOutStyle(indexToLineStyle(widget.strikethroughLineStyle->currentIndex()));
- style->setStrikeOutColor(widget.strikethroughColor->color());
- style->setStrikeOutType(indexToLineType(widget.strikethroughType->currentIndex()));
- if (widget.strikethroughType->currentIndex() == 0) {
- style->setStrikeOutStyle(KoCharacterStyle::NoLineStyle);
- }
- }
-
- if (m_uniqueFormat || widget.capitalizationList->currentIndex() >= 0) {
- if (widget.capitalizationList->currentIndex() == 0 && !m_mixedCaseInherited) {
- style->setFontCapitalization(QFont::MixedCase);
- } else if (widget.capitalizationList->currentIndex() == 1 && !m_smallCapsInherited) {
- style->setFontCapitalization(QFont::SmallCaps);
- } else if (widget.capitalizationList->currentIndex() == 2 && !m_allUpperCaseInherited) {
- style->setFontCapitalization(QFont::AllUppercase);
- } else if (widget.capitalizationList->currentIndex() == 3 && !m_allLowerCaseInherited) {
- style->setFontCapitalization(QFont::AllLowercase);
- } else if (widget.capitalizationList->currentIndex() == 4 && !m_capitalizInherited) {
- style->setFontCapitalization(QFont::Capitalize);
- }
- }
-
- QTextCharFormat::VerticalAlignment va;
- if (m_uniqueFormat || widget.positionList->currentIndex() >= 0) {
- if (!m_positionInherited) {
- if (widget.positionList->currentIndex() == 0) {
- va = QTextCharFormat::AlignNormal;
- } else if (widget.positionList->currentIndex() == 2) {
- va = QTextCharFormat::AlignSubScript;
- } else if (widget.positionList->currentIndex() == 1) {
- va = QTextCharFormat::AlignSuperScript;
- } else {
- va = QTextCharFormat::AlignNormal;
- }
- style->setVerticalAlignment(va);
- }
- }
-
- if (widget.enableBackground->isChecked() && m_backgroundColorReset) {
- style->setBackground(QBrush(Qt::NoBrush));
- } else if (widget.enableBackground->isChecked() && m_backgroundColorChanged) {
- style->setBackground(QBrush(widget.backgroundColor->color()));
- }
- if (widget.enableText->isChecked() && m_textColorReset) {
- style->setForeground(QBrush(Qt::NoBrush));
- } else if (widget.enableText->isChecked() && m_textColorChanged) {
- style->setForeground(QBrush(widget.textColor->color()));
- }
-}
diff --git a/plugins/flake/textshape/dialogs/CharacterHighlighting.h b/plugins/flake/textshape/dialogs/CharacterHighlighting.h
deleted file mode 100644
index 2bb0573bf0..0000000000
--- a/plugins/flake/textshape/dialogs/CharacterHighlighting.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2001,2002,2003 Montel Laurent <lmontel@mandrakesoft.com>
- Copyright (C) 2006 Thomas Zander <zander@kde.org>
- Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
-
- 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 CHARACTERHIGHLIGHTING_H
-#define CHARACTERHIGHLIGHTING_H
-
-#include <ui_CharacterHighlighting.h>
-
-#include "KoCharacterStyle.h"
-#include <kfontchooser.h>
-
-class QColor;
-
-class CharacterHighlighting : public QWidget
-{
- Q_OBJECT
-
-public:
- explicit CharacterHighlighting(bool uniqueFormat, QWidget *parent = 0);
- ~CharacterHighlighting() override {}
-
- void setDisplay(KoCharacterStyle *style);
- void save(KoCharacterStyle *style);
-
- QStringList capitalizationList();
- QStringList fontLayoutPositionList();
-
-Q_SIGNALS:
- void underlineChanged(KoCharacterStyle::LineType, KoCharacterStyle::LineStyle, QColor);
- void strikethroughChanged(KoCharacterStyle::LineType, KoCharacterStyle::LineStyle, QColor);
- void capitalizationChanged(QFont::Capitalization);
- void fontChanged(const QFont &font);
- void textColorChanged(QColor);
- void backgroundColorChanged(QColor);
- void charStyleChanged();
-
-private Q_SLOTS:
- void underlineTypeChanged(int item);
- void underlineStyleChanged(int item);
- void underlineColorChanged(QColor color);
- void strikethroughTypeChanged(int item);
- void strikethroughStyleChanged(int item);
- void strikethroughColorChanged(QColor color);
- void capitalisationChanged(int item);
- void positionChanged(int item);
- void textToggled(bool state);
- void backgroundToggled(bool state);
- void clearTextColor();
- void clearBackgroundColor();
- void textColorChanged();
- void backgroundColorChanged();
-
-private:
- KoCharacterStyle::LineType indexToLineType(int index);
- KoCharacterStyle::LineStyle indexToLineStyle(int index);
- int lineTypeToIndex(KoCharacterStyle::LineType type);
- int lineStyleToIndex(KoCharacterStyle::LineStyle type);
-
- Ui::CharacterHighlighting widget;
-
- KFontChooser *m_fontChooser;
-
- bool m_uniqueFormat;
- bool m_underlineInherited;
- bool m_strikeoutInherited;
- bool m_mixedCaseInherited;
- bool m_smallCapsInherited;
- bool m_allUpperCaseInherited;
- bool m_allLowerCaseInherited;
- bool m_capitalizInherited;
- bool m_positionInherited;
- bool m_hyphenateInherited;
- bool m_textColorChanged;
- bool m_textColorReset;
- bool m_backgroundColorChanged;
- bool m_backgroundColorReset;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/CharacterHighlighting.ui b/plugins/flake/textshape/dialogs/CharacterHighlighting.ui
deleted file mode 100644
index e791aee5ae..0000000000
--- a/plugins/flake/textshape/dialogs/CharacterHighlighting.ui
+++ /dev/null
@@ -1,227 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>CharacterHighlighting</class>
- <widget class="QWidget" name="CharacterHighlighting">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>520</width>
- <height>456</height>
- </rect>
- </property>
- <layout class="QVBoxLayout">
- <item>
- <layout class="QGridLayout" name="fontLayout"/>
- </item>
- <item>
- <layout class="QHBoxLayout">
- <item>
- <layout class="QHBoxLayout" stretch="0,0,0,0,1">
- <item>
- <widget class="QCheckBox" name="enableText"/>
- </item>
- <item>
- <widget class="QLabel" name="textColorLabel">
- <property name="text">
- <string>Text color:</string>
- </property>
- <property name="buddy">
- <cstring>textColor</cstring>
- </property>
- </widget>
- </item>
- <item>
- <widget class="KColorButton" name="textColor"/>
- </item>
- <item>
- <widget class="QToolButton" name="resetTextColor">
- <property name="text">
- <string>...</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QHBoxLayout" stretch="0,0,0,0,1">
- <item>
- <widget class="QCheckBox" name="enableBackground">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="backgroundColorLabel">
- <property name="text">
- <string>Background color:</string>
- </property>
- <property name="buddy">
- <cstring>backgroundColor</cstring>
- </property>
- </widget>
- </item>
- <item>
- <widget class="KColorButton" name="backgroundColor"/>
- </item>
- <item>
- <widget class="QToolButton" name="resetBackground">
- <property name="text">
- <string>...</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QFormLayout">
- <item row="0" column="0">
- <widget class="QLabel">
- <property name="text">
- <string>Underlining:</string>
- </property>
- <property name="buddy">
- <cstring>underlineStyle</cstring>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <layout class="QHBoxLayout">
- <item>
- <widget class="KComboBox" name="underlineStyle"/>
- </item>
- <item>
- <widget class="KComboBox" name="underlineLineStyle">
- <property name="enabled">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="KColorButton" name="underlineColor">
- <property name="enabled">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="1" column="0">
- <widget class="QLabel">
- <property name="text">
- <string>Strikethrough:</string>
- </property>
- <property name="buddy">
- <cstring>strikethroughType</cstring>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <layout class="QHBoxLayout">
- <item>
- <widget class="QComboBox" name="strikethroughType"/>
- </item>
- <item>
- <widget class="QComboBox" name="strikethroughLineStyle">
- <property name="enabled">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="KColorButton" name="strikethroughColor">
- <property name="enabled">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="2" column="0">
- <widget class="QLabel">
- <property name="text">
- <string>Capitalization:</string>
- </property>
- <property name="buddy">
- <cstring>capitalizationList</cstring>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QComboBox" name="capitalizationList"/>
- </item>
- <item row="3" column="0">
- <widget class="QLabel">
- <property name="text">
- <string comment="Character position">Position:</string>
- </property>
- <property name="buddy">
- <cstring>positionList</cstring>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QComboBox" name="positionList"/>
- </item>
- </layout>
- </item>
- <item>
- <spacer>
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>KColorButton</class>
- <extends>QPushButton</extends>
- <header>kcolorbutton.h</header>
- <container>1</container>
- </customwidget>
- <customwidget>
- <class>KComboBox</class>
- <extends>QComboBox</extends>
- <header>kcombobox.h</header>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/DockerStylesComboModel.cpp b/plugins/flake/textshape/dialogs/DockerStylesComboModel.cpp
deleted file mode 100644
index 6979622320..0000000000
--- a/plugins/flake/textshape/dialogs/DockerStylesComboModel.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2012 Pierre Stirnweiss <pstirnweiss@googlemail.org>
- *
- * 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 "DockerStylesComboModel.h"
-
-#include <KoCharacterStyle.h>
-#include <KoParagraphStyle.h>
-#include <KoStyleManager.h>
-
-#include <klocalizedstring.h>
-
-#include <QDebug>
-
-#include "StylesModel.h"
-
-DockerStylesComboModel::DockerStylesComboModel(QObject *parent)
- : StylesFilteredModelBase(parent)
- , m_styleManager(0)
-{
-}
-
-Qt::ItemFlags DockerStylesComboModel::flags(const QModelIndex &index) const
-{
- if (index.internalId() == (quintptr)UsedStyleId || index.internalId() == (quintptr)UnusedStyleId) {
- return (Qt::NoItemFlags);
- }
- return (Qt::ItemIsEnabled | Qt::ItemIsSelectable);
-}
-
-QModelIndex DockerStylesComboModel::index(int row, int column, const QModelIndex &parent) const
-{
- if (row < 0 || column != 0) {
- return QModelIndex();
- }
-
- if (!parent.isValid()) {
- if (row >= m_proxyToSource.count()) {
- return QModelIndex();
- }
- return createIndex(row, column, (m_proxyToSource.at(row) >= 0) ? int(m_sourceModel->index(m_proxyToSource.at(row), 0, QModelIndex()).internalId()) : m_proxyToSource.at(row));
- }
- return QModelIndex();
-}
-
-QVariant DockerStylesComboModel::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid()) {
- return QVariant();
- }
-
- switch (role) {
- case AbstractStylesModel::isTitleRole: {
- return (index.internalId() == (quintptr)UsedStyleId || index.internalId() == (quintptr)UnusedStyleId);
- }
- case Qt::DisplayRole: {
- if (index.internalId() == (quintptr)UsedStyleId) {
- return i18n("Used Styles");
- }
- if (index.internalId() == (quintptr)UnusedStyleId) {
- return i18n("Unused Styles");
- }
- return QVariant();
- }
- case Qt::DecorationRole: {
- return m_sourceModel->data(m_sourceModel->index(m_proxyToSource.at(index.row()), 0, QModelIndex()), role);
- break;
- }
- case Qt::SizeHintRole: {
- return QVariant(QSize(250, 48));
- }
- default: break;
- };
- return QVariant();
-}
-
-void DockerStylesComboModel::setInitialUsedStyles(QVector<int> usedStyles)
-{
- Q_UNUSED(usedStyles);
- // This is not used yet. Let's revisit this later.
-
-// m_usedStyles << usedStyles;
-// beginResetModel();
-// createMapping();
-// endResetModel();
-}
-
-void DockerStylesComboModel::setStyleManager(KoStyleManager *sm)
-{
- Q_ASSERT(sm);
- Q_ASSERT(m_sourceModel);
- if (!sm || !m_sourceModel || m_styleManager == sm) {
- return;
- }
- m_styleManager = sm;
- createMapping();
-}
-
-void DockerStylesComboModel::styleApplied(const KoCharacterStyle *style)
-{
- QModelIndex sourceIndex = m_sourceModel->indexOf(style);
- if (!sourceIndex.isValid()) {
- return; // Probably default style.
- }
- if (m_usedStylesId.contains(style->styleId())) {
- return; // Style already among used styles.
- }
- beginResetModel();
- createMapping();
- endResetModel();
-}
-
-void DockerStylesComboModel::createMapping()
-{
- Q_ASSERT(m_sourceModel);
- if (!m_sourceModel || !m_styleManager) {
- return;
- }
-
- m_proxyToSource.clear();
- m_sourceToProxy.clear();
- m_unusedStyles.clear();
- m_usedStyles.clear();
- m_usedStylesId.clear();
-
- QVector<int> usedStyles;
- if (m_sourceModel->stylesType() == AbstractStylesModel::CharacterStyle) {
- usedStyles = m_styleManager->usedCharacterStyles();
- } else {
- usedStyles = m_styleManager->usedParagraphStyles();
- }
-
- // The order of the styles is already correctly given by the source model.
- // Therefore it is not needed to resort the styles again here. The source model
- // makes sure to have the NoneStyleId as first style and the styles after
- // that are ordered by name.
- for (int i = 0; i < m_sourceModel->rowCount(QModelIndex()); ++i) {
- QModelIndex index = m_sourceModel->index(i, 0, QModelIndex());
- int id = (int)index.internalId();
- if (id == StylesModel::NoneStyleId || usedStyles.contains(id)) {
- m_usedStylesId.append(id);
- m_usedStyles.append(i);
- } else {
- m_unusedStyles.append(i);
- }
- }
- if (!m_usedStyles.isEmpty()) {
- m_proxyToSource << UsedStyleId << m_usedStyles;
- }
- if (!m_unusedStyles.isEmpty()) {
- m_proxyToSource << UnusedStyleId << m_unusedStyles; //UsedStyleId and UnusedStyleId will be detected as title (in index method) and will be treated accordingly
- }
- m_sourceToProxy.fill(-1, m_sourceModel->rowCount((QModelIndex())));
- for (int i = 0; i < m_proxyToSource.count(); ++i) {
- if (m_proxyToSource.at(i) >= 0) { //we do not need to map to the titles
- m_sourceToProxy[m_proxyToSource.at(i)] = i;
- }
- }
-}
-
-KoCharacterStyle *DockerStylesComboModel::findStyle(int styleId) const
-{
- if (m_sourceModel->stylesType() == AbstractStylesModel::CharacterStyle) {
- return m_styleManager->characterStyle(styleId);
- } else {
- return m_styleManager->paragraphStyle(styleId);
- }
-}
diff --git a/plugins/flake/textshape/dialogs/DockerStylesComboModel.h b/plugins/flake/textshape/dialogs/DockerStylesComboModel.h
deleted file mode 100644
index 2c2ee76199..0000000000
--- a/plugins/flake/textshape/dialogs/DockerStylesComboModel.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2012 Pierre Stirnweiss <pstirnweiss@googlemail.org>
- *
- * 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 DOCKERSTYLESCOMBOMODEL_H
-#define DOCKERSTYLESCOMBOMODEL_H
-
-#include "StylesFilteredModelBase.h"
-
-#include <QVector>
-
-class KoCharacterStyle;
-class KoStyleManager;
-
-class DockerStylesComboModel : public StylesFilteredModelBase
-{
- Q_OBJECT
-public:
-
- enum CategoriesInternalIds {
- UsedStyleId = -32000,
- UnusedStyleId = -32001
- };
-
- explicit DockerStylesComboModel(QObject *parent = 0);
-
- Qt::ItemFlags flags(const QModelIndex &index) const override;
-
- QModelIndex index(int row, int column, const QModelIndex &parent) const override;
-
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
-
- void setStyleManager(KoStyleManager *sm);
-
- void setInitialUsedStyles(QVector<int> usedStyles);
-
-Q_SIGNALS:
-
-public Q_SLOTS:
- void styleApplied(const KoCharacterStyle *style);
-
-protected:
- void createMapping() override;
-
-private:
- KoCharacterStyle *findStyle(int styleId) const;
- KoStyleManager *m_styleManager;
- QVector<int> m_usedStylesId;
- QVector<int> m_usedStyles;
- QVector<int> m_unusedStyles;
-};
-
-#endif // DOCKERSTYLESCOMBOMODEL_H
diff --git a/plugins/flake/textshape/dialogs/FontDecorations.cpp b/plugins/flake/textshape/dialogs/FontDecorations.cpp
deleted file mode 100644
index 4c87256294..0000000000
--- a/plugins/flake/textshape/dialogs/FontDecorations.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2001, 2002 Montel Laurent <lmontel@mandrakesoft.com>
- Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
- Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
-
- 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 "FontDecorations.h"
-
-FontDecorations::FontDecorations(bool uniqueFormat, QWidget *parent)
- : QWidget(parent)
- , m_uniqueFormat(uniqueFormat)
-{
- widget.setupUi(this);
-
- connect(widget.hyphenate, SIGNAL(stateChanged(int)), this, SLOT(hyphenateStateChanged()));
-
- widget.shadowGroupBox->setVisible(false);
- widget.positionGroupBox->setVisible(false);
-}
-
-void FontDecorations::hyphenateStateChanged()
-{
- m_hyphenateInherited = false;
-}
-
-void FontDecorations::setDisplay(KoCharacterStyle *style)
-{
- if (!style) {
- return;
- }
-
- m_hyphenateInherited = !style->hasProperty(KoCharacterStyle::HasHyphenation);
- if (!m_uniqueFormat) {
- widget.hyphenate->setTristate(true);
- widget.hyphenate->setCheckState(Qt::PartiallyChecked);
- } else {
- widget.hyphenate->setChecked(style->hasHyphenation());
- }
-}
-
-void FontDecorations::save(KoCharacterStyle *style) const
-{
- if (!style) {
- return;
- }
-
- if (!m_hyphenateInherited) {
- if (widget.hyphenate->checkState() == Qt::Checked) {
- style->setHasHyphenation(true);
- } else if (widget.hyphenate->checkState() == Qt::Unchecked) {
- style->setHasHyphenation(false);
- }
- }
-
-}
diff --git a/plugins/flake/textshape/dialogs/FontDecorations.h b/plugins/flake/textshape/dialogs/FontDecorations.h
deleted file mode 100644
index 3d39139902..0000000000
--- a/plugins/flake/textshape/dialogs/FontDecorations.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2001,2002,2003 Montel Laurent <lmontel@mandrakesoft.com>
- Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
-
- 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 FONTDECORATIONS_H
-#define FONTDECORATIONS_H
-
-#include <ui_FontDecorations.h>
-
-#include <KoCharacterStyle.h>
-
-class FontDecorations : public QWidget
-{
- Q_OBJECT
-
-public:
- explicit FontDecorations(bool uniqueFormat, QWidget *parent = 0);
- ~FontDecorations() override {}
-
- void setDisplay(KoCharacterStyle *style);
- void save(KoCharacterStyle *style) const;
-
-private Q_SLOTS:
- void hyphenateStateChanged();
-
-private:
- Ui::FontDecorations widget;
-
- bool m_hyphenateInherited;
- bool m_uniqueFormat;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/FontDecorations.ui b/plugins/flake/textshape/dialogs/FontDecorations.ui
deleted file mode 100644
index 0a7f8fff1e..0000000000
--- a/plugins/flake/textshape/dialogs/FontDecorations.ui
+++ /dev/null
@@ -1,328 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>FontDecorations</class>
- <widget class="QWidget" name="FontDecorations">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>437</width>
- <height>429</height>
- </rect>
- </property>
- <layout class="QGridLayout">
- <item row="0" column="0">
- <widget class="QGroupBox">
- <property name="title">
- <string>Colors</string>
- </property>
- <layout class="QGridLayout">
- <item row="0" column="4" rowspan="2">
- <spacer>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>41</width>
- <height>78</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="3">
- <widget class="QToolButton" name="resetBackground">
- <property name="text">
- <string>...</string>
- </property>
- </widget>
- </item>
- <item row="1" column="2">
- <widget class="KColorButton" name="backgroundColor"/>
- </item>
- <item row="0" column="2">
- <widget class="KColorButton" name="textColor"/>
- </item>
- <item row="0" column="1">
- <widget class="QLabel" name="textColorLabel">
- <property name="text">
- <string>Text color:</string>
- </property>
- <property name="wordWrap">
- <bool>false</bool>
- </property>
- <property name="buddy">
- <cstring>textColor</cstring>
- </property>
- </widget>
- </item>
- <item row="0" column="3">
- <widget class="QToolButton" name="resetTextColor">
- <property name="text">
- <string>...</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLabel" name="backgroundColorLabel">
- <property name="text">
- <string>Background color:</string>
- </property>
- <property name="wordWrap">
- <bool>false</bool>
- </property>
- <property name="buddy">
- <cstring>backgroundColor</cstring>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QCheckBox" name="enableText"/>
- </item>
- <item row="1" column="0">
- <widget class="QCheckBox" name="enableBackground">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QGroupBox" name="shadowGroupBox">
- <property name="title">
- <string>Text Shadow</string>
- </property>
- <layout class="QGridLayout">
- <item row="0" column="3" rowspan="3">
- <layout class="QGridLayout">
- <property name="margin">
- <number>0</number>
- </property>
- <property name="spacing">
- <number>0</number>
- </property>
- <item row="2" column="1">
- <widget class="QToolButton" name="toolButton">
- <property name="text">
- <string>...</string>
- </property>
- <property name="checkable">
- <bool>true</bool>
- </property>
- <property name="autoExclusive">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="1" column="2">
- <widget class="QToolButton" name="toolButton_5">
- <property name="text">
- <string>...</string>
- </property>
- <property name="checkable">
- <bool>true</bool>
- </property>
- <property name="autoExclusive">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QToolButton" name="toolButton_7">
- <property name="text">
- <string>...</string>
- </property>
- <property name="checkable">
- <bool>true</bool>
- </property>
- <property name="autoExclusive">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QToolButton" name="toolButton_4">
- <property name="text">
- <string>...</string>
- </property>
- <property name="checkable">
- <bool>true</bool>
- </property>
- <property name="autoExclusive">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QToolButton" name="toolButton_8">
- <property name="text">
- <string>...</string>
- </property>
- <property name="checkable">
- <bool>true</bool>
- </property>
- <property name="autoExclusive">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="0" column="2">
- <widget class="QToolButton" name="toolButton_3">
- <property name="text">
- <string>...</string>
- </property>
- <property name="checkable">
- <bool>true</bool>
- </property>
- <property name="autoExclusive">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="2">
- <widget class="QToolButton" name="toolButton_6">
- <property name="text">
- <string>...</string>
- </property>
- <property name="checkable">
- <bool>true</bool>
- </property>
- <property name="autoExclusive">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QToolButton" name="toolButton_2">
- <property name="text">
- <string>...</string>
- </property>
- <property name="checkable">
- <bool>true</bool>
- </property>
- <property name="autoExclusive">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="2" column="0">
- <spacer>
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Fixed</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>10</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="2">
- <spacer>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>31</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="shadowColorLabel">
- <property name="text">
- <string>Color:</string>
- </property>
- <property name="wordWrap">
- <bool>false</bool>
- </property>
- <property name="buddy">
- <cstring>shadowGroupBox</cstring>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="shadowDistanceLabel">
- <property name="text">
- <string>Distance:</string>
- </property>
- <property name="wordWrap">
- <bool>false</bool>
- </property>
- <property name="buddy">
- <cstring>shadowDistance</cstring>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QDoubleSpinBox" name="shadowDistance">
- <property name="decimals">
- <number>1</number>
- </property>
- <property name="maximum">
- <double>9.000000000000000</double>
- </property>
- <property name="singleStep">
- <double>0.500000000000000</double>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="KColorButton" name="shadow"/>
- </item>
- </layout>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QGroupBox" name="positionGroupBox">
- <property name="title">
- <string>Position</string>
- </property>
- <layout class="QGridLayout">
- <item row="0" column="0">
- <widget class="QCheckBox" name="hyphenate">
- <property name="text">
- <string>Automatic hyphenation</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item row="3" column="0">
- <spacer>
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>16</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <layoutdefault spacing="6" margin="11"/>
- <customwidgets>
- <customwidget>
- <class>KColorButton</class>
- <extends>QPushButton</extends>
- <header>kcolorbutton.h</header>
- <container>1</container>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/FontDia.cpp b/plugins/flake/textshape/dialogs/FontDia.cpp
deleted file mode 100644
index 21b881553e..0000000000
--- a/plugins/flake/textshape/dialogs/FontDia.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2001, 2002 Montel Laurent <lmontel@mandrakesoft.com>
- Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
- Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- Copyright (C) 2008 Pierre Stirnweiss <pstirnweiss@googlemail.com>
-
- 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 "FontDia.h"
-#include "CharacterHighlighting.h"
-#include "FontDecorations.h"
-
-#include "CharacterGeneral.h"
-
-#include "FormattingPreview.h"
-
-#include <KoTextEditor.h>
-
-#include <klocalizedstring.h>
-
-#include <QTextBlock>
-#include <QTextFragment>
-#include <QTextDocument>
-#include <QTextCursor>
-
-FontDia::FontDia(KoTextEditor *editor, QWidget *parent)
- : KoDialog(parent)
- , m_editor(editor)
- , m_styleChanged(false)
-{
- m_initialFormat = m_editor->charFormat();
-
- setCaption(i18n("Select Font"));
- setModal(true);
- setButtons(Ok | Cancel | Reset | Apply);
- setDefaultButton(Ok);
-
- m_characterGeneral = new CharacterGeneral(this);
- m_characterGeneral->hideStyleName(true);
- setMainWidget(m_characterGeneral);
-
- connect(this, SIGNAL(applyClicked()), this, SLOT(slotApply()));
- connect(this, SIGNAL(okClicked()), this, SLOT(slotOk()));
- connect(this, SIGNAL(resetClicked()), this, SLOT(slotReset()));
- initTabs();
-
- // Do this after initTabs so it doesn't cause signals prematurely
- connect(m_characterGeneral, SIGNAL(styleChanged()), this, SLOT(styleChanged()));
-}
-
-void FontDia::initTabs()
-{
- KoCharacterStyle style(m_initialFormat);
- m_characterGeneral->setStyle(&style);
-}
-
-void FontDia::styleChanged(bool state)
-{
- m_styleChanged = state;
-}
-
-void FontDia::slotApply()
-{
- if (!m_styleChanged) {
- return;
- }
-
- m_editor->beginEditBlock(kundo2_i18n("Font"));
- KoCharacterStyle chosenStyle;
- m_characterGeneral->save(&chosenStyle);
- QTextCharFormat cformat;
- chosenStyle.applyStyle(cformat);
- m_editor->mergeAutoStyle(cformat);
- m_editor->endEditBlock();
-
- m_styleChanged = false;
-}
-
-void FontDia::slotOk()
-{
- slotApply();
- KoDialog::accept();
-}
-
-void FontDia::slotReset()
-{
- initTabs();
- slotApply(); // ### Should reset() apply?
-}
diff --git a/plugins/flake/textshape/dialogs/FontDia.h b/plugins/flake/textshape/dialogs/FontDia.h
deleted file mode 100644
index d75a2c3766..0000000000
--- a/plugins/flake/textshape/dialogs/FontDia.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2001,2002,2003 Montel Laurent <lmontel@mandrakesoft.com>
- Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
- Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- Copyright (C) 2008 Pierre Stirnweiss <pstirnweiss@googlemail.com>
-
- 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 FONTDIA_H
-#define FONTDIA_H
-
-#include <KoDialog.h>
-#include <KoCharacterStyle.h>
-
-class KoTextEditor;
-
-class CharacterGeneral;
-
-class FontDia : public KoDialog
-{
- Q_OBJECT
-public:
- explicit FontDia(KoTextEditor *cursor, QWidget *parent = 0);
-
-protected Q_SLOTS:
- void styleChanged(bool state = true);
-
- void slotReset();
- void slotApply();
- void slotOk();
-
-private:
- void initTabs();
-
- CharacterGeneral *m_characterGeneral;
-
- KoTextEditor *m_editor;
- QTextCharFormat m_initialFormat;
-
- bool m_uniqueFormat;
- bool m_styleChanged;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/FormattingButton.cpp b/plugins/flake/textshape/dialogs/FormattingButton.cpp
deleted file mode 100644
index 18af4172ea..0000000000
--- a/plugins/flake/textshape/dialogs/FormattingButton.cpp
+++ /dev/null
@@ -1,213 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2009 C. Boemann <cbo@boemann.dk>
- *
- * 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 "FormattingButton.h"
-
-#include <QMenu>
-#include <QFrame>
-#include <QLabel>
-#include <QGridLayout>
-#include <QWidgetAction>
-
-#include <QDebug>
-
-//This class is a helper to add a label
-class LabelAction : public QWidgetAction
-{
-public:
- LabelAction(QString label);
- QLabel *m_label;
-};
-
-LabelAction::LabelAction(QString label)
- : QWidgetAction(0)
-{
- m_label = new QLabel(label);
- setDefaultWidget(m_label);
-}
-
-//This class is the main place where the expanding grid is done
-class ItemChooserAction : public QWidgetAction
-{
-public:
- ItemChooserAction(int columns);
- QFrame *m_widget;
- QGridLayout *m_containerLayout;
- int m_cnt;
- int m_columns;
- QToolButton *addItem(QPixmap pm);
- void addBlanks(int n);
-};
-
-ItemChooserAction::ItemChooserAction(int columns)
- : QWidgetAction(0)
- , m_cnt(0)
- , m_columns(columns)
-{
- m_widget = new QFrame;
- QGridLayout *l = new QGridLayout();
- l->setSpacing(0);
- l->setMargin(0);
- m_widget->setLayout(l);
-
- QWidget *w = new QWidget();
- l->addWidget(w);
-
- m_containerLayout = new QGridLayout();
- m_containerLayout->setSpacing(4);
- w->setLayout(m_containerLayout);
-
- setDefaultWidget(m_widget);
-}
-
-QToolButton *ItemChooserAction::addItem(QPixmap pm)
-{
- QToolButton *b = new QToolButton();
- b->setIcon(QIcon(pm));
- b->setIconSize(pm.size());
- b->setAutoRaise(true);
- m_containerLayout->addWidget(b, m_cnt / m_columns, m_cnt % m_columns);
- ++m_cnt;
- return b;
-}
-
-void ItemChooserAction::addBlanks(int n)
-{
- m_cnt += n;
-}
-
-FormattingButton::FormattingButton(QWidget *parent)
- : QToolButton(parent)
- , m_lastId(0)
- , m_styleAction(0)
- , m_columns(1)
- , m_menuShownFirstTime(true)
-{
- m_menu = new QMenu();
- setPopupMode(MenuButtonPopup);
- setMenu(m_menu);
- connect(this, SIGNAL(released()), this, SLOT(itemSelected()));
- connect(m_menu, SIGNAL(aboutToHide()), this, SIGNAL(doneWithFocus()));
- connect(m_menu, SIGNAL(aboutToShow()), this, SIGNAL(aboutToShowMenu()));
- connect(m_menu, SIGNAL(aboutToHide()), this, SLOT(menuShown()));
-}
-
-void FormattingButton::setNumColumns(int columns)
-{
- m_styleAction = 0;
- m_columns = columns;
-}
-
-void FormattingButton::setItemsBackground(const QColor &color)
-{
- if (m_styleAction) {
- foreach (QObject *o, m_styleAction->defaultWidget()->children()) {
- QWidget *w = qobject_cast<QWidget *>(o);
- if (w) {
- QPalette p = w->palette();
- p.setColor(QPalette::Window, color);
- w->setPalette(p);
- w->setAutoFillBackground(true);
- break;
- }
- }
- qobject_cast<QFrame *>(m_styleAction->defaultWidget())->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
- }
-}
-
-void FormattingButton::addItem(const QPixmap &pm, int id, const QString &toolTip)
-{
- //Note: Do not use 0 as the item id, because that will break the m_lastId functionality
- Q_ASSERT(id != 0);
-
- if (m_styleMap.contains(id)) {
- QToolButton *button = dynamic_cast<QToolButton *>(m_styleMap.value(id));
- if (button) {
- button->setIcon(QIcon(pm));
- button->setIconSize(pm.size());
- }
- } else {
- if (m_styleAction == 0) {
- m_styleAction = new ItemChooserAction(m_columns);
- m_menu->addAction(m_styleAction);
- }
-
- QToolButton *b = m_styleAction->addItem(pm);
- b->setToolTip(toolTip);
- m_styleMap.insert(id, b);
- connect(b, SIGNAL(released()), this, SLOT(itemSelected()));
- }
- if (!m_lastId) {
- m_lastId = id;
- }
-}
-
-void FormattingButton::addBlanks(int n)
-{
- if (m_styleAction) {
- m_styleAction->addBlanks(n);
- }
-}
-
-void FormattingButton::addAction(QAction *action)
-{
- m_styleAction = 0;
- m_menu->addAction(action);
-}
-
-void FormattingButton::addSeparator()
-{
- m_styleAction = 0;
- m_menu->addSeparator();
-}
-
-void FormattingButton::itemSelected()
-{
- if (sender() != this && m_styleMap.key(sender()) == 0) {
- // this means that the sender() is not in the m_styleMap. Have you missed something?
- return;
- }
-
- if (sender() == this && m_lastId == 0) {
- //menu not yet populated
- return;
- }
-
- if (sender() != this) {
- m_lastId = m_styleMap.key(sender());
- }
- m_menu->hide();
- emit itemTriggered(m_lastId);
-}
-
-bool FormattingButton::hasItemId(int id)
-{
- return m_styleMap.contains(id);
-}
-
-void FormattingButton::menuShown()
-{
- m_menuShownFirstTime = false;
-}
-
-bool FormattingButton::isFirstTimeMenuShown()
-{
- return m_menuShownFirstTime;
-}
diff --git a/plugins/flake/textshape/dialogs/FormattingButton.h b/plugins/flake/textshape/dialogs/FormattingButton.h
deleted file mode 100644
index 440e735971..0000000000
--- a/plugins/flake/textshape/dialogs/FormattingButton.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2009 C. Boemann <cbo@boemann.dk>
- *
- * 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 FORMATTINGBUTTON_H
-#define FORMATTINGBUTTON_H
-
-#include <KoListStyle.h>
-
-#include <QToolButton>
-#include <QPixmap>
-#include <QMap>
-
-class QMenu;
-class QAction;
-class ItemChooserAction;
-
-class FormattingButton : public QToolButton
-{
- Q_OBJECT
-public:
- explicit FormattingButton(QWidget *parent = 0);
-
- void setNumColumns(int columns);
- void setItemsBackground(const QColor &color);
- void addItem(const QPixmap &pm, int id, const QString &toolTip = QString());
- void addAction(QAction *action);
- void addBlanks(int n);
- void addSeparator();
- bool hasItemId(int id);
- bool isFirstTimeMenuShown();
-
-Q_SIGNALS:
- void itemTriggered(int id);
- void doneWithFocus();
- void aboutToShowMenu();
-
-private Q_SLOTS:
- void itemSelected();
- void menuShown();
-
-private:
- int m_lastId;
- QMenu *m_menu;
- QMap<int, QObject *> m_styleMap;
- ItemChooserAction *m_styleAction;
- int m_columns;
- bool m_menuShownFirstTime;
-};
-
-#endif //FORMATTINGBUTTON_H
diff --git a/plugins/flake/textshape/dialogs/FormattingPreview.cpp b/plugins/flake/textshape/dialogs/FormattingPreview.cpp
deleted file mode 100644
index d494c78f74..0000000000
--- a/plugins/flake/textshape/dialogs/FormattingPreview.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2009-2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 "FormattingPreview.h"
-
-#include <KoPostscriptPaintDevice.h>
-#include <KoZoomHandler.h>
-#include <KoStyleThumbnailer.h>
-#include <KoCharacterStyle.h>
-
-#include <QBrush>
-#include <QColor>
-#include <QFont>
-#include <QFontMetrics>
-#include <QFrame>
-#include <QPainter>
-#include <QPen>
-#include <QPointF>
-#include <QRect>
-#include <QRectF>
-#include <QString>
-#include <QTextLayout>
-#include <QTextLine>
-#include <QTextOption>
-
-#include <math.h>
-
-#include <klocalizedstring.h>
-#include <QDebug>
-
-FormattingPreview::FormattingPreview(QWidget *parent)
- : QFrame(parent)
- , m_sampleText(i18n("Font"))
- , m_characterStyle(0)
- , m_paragraphStyle(0)
- , m_thumbnailer(new KoStyleThumbnailer())
- , m_previewLayoutRequired(true)
-{
- setFrameStyle(QFrame::Box | QFrame::Plain);
- setMinimumSize(500, 150);
-
- m_thumbnailer->setText(m_sampleText);
-}
-
-FormattingPreview::~FormattingPreview()
-{
- delete m_thumbnailer;
- if (m_characterStyle) {
- delete m_characterStyle;
- }
- if (m_paragraphStyle) {
- delete m_paragraphStyle;
- }
-}
-
-void FormattingPreview::setText(const QString &sampleText)
-{
- m_sampleText = sampleText;
- m_thumbnailer->setText(m_sampleText);
-
- m_previewLayoutRequired = true;
-
- update();
-}
-
-//Character properties
-void FormattingPreview::setCharacterStyle(const KoCharacterStyle *style)
-{
- if (m_characterStyle) {
- delete m_characterStyle;
- }
-
- m_characterStyle = style->clone();
-
- m_previewLayoutRequired = true;
-
- update();
-}
-
-void FormattingPreview::setParagraphStyle(const KoParagraphStyle *style)
-{
- if (m_paragraphStyle) {
- delete m_paragraphStyle;
- }
-
- m_paragraphStyle = style->clone();
-
- m_previewLayoutRequired = true;
-
- update();
-}
-
-//Painting related methods
-
-void FormattingPreview::paintEvent(QPaintEvent *event)
-{
- Q_UNUSED(event)
-
- QPainter *p = new QPainter(this);
- p->save();
-
- QRect rectang = contentsRect();
-
- p->fillRect(rectang, QBrush(QColor(Qt::white)));
- p->drawImage(rectang, m_thumbnailer->thumbnail(m_characterStyle, m_paragraphStyle, rectang.size(), m_previewLayoutRequired, KoStyleThumbnailer::NoFlags));
-
- m_previewLayoutRequired = false;
-
- p->restore();
- delete p;
-}
diff --git a/plugins/flake/textshape/dialogs/FormattingPreview.h b/plugins/flake/textshape/dialogs/FormattingPreview.h
deleted file mode 100644
index 35ce5608a8..0000000000
--- a/plugins/flake/textshape/dialogs/FormattingPreview.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2008 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- Copyright (C) 2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
-
- 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 FORMATTINGPREVIEW_H
-#define FORMATTINGPREVIEW_H
-
-#include <KoCharacterStyle.h>
-#include <KoParagraphStyle.h>
-
-#include <QFont>
-#include <QFrame>
-#include <QWidget>
-
-class QString;
-class KoStyleThumbnailer;
-
-class FormattingPreview : public QFrame
-{
- Q_OBJECT
-
-public:
- explicit FormattingPreview(QWidget *parent = 0);
- ~FormattingPreview() override;
-
-public Q_SLOTS:
- ///Character properties
- void setCharacterStyle(const KoCharacterStyle *style);
- void setParagraphStyle(const KoParagraphStyle *style);
-
- void setText(const QString &sampleText);
-
-protected:
- void paintEvent(QPaintEvent *event) override;
-
-private:
- QString m_sampleText;
-
- KoCharacterStyle *m_characterStyle;
- KoParagraphStyle *m_paragraphStyle;
- KoStyleThumbnailer *m_thumbnailer;
- bool m_previewLayoutRequired;
-};
-
-#endif //FORMATTINGPREVIEW_H
diff --git a/plugins/flake/textshape/dialogs/InsertCharacter.cpp b/plugins/flake/textshape/dialogs/InsertCharacter.cpp
deleted file mode 100644
index 1a39723591..0000000000
--- a/plugins/flake/textshape/dialogs/InsertCharacter.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 "InsertCharacter.h"
-
-#include <klocalizedstring.h>
-#include <kcharselect.h>
-
-#include <QMainWindow>
-#include <QGridLayout>
-#include <QPushButton>
-
-InsertCharacter::InsertCharacter(QWidget *parent)
- : QDockWidget(i18n("Special Characters"))
-{
- QWidget *specialCharacterWidget = new QWidget();
- QGridLayout *lay = new QGridLayout(specialCharacterWidget);
- lay->setMargin(6);
- m_charSelector = new KCharSelect(specialCharacterWidget,
- 0,
- KCharSelect::SearchLine | KCharSelect::FontCombo | KCharSelect::BlockCombos |
- KCharSelect::CharacterTable | KCharSelect::DetailBrowser);
- lay->addWidget(m_charSelector, 0, 0, 1, 3);
- QPushButton *insert = new QPushButton(i18n("Insert"), specialCharacterWidget);
- lay->addWidget(insert, 1, 1);
- QPushButton *close = new QPushButton(i18nc("Close dialog", "Close"), specialCharacterWidget);
- lay->addWidget(close, 1, 2);
- lay->setColumnStretch(0, 9);
-
- setObjectName("insertSpecialCharacter");
- setWidget(specialCharacterWidget);
- while (parent->parentWidget()) {
- parent = parent->parentWidget();
- }
- QMainWindow *mw = dynamic_cast<QMainWindow *>(parent);
- if (mw) {
- mw->addDockWidget(Qt::TopDockWidgetArea, this);
- }
- setFloating(true);
-
- connect(close, SIGNAL(released()), this, SLOT(hide()));
- connect(insert, SIGNAL(released()), this, SLOT(insertCharacter()));
- connect(m_charSelector, SIGNAL(charSelected(QChar)), this, SLOT(insertCharacter()));
-}
-
-void InsertCharacter::insertCharacter()
-{
- emit insertCharacter(QString(m_charSelector->currentChar()));
-}
diff --git a/plugins/flake/textshape/dialogs/InsertCharacter.h b/plugins/flake/textshape/dialogs/InsertCharacter.h
deleted file mode 100644
index 27e07470dd..0000000000
--- a/plugins/flake/textshape/dialogs/InsertCharacter.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 INSERTCHARACTER_H
-#define INSERTCHARACTER_H
-
-#include <QDockWidget>
-class KCharSelect;
-
-class InsertCharacter : public QDockWidget
-{
- Q_OBJECT
-public:
- explicit InsertCharacter(QWidget *parent);
-
-Q_SIGNALS:
- void insertCharacter(const QString &character);
-
-private Q_SLOTS:
- void insertCharacter();
-
-private:
- KCharSelect *m_charSelector;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/LanguageTab.cpp b/plugins/flake/textshape/dialogs/LanguageTab.cpp
deleted file mode 100644
index 9d685f616c..0000000000
--- a/plugins/flake/textshape/dialogs/LanguageTab.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2001, 2002 Montel Laurent <lmontel@mandrakesoft.com>
-
- 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 "LanguageTab.h"
-
-#include <KoCharacterStyle.h>
-#include <KoIcon.h>
-
-#include <QSet>
-#include <QStringList>
-
-LanguageTab::LanguageTab(/*KSpell2::Loader::Ptr loader,*/bool uniqueFormat, QWidget *parent, Qt::WFlags fl)
- : QWidget(parent)
- , m_uniqueFormat(uniqueFormat)
-{
- widget.setupUi(this);
-
- Q_UNUSED(fl);
-
- widget.languageListSearchLine->setListWidget(widget.languageList);
-
- //TODO use fl
- const QStringList langNames;
- const QStringList langTags;
- QSet<QString> spellCheckLanguages;
-
- widget.languageList->addItem(QString("None"));
-#if 0 //Port it
- if (loader) {
- spellCheckLanguages = QSet<QString>::fromList(loader->languages());
- }
-#endif
- QStringList::ConstIterator itName = langNames.begin();
- QStringList::ConstIterator itTag = langTags.begin();
- for (; itName != langNames.end() && itTag != langTags.end(); ++itName, ++itTag) {
- if (spellCheckLanguages.contains(*itTag)) {
- QListWidgetItem *item = new QListWidgetItem();
- item->setText(*itName);
- item->setIcon(koIcon("tools-check-spelling"));
-
- widget.languageList->addItem(item);
- } else {
- widget.languageList->addItem(*itName);
- }
- }
- connect(widget.languageList, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
- this, SIGNAL(languageChanged()));
-}
-
-LanguageTab::~LanguageTab()
-{
-}
-
-void LanguageTab::save(KoCharacterStyle *style) const
-{
- style->setLanguage(QString());
-}
-
-void LanguageTab::setDisplay(KoCharacterStyle *)
-{
- if (m_uniqueFormat) {
- const QString name;
-
- QList<QListWidgetItem *> items = widget.languageList->findItems(name,
- Qt::MatchFixedString);
- if (!items.isEmpty()) {
- widget.languageList->setCurrentItem(items.first());
- widget.languageList->scrollToItem(items.first());
- }
- }
-}
diff --git a/plugins/flake/textshape/dialogs/LanguageTab.h b/plugins/flake/textshape/dialogs/LanguageTab.h
deleted file mode 100644
index b42fc5ea3f..0000000000
--- a/plugins/flake/textshape/dialogs/LanguageTab.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2001,2002,2003,2006 Montel Laurent <lmontel@mandrakesoft.com>
-
- 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 __kolanguagetab_h__
-#define __kolanguagetab_h__
-
-#include <ui_LanguageTab.h>
-
-class KoCharacterStyle;
-
-class LanguageTab : public QWidget
-{
- Q_OBJECT
-
-public:
- explicit LanguageTab(/*KSpell2::Loader::Ptr loader = KSpell2::Loader::Ptr()*/bool uniqueFormat, QWidget *parent = 0, Qt::WFlags fl = 0);
- ~LanguageTab() override;
-
- QString language() const;
- void setDisplay(KoCharacterStyle *style);
- void save(KoCharacterStyle *style) const;
-
-Q_SIGNALS:
- void languageChanged();
-
-private:
- Ui::LanguageTab widget;
-
- bool m_uniqueFormat;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/LanguageTab.ui b/plugins/flake/textshape/dialogs/LanguageTab.ui
deleted file mode 100644
index 1efc98725b..0000000000
--- a/plugins/flake/textshape/dialogs/LanguageTab.ui
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>LanguageTab</class>
- <widget class="QWidget" name="LanguageTab">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>415</width>
- <height>386</height>
- </rect>
- </property>
- <layout class="QVBoxLayout">
- <item>
- <layout class="QHBoxLayout">
- <item>
- <widget class="QLabel" name="filterLabel">
- <property name="text">
- <string>Quick search:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="KListWidgetSearchLine" name="languageListSearchLine"/>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QListWidget" name="languageList"/>
- </item>
- </layout>
- </widget>
- <layoutdefault spacing="6" margin="11"/>
- <customwidgets>
- <customwidget>
- <class>KListWidgetSearchLine</class>
- <extends>KLineEdit</extends>
- <header>klistwidgetsearchline.h</header>
- </customwidget>
- <customwidget>
- <class>KLineEdit</class>
- <extends>QLineEdit</extends>
- <header>klineedit.h</header>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/ListLevelChooser.cpp b/plugins/flake/textshape/dialogs/ListLevelChooser.cpp
deleted file mode 100644
index 6cc98c2124..0000000000
--- a/plugins/flake/textshape/dialogs/ListLevelChooser.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 "ListLevelChooser.h"
-
-#include <QPushButton>
-#include <QPainter>
-#include <QDebug>
-
-ListLevelChooser::ListLevelChooser(const int offset, QWidget *parent)
- : QPushButton("", parent)
- , m_offset(offset)
-{
- setFlat(true);
- setMinimumSize(QSize(256, 20));
-}
-
-void ListLevelChooser::paintEvent(QPaintEvent *event)
-{
- Q_UNUSED(event);
-
- QPushButton::paintEvent(event);
- QPainter painter(this);
- painter.save();
- painter.setPen(QPen(painter.pen().brush(), 1, Qt::DashLine, Qt::RoundCap, Qt::RoundJoin));
- QRect rectang = rect();
- //painter.fillRect(rectang, QBrush(QColor(Qt::white)));
- painter.translate(m_offset, 1.5);
- painter.setRenderHint(QPainter::Antialiasing);
- painter.drawText(rectang, Qt::AlignVCenter, QString::fromUtf8("●"));
-
- int lineY = rectang.y() + (rectang.height() / 2);
- painter.drawLine(13, lineY, rectang.bottomRight().x() - m_offset - 15, lineY);
-
- painter.restore();
-}
diff --git a/plugins/flake/textshape/dialogs/ListLevelChooser.h b/plugins/flake/textshape/dialogs/ListLevelChooser.h
deleted file mode 100644
index 7ffb1bf1ae..0000000000
--- a/plugins/flake/textshape/dialogs/ListLevelChooser.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 LISTLEVELCHOOSER_H
-#define LISTLEVELCHOOSER_H
-
-#include <QWidget>
-#include <QPushButton>
-
-class ListLevelChooser : public QPushButton
-{
- Q_OBJECT
-public:
- explicit ListLevelChooser(const int offset, QWidget *parent = 0);
-
-protected:
- void paintEvent(QPaintEvent *event) override;
-
-private:
- int m_offset;
-};
-
-#endif // LISTLEVELCHOOSER_H
diff --git a/plugins/flake/textshape/dialogs/ListsSpinBox.cpp b/plugins/flake/textshape/dialogs/ListsSpinBox.cpp
deleted file mode 100644
index f699266d54..0000000000
--- a/plugins/flake/textshape/dialogs/ListsSpinBox.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 "ListsSpinBox.h"
-
-#include "ListItemsHelper.h"
-
-ListsSpinBox::ListsSpinBox(QWidget *parent)
- : QSpinBox(parent)
- , m_type(KoListStyle::DecimalItem)
- , m_letterSynchronization(false)
-{
-}
-
-void ListsSpinBox::setCounterType(KoListStyle::Style type)
-{
- m_type = type;
- update();
-}
-
-int ListsSpinBox::valueFromText(const QString &text) const
-{
- Q_UNUSED(text);
- return 0;
-}
-
-QString ListsSpinBox::textFromValue(int value) const
-{
- switch (m_type) {
- case KoListStyle::DecimalItem:
- return QString::number(value);
- case KoListStyle::AlphaLowerItem:
- return Lists::intToAlpha(value, Lists::Lowercase, m_letterSynchronization);
- case KoListStyle::UpperAlphaItem:
- return Lists::intToAlpha(value, Lists::Uppercase, m_letterSynchronization);
- case KoListStyle::RomanLowerItem:
- return Lists::intToRoman(value);
- case KoListStyle::UpperRomanItem:
- return Lists::intToRoman(value).toUpper();
- case KoListStyle::Bengali:
- case KoListStyle::Gujarati:
- case KoListStyle::Gurumukhi:
- case KoListStyle::Kannada:
- case KoListStyle::Malayalam:
- case KoListStyle::Oriya:
- case KoListStyle::Tamil:
- case KoListStyle::Telugu:
- case KoListStyle::Tibetan:
- case KoListStyle::Thai:
- return Lists::intToScript(value, m_type);
- case KoListStyle::Abjad:
- case KoListStyle::ArabicAlphabet:
- case KoListStyle::AbjadMinor:
- return Lists::intToScriptList(value, m_type);
- default: // others we ignore.
- return "X";
- }
-}
diff --git a/plugins/flake/textshape/dialogs/ListsSpinBox.h b/plugins/flake/textshape/dialogs/ListsSpinBox.h
deleted file mode 100644
index b731d233c8..0000000000
--- a/plugins/flake/textshape/dialogs/ListsSpinBox.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 lISTSSPINBOX_H
-#define lISTSSPINBOX_H
-
-#include <KoListStyle.h>
-
-#include <QSpinBox>
-
-class ListsSpinBox : public QSpinBox
-{
- Q_OBJECT
-public:
- explicit ListsSpinBox(QWidget *parent = 0);
-
- void setCounterType(KoListStyle::Style type);
- QString textFromValue(int value) const override;
-
-public Q_SLOTS:
- void setLetterSynchronization(bool on)
- {
- m_letterSynchronization = on;
- }
-
-private:
- int valueFromText(const QString &text) const override;
-
- KoListStyle::Style m_type;
- bool m_letterSynchronization;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/ParagraphBulletsNumbers.cpp b/plugins/flake/textshape/dialogs/ParagraphBulletsNumbers.cpp
deleted file mode 100644
index 7893d0a904..0000000000
--- a/plugins/flake/textshape/dialogs/ParagraphBulletsNumbers.cpp
+++ /dev/null
@@ -1,387 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007, 2009-2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 "ParagraphBulletsNumbers.h"
-
-#include <KoParagraphStyle.h>
-#include <KoListLevelProperties.h>
-#include <KoImageData.h>
-#include <KoImageCollection.h>
-#include <KoUnit.h>
-#include <KoFileDialog.h>
-#include <KoDialog.h>
-
-#include <QDebug>
-#include <QUrl>
-
-#include <kcharselect.h>
-
-ParagraphBulletsNumbers::ParagraphBulletsNumbers(QWidget *parent)
- : QWidget(parent)
- , m_alignmentMode(false)
- , m_imageCollection(0)
- , m_data(0)
- , m_fontSize(0)
-{
- widget.setupUi(this);
-
- Q_FOREACH (const Lists::ListStyleItem &item, Lists::genericListStyleItems()) {
- addStyle(item);
- }
- addStyle(Lists::ListStyleItem(i18n("Custom Bullet"), KoListStyle::CustomCharItem));
- m_blankCharIndex = addStyle(Lists::ListStyleItem(i18n("No Bullet"), KoListStyle::CustomCharItem));
- Q_FOREACH (const Lists::ListStyleItem &item, Lists::otherListStyleItems()) {
- addStyle(item);
- }
-
- widget.alignment->addItem(i18nc("Automatic horizontal alignment", "Auto"));
- widget.alignment->addItem(i18nc("Text alignment", "Left"));
- widget.alignment->addItem(i18nc("Text alignment", "Right"));
- widget.alignment->addItem(i18nc("Text alignment", "Centered"));
-
- widget.labelFollowedBy->addItem(i18nc("Tab follows the bullet or number", "Tab Stop"));
- widget.labelFollowedBy->addItem(i18nc("Space", "Space"));
- widget.labelFollowedBy->addItem(i18nc("None", "Nothing"));
-
- widget.doubleSpinBox->setSingleStep(0.05);
- widget.doubleSpinBox_2->setSingleStep(0.05);
- widget.doubleSpinBox_3->setSingleStep(0.05);
-
- connect(widget.labelFollowedBy, SIGNAL(currentIndexChanged(int)), this, SLOT(labelFollowedByIndexChanged(int)));
- connect(widget.listTypes, SIGNAL(currentRowChanged(int)), this, SLOT(styleChanged(int)));
- connect(widget.customCharacter, SIGNAL(clicked(bool)), this, SLOT(customCharButtonPressed()));
- connect(widget.letterSynchronization, SIGNAL(toggled(bool)), widget.startValue, SLOT(setLetterSynchronization(bool)));
- connect(widget.prefix, SIGNAL(textChanged(QString)), this, SLOT(recalcPreview()));
- connect(widget.suffix, SIGNAL(textChanged(QString)), this, SLOT(recalcPreview()));
- connect(widget.depth, SIGNAL(valueChanged(int)), this, SLOT(recalcPreview()));
- connect(widget.levels, SIGNAL(valueChanged(int)), this, SLOT(recalcPreview()));
- connect(widget.startValue, SIGNAL(valueChanged(int)), this, SLOT(recalcPreview()));
- connect(widget.insertImage, SIGNAL(clicked()), this, SLOT(selectListImage()));
- connect(widget.imageHeight, SIGNAL(valueChanged(double)), this, SLOT(recalcPreview()));
- connect(widget.imageWidth, SIGNAL(valueChanged(double)), this, SLOT(recalcPreview()));
- connect(widget.restartNumbering, SIGNAL(clicked()), this, SLOT(recalcPreview()));
-}
-
-int ParagraphBulletsNumbers::addStyle(const Lists::ListStyleItem &lsi)
-{
- m_mapping.insert(widget.listTypes->count(), lsi.style);
- widget.listTypes->addItem(lsi.name);
- return widget.listTypes->count() - 1;
-}
-
-void ParagraphBulletsNumbers::setDisplay(KoParagraphStyle *style, int level)
-{
- KoListStyle *listStyle = style->listStyle();
- widget.listPropertiesPane->setEnabled(listStyle != 0);
- widget.customCharacter->setText("-");
- if (listStyle == 0) {
- widget.listTypes->setCurrentRow(0);
- return;
- }
-
- KoListLevelProperties llp = listStyle->levelProperties(level);
- m_previousLevel = llp.level();
- widget.prefix->setText(llp.listItemPrefix());
- widget.suffix->setText(llp.listItemSuffix());
- widget.letterSynchronization->setChecked(llp.letterSynchronization());
- KoListStyle::Style s = llp.style();
- Q_FOREACH (int row, m_mapping.keys()) {
- if (m_mapping[row] == s) {
- widget.listTypes->setCurrentRow(row);
- break;
- }
- }
- int align;
- if (llp.alignment() == (Qt::AlignLeft | Qt::AlignAbsolute)) {
- align = 1;
- } else if (llp.alignment() == (Qt::AlignRight | Qt::AlignAbsolute)) {
- align = 2;
- } else if (llp.alignment() == Qt::AlignCenter) {
- align = 3;
- } else {
- align = 0;
- }
-
- widget.alignment->setCurrentIndex(align);
- widget.depth->setValue(llp.level());
- widget.levels->setValue(llp.displayLevel());
- widget.startValue->setValue(llp.startValue());
- if (s == KoListStyle::CustomCharItem) {
- widget.customCharacter->setText(llp.bulletCharacter());
- }
-
- if (s == KoListStyle::ImageItem) {
- m_data = llp.bulletImage();
- widget.imageHeight->setValue(llp.height());
- widget.imageWidth->setValue(llp.width());
- } else {
- m_data = 0;
- widget.imageHeight->setValue(0);
- widget.imageWidth->setValue(0);
- }
-
- if (llp.alignmentMode() == false) { //for list-level-position-and-space-mode=label-width-and-position disable the following options
- widget.label_8->setEnabled(false);
- widget.label_9->setEnabled(false);
- widget.label_10->setEnabled(false);
- widget.label_11->setEnabled(false);
-
- widget.labelFollowedBy->setEnabled(false);
- widget.doubleSpinBox->setEnabled(false);
- widget.doubleSpinBox_2->setEnabled(false);
- widget.doubleSpinBox_3->setEnabled(false);
- } else {
- m_alignmentMode = true;
- switch (llp.labelFollowedBy()) {
- case KoListStyle::ListTab:
- widget.doubleSpinBox->setEnabled(true);
- widget.labelFollowedBy->setCurrentIndex(0);
- widget.doubleSpinBox->setValue(KoUnit(KoUnit::Centimeter).toUserValue(llp.tabStopPosition()));
- break;
- case KoListStyle::Space:
- widget.doubleSpinBox->setEnabled(false);
- widget.labelFollowedBy->setCurrentIndex(1);
- break;
- case KoListStyle::Nothing:
- widget.doubleSpinBox->setEnabled(false);
- widget.labelFollowedBy->setCurrentIndex(2);
- break;
- default:
- Q_ASSERT(false);
- }
-
- widget.doubleSpinBox_2->setValue(KoUnit(KoUnit::Centimeter).toUserValue(llp.margin()));
- widget.doubleSpinBox_3->setValue(KoUnit(KoUnit::Centimeter).toUserValue(llp.margin()) + KoUnit(KoUnit::Centimeter).toUserValue(llp.textIndent()));
- }
-
- // *** features not in GUI;
- // character style
- // relative bullet size (percent)
- // minimum label width
- recalcPreview();
-}
-
-void ParagraphBulletsNumbers::save(KoParagraphStyle *savingStyle)
-{
- Q_ASSERT(savingStyle);
-
- KoUnit unit(KoUnit::Centimeter);
-
- const int currentRow = widget.listTypes->currentRow();
- KoListStyle::Style style = m_mapping[currentRow];
- if (style == KoListStyle::None) {
- savingStyle->setListStyle(0);
- return;
- }
- if (savingStyle->listStyle() == 0) {
- KoListStyle *listStyle = new KoListStyle(savingStyle);
- savingStyle->setListStyle(listStyle);
- }
- KoListStyle *listStyle = savingStyle->listStyle();
- KoListLevelProperties llp = listStyle->levelProperties(widget.depth->value());
- llp.setStyle(style);
- llp.setLevel(widget.depth->value());
- llp.setDisplayLevel(widget.levels->value());
- llp.setStartValue(widget.startValue->value());
- llp.setListItemPrefix(widget.prefix->text());
- llp.setListItemSuffix(widget.suffix->text());
- llp.setLetterSynchronization(widget.letterSynchronization->isVisible() && widget.letterSynchronization->isChecked());
-
- if (m_alignmentMode == true) {
- llp.setAlignmentMode(true);
- switch (widget.labelFollowedBy->currentIndex()) {
- case 0: llp.setLabelFollowedBy(KoListStyle::ListTab);
- llp.setTabStopPosition(unit.fromUserValue(widget.doubleSpinBox->value()));
- break;
- case 1: llp.setLabelFollowedBy(KoListStyle::Space);
- break;
- case 2: llp.setLabelFollowedBy(KoListStyle::Nothing);
- break;
- default:
- Q_ASSERT(false);
- }
-
- llp.setMargin(unit.fromUserValue(widget.doubleSpinBox_2->value()));
- llp.setTextIndent(unit.fromUserValue(widget.doubleSpinBox_3->value()) - unit.fromUserValue(widget.doubleSpinBox_2->value()));
- }
-
- if (style == KoListStyle::ImageItem) {
- if (m_data) {
- llp.setBulletImage(m_data);
- }
- llp.setWidth(widget.imageWidth->value());
- llp.setHeight(widget.imageHeight->value());
- } else if (style == KoListStyle::CustomCharItem) {
- llp.setBulletCharacter((currentRow == m_blankCharIndex) ? QChar() : widget.customCharacter->text().remove('&').at(0));
- }
- // it is important to not use 45 for CustomCharItem as it is also char based
- else if (!KoListStyle::isNumberingStyle(style)) {
- llp.setRelativeBulletSize(45); //for non-numbering bullets the default relative bullet size is 45%(The spec does not say it; we take it)
- }
-
- Qt::Alignment align;
- switch (widget.alignment->currentIndex()) {
- case 0: align = Qt::AlignLeft; break;
- case 1: align = Qt::AlignLeft | Qt::AlignAbsolute; break;
- case 2: align = Qt::AlignRight | Qt::AlignAbsolute; break;
- case 3: align = Qt::AlignCenter; break;
- default:
- Q_ASSERT(false);
- }
- llp.setAlignment(align);
-
- if (llp.level() != m_previousLevel) {
- listStyle->removeLevelProperties(m_previousLevel);
- }
- listStyle->setLevelProperties(llp);
-}
-
-void ParagraphBulletsNumbers::styleChanged(int index)
-{
- KoListStyle::Style style = m_mapping[index];
- bool showLetterSynchronization = false;
-
- if (style == KoListStyle::ImageItem) {
- widget.startValue->setValue(1);
- widget.startValue->setEnabled(false);
- widget.levels->setValue(1);
- widget.levels->setEnabled(false);
- widget.insertImage->setEnabled(true);
- widget.imageHeight->setEnabled(true);
- widget.imageWidth->setEnabled(true);
-
- if (widget.imageHeight->value() == 0 && widget.imageWidth->value() == 0) {
- widget.imageHeight->setValue(m_fontSize);
- widget.imageWidth->setValue(m_fontSize);
- }
- } else if (!KoListStyle::isNumberingStyle(style)) {
- widget.startValue->setCounterType(KoListStyle::DecimalItem);
- widget.startValue->setValue(1);
- widget.startValue->setEnabled(false);
- widget.levels->setValue(1);
- widget.levels->setEnabled(false);
- widget.insertImage->setEnabled(false);
- widget.imageHeight->setEnabled(false);
- widget.imageWidth->setEnabled(false);
- widget.imageHeight->setValue(0);
- widget.imageWidth->setValue(0);
- } else {
- switch (style) {
- case KoListStyle::AlphaLowerItem:
- case KoListStyle::UpperAlphaItem:
- showLetterSynchronization = true;
- Q_FALLTHROUGH();
- default:
- widget.levels->setEnabled(true);
- widget.startValue->setEnabled(true);
- widget.startValue->setCounterType(style);
- int value = widget.startValue->value();
- widget.startValue->setValue(value + 1);
- widget.startValue->setValue(value); // surely to trigger a change event.
- widget.insertImage->setEnabled(false);
- widget.imageHeight->setEnabled(false);
- widget.imageWidth->setEnabled(false);
- }
- widget.imageHeight->setValue(0);
- widget.imageWidth->setValue(0);
- }
-
- widget.customCharacter->setEnabled(style == KoListStyle::CustomCharItem && index != m_blankCharIndex);
- widget.letterSynchronization->setVisible(showLetterSynchronization);
- widget.listPropertiesPane->setEnabled(style != KoListStyle::None);
- recalcPreview();
-}
-
-void ParagraphBulletsNumbers::customCharButtonPressed()
-{
- KoDialog *dialog = new KoDialog(this);
- dialog->setModal(true);
- dialog->setButtons(KoDialog::Ok | KoDialog::Cancel);
- dialog->setDefaultButton(KoDialog::Ok);
-
- KCharSelect *kcs = new KCharSelect(dialog, 0,
- KCharSelect::SearchLine | KCharSelect::FontCombo | KCharSelect::BlockCombos
- | KCharSelect::CharacterTable | KCharSelect::DetailBrowser);
-
- dialog->setMainWidget(kcs);
- if (dialog->exec() == KoDialog::Accepted) {
- QChar character = kcs->currentChar();
- widget.customCharacter->setText(character);
-
- // also switch to the custom list style.
- Q_FOREACH (int row, m_mapping.keys()) {
- if (m_mapping[row] == KoListStyle::CustomCharItem) {
- widget.listTypes->setCurrentRow(row);
- break;
- }
- }
- }
- delete dialog;
- recalcPreview();
-}
-
-void ParagraphBulletsNumbers::recalcPreview()
-{
- emit parStyleChanged();
-}
-
-void ParagraphBulletsNumbers::labelFollowedByIndexChanged(int index)
-{
- if (index == 1 || index == 2) {
- widget.doubleSpinBox->setEnabled(false);
- } else {
- widget.doubleSpinBox->setEnabled(true);
- }
- emit parStyleChanged();
- emit recalcPreview();
-}
-
-void ParagraphBulletsNumbers::setImageCollection(KoImageCollection *imageCollection)
-{
- m_imageCollection = imageCollection;
-}
-
-void ParagraphBulletsNumbers::selectListImage()
-{
- if (!m_imageCollection) {
- return;
- }
-
- KoFileDialog dlg(0, KoFileDialog::OpenFile, "bullets");
- dlg.setCaption(i18n("Select a list image"));
- if (!dlg.filename().isEmpty()) {
- QFile f(dlg.filename());
- if (f.exists()) {
- f.open(QIODevice::ReadOnly);
- QByteArray ba = f.readAll();
- f.close();
- if (m_imageCollection) {
- m_data = m_imageCollection->createImageData(ba);
- }
- emit recalcPreview();
- }
- }
-}
-
-void ParagraphBulletsNumbers::setFontSize(const KoCharacterStyle *style)
-{
- m_fontSize = style->fontPointSize();
-}
diff --git a/plugins/flake/textshape/dialogs/ParagraphBulletsNumbers.h b/plugins/flake/textshape/dialogs/ParagraphBulletsNumbers.h
deleted file mode 100644
index fb68d523fb..0000000000
--- a/plugins/flake/textshape/dialogs/ParagraphBulletsNumbers.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007, 2010 Thomas Zander <zander@kde.org>
- *
- * 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 PARAGRAPHBULLETSNUMBERS_H
-#define PARAGRAPHBULLETSNUMBERS_H
-
-#include <ui_ParagraphBulletsNumbers.h>
-#include <ListItemsHelper.h>
-
-#include <KoListStyle.h>
-
-#include <QWidget>
-
-class KoParagraphStyle;
-class KoCharacterStyle;
-class KoImageCollection;
-class KoImageData;
-
-class ParagraphBulletsNumbers : public QWidget
-{
- Q_OBJECT
-public:
- explicit ParagraphBulletsNumbers(QWidget *parent);
-
- void setDisplay(KoParagraphStyle *style, int level = 0);
-
- void save(KoParagraphStyle *style);
-
- int addStyle(const Lists::ListStyleItem &lsi);
-
- void setImageCollection(KoImageCollection *imageCollection);
-
-Q_SIGNALS:
- void parStyleChanged();
-
-public Q_SLOTS:
- void setFontSize(const KoCharacterStyle *style);
-
-private Q_SLOTS:
- void styleChanged(int);
- void customCharButtonPressed();
- void recalcPreview();
- void labelFollowedByIndexChanged(int);
- void selectListImage();
-
-private:
- Ui::ParagraphBulletsNumbers widget;
-
- QHash<int, KoListStyle::Style> m_mapping;
- int m_previousLevel;
- int m_blankCharIndex;
- bool m_alignmentMode;
- KoImageCollection *m_imageCollection;
- KoImageData *m_data;
- int m_fontSize;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/ParagraphBulletsNumbers.ui b/plugins/flake/textshape/dialogs/ParagraphBulletsNumbers.ui
deleted file mode 100644
index 430994982f..0000000000
--- a/plugins/flake/textshape/dialogs/ParagraphBulletsNumbers.ui
+++ /dev/null
@@ -1,317 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ParagraphBulletsNumbers</class>
- <widget class="QWidget" name="ParagraphBulletsNumbers">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>453</width>
- <height>386</height>
- </rect>
- </property>
- <layout class="QGridLayout">
- <item row="0" column="0">
- <widget class="QListWidget" name="listTypes"/>
- </item>
- <item row="0" column="1">
- <widget class="QWidget" name="listPropertiesPane">
- <layout class="QGridLayout">
- <property name="margin">
- <number>0</number>
- </property>
- <item row="0" column="0" colspan="3">
- <layout class="QGridLayout">
- <item row="0" column="3">
- <widget class="QLineEdit" name="suffix"/>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>Start at:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>startValue</cstring>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="ListsSpinBox" name="startValue">
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>9999</number>
- </property>
- <property name="value">
- <number>1</number>
- </property>
- </widget>
- </item>
- <item row="1" column="2">
- <widget class="QLabel" name="label_6">
- <property name="text">
- <string>Alignment:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>alignment</cstring>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Prefix:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>prefix</cstring>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLineEdit" name="prefix"/>
- </item>
- <item row="0" column="2">
- <widget class="QLabel" name="label_5">
- <property name="text">
- <string>Suffix:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>suffix</cstring>
- </property>
- </widget>
- </item>
- <item row="3" column="3">
- <widget class="QComboBox" name="labelFollowedBy"/>
- </item>
- <item row="1" column="3">
- <widget class="QComboBox" name="alignment"/>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="label_3">
- <property name="text">
- <string>Depth:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>depth</cstring>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QSpinBox" name="depth">
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>10</number>
- </property>
- </widget>
- </item>
- <item row="2" column="2">
- <widget class="QLabel" name="label_7">
- <property name="text">
- <string>Display Levels:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>levels</cstring>
- </property>
- </widget>
- </item>
- <item row="2" column="3">
- <widget class="QSpinBox" name="levels">
- <property name="minimum">
- <number>1</number>
- </property>
- </widget>
- </item>
- <item row="3" column="0" colspan="3">
- <widget class="QLabel" name="label_8">
- <property name="text">
- <string>Bullet/Number followed by</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item row="4" column="3">
- <widget class="QDoubleSpinBox" name="doubleSpinBox">
- <property name="suffix">
- <string> cm</string>
- </property>
- </widget>
- </item>
- <item row="4" column="2">
- <widget class="QLabel" name="label_9">
- <property name="text">
- <string>at</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item row="5" column="1">
- <widget class="QDoubleSpinBox" name="doubleSpinBox_2">
- <property name="suffix">
- <string> cm</string>
- </property>
- </widget>
- </item>
- <item row="5" column="0">
- <widget class="QLabel" name="label_10">
- <property name="text">
- <string>Aligned at</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item row="5" column="3">
- <widget class="QDoubleSpinBox" name="doubleSpinBox_3">
- <property name="suffix">
- <string> cm</string>
- </property>
- </widget>
- </item>
- <item row="5" column="2">
- <widget class="QLabel" name="label_11">
- <property name="text">
- <string>Indented at</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_4">
- <property name="text">
- <string>Custom character:</string>
- </property>
- <property name="buddy">
- <cstring>customCharacter</cstring>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QToolButton" name="customCharacter">
- <property name="text">
- <string>...</string>
- </property>
- </widget>
- </item>
- <item row="1" column="2">
- <spacer>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>251</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="13" column="0" colspan="3">
- <widget class="QCheckBox" name="restartNumbering">
- <property name="text">
- <string>Restart numbering at this paragraph</string>
- </property>
- </widget>
- </item>
- <item row="14" column="0" colspan="3">
- <widget class="QCheckBox" name="letterSynchronization">
- <property name="text">
- <string>Letter Synchronization</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0" colspan="3">
- <layout class="QGridLayout">
- <item row="1" column="0">
- <widget class="QLabel" name="widthLabel">
- <property name="text">
- <string>Width</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="insertImageLabel">
- <property name="text">
- <string>Insert Image</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QDoubleSpinBox" name="imageWidth"/>
- </item>
- <item row="1" column="2">
- <widget class="QLabel" name="heightLabel">
- <property name="text">
- <string>Height</string>
- </property>
- </widget>
- </item>
- <item row="1" column="3">
- <widget class="QDoubleSpinBox" name="imageHeight"/>
- </item>
- <item row="0" column="1">
- <widget class="QPushButton" name="insertImage">
- <property name="text">
- <string>Browse...</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="15" column="0" colspan="3">
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>ListsSpinBox</class>
- <extends>QSpinBox</extends>
- <header>dialogs/ListsSpinBox.h</header>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/ParagraphDecorations.cpp b/plugins/flake/textshape/dialogs/ParagraphDecorations.cpp
deleted file mode 100644
index 52323f0d59..0000000000
--- a/plugins/flake/textshape/dialogs/ParagraphDecorations.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2001, 2002 Montel Laurent <lmontel@mandrakesoft.com>
- Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
-
- 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 "ParagraphDecorations.h"
-
-#include <QDebug>
-
-ParagraphDecorations::ParagraphDecorations(QWidget *parent)
- : QWidget(parent)
-{
- widget.setupUi(this);
-
- connect(widget.backgroundColor, SIGNAL(changed(QColor)), this, SLOT(slotBackgroundColorChanged()));
- connect(widget.resetBackgroundColor, SIGNAL(clicked()), this, SLOT(clearBackgroundColor()));
-}
-
-void ParagraphDecorations::slotBackgroundColorChanged()
-{
- m_backgroundColorReset = false; m_backgroundColorChanged = true;
- emit parStyleChanged();
-}
-
-void ParagraphDecorations::setDisplay(KoParagraphStyle *style)
-{
- m_backgroundColorChanged = false;
- m_backgroundColorReset = style->background().style() == Qt::NoBrush;
- if (m_backgroundColorReset) {
- clearBackgroundColor();
- } else {
- widget.backgroundColor->setColor(style->background().color());
- }
-}
-
-void ParagraphDecorations::save(KoParagraphStyle *style) const
-{
- Q_ASSERT(style);
- if (m_backgroundColorReset)
- // clearing the property doesn't work since ParagraphSettingsDialog does a mergeBlockFormat
- // so we'll set it to a Qt::NoBrush brush instead
- {
- style->setBackground(QBrush(Qt::NoBrush));
- } else if (m_backgroundColorChanged) {
- style->setBackground(QBrush(widget.backgroundColor->color()));
- }
-}
-
-void ParagraphDecorations::clearBackgroundColor()
-{
- widget.backgroundColor->setColor(widget.backgroundColor->defaultColor());
- m_backgroundColorReset = true;
- emit parStyleChanged();
-}
diff --git a/plugins/flake/textshape/dialogs/ParagraphDecorations.h b/plugins/flake/textshape/dialogs/ParagraphDecorations.h
deleted file mode 100644
index 3bf1ea8231..0000000000
--- a/plugins/flake/textshape/dialogs/ParagraphDecorations.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2001,2002,2003 Montel Laurent <lmontel@mandrakesoft.com>
- Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
-
- 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 PARAGRAPHDECORATIONS_H
-#define PARAGRAPHDECORATIONS_H
-
-#include <ui_ParagraphDecorations.h>
-
-#include <KoParagraphStyle.h>
-
-class ParagraphDecorations : public QWidget
-{
- Q_OBJECT
-
-public:
- explicit ParagraphDecorations(QWidget *parent = 0);
- ~ParagraphDecorations() override {}
-
- void setDisplay(KoParagraphStyle *style);
- void save(KoParagraphStyle *style) const;
-
-Q_SIGNALS:
- void parStyleChanged();
-
-private Q_SLOTS:
- void clearBackgroundColor();
- void slotBackgroundColorChanged();
-
-private:
- Ui::ParagraphDecorations widget;
-
- bool m_backgroundColorChanged, m_backgroundColorReset;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/ParagraphDecorations.ui b/plugins/flake/textshape/dialogs/ParagraphDecorations.ui
deleted file mode 100644
index 3c0733e6d2..0000000000
--- a/plugins/flake/textshape/dialogs/ParagraphDecorations.ui
+++ /dev/null
@@ -1,118 +0,0 @@
-<ui version="4.0" >
- <class>ParagraphDecorations</class>
- <widget class="QWidget" name="ParagraphDecorations" >
- <property name="geometry" >
- <rect>
- <x>0</x>
- <y>0</y>
- <width>437</width>
- <height>271</height>
- </rect>
- </property>
- <layout class="QVBoxLayout" >
- <property name="spacing" >
- <number>6</number>
- </property>
- <property name="leftMargin" >
- <number>9</number>
- </property>
- <property name="topMargin" >
- <number>9</number>
- </property>
- <property name="rightMargin" >
- <number>9</number>
- </property>
- <property name="bottomMargin" >
- <number>9</number>
- </property>
- <item>
- <widget class="QGroupBox" name="groupBox" >
- <property name="title" >
- <string>Background</string>
- </property>
- <layout class="QGridLayout" >
- <property name="leftMargin" >
- <number>9</number>
- </property>
- <property name="topMargin" >
- <number>9</number>
- </property>
- <property name="rightMargin" >
- <number>9</number>
- </property>
- <property name="bottomMargin" >
- <number>9</number>
- </property>
- <property name="horizontalSpacing" >
- <number>6</number>
- </property>
- <property name="verticalSpacing" >
- <number>6</number>
- </property>
- <item row="0" column="2" >
- <widget class="QToolButton" name="resetBackgroundColor" >
- <property name="text" >
- <string>...</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1" >
- <widget class="KColorButton" native="1" name="backgroundColor" />
- </item>
- <item row="0" column="0" >
- <widget class="QLabel" name="backgroundColorLabel" >
- <property name="text" >
- <string>Background color</string>
- </property>
- <property name="wordWrap" >
- <bool>false</bool>
- </property>
- <property name="buddy" >
- <cstring>backgroundColor</cstring>
- </property>
- </widget>
- </item>
- <item row="0" column="3" >
- <spacer>
- <property name="orientation" >
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" >
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer>
- <property name="orientation" >
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" >
- <size>
- <width>20</width>
- <height>16</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <layoutdefault spacing="6" margin="11" />
- <customwidgets>
- <customwidget>
- <class>KColorButton</class>
- <extends>QWidget</extends>
- <header>kcolorbutton.h</header>
- <container>1</container>
- </customwidget>
- </customwidgets>
- <resources>
- </resources>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/ParagraphDropCaps.cpp b/plugins/flake/textshape/dialogs/ParagraphDropCaps.cpp
deleted file mode 100644
index 8357f46639..0000000000
--- a/plugins/flake/textshape/dialogs/ParagraphDropCaps.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-/* This file is part of the KDE project
-
- Copyright (C) 2011 Mojtaba Shahi Senobari <mojtaba.shahi3000@gmail.com>
- Copyright (C) 2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
-
- 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 "ParagraphDropCaps.h"
-
-#include "KoParagraphStyle.h"
-#include <QMessageBox>
-
-ParagraphDropCaps::ParagraphDropCaps(QWidget *parent)
- : QWidget(parent)
-{
- widget.setupUi(this);
-
- widget.distance->changeValue(0);
- widget.characters->setSpecialValueText(i18n("Whole Word"));
- widget.characters->setValue(0);
- widget.lines->setValue(2);
-
- connect(widget.capsState, SIGNAL(stateChanged(int)), this, SLOT(dropCapsStateChanged()));
- connect(widget.distance, SIGNAL(valueChangedPt(qreal)), this, SLOT(paragraphDistanceChanged(qreal)));
- connect(widget.characters, SIGNAL(valueChanged(int)), this, SLOT(dropedCharacterCountChanged(int)));
- connect(widget.lines, SIGNAL(valueChanged(int)), this, SLOT(dropsLineSpanChanged(int)));
-}
-
-void ParagraphDropCaps::dropCapsStateChanged()
-{
- if (widget.capsState->isChecked()) {
- widget.setting->setEnabled(true);
- m_dropCapsInherited = false;
- } else {
- widget.setting->setEnabled(false);
- }
- emit parStyleChanged();
-}
-
-void ParagraphDropCaps::setDisplay(KoParagraphStyle *style)
-{
- if (!style) {
- return;
- }
- if (!style->dropCaps()) {
- widget.setting->setEnabled(false);
- return;
- }
-
- widget.capsState->setChecked(true);
- widget.distance->changeValue(style->dropCapsDistance());
- widget.characters->setValue(style->dropCapsLength());
- widget.lines->setValue(style->dropCapsLines());
-
- m_dropCapsInherited = !style->hasProperty(KoParagraphStyle::DropCaps);
- m_capsDistanceInherited = !style->hasProperty(KoParagraphStyle::DropCapsDistance);
- m_capsLengthInherited = !style->hasProperty(KoParagraphStyle::DropCapsLength);
- m_capsLinesInherited = !style->hasProperty(KoParagraphStyle::DropCapsLines);
-}
-
-void ParagraphDropCaps::save(KoParagraphStyle *style)
-{
- if (!style) {
- return;
- }
-
- if (!m_dropCapsInherited) {
- style->setDropCaps(widget.capsState->isChecked());
- }
-
- if (!m_capsDistanceInherited) {
- style->setDropCapsDistance(widget.distance->value());
- }
-
- if (!m_capsLengthInherited) {
- style->setDropCapsLength(widget.characters->value());
- }
-
- if (!m_capsLinesInherited) {
- style->setDropCapsLines(widget.lines->value());
- }
-}
-
-void ParagraphDropCaps::setUnit(const KoUnit &unit)
-{
- widget.distance->setUnit(unit);
-}
-
-void ParagraphDropCaps::paragraphDistanceChanged(qreal distance)
-{
- Q_UNUSED(distance);
- m_capsDistanceInherited = false;
- emit parStyleChanged();
-}
-
-void ParagraphDropCaps::dropsLineSpanChanged(int lineSpan)
-{
- Q_UNUSED(lineSpan);
- m_capsLinesInherited = false;
- emit parStyleChanged();
-}
-
-void ParagraphDropCaps::dropedCharacterCountChanged(int count)
-{
- Q_UNUSED(count);
- m_capsLengthInherited = false;
- emit parStyleChanged();
-}
diff --git a/plugins/flake/textshape/dialogs/ParagraphDropCaps.h b/plugins/flake/textshape/dialogs/ParagraphDropCaps.h
deleted file mode 100644
index 8809a3e2d9..0000000000
--- a/plugins/flake/textshape/dialogs/ParagraphDropCaps.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* This file is part of the KDE project
-
- Copyright (C) 2011 Mojtaba Shahi Senobari <mojtaba.shahi3000@gmail.com>
- Copyright (C) 2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
-
- 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 PARAGRAPHDROPCAPS_H
-#define PARAGRAPHDROPCAPS_H
-#include "ui_ParagraphDropCaps.h"
-
-#include <QWidget>
-
-class KoParagraphStyle;
-class KoUnit;
-
-namespace Ui
-{
-class ParagraphDropCaps;
-}
-
-class ParagraphDropCaps : public QWidget
-{
- Q_OBJECT
-
-public:
- explicit ParagraphDropCaps(QWidget *parent = 0);
-
- void setDisplay(KoParagraphStyle *style);
- void save(KoParagraphStyle *style);
-
- void setUnit(const KoUnit &unit);
-
-Q_SIGNALS:
- void parStyleChanged();
-
-private Q_SLOTS:
- void dropCapsStateChanged();
- void paragraphDistanceChanged(qreal distance);
- void dropsLineSpanChanged(int lineSpan);
- void dropedCharacterCountChanged(int count);
-
-private:
- Ui::ParagraphDropCaps widget;
-
- bool m_dropCapsInherited;
- bool m_capsDistanceInherited;
- bool m_capsLengthInherited;
- bool m_capsLinesInherited;
-};
-
-#endif // PARAGRAPHDROPCAPS_H
diff --git a/plugins/flake/textshape/dialogs/ParagraphDropCaps.ui b/plugins/flake/textshape/dialogs/ParagraphDropCaps.ui
deleted file mode 100644
index 760025966d..0000000000
--- a/plugins/flake/textshape/dialogs/ParagraphDropCaps.ui
+++ /dev/null
@@ -1,173 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ParagraphDropCaps</class>
- <widget class="QWidget" name="ParagraphDropCaps">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>368</width>
- <height>318</height>
- </rect>
- </property>
- <layout class="QGridLayout" name="gridLayout_3">
- <item row="2" column="0">
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>144</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="0">
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Drop caps:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="capsState">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>118</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item row="1" column="0">
- <widget class="QWidget" name="setting">
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="1" column="0">
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Fixed</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <layout class="QVBoxLayout" name="verticalLayout_3">
- <item>
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>Distance to paragraph:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="label_3">
- <property name="text">
- <string>Number of characters:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="label_4">
- <property name="text">
- <string>Number of lines it covers:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="KoUnitDoubleSpinBox" name="distance"/>
- </item>
- <item>
- <widget class="QSpinBox" name="characters">
- <property name="wrapping">
- <bool>false</bool>
- </property>
- <property name="minimum">
- <number>0</number>
- </property>
- <property name="value">
- <number>0</number>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QSpinBox" name="lines">
- <property name="minimum">
- <number>2</number>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <item>
- <spacer name="horizontalSpacer_4">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>KoUnitDoubleSpinBox</class>
- <extends>QDoubleSpinBox</extends>
- <header>KoUnitDoubleSpinBox.h</header>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/ParagraphGeneral.cpp b/plugins/flake/textshape/dialogs/ParagraphGeneral.cpp
deleted file mode 100644
index c36cd83dab..0000000000
--- a/plugins/flake/textshape/dialogs/ParagraphGeneral.cpp
+++ /dev/null
@@ -1,229 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007, 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- * Copyright (C) 2012 Mojtaba Shahi Senobari <mojtaba.shahi3000@gmail.com>
- *
- * 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 "ParagraphGeneral.h"
-#include "ParagraphIndentSpacing.h"
-#include "ParagraphLayout.h"
-#include "ParagraphBulletsNumbers.h"
-#include "ParagraphDecorations.h"
-#include "ParagraphDropCaps.h"
-#include "StylesModel.h"
-
-#include <KoStyleManager.h>
-#include <KoParagraphStyle.h>
-#include <KoStyleThumbnailer.h>
-
-ParagraphGeneral::ParagraphGeneral(QWidget *parent)
- : CharacterGeneral(parent)
- , m_nameHidden(false)
- , m_style(0)
- , m_styleManager(0)
- , m_thumbnail(new KoStyleThumbnailer())
- , m_paragraphInheritedStyleModel(new StylesModel(0, StylesModel::ParagraphStyle))
-{
-//Disable for now
- //include in TOC
- widget.inToc->setVisible(false);
-//
- widget.nextStyle->setVisible(true);
- widget.label_2->setVisible(true);
-
- m_paragraphInheritedStyleModel->setStyleThumbnailer(m_thumbnail);
- widget.inheritStyle->setStylesModel(m_paragraphInheritedStyleModel);
-
- m_paragraphIndentSpacing = new ParagraphIndentSpacing(this);
- widget.tabs->addTab(m_paragraphIndentSpacing, i18n("Indent/Spacing"));
-
- connect(m_paragraphIndentSpacing, SIGNAL(parStyleChanged()), this, SIGNAL(styleChanged()));
-
- m_paragraphLayout = new ParagraphLayout(this);
- widget.tabs->addTab(m_paragraphLayout, i18n("General Layout"));
-
- connect(m_paragraphLayout, SIGNAL(parStyleChanged()), this, SIGNAL(styleChanged()));
-
- m_paragraphBulletsNumbers = new ParagraphBulletsNumbers(this);
- widget.tabs->addTab(m_paragraphBulletsNumbers, i18n("Bullets/Numbers"));
-
- connect(m_paragraphBulletsNumbers, SIGNAL(parStyleChanged()), this, SIGNAL(styleChanged()));
-
- m_paragraphDecorations = new ParagraphDecorations(this);
- widget.tabs->addTab(m_paragraphDecorations, i18n("Decorations"));
-
- connect(m_paragraphDecorations, SIGNAL(parStyleChanged()), this, SIGNAL(styleChanged()));
-
- m_paragraphDropCaps = new ParagraphDropCaps(this);
- widget.tabs->addTab(m_paragraphDropCaps, i18n("Drop Caps"));
-
- connect(m_paragraphDropCaps, SIGNAL(parStyleChanged()), this, SIGNAL(styleChanged()));
-
- widget.preview->setText(QString("Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat."));
-
- connect(widget.name, SIGNAL(textChanged(QString)), this, SIGNAL(nameChanged(QString)));
- connect(widget.nextStyle, SIGNAL(currentIndexChanged(int)), this, SIGNAL(styleChanged()));
-
- connect(this, SIGNAL(styleChanged()), this, SLOT(setPreviewParagraphStyle()));
-}
-
-void ParagraphGeneral::hideStyleName(bool hide)
-{
- if (hide) {
- disconnect(widget.name, SIGNAL(textChanged(QString)), this, SIGNAL(nameChanged(QString)));
- widget.tabs->removeTab(0);
- m_nameHidden = true;
- }
-}
-
-void ParagraphGeneral::selectName()
-{
- widget.tabs->setCurrentIndex(widget.tabs->indexOf(widget.generalTab));
- widget.name->selectAll();
- widget.name->setFocus(Qt::OtherFocusReason);
-}
-
-void ParagraphGeneral::setStyle(KoParagraphStyle *style, int level)
-{
- m_style = style;
- if (m_style == 0) {
- return;
- }
-
- CharacterGeneral::setStyle(style);
-
- blockSignals(true);
-
- /* widget.inheritStyle->clear();
- widget.inheritStyle->addItem(i18nc("Inherit style", "None"));
- widget.inheritStyle->setCurrentIndex(0);
- Q_FOREACH (KoParagraphStyle *s, m_paragraphStyles) {
- KoParagraphStyle *parent = s;
- bool ok = true;
- while (ok && parent) {
- ok = parent->styleId() != style->styleId();
- parent = parent->parentStyle();
- }
- if (!ok) continue; // can't inherit from myself, even indirectly.
-
- widget.inheritStyle->addItem(s->name(), s->styleId());
- if (s == style->parent())
- widget.inheritStyle->setCurrentIndex(widget.inheritStyle->count() - 1);
- }
- */
- if (!m_nameHidden) {
- widget.name->setText(style->name());
- }
-
- if (m_styleManager) {
- CharacterGeneral::updateNextStyleCombo(m_styleManager->paragraphStyle(style->nextStyle()));
- KoParagraphStyle *parentStyle = style->parentStyle();
- if (parentStyle) {
- widget.inheritStyle->setCurrentIndex(m_paragraphInheritedStyleModel->indexOf(parentStyle).row());
- //m_paragraphInheritedStyleModel->setCurrentParagraphStyle(parentStyle->styleId());
- }
- }
-
- m_paragraphIndentSpacing->setDisplay(style);
- m_paragraphLayout->setDisplay(style);
- m_paragraphBulletsNumbers->setDisplay(style, level);
- m_paragraphDecorations->setDisplay(style);
- m_paragraphDropCaps->setDisplay(style);
-
- widget.preview->setParagraphStyle(style);
-
- blockSignals(false);
-}
-
-void ParagraphGeneral::setUnit(const KoUnit &unit)
-{
- m_paragraphIndentSpacing->setUnit(unit);
- m_paragraphDropCaps->setUnit(unit);
-}
-
-void ParagraphGeneral::save(KoParagraphStyle *style)
-{
- KoParagraphStyle *savingStyle;
-
- if (style == 0) {
- if (m_style == 0) {
- return;
- } else {
- savingStyle = m_style;
- }
- } else {
- savingStyle = style;
- }
-
- CharacterGeneral::save(style);
-
- m_paragraphIndentSpacing->save(savingStyle);
- m_paragraphLayout->save(savingStyle);
- m_paragraphBulletsNumbers->save(savingStyle);
- m_paragraphDecorations->save(savingStyle);
- m_paragraphDropCaps->save(savingStyle);
- savingStyle->setName(widget.name->text());
- if (int nextStyleId = CharacterGeneral::nextStyleId()) {
- savingStyle->setNextStyle(nextStyleId);
- }
-
- if (m_style == savingStyle) {
- emit styleAltered(savingStyle);
- }
-}
-
-void ParagraphGeneral::switchToGeneralTab()
-{
- widget.tabs->setCurrentIndex(0);
-}
-
-void ParagraphGeneral::setPreviewParagraphStyle()
-{
- KoParagraphStyle *parStyle = new KoParagraphStyle();
- save(parStyle);
- if (parStyle) {
- widget.preview->setParagraphStyle(parStyle);
- }
-
- delete parStyle;
-}
-
-void ParagraphGeneral::setImageCollection(KoImageCollection *imageCollection)
-{
- m_paragraphBulletsNumbers->setImageCollection(imageCollection);
-}
-
-QString ParagraphGeneral::styleName() const
-{
- return widget.name->text();
-}
-
-void ParagraphGeneral::setStyleManager(KoStyleManager *sm)
-{
- if (!sm) {
- return;
- }
- m_styleManager = sm;
- CharacterGeneral::setStyleManager(m_styleManager);
- m_paragraphInheritedStyleModel->setStyleManager(m_styleManager);
-}
-
-KoParagraphStyle *ParagraphGeneral::style() const
-{
- return m_style;
-}
diff --git a/plugins/flake/textshape/dialogs/ParagraphGeneral.h b/plugins/flake/textshape/dialogs/ParagraphGeneral.h
deleted file mode 100644
index 172d12a00c..0000000000
--- a/plugins/flake/textshape/dialogs/ParagraphGeneral.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007, 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 PARAGRAPHGENERAL_H
-#define PARAGRAPHGENERAL_H
-
-#include "CharacterGeneral.h"
-
-#include <QList>
-
-class KoParagraphStyle;
-class KoStyleThumbnailer;
-class KoStyleManager;
-class KoImageCollection;
-class KoUnit;
-class ParagraphBulletsNumbers;
-class ParagraphIndentSpacing;
-class ParagraphLayout;
-class ParagraphDecorations;
-class ParagraphDropCaps;
-class StylesModel;
-
-class ParagraphGeneral : public CharacterGeneral
-{
- Q_OBJECT
-public:
- explicit ParagraphGeneral(QWidget *parent = 0);
-
- void setStyle(KoParagraphStyle *style, int level = 0);
- void setUnit(const KoUnit &unit);
-
- void switchToGeneralTab();
- void hideStyleName(bool hide);
- bool isStyleChanged();
- QString styleName() const;
- void selectName();
-
- void setImageCollection(KoImageCollection *imageCollection);
- KoImageCollection *imageCollection();
- void setStyleManager(KoStyleManager *sm);
-
- KoParagraphStyle *style() const;
-
-public Q_SLOTS:
- void save(KoParagraphStyle *style = 0);
-
-Q_SIGNALS:
- void nameChanged(const QString &name);
- void styleAltered(const KoParagraphStyle *style); /// when saving
-
-private Q_SLOTS:
- void setPreviewParagraphStyle();
-
-private:
- bool m_nameHidden;
-
- ParagraphIndentSpacing *m_paragraphIndentSpacing;
- ParagraphLayout *m_paragraphLayout;
- ParagraphBulletsNumbers *m_paragraphBulletsNumbers;
- ParagraphDecorations *m_paragraphDecorations;
- ParagraphDropCaps *m_paragraphDropCaps;
-
- KoParagraphStyle *m_style;
- QList<KoParagraphStyle *> m_paragraphStyles;
- KoStyleManager *m_styleManager;
-
- KoStyleThumbnailer *m_thumbnail;
- StylesModel *m_paragraphInheritedStyleModel;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/ParagraphIndentSpacing.cpp b/plugins/flake/textshape/dialogs/ParagraphIndentSpacing.cpp
deleted file mode 100644
index 520e805e8f..0000000000
--- a/plugins/flake/textshape/dialogs/ParagraphIndentSpacing.cpp
+++ /dev/null
@@ -1,292 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007, 2009 Thomas Zander <zander@kde.org>
- * Copyright (c) 2003 David Faure <faure@kde.org>
- * Copyright (C) 2011 Mojtaba Shahi Senobari <mojtaba.shahi3000@gmail.com>
- *
- * 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 "ParagraphIndentSpacing.h"
-
-#include <KoParagraphStyle.h>
-#include <QDebug>
-
-ParagraphIndentSpacing::ParagraphIndentSpacing(QWidget *parent)
- : QWidget(parent)
- , m_fontMetricsChecked(false)
-{
- widget.setupUi(this);
-
- connect(widget.first, SIGNAL(valueChangedPt(qreal)), this, SLOT(firstLineMarginChanged(qreal)));
- connect(widget.left, SIGNAL(valueChangedPt(qreal)), this, SLOT(leftMarginChanged(qreal)));
- connect(widget.right, SIGNAL(valueChangedPt(qreal)), this, SLOT(rightMarginChanged(qreal)));
-
- // Keep order in sync with lineSpacingType() and display()
- widget.lineSpacing->addItem(i18nc("Line spacing value", "Single"));
- widget.lineSpacing->addItem(i18nc("Line spacing value", "1.5 Lines"));
- widget.lineSpacing->addItem(i18nc("Line spacing value", "Double"));
- widget.lineSpacing->addItem(i18nc("Line spacing type", "Proportional")); // called Proportional like in OO
- widget.lineSpacing->addItem(i18nc("Line spacing type", "Additional")); // normal distance + absolute value
- widget.lineSpacing->addItem(i18nc("Line spacing type", "Fixed"));
- widget.lineSpacing->addItem(i18nc("Line spacing type", "At least"));
-
- connect(widget.first, SIGNAL(valueChangedPt(qreal)), this, SLOT(firstIndentValueChanged()));
- connect(widget.left, SIGNAL(valueChangedPt(qreal)), this, SLOT(leftMarginValueChanged()));
- connect(widget.right, SIGNAL(valueChangedPt(qreal)), this, SLOT(rightMarginValueChanged()));
- connect(widget.after, SIGNAL(valueChangedPt(qreal)), this, SLOT(bottomMarginValueChanged()));
- connect(widget.before, SIGNAL(valueChangedPt(qreal)), this, SLOT(topMarginValueChanged()));
- connect(widget.lineSpacing, SIGNAL(currentIndexChanged(int)), this, SLOT(lineSpacingChanged(int)));
- connect(widget.useFont, SIGNAL(toggled(bool)), this, SLOT(useFontMetrices(bool)));
- connect(widget.autoTextIndent, SIGNAL(stateChanged(int)), this, SLOT(autoTextIndentChanged(int)));
- connect(widget.proportional, SIGNAL(valueChanged(int)), this, SLOT(spacingPercentChanged()));
- connect(widget.custom, SIGNAL(valueChangedPt(qreal)), this, SLOT(spacingValueChanged()));
- lineSpacingChanged(0);
-}
-
-void ParagraphIndentSpacing::autoTextIndentChanged(int state)
-{
- widget.first->setEnabled(state == Qt::Unchecked);
- m_autoTextIndentInherited = false;
- emit parStyleChanged();
-}
-void ParagraphIndentSpacing::firstIndentValueChanged()
-{
- m_textIndentInherited = false;
- emit parStyleChanged();
-}
-
-void ParagraphIndentSpacing::rightMarginValueChanged()
-{
- m_rightMarginIngerited = false;
- emit parStyleChanged();
-}
-
-void ParagraphIndentSpacing::leftMarginValueChanged()
-{
- m_leftMarginInherited = false;
- emit parStyleChanged();
-}
-
-void ParagraphIndentSpacing::topMarginValueChanged()
-{
- m_topMarginInherited = false;
- emit parStyleChanged();
-}
-
-void ParagraphIndentSpacing::bottomMarginValueChanged()
-{
- m_bottomMarginInherited = false;
- emit parStyleChanged();
-}
-
-void ParagraphIndentSpacing::setDisplay(KoParagraphStyle *style)
-{
- m_style = style;
- // TODO : handle relatives
- widget.first->changeValue(style->textIndent());
- widget.left->changeValue(style->leftMargin());
- widget.right->changeValue(style->rightMargin());
- widget.before->changeValue(style->topMargin());
- widget.after->changeValue(style->bottomMargin());
-
- m_rightMarginIngerited = !style->hasProperty(QTextFormat::BlockRightMargin);
- m_leftMarginInherited = !style->hasProperty(QTextFormat::BlockLeftMargin);
- m_topMarginInherited = !style->hasProperty(QTextFormat::BlockTopMargin);
- m_bottomMarginInherited = !style->hasProperty(QTextFormat::BlockBottomMargin);
- m_autoTextIndentInherited = !style->hasProperty(KoParagraphStyle::AutoTextIndent);
- m_textIndentInherited = !style->hasProperty(QTextFormat::TextIndent);
-
- widget.autoTextIndent->setChecked(style->autoTextIndent());
-
- m_spacingInherited = !(style->hasProperty(KoParagraphStyle::FixedLineHeight) || style->hasProperty(KoParagraphStyle::LineSpacing) || style->hasProperty(KoParagraphStyle::PercentLineHeight) || style->hasProperty(KoParagraphStyle::MinimumLineHeight));
-
- int index;
- if (style->hasProperty(KoParagraphStyle::FixedLineHeight) && style->lineHeightAbsolute() != 0) {
- // this is the strongest; if this is set we don't care what other properties there are.
- index = 5;
- } else if (style->hasProperty(KoParagraphStyle::LineSpacing) && style->lineSpacing() != 0) {
- // if LineSpacing is set then percent is ignored.
- index = 4;
- } else if (style->hasProperty(KoParagraphStyle::PercentLineHeight) && style->lineHeightPercent() != 0) {
- int percent = style->lineHeightPercent();
- if (percent == 120) {
- index = 0; // single
- } else if (percent == 180) {
- index = 1; // 1.5
- } else if (percent == 240) {
- index = 2; // double
- } else {
- index = 3; // proportional
- }
- } else if (style->hasProperty(KoParagraphStyle::MinimumLineHeight) && style->minimumLineHeight() != 0) {
- index = 6;
- } else {
- index = 0; // nothing set, default is 'single' just like for geeks.
- }
- widget.lineSpacing->setCurrentIndex(index);
- //widget.minimumLineSpacing->changeValue(style->minimumLineHeight());
- widget.useFont->setChecked(style->lineSpacingFromFont());
- m_fontMetricsChecked = style->lineSpacingFromFont();
-}
-
-void ParagraphIndentSpacing::lineSpacingChanged(int row)
-{
- bool percent = false, custom = false;
- qreal customValue = 0.0;
- switch (row) {
- case 0:
- case 1:
- case 2:
- break;
- case 3: // proportional
- percent = true;
- widget.proportional->setValue(m_style->lineHeightPercent());
- break;
- case 4: // additional
- custom = true;
- customValue = qMax(qreal(0.1), m_style->lineSpacing());
- break;
- case 5: // fixed
- custom = true;
- if (m_style->lineHeightAbsolute() == 0) { // unset
- customValue = 12.0; // nice default value...
- } else {
- customValue = m_style->lineHeightAbsolute();
- }
- break;
- case 6: // minimum
- custom = true;
- customValue = m_style->minimumLineHeight();
- break;
- default:; // other cases don't need the spinboxes
- }
-
- m_spacingInherited = false;
-
- if (custom) {
- widget.custom->setEnabled(true);
- widget.spacingStack->setCurrentWidget(widget.unitsPage);
- widget.custom->changeValue(customValue);
- } else {
- widget.spacingStack->setCurrentWidget(widget.percentPage);
- widget.proportional->setEnabled(percent);
- if (!percent) {
- widget.proportional->setValue(100);
- }
- }
-
- widget.useFont->setEnabled(row != 5);
- widget.useFont->setChecked(row == 5 ? false : m_fontMetricsChecked);
- emit parStyleChanged();
-}
-
-void ParagraphIndentSpacing::spacingPercentChanged()
-{
- m_spacingInherited = false;
- emit parStyleChanged();
-}
-
-void ParagraphIndentSpacing::spacingValueChanged()
-{
- m_spacingInherited = false;
- emit parStyleChanged();
-}
-
-void ParagraphIndentSpacing::save(KoParagraphStyle *style)
-{
- // general note; we have to unset values by setting it to zero instead of removing the item
- // since this dialog may be used on a copy style, which will be applied later. And removing
- // items doesn't work for that.
- if (!m_textIndentInherited) {
- style->setTextIndent(QTextLength(QTextLength::FixedLength, widget.first->value()));
- }
- if (!m_leftMarginInherited) {
- style->setLeftMargin(QTextLength(QTextLength::FixedLength, widget.left->value()));
- }
- if (!m_rightMarginIngerited) {
- style->setRightMargin(QTextLength(QTextLength::FixedLength, widget.right->value()));
- }
- if (!m_topMarginInherited) {
- style->setTopMargin(QTextLength(QTextLength::FixedLength, widget.before->value()));
- }
- if (!m_bottomMarginInherited) {
- style->setBottomMargin(QTextLength(QTextLength::FixedLength, widget.after->value()));
- }
- if (!m_autoTextIndentInherited) {
- style->setAutoTextIndent(widget.autoTextIndent->isChecked());
- }
- if (!m_spacingInherited) {
- style->setLineHeightAbsolute(0); // since it trumps percentage based line heights, unset it.
- style->setMinimumLineHeight(QTextLength(QTextLength::FixedLength, 0));
- style->setLineSpacing(0);
- switch (widget.lineSpacing->currentIndex()) {
- case 0: style->setLineHeightPercent(120); break;
- case 1: style->setLineHeightPercent(180); break;
- case 2: style->setLineHeightPercent(240); break;
- case 3: style->setLineHeightPercent(widget.proportional->value()); break;
- case 4:
- if (widget.custom->value() == 0.0) { // then we need to save it differently.
- style->setLineHeightPercent(100);
- } else {
- style->setLineSpacing(widget.custom->value());
- }
- break;
- case 5:
- style->setLineHeightAbsolute(widget.custom->value());
- break;
- case 6:
- style->setMinimumLineHeight(QTextLength(QTextLength::FixedLength, widget.custom->value()));
- break;
- }
- style->setLineSpacingFromFont(widget.lineSpacing->currentIndex() != 5 && widget.useFont->isChecked());
- }
-}
-
-void ParagraphIndentSpacing::setUnit(const KoUnit &unit)
-{
- widget.first->setUnit(unit);
- widget.left->setUnit(unit);
- widget.right->setUnit(unit);
- widget.before->setUnit(unit);
- widget.after->setUnit(unit);
- widget.custom->setUnit(unit);
-}
-
-void ParagraphIndentSpacing::useFontMetrices(bool on)
-{
- if (widget.lineSpacing->currentIndex() != 5) {
- m_fontMetricsChecked = on;
- }
- emit parStyleChanged();
-}
-
-void ParagraphIndentSpacing::firstLineMarginChanged(qreal margin)
-{
- Q_UNUSED(margin);
- emit parStyleChanged();
-}
-
-void ParagraphIndentSpacing::leftMarginChanged(qreal margin)
-{
- Q_UNUSED(margin);
- emit parStyleChanged();
-}
-
-void ParagraphIndentSpacing::rightMarginChanged(qreal margin)
-{
- Q_UNUSED(margin);
- emit parStyleChanged();
-}
diff --git a/plugins/flake/textshape/dialogs/ParagraphIndentSpacing.h b/plugins/flake/textshape/dialogs/ParagraphIndentSpacing.h
deleted file mode 100644
index ee9d9e6aac..0000000000
--- a/plugins/flake/textshape/dialogs/ParagraphIndentSpacing.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 PARAGRAPHINDENTSPACING_H
-#define PARAGRAPHINDENTSPACING_H
-
-#include <ui_ParagraphIndentSpacing.h>
-
-#include <QWidget>
-
-class KoParagraphStyle;
-class KoUnit;
-
-class ParagraphIndentSpacing : public QWidget
-{
- Q_OBJECT
-public:
- explicit ParagraphIndentSpacing(QWidget *parent);
- // open and display the style
- void setDisplay(KoParagraphStyle *style);
- void setUnit(const KoUnit &unit);
-
- // save widget state to style
- void save(KoParagraphStyle *style);
-
-Q_SIGNALS:
- void parStyleChanged();
-
-private Q_SLOTS:
- void lineSpacingChanged(int);
- void spacingValueChanged();
- void spacingPercentChanged();
- void useFontMetrices(bool);
- void autoTextIndentChanged(int state);
- void firstIndentValueChanged();
- void leftMarginValueChanged();
- void rightMarginValueChanged();
- void bottomMarginValueChanged();
- void topMarginValueChanged();
- void firstLineMarginChanged(qreal margin);
- void leftMarginChanged(qreal margin);
- void rightMarginChanged(qreal margin);
-
-private:
- Ui::ParagraphIndentSpacing widget;
-
- KoParagraphStyle *m_style;
- bool m_fontMetricsChecked;
- bool m_rightMarginIngerited;
- bool m_leftMarginInherited;
- bool m_topMarginInherited;
- bool m_bottomMarginInherited;
- bool m_textIndentInherited;
- bool m_autoTextIndentInherited;
- bool m_spacingInherited;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/ParagraphIndentSpacing.ui b/plugins/flake/textshape/dialogs/ParagraphIndentSpacing.ui
deleted file mode 100644
index 41268b17fb..0000000000
--- a/plugins/flake/textshape/dialogs/ParagraphIndentSpacing.ui
+++ /dev/null
@@ -1,258 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ParagraphIndentSpacing</class>
- <widget class="QWidget" name="ParagraphIndentSpacing">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>449</width>
- <height>412</height>
- </rect>
- </property>
- <property name="whatsThis">
- <string>&lt;p&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Single&lt;/b&gt;: The normal linespacing&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt; </string>
- </property>
- <layout class="QGridLayout">
- <item row="0" column="0">
- <widget class="QGroupBox" name="groupBox">
- <property name="title">
- <string>Indent</string>
- </property>
- <layout class="QGridLayout" columnstretch="0,0,1">
- <item row="0" column="0">
- <widget class="QLabel">
- <property name="text">
- <string>Left:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>left</cstring>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="KoUnitDoubleSpinBox" name="left"/>
- </item>
- <item row="0" column="2" rowspan="2">
- <spacer>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="0">
- <widget class="QLabel">
- <property name="text">
- <string>Right:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>right</cstring>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="KoUnitDoubleSpinBox" name="right"/>
- </item>
- <item row="2" column="0">
- <widget class="QLabel">
- <property name="text">
- <string>First Line:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>first</cstring>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="KoUnitDoubleSpinBox" name="first"/>
- </item>
- <item row="2" column="2">
- <widget class="QCheckBox" name="autoTextIndent">
- <property name="text">
- <string>Auto-infer from text size</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QGroupBox">
- <property name="whatsThis">
- <string>&lt;p&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Single&lt;/b&gt;: The normal linespacing&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt; </string>
- </property>
- <property name="title">
- <string>Line Spacing</string>
- </property>
- <layout class="QVBoxLayout">
- <item>
- <layout class="QHBoxLayout" stretch="0,0,1">
- <property name="margin">
- <number>0</number>
- </property>
- <item>
- <widget class="QComboBox" name="lineSpacing"/>
- </item>
- <item>
- <widget class="QStackedWidget" name="spacingStack">
- <property name="currentIndex">
- <number>0</number>
- </property>
- <widget class="QWidget" name="unitsPage">
- <layout class="QHBoxLayout">
- <property name="margin">
- <number>0</number>
- </property>
- <item>
- <widget class="KoUnitDoubleSpinBox" name="custom"/>
- </item>
- </layout>
- </widget>
- <widget class="QWidget" name="percentPage">
- <layout class="QHBoxLayout">
- <property name="margin">
- <number>0</number>
- </property>
- <item>
- <widget class="QSpinBox" name="proportional">
- <property name="suffix">
- <string> %</string>
- </property>
- <property name="minimum">
- <number>85</number>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- <property name="singleStep">
- <number>5</number>
- </property>
- <property name="value">
- <number>100</number>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </widget>
- </item>
- <item>
- <spacer>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QFormLayout">
- <property name="fieldGrowthPolicy">
- <enum>QFormLayout::ExpandingFieldsGrow</enum>
- </property>
- <property name="margin">
- <number>0</number>
- </property>
- <item row="0" column="0">
- <widget class="QLabel">
- <property name="text">
- <string>Use Font Metrics:</string>
- </property>
- <property name="buddy">
- <cstring>useFont</cstring>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QCheckBox" name="useFont">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QGroupBox">
- <property name="title">
- <string>Paragraph Space</string>
- </property>
- <layout class="QFormLayout">
- <item row="0" column="0">
- <widget class="QLabel">
- <property name="text">
- <string>Before:</string>
- </property>
- <property name="buddy">
- <cstring>before</cstring>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="KoUnitDoubleSpinBox" name="before"/>
- </item>
- <item row="1" column="0">
- <widget class="QLabel">
- <property name="text">
- <string>After:</string>
- </property>
- <property name="buddy">
- <cstring>after</cstring>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="KoUnitDoubleSpinBox" name="after"/>
- </item>
- </layout>
- </widget>
- </item>
- <item row="3" column="0">
- <spacer>
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>313</width>
- <height>16</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>KoUnitDoubleSpinBox</class>
- <extends>QDoubleSpinBox</extends>
- <header>KoUnitDoubleSpinBox.h</header>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/ParagraphLayout.cpp b/plugins/flake/textshape/dialogs/ParagraphLayout.cpp
deleted file mode 100644
index ddf85f5758..0000000000
--- a/plugins/flake/textshape/dialogs/ParagraphLayout.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2011 Mojtaba Shahi Senobari <mojtaba.shahi3000@gmail.com>
- *
- * 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 "ParagraphLayout.h"
-
-#include <KoParagraphStyle.h>
-
-ParagraphLayout::ParagraphLayout(QWidget *parent)
- : QWidget(parent)
-{
- widget.setupUi(this);
-
- connect(widget.right, SIGNAL(toggled(bool)), this, SLOT(slotAlignChanged()));
- connect(widget.center, SIGNAL(toggled(bool)), this, SLOT(slotAlignChanged()));
- connect(widget.justify, SIGNAL(toggled(bool)), this, SLOT(slotAlignChanged()));
- connect(widget.left, SIGNAL(toggled(bool)), this, SLOT(slotAlignChanged()));
- connect(widget.keepTogether, SIGNAL(stateChanged(int)), this, SLOT(keepTogetherChanged()));
- connect(widget.breakAfter, SIGNAL(stateChanged(int)), this, SLOT(breakAfterChanged()));
- connect(widget.breakBefore, SIGNAL(stateChanged(int)), this, SLOT(breakBeforeChanged()));
- connect(widget.threshold, SIGNAL(valueChanged(int)), this, SLOT(thresholdValueChanged()));
-}
-
-void ParagraphLayout::slotAlignChanged()
-{
- Qt::Alignment align;
- if (widget.right->isChecked()) {
- align = Qt::AlignRight;
- } else if (widget.center->isChecked()) {
- align = Qt::AlignHCenter;
- } else if (widget.justify->isChecked()) {
- align = Qt::AlignJustify;
- } else {
- align = Qt::AlignLeft;
- }
-
- m_alignmentInherited = false;
-
- emit parStyleChanged();
-}
-
-void ParagraphLayout::breakAfterChanged()
-{
- m_breakAfterInherited = false;
- emit parStyleChanged();
-}
-
-void ParagraphLayout::keepTogetherChanged()
-{
- m_keepTogetherInherited = false;
- emit parStyleChanged();
-}
-
-void ParagraphLayout::breakBeforeChanged()
-{
- m_breakBeforeInherited = false;
- emit parStyleChanged();
-}
-
-void ParagraphLayout::thresholdValueChanged()
-{
- m_orphanThresholdInherited = false;
- emit parStyleChanged();
-}
-
-void ParagraphLayout::setDisplay(KoParagraphStyle *style)
-{
- switch (style->alignment()) {
- case Qt::AlignRight: widget.right->setChecked(true); break;
- case Qt::AlignHCenter: widget.center->setChecked(true); break;
- case Qt::AlignJustify: widget.justify->setChecked(true); break;
- case Qt::AlignLeft:
- default:
- widget.left->setChecked(true); break;
- }
-
- m_alignmentInherited = !style->hasProperty(QTextFormat::BlockAlignment);
- m_keepTogetherInherited = !style->hasProperty(QTextFormat::BlockNonBreakableLines);
- m_breakAfterInherited = !style->hasProperty(KoParagraphStyle::BreakAfter);
- m_breakBeforeInherited = !style->hasProperty(KoParagraphStyle::BreakBefore);
- m_orphanThresholdInherited = !style->hasProperty(KoParagraphStyle::OrphanThreshold);
-
- widget.keepTogether->setChecked(style->nonBreakableLines());
- widget.breakBefore->setChecked(style->breakBefore());
- widget.breakAfter->setChecked(style->breakAfter());
-
- widget.threshold->setValue(style->orphanThreshold());
-}
-
-void ParagraphLayout::save(KoParagraphStyle *style)
-{
- if (!m_alignmentInherited) {
- Qt::Alignment align;
- if (widget.right->isChecked()) {
- align = Qt::AlignRight;
- } else if (widget.center->isChecked()) {
- align = Qt::AlignHCenter;
- } else if (widget.justify->isChecked()) {
- align = Qt::AlignJustify;
- } else {
- align = Qt::AlignLeft;
- }
- style->setAlignment(align);
- }
-
- if (!m_keepTogetherInherited) {
- style->setNonBreakableLines(widget.keepTogether->isChecked());
- }
- if (!m_breakBeforeInherited) {
- if (widget.breakBefore->isChecked()) {
- style->setBreakBefore(KoText::PageBreak);
- } else {
- style->setBreakBefore(KoText::NoBreak);
- }
- }
- if (!m_breakAfterInherited) {
- if (widget.breakAfter->isChecked()) {
- style->setBreakAfter(KoText::PageBreak);
- } else {
- style->setBreakAfter(KoText::NoBreak);
- }
- }
-
- if (!m_orphanThresholdInherited) {
- style->setOrphanThreshold(widget.threshold->value());
- }
-}
diff --git a/plugins/flake/textshape/dialogs/ParagraphLayout.h b/plugins/flake/textshape/dialogs/ParagraphLayout.h
deleted file mode 100644
index 4b0f9f9510..0000000000
--- a/plugins/flake/textshape/dialogs/ParagraphLayout.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 PARAGRAPHLAYOUT_H
-#define PARAGRAPHLAYOUT_H
-
-#include <ui_ParagraphLayout.h>
-
-#include <QWidget>
-
-class KoParagraphStyle;
-
-class ParagraphLayout : public QWidget
-{
- Q_OBJECT
-public:
- explicit ParagraphLayout(QWidget *parent);
-
- void setDisplay(KoParagraphStyle *style);
-
- void save(KoParagraphStyle *style);
-
-Q_SIGNALS:
- void parStyleChanged();
-
-private Q_SLOTS:
- void slotAlignChanged();
- void keepTogetherChanged();
- void breakAfterChanged();
- void breakBeforeChanged();
- void thresholdValueChanged();
-
-private:
- Ui::ParagraphLayout widget;
- bool m_alignmentInherited;
- bool m_keepTogetherInherited;
- bool m_breakAfterInherited;
- bool m_breakBeforeInherited;
- bool m_orphanThresholdInherited;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/ParagraphLayout.ui b/plugins/flake/textshape/dialogs/ParagraphLayout.ui
deleted file mode 100644
index b08ee8d877..0000000000
--- a/plugins/flake/textshape/dialogs/ParagraphLayout.ui
+++ /dev/null
@@ -1,125 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ParagraphLayout</class>
- <widget class="QWidget" name="ParagraphLayout">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>400</width>
- <height>376</height>
- </rect>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QGroupBox" name="groupBox">
- <property name="title">
- <string>Alignment</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_3">
- <item row="0" column="0">
- <widget class="QRadioButton" name="left">
- <property name="text">
- <string>Left</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QRadioButton" name="center">
- <property name="text">
- <string>Center</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QRadioButton" name="right">
- <property name="text">
- <string>Right</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QRadioButton" name="justify">
- <property name="text">
- <string>Justify</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="groupBox_2">
- <property name="title">
- <string>Behavior at End of Frame/Page</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="0" column="0">
- <widget class="QCheckBox" name="keepTogether">
- <property name="text">
- <string>Keep lines together</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QCheckBox" name="breakBefore">
- <property name="text">
- <string>Insert break before paragraph</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QCheckBox" name="breakAfter">
- <property name="text">
- <string>Insert break after paragraph</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Leave at least this many lines (orphans):</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QSpinBox" name="threshold"/>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer>
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/ParagraphSettingsDialog.cpp b/plugins/flake/textshape/dialogs/ParagraphSettingsDialog.cpp
deleted file mode 100644
index 7b96ead2d5..0000000000
--- a/plugins/flake/textshape/dialogs/ParagraphSettingsDialog.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007, 2010 Thomas Zander <zander@kde.org>
- *
- * 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 "ParagraphSettingsDialog.h"
-
-#include "ParagraphGeneral.h"
-#include "../TextTool.h"
-
-#include <KoParagraphStyle.h>
-#include <KoTextDocument.h>
-#include <KoList.h>
-#include <KoTextEditor.h>
-#include <KoListLevelProperties.h>
-#include <commands/ParagraphFormattingCommand.h>
-
-#include <QTextBlock>
-#include <QTimer>
-
-ParagraphSettingsDialog::ParagraphSettingsDialog(TextTool *tool, KoTextEditor *editor, QWidget *parent)
- : KoDialog(parent)
- , m_tool(tool)
- , m_editor(editor)
- , m_styleChanged(false)
-{
- setCaption(i18n("Paragraph Format"));
- setModal(true);
- setButtons(Ok | Cancel | Apply);
- setDefaultButton(Ok);
-
- m_paragraphGeneral = new ParagraphGeneral;
- m_paragraphGeneral->hideStyleName(true);
- setMainWidget(m_paragraphGeneral);
-
- connect(this, SIGNAL(applyClicked()), this, SLOT(slotApply()));
- connect(this, SIGNAL(okClicked()), this, SLOT(slotOk()));
- initTabs();
-
- // Do this after initTabs so it doesn't cause signals prematurely
- connect(m_paragraphGeneral, SIGNAL(styleChanged()), this, SLOT(styleChanged()));
-}
-
-ParagraphSettingsDialog::~ParagraphSettingsDialog()
-{
-}
-
-void ParagraphSettingsDialog::initTabs()
-{
- KoParagraphStyle *style = KoParagraphStyle::fromBlock(m_editor->block());
- m_paragraphGeneral->setStyle(style, KoList::level(m_editor->block()));
-}
-
-void ParagraphSettingsDialog::styleChanged(bool state)
-{
- m_styleChanged = state;
-}
-
-void ParagraphSettingsDialog::slotOk()
-{
- slotApply();
- KoDialog::accept();
-}
-
-void ParagraphSettingsDialog::slotApply()
-{
- if (!m_styleChanged) {
- return;
- }
-
- KoParagraphStyle chosenStyle;
- m_paragraphGeneral->save(&chosenStyle);
-
- QTextCharFormat cformat;
- QTextBlockFormat format;
- chosenStyle.KoCharacterStyle::applyStyle(cformat);
- chosenStyle.applyStyle(format);
-
- KoListLevelProperties llp;
- if (chosenStyle.listStyle()) {
- llp = chosenStyle.listStyle()->levelProperties(chosenStyle.listStyle()->listLevels().first());
- } else {
- llp.setStyle(KoListStyle::None);
- }
-
- m_editor->applyDirectFormatting(cformat, format, llp);
-
- m_styleChanged = false;
-}
-
-void ParagraphSettingsDialog::setUnit(const KoUnit &unit)
-{
- m_paragraphGeneral->setUnit(unit);
-}
-
-void ParagraphSettingsDialog::setImageCollection(KoImageCollection *imageCollection)
-{
- m_paragraphGeneral->setImageCollection(imageCollection);
-}
diff --git a/plugins/flake/textshape/dialogs/ParagraphSettingsDialog.h b/plugins/flake/textshape/dialogs/ParagraphSettingsDialog.h
deleted file mode 100644
index 5b84b534f3..0000000000
--- a/plugins/flake/textshape/dialogs/ParagraphSettingsDialog.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 PARAGRAPHSETTINGSDIALOG_H
-#define PARAGRAPHSETTINGSDIALOG_H
-
-#include <KoTextEditor.h>
-
-#include <KoDialog.h>
-
-class TextTool;
-class ParagraphGeneral;
-class KoImageCollection;
-
-class KoUnit;
-
-/// A dialog to show the settings for a paragraph
-class ParagraphSettingsDialog : public KoDialog
-{
- Q_OBJECT
-public:
- explicit ParagraphSettingsDialog(TextTool *tool, KoTextEditor *editor, QWidget *parent = 0);
- ~ParagraphSettingsDialog() override;
-
- void setUnit(const KoUnit &unit);
-
- void setImageCollection(KoImageCollection *imageCollection);
-
-protected Q_SLOTS:
- void styleChanged(bool state = true);
-
- void slotApply();
- void slotOk();
-
-private:
- void initTabs();
-
- ParagraphGeneral *m_paragraphGeneral;
- TextTool *m_tool;
- KoTextEditor *m_editor;
- bool m_uniqueFormat;
- bool m_styleChanged;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/QuickTableButton.cpp b/plugins/flake/textshape/dialogs/QuickTableButton.cpp
deleted file mode 100644
index 41e5c843c4..0000000000
--- a/plugins/flake/textshape/dialogs/QuickTableButton.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2010 C. Boemann <cbo@boemann.dk>
- *
- * 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 "QuickTableButton.h"
-
-#include <KoIcon.h>
-#include <klocalizedstring.h>
-#include <QDebug>
-
-#include <QMenu>
-#include <QFrame>
-#include <QGridLayout>
-#include <QPainter>
-#include <QMouseEvent>
-#include <QWidgetAction>
-
-//This class is the main place where the expanding grid is done
-class SizeChooserGrid : public QFrame
-{
-public:
- SizeChooserGrid(QuickTableButton *button, QAction *action);
- QSize sizeHint() const override;
- void mouseMoveEvent(QMouseEvent *ev) override;
- void enterEvent(QEvent *ev) override;
- void leaveEvent(QEvent *ev) override;
- void mouseReleaseEvent(QMouseEvent *ev) override;
- void paintEvent(QPaintEvent *event) override;
-private:
- int m_column;
- int m_row;
- qreal m_columnWidth;
- qreal m_rowHeight;
- int m_leftMargin;
- int m_topMargin;
- int m_extraWidth;
- int m_extraHeight;
- QuickTableButton *m_button;
- QAction *m_action;
-};
-
-SizeChooserGrid::SizeChooserGrid(QuickTableButton *button, QAction *action)
- : QFrame()
- , m_column(0)
- , m_row(0)
- , m_columnWidth(30)
- , m_button(button)
- , m_action(action)
-{
- setFrameShadow(Sunken);
- setBackgroundRole(QPalette::Base);
- setFrameShape(StyledPanel);
- setMouseTracking(true);
-
- QFontMetrics metrics(font());
- m_rowHeight = metrics.height() + 2;
- m_columnWidth = metrics.width("8x22") + 2;
-
- getContentsMargins(&m_leftMargin, &m_topMargin, &m_extraWidth, &m_extraHeight);
- m_leftMargin += 4;
- m_topMargin += 4;
- m_extraWidth += m_leftMargin + 4 + 1;
- m_extraHeight += m_topMargin + 4 + 1;
-}
-
-QSize SizeChooserGrid::sizeHint() const
-{
- return QSize(m_extraWidth + 8 * m_columnWidth, m_extraHeight + 8 * m_rowHeight);
-}
-
-void SizeChooserGrid::mouseMoveEvent(QMouseEvent *ev)
-{
- m_column = qMin(qreal(7.0), (ev->x() - m_leftMargin) / m_columnWidth);
- m_row = qMin(qreal(7.0), (ev->y() - m_topMargin) / m_rowHeight);
- repaint();
-}
-
-void SizeChooserGrid::enterEvent(QEvent *event)
-{
- m_action->activate(QAction::Hover);
- QFrame::enterEvent(event);
-}
-
-void SizeChooserGrid::leaveEvent(QEvent *)
-{
- m_column = -1;
- m_row = -1;
- repaint();
-}
-
-void SizeChooserGrid::mouseReleaseEvent(QMouseEvent *ev)
-{
- if (contentsRect().contains(ev->pos())) {
- m_button->emitCreate(m_row + 1, m_column + 1);
- }
- QFrame::mouseReleaseEvent(ev);
-}
-
-void SizeChooserGrid::paintEvent(QPaintEvent *event)
-{
- QFrame::paintEvent(event);
-
- QPainter painter(this);
- painter.setRenderHint(QPainter::Antialiasing);
- painter.fillRect(contentsRect(), palette().brush(QPalette::Base));
- painter.translate(m_leftMargin, m_topMargin);
- painter.translate(0.5, 0.5);
- QPen pen = painter.pen();
- pen.setWidthF(0.5);
- painter.setPen(pen);
- painter.fillRect(QRectF(0.0, 0.0, (m_column + 1) * m_columnWidth, (m_row + 1) * m_rowHeight), palette().brush(QPalette::Highlight));
- for (int c = 0; c <= 8; c++) {
- painter.drawLine(QPointF(c * m_columnWidth, 0.0), QPointF(c * m_columnWidth, 8 * m_rowHeight));
- }
- for (int r = 0; r <= 8; r++) {
- painter.drawLine(QPointF(0.0, r * m_rowHeight), QPointF(8 * m_columnWidth, r * m_rowHeight));
- }
- QTextOption option(Qt::AlignCenter);
- option.setUseDesignMetrics(true);
- painter.drawText(QRectF(0.0, 0.0, m_columnWidth, m_rowHeight), QString("%1x%2").arg(m_column + 1).arg(m_row + 1), option);
- painter.end();
-}
-
-//This class is the main place where the expanding grid is done
-class SizeChooserAction : public QWidgetAction
-{
-public:
- SizeChooserAction(QuickTableButton *button);
- SizeChooserGrid *m_widget;
-};
-
-SizeChooserAction::SizeChooserAction(QuickTableButton *button)
- : QWidgetAction(0)
-{
- m_widget = new SizeChooserGrid(button, this);
- setDefaultWidget(m_widget);
-}
-
-//And now for the button itself
-QuickTableButton::QuickTableButton(QWidget *parent)
- : QToolButton(parent)
-{
- setToolTip(i18n("Insert a table"));
- setToolButtonStyle(Qt::ToolButtonIconOnly);
- setIcon(koIcon("insert-table"));
- setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
-
- m_menu = new QMenu(this);
- setMenu(m_menu);
- setPopupMode(InstantPopup);
-}
-
-void QuickTableButton::addAction(QAction *action)
-{
- m_menu->addAction(action);
- m_menu->addAction(new SizeChooserAction(this));
-}
-
-void QuickTableButton::emitCreate(int rows, int columns)
-{
- m_menu->hide();
- emit create(rows, columns);
-}
diff --git a/plugins/flake/textshape/dialogs/QuickTableButton.h b/plugins/flake/textshape/dialogs/QuickTableButton.h
deleted file mode 100644
index 08415ae95b..0000000000
--- a/plugins/flake/textshape/dialogs/QuickTableButton.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2010 C. Boemann <cbo@boemann.dk>
- *
- * 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 TABLECREATEBUTTON_H
-#define TABLECREATEBUTTON_H
-
-#include <QToolButton>
-
-class QMenu;
-
-class QuickTableButton : public QToolButton
-{
- Q_OBJECT
-public:
- explicit QuickTableButton(QWidget *parent = 0);
- void emitCreate(int rows, int columns);
- void addAction(QAction *action);
-
-Q_SIGNALS:
- void create(int rows, int columns);
-
-private:
- QMenu *m_menu;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/SectionFormatDialog.cpp b/plugins/flake/textshape/dialogs/SectionFormatDialog.cpp
deleted file mode 100644
index d1315f293d..0000000000
--- a/plugins/flake/textshape/dialogs/SectionFormatDialog.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2014-2015 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 "SectionFormatDialog.h"
-
-#include <KoTextDocument.h>
-#include <KoSectionModel.h>
-#include <KoSection.h>
-#include <KoTextEditor.h>
-
-#include <QIdentityProxyModel>
-#include <QToolTip>
-#include <kcolorscheme.h>
-#include <klocalizedstring.h>
-
-class SectionFormatDialog::ProxyModel : public QIdentityProxyModel
-{
-public:
- ProxyModel(KoSectionModel *model, QObject *parent = 0)
- : QIdentityProxyModel(parent)
- {
- setSourceModel(model);
- }
-
- int columnCount(const QModelIndex &parent = QModelIndex()) const override
- {
- Q_UNUSED(parent);
- return 1; // We have one column with "Name of section"
- }
-
- QVariant headerData(int section, Qt::Orientation orientation, int role) const override
- {
- if (orientation != Qt::Horizontal || section != 0) {
- return QVariant();
- }
-
- if (role == Qt::DisplayRole) {
- return i18n("Section name");
- }
- return QVariant();
- }
-
- QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const override
- {
- if (!proxyIndex.isValid() || proxyIndex.column() != 0) {
- return QVariant();
- }
-
- if (role == Qt::DisplayRole) {
- KoSection *ptr = getSectionByIndex(proxyIndex);
- return ptr->name();
- }
- return QVariant();
- }
-
- KoSection *getSectionByIndex(const QModelIndex &idx) const
- {
- return sourceModel()->data(
- mapToSource(idx),
- KoSectionModel::PointerRole
- ).value<KoSection *>();
- }
-
-private:
- // Make it private. It is intended to be used only with KoSectionModel that is passed through constructor
- void setSourceModel(QAbstractItemModel *sourceModel) override
- {
- QAbstractProxyModel::setSourceModel(sourceModel);
- }
-};
-
-class SectionFormatDialog::SectionNameValidator : public QValidator
-{
-public:
- SectionNameValidator(QObject *parent, KoSectionModel *sectionManager, KoSection *section)
- : QValidator(parent)
- , m_sectionModel(sectionManager)
- , m_section(section)
- {
- }
-
- State validate(QString &input, int &pos) const override
- {
- Q_UNUSED(pos);
- if (m_section->name() == input || m_sectionModel->isValidNewName(input)) {
- return QValidator::Acceptable;
- }
- return QValidator::Intermediate;
- }
-
-private:
- KoSectionModel *m_sectionModel;
- KoSection *m_section;
-};
-
-SectionFormatDialog::SectionFormatDialog(QWidget *parent, KoTextEditor *editor)
- : KoDialog(parent)
- , m_editor(editor)
-{
- setCaption(i18n("Configure sections"));
- setButtons(KoDialog::Ok | KoDialog::Cancel);
- showButtonSeparator(true);
- QWidget *form = new QWidget;
- m_widget.setupUi(form);
- setMainWidget(form);
-
- m_sectionModel = KoTextDocument(editor->document()).sectionModel();
- m_widget.sectionTree->setModel(new ProxyModel(m_sectionModel, this));
- m_widget.sectionTree->expandAll();
-
- m_widget.sectionNameLineEdit->setEnabled(false);
-
- connect(m_widget.sectionTree, SIGNAL(activated(QModelIndex)), this, SLOT(sectionSelected(QModelIndex)));
- connect(m_widget.sectionNameLineEdit, SIGNAL(editingFinished()), this, SLOT(sectionNameChanged()));
- connect(m_widget.sectionNameLineEdit, SIGNAL(textEdited(QString)), this, SLOT(updateTreeState()));
-
- m_curIdx = m_widget.sectionTree->currentIndex();
-}
-
-void SectionFormatDialog::sectionNameChanged()
-{
- m_editor->renameSection(sectionFromModel(m_curIdx), m_widget.sectionNameLineEdit->text());
- m_widget.sectionNameLineEdit->setModified(false); // value is set to line edit isn't modified (has new default value)
-}
-
-void SectionFormatDialog::sectionSelected(const QModelIndex &idx)
-{
- KoSection *curSection = sectionFromModel(idx);
- m_curIdx = m_widget.sectionTree->currentIndex();
-
- // Update widgets
- m_widget.sectionNameLineEdit->setEnabled(true);
- m_widget.sectionNameLineEdit->setText(curSection->name());
- m_widget.sectionNameLineEdit->setValidator(
- new SectionNameValidator(this, m_sectionModel, curSection));
-}
-
-void SectionFormatDialog::updateTreeState()
-{
- if (!m_curIdx.isValid()) {
- return;
- }
-
- bool allOk = true;
- QPalette pal = m_widget.sectionNameLineEdit->palette();
- if (!m_widget.sectionNameLineEdit->hasAcceptableInput()) {
- KColorScheme::adjustBackground(pal, KColorScheme::NegativeBackground);
- m_widget.sectionNameLineEdit->setPalette(pal);
-
- QToolTip::showText(m_widget.sectionNameLineEdit->mapToGlobal(QPoint()),
- i18n("Invalid characters or section with such name exists."));
-
- allOk = false;
- } else {
- KColorScheme::adjustBackground(pal, KColorScheme::NormalBackground);
- m_widget.sectionNameLineEdit->setPalette(pal);
- }
-
- m_widget.sectionTree->setEnabled(allOk);
- enableButtonOk(allOk);
-}
-
-inline KoSection *SectionFormatDialog::sectionFromModel(const QModelIndex &idx)
-{
- return dynamic_cast<ProxyModel *>(m_widget.sectionTree->model())->getSectionByIndex(idx);
-}
diff --git a/plugins/flake/textshape/dialogs/SectionFormatDialog.h b/plugins/flake/textshape/dialogs/SectionFormatDialog.h
deleted file mode 100644
index 6dc1fe5d24..0000000000
--- a/plugins/flake/textshape/dialogs/SectionFormatDialog.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2014-2015 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 SECTIONFORMATDIALOG_H
-#define SECTIONFORMATDIALOG_H
-
-#include <KoDialog.h>
-
-class KoTextEditor;
-class KoSection;
-class KoSectionModel;
-
-#include <ui_SectionFormatDialog.h>
-class SectionFormatDialog : public KoDialog
-{
- Q_OBJECT
-
-public:
- explicit SectionFormatDialog(QWidget *parent, KoTextEditor *editor);
-
-private Q_SLOTS:
- void sectionSelected(const QModelIndex &idx);
- void sectionNameChanged();
- void updateTreeState();
-
-private:
- class ProxyModel;
- class SectionNameValidator;
-
- Ui::SectionFormatDialog m_widget;
- KoTextEditor *m_editor;
- QModelIndex m_curIdx;
- KoSectionModel *m_sectionModel;
-
- KoSection *sectionFromModel(const QModelIndex &idx);
-};
-
-#endif //SECTIONFORMATDIALOG_H
diff --git a/plugins/flake/textshape/dialogs/SectionFormatDialog.ui b/plugins/flake/textshape/dialogs/SectionFormatDialog.ui
deleted file mode 100644
index 6502554b75..0000000000
--- a/plugins/flake/textshape/dialogs/SectionFormatDialog.ui
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>SectionFormatDialog</class>
- <widget class="QWidget" name="SectionFormatDialog">
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QTreeView" name="sectionTree">
- <property name="editTriggers">
- <set>QAbstractItemView::NoEditTriggers</set>
- </property>
- <property name="uniformRowHeights">
- <bool>true</bool>
- </property>
- <property name="itemsExpandable">
- <bool>false</bool>
- </property>
- <attribute name="headerVisible">
- <bool>false</bool>
- </attribute>
- </widget>
- </item>
- <item>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Section name:</string>
- </property>
- <property name="buddy">
- <cstring>sectionNameLineEdit</cstring>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLineEdit" name="sectionNameLineEdit">
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>QLineEdit</class>
- <extends>QLineEdit</extends>
- <header>klineedit.h</header>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/SectionsSplitDialog.cpp b/plugins/flake/textshape/dialogs/SectionsSplitDialog.cpp
deleted file mode 100644
index a3c91e5740..0000000000
--- a/plugins/flake/textshape/dialogs/SectionsSplitDialog.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2015 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 "SectionsSplitDialog.h"
-
-#include <KoTextDocument.h>
-#include <KoSection.h>
-#include <KoTextEditor.h>
-#include <KoSectionUtils.h>
-
-#include <klocalizedstring.h>
-
-SectionsSplitDialog::SectionsSplitDialog(QWidget *parent, KoTextEditor *editor)
- : KoDialog(parent)
- , m_editor(editor)
-{
- setCaption(i18n("Configure sections"));
- setButtons(KoDialog::Ok | KoDialog::Cancel);
- enableButton(KoDialog::Ok, false);
- showButtonSeparator(true);
- QWidget *form = new QWidget;
- m_widget.setupUi(form);
- setMainWidget(form);
-
- QList<KoSection *> secStartings = KoSectionUtils::sectionStartings(editor->blockFormat());
- QList<KoSectionEnd *> secEndings = KoSectionUtils::sectionEndings(editor->blockFormat());
- foreach (KoSection *sec, secStartings) {
- m_widget.beforeList->addItem(sec->name());
- }
- foreach (KoSectionEnd *secEnd, secEndings) {
- m_widget.afterList->addItem(secEnd->name());
- }
-
- connect(m_widget.beforeList, SIGNAL(itemSelectionChanged()), this, SLOT(beforeListSelection()));
- connect(m_widget.afterList, SIGNAL(itemSelectionChanged()), this, SLOT(afterListSelection()));
-
- connect(this, SIGNAL(okClicked()), this, SLOT(okClicked()));
-}
-
-void SectionsSplitDialog::afterListSelection()
-{
- if (m_widget.afterList->selectedItems().size()) { // FIXME: more elegant way to check selection?
- enableButton(KoDialog::Ok, true);
- m_widget.beforeList->clearSelection();
- }
-}
-
-void SectionsSplitDialog::beforeListSelection()
-{
- if (m_widget.beforeList->selectedItems().size()) {
- enableButton(KoDialog::Ok, true);
- m_widget.afterList->clearSelection();
- }
-}
-
-void SectionsSplitDialog::okClicked()
-{
- if (m_widget.beforeList->selectedItems().size()) {
- m_editor->splitSectionsStartings(m_widget.beforeList->currentRow());
- } else {
- m_editor->splitSectionsEndings(m_widget.afterList->currentRow());
- }
-}
diff --git a/plugins/flake/textshape/dialogs/SectionsSplitDialog.h b/plugins/flake/textshape/dialogs/SectionsSplitDialog.h
deleted file mode 100644
index 49da8ff480..0000000000
--- a/plugins/flake/textshape/dialogs/SectionsSplitDialog.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2015 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 SECTIONSSPLITDIALOG_H
-#define SECTIONSSPLITDIALOG_H
-
-#include <KoDialog.h>
-
-class KoTextEditor;
-class KoSection;
-class KoSectionModel;
-
-#include <ui_SectionsSplitDialog.h>
-class SectionsSplitDialog : public KoDialog
-{
- Q_OBJECT
-
-public:
- explicit SectionsSplitDialog(QWidget *parent, KoTextEditor *editor);
-
-private Q_SLOTS:
- void beforeListSelection();
- void afterListSelection();
-
- void okClicked();
-
-private:
- Ui::SectionsSplitDialog m_widget;
- KoTextEditor *m_editor;
-};
-
-#endif //SECTIONSSPLITDIALOG_H
diff --git a/plugins/flake/textshape/dialogs/SectionsSplitDialog.ui b/plugins/flake/textshape/dialogs/SectionsSplitDialog.ui
deleted file mode 100644
index 36d2acd8fb..0000000000
--- a/plugins/flake/textshape/dialogs/SectionsSplitDialog.ui
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>SectionsSplitDialog</class>
- <widget class="QWidget" name="SectionsSplitDialog">
- <property name="windowTitle">
- <string>Split sections</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Insert paragraph...</string>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <item>
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>before start of section:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QListWidget" name="beforeList"/>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QVBoxLayout" name="verticalLayout_3">
- <item>
- <widget class="QLabel" name="label_3">
- <property name="text">
- <string>after end of section:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QListWidget" name="afterList"/>
- </item>
- </layout>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/SelectBookmarkDialog.h b/plugins/flake/textshape/dialogs/SelectBookmarkDialog.h
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/plugins/flake/textshape/dialogs/SimpleCharacterWidget.cpp b/plugins/flake/textshape/dialogs/SimpleCharacterWidget.cpp
deleted file mode 100644
index d1e3285a48..0000000000
--- a/plugins/flake/textshape/dialogs/SimpleCharacterWidget.cpp
+++ /dev/null
@@ -1,266 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007, 2008, 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2009-2010 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2011-2012 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- *
- * 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 "SimpleCharacterWidget.h"
-#include "TextTool.h"
-#include "../commands/ChangeListCommand.h"
-#include "StylesModel.h"
-#include "DockerStylesComboModel.h"
-#include "StylesDelegate.h"
-#include <KoStyleThumbnailer.h>
-
-#include <QAction>
-#include <kselectaction.h>
-#include <KoTextBlockData.h>
-#include <KoCharacterStyle.h>
-#include <KoParagraphStyle.h>
-#include <KoInlineTextObjectManager.h>
-#include <KoTextDocumentLayout.h>
-#include <KoZoomHandler.h>
-#include <KoStyleManager.h>
-
-#include <QDebug>
-
-#include <QTextLayout>
-#include <QComboBox>
-
-SimpleCharacterWidget::SimpleCharacterWidget(TextTool *tool, QWidget *parent)
- : QWidget(parent)
- , m_styleManager(0)
- , m_blockSignals(false)
- , m_comboboxHasBidiItems(false)
- , m_tool(tool)
- , m_thumbnailer(new KoStyleThumbnailer())
- , m_stylesModel(new StylesModel(0, StylesModel::CharacterStyle))
- , m_sortedStylesModel(new DockerStylesComboModel())
- , m_stylesDelegate(0)
-{
- widget.setupUi(this);
- widget.bold->setDefaultAction(tool->action("format_bold"));
- widget.italic->setDefaultAction(tool->action("format_italic"));
- widget.strikeOut->setDefaultAction(tool->action("format_strike"));
- widget.underline->setDefaultAction(tool->action("format_underline"));
- widget.textColor->setDefaultAction(tool->action("format_textcolor"));
- widget.backgroundColor->setDefaultAction(tool->action("format_backgroundcolor"));
- widget.superscript->setDefaultAction(tool->action("format_super"));
- widget.subscript->setDefaultAction(tool->action("format_sub"));
- widget.moreOptions->setText("...");
- widget.moreOptions->setToolTip(i18n("Change font format"));
- connect(widget.moreOptions, SIGNAL(clicked(bool)), tool->action("format_font"), SLOT(trigger()));
-
- connect(widget.bold, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.italic, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.strikeOut, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.underline, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.textColor, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.backgroundColor, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.superscript, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.subscript, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
-
- QWidgetAction *fontFamilyAction = qobject_cast<QWidgetAction *>(tool->action("format_fontfamily"));
- QComboBox *family = fontFamilyAction ? qobject_cast<QComboBox *> (fontFamilyAction->requestWidget(this)) : 0;
- if (family) { // kdelibs 4.1 didn't return anything here.
- widget.fontsFrame->addWidget(family, 0, 0);
- connect(family, SIGNAL(activated(int)), this, SIGNAL(doneWithFocus()));
- connect(family, SIGNAL(activated(int)), this, SLOT(fontFamilyActivated(int)));
- }
- QWidgetAction *fontSizeAction = qobject_cast<QWidgetAction *>(tool->action("format_fontsize"));
- QComboBox *size = fontSizeAction ? qobject_cast<QComboBox *> (fontSizeAction->requestWidget(this)) : 0;
- if (size) { // kdelibs 4.1 didn't return anything here.
- widget.fontsFrame->addWidget(size, 0, 1);
- connect(size, SIGNAL(activated(int)), this, SIGNAL(doneWithFocus()));
- connect(size, SIGNAL(activated(int)), this, SLOT(fontSizeActivated(int)));
- QDoubleValidator *validator = new QDoubleValidator(2, 999, 1, size);
- size->setValidator(validator);
- }
-
- widget.fontsFrame->setColumnStretch(0, 1);
-
- m_stylesModel->setStyleThumbnailer(m_thumbnailer);
- widget.characterStyleCombo->setStylesModel(m_sortedStylesModel);
- connect(widget.characterStyleCombo, SIGNAL(selected(QModelIndex)), this, SLOT(styleSelected(QModelIndex)));
- connect(widget.characterStyleCombo, SIGNAL(newStyleRequested(QString)), this, SIGNAL(newStyleRequested(QString)));
- connect(widget.characterStyleCombo, SIGNAL(newStyleRequested(QString)), this, SIGNAL(doneWithFocus()));
- connect(widget.characterStyleCombo, SIGNAL(showStyleManager(int)), this, SLOT(slotShowStyleManager(int)));
-
- m_sortedStylesModel->setStylesModel(m_stylesModel);
-}
-
-SimpleCharacterWidget::~SimpleCharacterWidget()
-{
- //the model is set on the comboBox which takes ownership
- delete m_thumbnailer;
-}
-
-void SimpleCharacterWidget::setStyleManager(KoStyleManager *sm)
-{
- Q_ASSERT(sm);
- if (!sm || m_styleManager == sm) {
- return;
- }
- if (m_styleManager) {
- disconnect(m_styleManager, SIGNAL(styleApplied(const KoCharacterStyle*)), this, SLOT(slotParagraphStyleApplied(const KoCharacterStyle*)));
- }
- m_styleManager = sm;
- //we want to disconnect this before setting the stylemanager. Populating the model apparently selects the first inserted item. We don't want this to actually set a new style.
- disconnect(widget.characterStyleCombo, SIGNAL(selected(QModelIndex)), this, SLOT(styleSelected(QModelIndex)));
- m_stylesModel->setStyleManager(sm);
- m_sortedStylesModel->setStyleManager(sm);
- connect(widget.characterStyleCombo, SIGNAL(selected(QModelIndex)), this, SLOT(styleSelected(QModelIndex)));
- connect(m_styleManager, SIGNAL(styleApplied(const KoCharacterStyle*)), this, SLOT(slotCharacterStyleApplied(const KoCharacterStyle*)));
-}
-
-void SimpleCharacterWidget::setInitialUsedStyles(QVector<int> list)
-{
- m_sortedStylesModel->setInitialUsedStyles(list);
-}
-
-void SimpleCharacterWidget::setCurrentFormat(const QTextCharFormat &format, const QTextCharFormat &refBlockCharFormat)
-{
- if (!m_styleManager || format == m_currentCharFormat) {
- return;
- }
- m_currentCharFormat = format;
-
- KoCharacterStyle *style(m_styleManager->characterStyle(m_currentCharFormat.intProperty(KoCharacterStyle::StyleId)));
- bool useParagraphStyle = false;
- if (!style) {
- style = static_cast<KoCharacterStyle *>(m_styleManager->paragraphStyle(m_currentCharFormat.intProperty(KoParagraphStyle::StyleId)));
- useParagraphStyle = true;
- }
- if (style) {
- bool unchanged = true;
- QTextCharFormat comparisonFormat = refBlockCharFormat;
- style->applyStyle(comparisonFormat);
- //Here we are making quite a few assumptions:
- //i. we can set the "ensured" properties on a blank charFormat. These corresponds to Qt default. We are not creating false positive (ie. different styles showing as identical).
- //ii. a property whose toBool returns as false is identical to an unset property (this is done through the clearUnsetProperties method)
- style->ensureMinimalProperties(comparisonFormat);
- style->ensureMinimalProperties(m_currentCharFormat);
- clearUnsetProperties(comparisonFormat);
- clearUnsetProperties(m_currentCharFormat);
- if (m_currentCharFormat.properties().count() != comparisonFormat.properties().count()) {
- unchanged = false;
- } else {
- Q_FOREACH (int property, m_currentCharFormat.properties().keys()) {
- if (m_currentCharFormat.property(property) != comparisonFormat.property(property)) {
- unchanged = false;
- }
- }
- }
- disconnect(widget.characterStyleCombo, SIGNAL(selected(QModelIndex)), this, SLOT(styleSelected(QModelIndex)));
- //TODO, this is very brittle index 1 is because index 0 is the title. The proper solution to that would be for the "None" style to have a styleId which does not get applied on the text, but can be used in the ui
- widget.characterStyleCombo->setCurrentIndex((useParagraphStyle) ? 1 : m_sortedStylesModel->indexOf(style).row());
- widget.characterStyleCombo->setStyleIsOriginal(unchanged);
- widget.characterStyleCombo->slotUpdatePreview();
- connect(widget.characterStyleCombo, SIGNAL(selected(QModelIndex)), this, SLOT(styleSelected(QModelIndex)));
- }
-}
-
-void SimpleCharacterWidget::clearUnsetProperties(QTextFormat &format)
-{
- Q_FOREACH (int property, format.properties().keys()) {
- if (!format.property(property).toBool()) {
- format.clearProperty(property);
- }
- }
-}
-
-void SimpleCharacterWidget::fontFamilyActivated(int index)
-{
- /**
- * Hack:
- *
- * Selecting a font that is already selected in the combobox
- * will not trigger the action, so we help it on the way by
- * manually triggering it here if that happens.
- */
- if (index == m_lastFontFamilyIndex) {
- KSelectAction *action = qobject_cast<KSelectAction *>(m_tool->action("format_fontfamily"));
- if (action->currentAction()) {
- action->currentAction()->trigger();
- }
- }
- m_lastFontFamilyIndex = index;
-}
-
-void SimpleCharacterWidget::fontSizeActivated(int index)
-{
- /**
- * Hack:
- *
- * Selecting a font size that is already selected in the
- * combobox will not trigger the action, so we help it on
- * the way by manually triggering it here if that happens.
- */
- if (index == m_lastFontSizeIndex) {
- KSelectAction *action = qobject_cast<KSelectAction *>(m_tool->action("format_fontsize"));
- action->currentAction()->trigger();
- }
- m_lastFontSizeIndex = index;
-}
-
-void SimpleCharacterWidget::setCurrentBlockFormat(const QTextBlockFormat &format)
-{
- if (format == m_currentBlockFormat) {
- return;
- }
- m_currentBlockFormat = format;
-
- m_stylesModel->setCurrentParagraphStyle(format.intProperty(KoParagraphStyle::StyleId));
- disconnect(widget.characterStyleCombo, SIGNAL(selected(QModelIndex)), this, SLOT(styleSelected(QModelIndex)));
- widget.characterStyleCombo->slotUpdatePreview();
- connect(widget.characterStyleCombo, SIGNAL(selected(QModelIndex)), this, SLOT(styleSelected(QModelIndex)));
-}
-
-void SimpleCharacterWidget::styleSelected(int index)
-{
- KoCharacterStyle *charStyle = m_styleManager->characterStyle(m_sortedStylesModel->index(index, 0, QModelIndex()).internalId());
-
- //if the selected item correspond to a null characterStyle, send the null pointer. the tool should set the characterStyle as per paragraph
- emit characterStyleSelected(charStyle);
- emit doneWithFocus();
-}
-
-void SimpleCharacterWidget::styleSelected(const QModelIndex &index)
-{
- if (!index.isValid()) {
- emit doneWithFocus();
- return;
- }
- KoCharacterStyle *charStyle = m_styleManager->characterStyle(index.internalId());
-
- //if the selected item correspond to a null characterStyle, send the null pointer. the tool should set the characterStyle as per paragraph
- emit characterStyleSelected(charStyle);
- emit doneWithFocus();
-}
-
-void SimpleCharacterWidget::slotShowStyleManager(int index)
-{
- int styleId = m_sortedStylesModel->index(index, 0, QModelIndex()).internalId();
- emit showStyleManager(styleId);
- emit doneWithFocus();
-}
-
-void SimpleCharacterWidget::slotCharacterStyleApplied(const KoCharacterStyle *style)
-{
- m_sortedStylesModel->styleApplied(style);
-}
diff --git a/plugins/flake/textshape/dialogs/SimpleCharacterWidget.h b/plugins/flake/textshape/dialogs/SimpleCharacterWidget.h
deleted file mode 100644
index 3f19adb10c..0000000000
--- a/plugins/flake/textshape/dialogs/SimpleCharacterWidget.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2010 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2011-2012 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- *
- * 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 SIMPLECHARACTERWIDGET_H
-#define SIMPLECHARACTERWIDGET_H
-
-#include <ui_SimpleCharacterWidget.h>
-#include <KoListStyle.h>
-
-#include <QWidget>
-#include <QTextBlock>
-
-class TextTool;
-class KoStyleManager;
-class KoCharacterStyle;
-class KoStyleThumbnailer;
-class DockerStylesComboModel;
-class StylesDelegate;
-class StylesModel;
-
-class SimpleCharacterWidget : public QWidget
-{
- Q_OBJECT
-public:
- explicit SimpleCharacterWidget(TextTool *tool, QWidget *parent = 0);
- ~SimpleCharacterWidget() override;
-
- void setInitialUsedStyles(QVector<int> list);
-
-public Q_SLOTS:
- void setStyleManager(KoStyleManager *sm);
- void setCurrentFormat(const QTextCharFormat &format, const QTextCharFormat &refBlockCharFormat);
- void setCurrentBlockFormat(const QTextBlockFormat &format);
- void slotCharacterStyleApplied(const KoCharacterStyle *style);
-
-private Q_SLOTS:
- void fontFamilyActivated(int index);
- void fontSizeActivated(int index);
- void styleSelected(int index);
- void styleSelected(const QModelIndex &index);
- void slotShowStyleManager(int index);
-
-Q_SIGNALS:
- void doneWithFocus();
- void characterStyleSelected(KoCharacterStyle *);
- void newStyleRequested(const QString &name);
- void showStyleManager(int styleId);
-
-private:
- void clearUnsetProperties(QTextFormat &format);
-
- Ui::SimpleCharacterWidget widget;
- KoStyleManager *m_styleManager;
- bool m_blockSignals;
- bool m_comboboxHasBidiItems;
- int m_lastFontFamilyIndex;
- int m_lastFontSizeIndex;
- TextTool *m_tool;
- QTextCharFormat m_currentCharFormat;
- QTextBlockFormat m_currentBlockFormat;
- KoStyleThumbnailer *m_thumbnailer;
- StylesModel *m_stylesModel;
- DockerStylesComboModel *m_sortedStylesModel;
- StylesDelegate *m_stylesDelegate;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/SimpleCharacterWidget.ui b/plugins/flake/textshape/dialogs/SimpleCharacterWidget.ui
deleted file mode 100644
index e7b3e0898c..0000000000
--- a/plugins/flake/textshape/dialogs/SimpleCharacterWidget.ui
+++ /dev/null
@@ -1,202 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>SimpleCharacterWidget</class>
- <widget class="QWidget" name="SimpleCharacterWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>303</width>
- <height>72</height>
- </rect>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <property name="spacing">
- <number>0</number>
- </property>
- <property name="margin">
- <number>0</number>
- </property>
- <item>
- <layout class="QGridLayout" name="gridLayout">
- <property name="spacing">
- <number>2</number>
- </property>
- <item row="1" column="0" colspan="11">
- <layout class="QGridLayout" name="fontsFrame">
- <property name="horizontalSpacing">
- <number>2</number>
- </property>
- <property name="verticalSpacing">
- <number>0</number>
- </property>
- </layout>
- </item>
- <item row="2" column="0">
- <widget class="QToolButton" name="bold">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QToolButton" name="italic">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="2">
- <widget class="QToolButton" name="underline">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="3">
- <widget class="QToolButton" name="strikeOut">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="4">
- <widget class="QToolButton" name="textColor">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="5">
- <widget class="QToolButton" name="backgroundColor">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="6">
- <widget class="QToolButton" name="superscript">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="7">
- <widget class="QToolButton" name="subscript">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="8" colspan="2">
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Minimum</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>0</width>
- <height>13</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="0" colspan="11">
- <widget class="StylesCombo" name="characterStyleCombo"/>
- </item>
- <item row="2" column="10">
- <widget class="QToolButton" name="moreOptions">
- <property name="text">
- <string>...</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QWidget" name="SpecialSpacer">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>StylesCombo</class>
- <extends>QComboBox</extends>
- <header>dialogs/StylesCombo.h</header>
- <container>1</container>
- </customwidget>
- </customwidgets>
- <tabstops>
- <tabstop>bold</tabstop>
- <tabstop>italic</tabstop>
- <tabstop>underline</tabstop>
- <tabstop>strikeOut</tabstop>
- <tabstop>subscript</tabstop>
- </tabstops>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/SimpleInsertWidget.cpp b/plugins/flake/textshape/dialogs/SimpleInsertWidget.cpp
deleted file mode 100644
index b000cd6ded..0000000000
--- a/plugins/flake/textshape/dialogs/SimpleInsertWidget.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2010-2011 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2014 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 "SimpleInsertWidget.h"
-#include "TextTool.h"
-
-#include <QAction>
-#include <QDebug>
-
-#include <QWidget>
-
-SimpleInsertWidget::SimpleInsertWidget(TextTool *tool, QWidget *parent)
- : QWidget(parent)
- , m_blockSignals(false)
- , m_tool(tool)
-{
- widget.setupUi(this);
- widget.insertVariable->setDefaultAction(tool->action("insert_variable"));
- widget.insertVariable->setPopupMode(QToolButton::InstantPopup); //because action overrode ui file
- widget.insertSpecialChar->setDefaultAction(tool->action("insert_specialchar"));
- widget.quickTable->addAction(tool->action("insert_table"));
- widget.insertSection->setDefaultAction(tool->action("insert_section"));
- widget.configureSection->setDefaultAction(tool->action("configure_section"));
- widget.insertPageBreak->setDefaultAction(tool->action("insert_framebreak"));
- widget.splitSections->setDefaultAction(tool->action("split_sections"));
-
- connect(widget.insertVariable, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.insertSpecialChar, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.insertPageBreak, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.insertSection, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.configureSection, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.splitSections, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
-
- connect(widget.quickTable, SIGNAL(create(int,int)), this, SIGNAL(insertTableQuick(int,int)));
- connect(widget.quickTable, SIGNAL(create(int,int)), this, SIGNAL(doneWithFocus()));
-}
-
-void SimpleInsertWidget::setStyleManager(KoStyleManager *sm)
-{
- m_styleManager = sm;
-}
diff --git a/plugins/flake/textshape/dialogs/SimpleInsertWidget.h b/plugins/flake/textshape/dialogs/SimpleInsertWidget.h
deleted file mode 100644
index b54338d477..0000000000
--- a/plugins/flake/textshape/dialogs/SimpleInsertWidget.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2010-2011 C. Boemann <cbo@boemann.dk>
- *
- * 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 SIMPLEINSERTWIDGET_H
-#define SIMPLEINSERTWIDGET_H
-
-#include <ui_SimpleInsertWidget.h>
-#include <KoListStyle.h>
-
-#include <QWidget>
-#include <QTextBlock>
-
-class TextTool;
-class KoStyleManager;
-
-class SimpleInsertWidget : public QWidget
-{
- Q_OBJECT
-public:
- explicit SimpleInsertWidget(TextTool *tool, QWidget *parent = 0);
-
-public Q_SLOTS:
- void setStyleManager(KoStyleManager *sm);
-
-Q_SIGNALS:
- void doneWithFocus();
- void insertTableQuick(int, int);
-
-private:
- Ui::SimpleInsertWidget widget;
- KoStyleManager *m_styleManager;
- bool m_blockSignals;
- TextTool *m_tool;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/SimpleInsertWidget.ui b/plugins/flake/textshape/dialogs/SimpleInsertWidget.ui
deleted file mode 100644
index 7ddbf4e530..0000000000
--- a/plugins/flake/textshape/dialogs/SimpleInsertWidget.ui
+++ /dev/null
@@ -1,200 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>SimpleInsertWidget</class>
- <widget class="QWidget" name="SimpleInsertWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>230</width>
- <height>66</height>
- </rect>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="toolTip">
- <string>Other insertions from &quot;References&quot; below and in &quot;Add Shape&quot; docker</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_2" columnstretch="0">
- <property name="sizeConstraint">
- <enum>QLayout::SetMinAndMaxSize</enum>
- </property>
- <property name="margin">
- <number>0</number>
- </property>
- <property name="spacing">
- <number>0</number>
- </property>
- <item row="0" column="0">
- <layout class="QGridLayout" name="gridLayout">
- <property name="spacing">
- <number>2</number>
- </property>
- <item row="1" column="6">
- <widget class="QToolButton" name="splitSections">
- <property name="text">
- <string>...</string>
- </property>
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="popupMode">
- <enum>QToolButton::InstantPopup</enum>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="1" column="5">
- <widget class="QToolButton" name="configureSection">
- <property name="text">
- <string>...</string>
- </property>
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="popupMode">
- <enum>QToolButton::InstantPopup</enum>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="1" column="4">
- <widget class="QToolButton" name="insertSection">
- <property name="text">
- <string>...</string>
- </property>
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="popupMode">
- <enum>QToolButton::InstantPopup</enum>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QuickTableButton" name="quickTable">
- <property name="text">
- <string>...</string>
- </property>
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="popupMode">
- <enum>QToolButton::InstantPopup</enum>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="1" column="6">
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="1">
- <widget class="QToolButton" name="insertVariable">
- <property name="text">
- <string>...</string>
- </property>
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="popupMode">
- <enum>QToolButton::InstantPopup</enum>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="1" column="2">
- <widget class="QToolButton" name="insertSpecialChar">
- <property name="text">
- <string>...</string>
- </property>
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="1" column="3">
- <widget class="QToolButton" name="insertPageBreak">
- <property name="text">
- <string>...</string>
- </property>
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="1" column="0">
- <widget class="QWidget" name="SpecialSpacer">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>QuickTableButton</class>
- <extends>QToolButton</extends>
- <header>dialogs/QuickTableButton.h</header>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/SimpleParagraphWidget.cpp b/plugins/flake/textshape/dialogs/SimpleParagraphWidget.cpp
deleted file mode 100644
index ab0b881037..0000000000
--- a/plugins/flake/textshape/dialogs/SimpleParagraphWidget.cpp
+++ /dev/null
@@ -1,365 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007, 2008, 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2009-2010 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2011 Mojtaba Shahi Senobari <mojtaba.shahi3000@gmail.com>
- * Copyright (C) 2011-2012 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- *
- * 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 "SimpleParagraphWidget.h"
-#include "TextTool.h"
-#include <ListItemsHelper.h>
-#include "FormattingButton.h"
-#include <KoStyleThumbnailer.h>
-
-#include "StylesCombo.h"
-#include "StylesModel.h"
-#include "DockerStylesComboModel.h"
-#include "StylesDelegate.h"
-#include "ListLevelChooser.h"
-#include "commands/ChangeListLevelCommand.h"
-
-#include <KoTextEditor.h>
-#include <KoTextBlockData.h>
-#include <KoParagraphStyle.h>
-#include <KoInlineTextObjectManager.h>
-#include <KoTextRangeManager.h>
-#include <KoTextDocumentLayout.h>
-#include <KoZoomHandler.h>
-#include <KoStyleManager.h>
-#include <KoListLevelProperties.h>
-#include <KoShapePaintingContext.h>
-
-#include <QAction>
-
-#include <QTextLayout>
-#include <QFlags>
-#include <QMenu>
-#include <QWidgetAction>
-#include <KisSignalMapper.h>
-
-#include <QDebug>
-
-SimpleParagraphWidget::SimpleParagraphWidget(TextTool *tool, QWidget *parent)
- : QWidget(parent)
- , m_styleManager(0)
- , m_blockSignals(false)
- , m_tool(tool)
- , m_directionButtonState(Auto)
- , m_thumbnailer(new KoStyleThumbnailer())
- , m_mapper(new KisSignalMapper(this))
- , m_stylesModel(new StylesModel(0, StylesModel::ParagraphStyle))
- , m_sortedStylesModel(new DockerStylesComboModel())
- , m_stylesDelegate(0)
-{
- widget.setupUi(this);
- widget.alignCenter->setDefaultAction(tool->action("format_aligncenter"));
- widget.alignBlock->setDefaultAction(tool->action("format_alignblock"));
- // RTL layout will reverse the button order, but the align left/right then get mixed up.
- // this makes sure that whatever happens the 'align left' is to the left of the 'align right'
- if (QApplication::isRightToLeft()) {
- widget.alignLeft->setDefaultAction(tool->action("format_alignright"));
- widget.alignRight->setDefaultAction(tool->action("format_alignleft"));
- } else {
- widget.alignLeft->setDefaultAction(tool->action("format_alignleft"));
- widget.alignRight->setDefaultAction(tool->action("format_alignright"));
- }
-
- widget.decreaseIndent->setDefaultAction(tool->action("format_decreaseindent"));
- widget.increaseIndent->setDefaultAction(tool->action("format_increaseindent"));
- widget.changeTextDirection->setDefaultAction(tool->action("change_text_direction"));
-
- widget.moreOptions->setText("...");
- widget.moreOptions->setToolTip(i18n("Change paragraph format"));
- connect(widget.moreOptions, SIGNAL(clicked(bool)), tool->action("format_paragraph"), SLOT(trigger()));
-
- connect(widget.changeTextDirection, SIGNAL(clicked()), this, SIGNAL(doneWithFocus()));
- connect(widget.alignCenter, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.alignBlock, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.alignLeft, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.alignRight, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.decreaseIndent, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.increaseIndent, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
-
- widget.bulletListButton->setDefaultAction(tool->action("format_bulletlist"));
- widget.bulletListButton->setNumColumns(3);
-
- fillListButtons();
- widget.bulletListButton->addSeparator();
-
- connect(widget.bulletListButton, SIGNAL(itemTriggered(int)), this, SLOT(listStyleChanged(int)));
-
- m_stylesModel->setStyleThumbnailer(m_thumbnailer);
- widget.paragraphStyleCombo->setStylesModel(m_sortedStylesModel);
- connect(widget.paragraphStyleCombo, SIGNAL(selected(QModelIndex)), this, SLOT(styleSelected(QModelIndex)));
- connect(widget.paragraphStyleCombo, SIGNAL(newStyleRequested(QString)), this, SIGNAL(newStyleRequested(QString)));
- connect(widget.paragraphStyleCombo, SIGNAL(newStyleRequested(QString)), this, SIGNAL(doneWithFocus()));
- connect(widget.paragraphStyleCombo, SIGNAL(showStyleManager(int)), this, SLOT(slotShowStyleManager(int)));
-
- connect(m_mapper, SIGNAL(mapped(int)), this, SLOT(changeListLevel(int)));
-
- m_sortedStylesModel->setStylesModel(m_stylesModel);
-}
-
-SimpleParagraphWidget::~SimpleParagraphWidget()
-{
- //the style model is set on the comboBox who takes over ownership
- delete m_thumbnailer;
-}
-
-void SimpleParagraphWidget::fillListButtons()
-{
- KoZoomHandler zoomHandler;
- zoomHandler.setZoom(1.2);
- zoomHandler.setDpi(72, 72);
-
- KoInlineTextObjectManager itom;
- KoTextRangeManager tlm;
- TextShape textShape(&itom, &tlm);
- textShape.setSize(QSizeF(300, 100));
- QTextCursor cursor(textShape.textShapeData()->document());
- Q_FOREACH (const Lists::ListStyleItem &item, Lists::genericListStyleItems()) {
- QPixmap pm(48, 48);
-
- pm.fill(Qt::transparent);
- QPainter p(&pm);
-
- p.translate(0, -1.5);
- p.setRenderHint(QPainter::Antialiasing);
- if (item.style != KoListStyle::None) {
- KoListStyle listStyle;
- KoListLevelProperties llp = listStyle.levelProperties(1);
- llp.setStyle(item.style);
- if (KoListStyle::isNumberingStyle(item.style)) {
- llp.setStartValue(1);
- llp.setListItemSuffix(".");
- }
- listStyle.setLevelProperties(llp);
- cursor.select(QTextCursor::Document);
- QTextCharFormat textCharFormat = cursor.blockCharFormat();
- textCharFormat.setFontPointSize(11);
- textCharFormat.setFontWeight(QFont::Normal);
- cursor.setCharFormat(textCharFormat);
-
- QTextBlock cursorBlock = cursor.block();
- KoTextBlockData data(cursorBlock);
- cursor.insertText("----");
- listStyle.applyStyle(cursor.block(), 1);
- cursorBlock = cursor.block();
- KoTextBlockData data1(cursorBlock);
- cursor.insertText("\n----");
- cursorBlock = cursor.block();
- KoTextBlockData data2(cursorBlock);
- cursor.insertText("\n----");
- cursorBlock = cursor.block();
- KoTextBlockData data3(cursorBlock);
-
- KoTextDocumentLayout *lay = dynamic_cast<KoTextDocumentLayout *>(textShape.textShapeData()->document()->documentLayout());
- if (lay) {
- lay->layout();
- }
-
- KoShapePaintingContext paintContext; //FIXME
- textShape.paintComponent(p, paintContext);
- widget.bulletListButton->addItem(pm, static_cast<int>(item.style));
- }
- }
-
- widget.bulletListButton->addSeparator();
-
- QAction *action = new QAction(i18n("Change List Level"), this);
- action->setToolTip(i18n("Change the level the list is at"));
-
- QMenu *listLevelMenu = new QMenu();
- const int levelIndent = 13;
- for (int level = 0; level < 10; ++level) {
- QWidgetAction *wa = new QWidgetAction(listLevelMenu);
- ListLevelChooser *chooserWidget = new ListLevelChooser((levelIndent * level) + 5);
- wa->setDefaultWidget(chooserWidget);
- listLevelMenu->addAction(wa);
- m_mapper->setMapping(wa, level + 1);
- connect(chooserWidget, SIGNAL(clicked()), wa, SLOT(trigger()));
- connect(wa, SIGNAL(triggered()), m_mapper, SLOT(map()));
- }
-
- action->setMenu(listLevelMenu);
- widget.bulletListButton->addAction(action);
-}
-
-void SimpleParagraphWidget::setCurrentBlock(const QTextBlock &block)
-{
- if (block == m_currentBlock) {
- return;
- }
-
- m_currentBlock = block;
- m_blockSignals = true;
- struct Finally {
- Finally(SimpleParagraphWidget *p)
- {
- parent = p;
- }
- ~Finally()
- {
- parent->m_blockSignals = false;
- }
- SimpleParagraphWidget *parent;
- };
- Finally finally(this);
-
- setCurrentFormat(m_currentBlock.blockFormat());
-}
-
-void SimpleParagraphWidget::setCurrentFormat(const QTextBlockFormat &format)
-{
- if (!m_styleManager || format == m_currentBlockFormat) {
- return;
- }
- m_currentBlockFormat = format;
-
- int id = m_currentBlockFormat.intProperty(KoParagraphStyle::StyleId);
- KoParagraphStyle *style(m_styleManager->paragraphStyle(id));
- if (style) {
- bool unchanged = true;
-
- Q_FOREACH (int property, m_currentBlockFormat.properties().keys()) {
- switch (property) {
- case QTextFormat::ObjectIndex:
- case KoParagraphStyle::ListStyleId:
- case KoParagraphStyle::OutlineLevel:
- case KoParagraphStyle::ListStartValue:
- case KoParagraphStyle::IsListHeader:
- case KoParagraphStyle::UnnumberedListItem:
- continue;
- // These can be both content and style properties so let's ignore
- case KoParagraphStyle::BreakBefore:
- case KoParagraphStyle::MasterPageName:
- continue;
-
- default:
- break;
- }
- if (property == QTextBlockFormat::BlockAlignment) { //the default alignment can be retrieved in the defaultTextOption. However, calligra sets the Qt::AlignAbsolute flag, so we need to or this flag with the default alignment before comparing.
- if ((m_currentBlockFormat.property(property) != style->value(property))
- && !(style->value(property).isNull()
- && ((m_currentBlockFormat.intProperty(property)) == int(m_currentBlock.document()->defaultTextOption().alignment() | Qt::AlignAbsolute)))) {
- unchanged = false;
- break;
- } else {
- continue;
- }
- }
- if (property == KoParagraphStyle::TextProgressionDirection) {
- if (style->value(property).isNull() && m_currentBlockFormat.intProperty(property) == KoText::LeftRightTopBottom) {
- //LTR seems to be Qt default when unset
- continue;
- }
- }
- if ((m_currentBlockFormat.property(property) != style->value(property)) && !(style->value(property).isNull() && !m_currentBlockFormat.property(property).toBool())) {
- //the last check seems to work. might be cause of a bug. The problem is when comparing an unset property in the style with a set to {0, false, ...) property in the format (eg. set then unset bold)
- unchanged = false;
- break;
- }
- }
- //we are updating the combo's selected item to what is the current format. we do not want this to apply the style as it would mess up the undo stack, the change tracking,...
- disconnect(widget.paragraphStyleCombo, SIGNAL(selected(QModelIndex)), this, SLOT(styleSelected(QModelIndex)));
- m_sortedStylesModel->styleApplied(style);
- widget.paragraphStyleCombo->setCurrentIndex(m_sortedStylesModel->indexOf(style).row());
- widget.paragraphStyleCombo->setStyleIsOriginal(unchanged);
- m_stylesModel->setCurrentParagraphStyle(id);
- widget.paragraphStyleCombo->slotUpdatePreview();
- connect(widget.paragraphStyleCombo, SIGNAL(selected(QModelIndex)), this, SLOT(styleSelected(QModelIndex)));
- }
-}
-
-void SimpleParagraphWidget::setStyleManager(KoStyleManager *sm)
-{
- Q_ASSERT(sm);
- if (!sm || m_styleManager == sm) {
- return;
- }
- if (m_styleManager) {
- disconnect(m_styleManager, SIGNAL(styleApplied(const KoParagraphStyle*)), this, SLOT(slotParagraphStyleApplied(const KoParagraphStyle*)));
- }
- m_styleManager = sm;
- //we want to disconnect this before setting the stylemanager. Populating the model apparently selects the first inserted item. We don't want this to actually set a new style.
- disconnect(widget.paragraphStyleCombo, SIGNAL(selected(QModelIndex)), this, SLOT(styleSelected(QModelIndex)));
- m_stylesModel->setStyleManager(sm);
- m_sortedStylesModel->setStyleManager(sm);
- connect(widget.paragraphStyleCombo, SIGNAL(selected(QModelIndex)), this, SLOT(styleSelected(QModelIndex)));
- connect(m_styleManager, SIGNAL(styleApplied(const KoParagraphStyle*)), this, SLOT(slotParagraphStyleApplied(const KoParagraphStyle*)));
-}
-
-void SimpleParagraphWidget::setInitialUsedStyles(QVector<int> list)
-{
- m_sortedStylesModel->setInitialUsedStyles(list);
-}
-
-void SimpleParagraphWidget::listStyleChanged(int id)
-{
- emit doneWithFocus();
- if (m_blockSignals) {
- return;
- }
- KoListLevelProperties llp;
- llp.setStyle(static_cast<KoListStyle::Style>(id));
- llp.setLevel(1);
- KoTextEditor::ChangeListFlags flags(KoTextEditor::AutoListStyle);
- m_tool->textEditor()->setListProperties(llp, flags);
-}
-
-void SimpleParagraphWidget::styleSelected(int index)
-{
- KoParagraphStyle *paragStyle = m_styleManager->paragraphStyle(m_sortedStylesModel->index(index, 0, QModelIndex()).internalId());
- if (paragStyle) {
- emit paragraphStyleSelected(paragStyle);
- }
- emit doneWithFocus();
-}
-
-void SimpleParagraphWidget::styleSelected(const QModelIndex &index)
-{
- if (!index.isValid()) {
- return;
- }
- KoParagraphStyle *paragStyle = m_styleManager->paragraphStyle(index.internalId());
- if (paragStyle) {
- emit paragraphStyleSelected(paragStyle);
- }
- emit doneWithFocus();
-}
-
-void SimpleParagraphWidget::slotShowStyleManager(int index)
-{
- int styleId = m_sortedStylesModel->index(index, 0, QModelIndex()).internalId();
- emit showStyleManager(styleId);
- emit doneWithFocus();
-}
-
-void SimpleParagraphWidget::slotParagraphStyleApplied(const KoParagraphStyle *style)
-{
- m_sortedStylesModel->styleApplied(style);
-}
-
-void SimpleParagraphWidget::changeListLevel(int level)
-{
- emit doneWithFocus();
- if (m_blockSignals) {
- return;
- }
-
- m_tool->setListLevel(level);
-}
diff --git a/plugins/flake/textshape/dialogs/SimpleParagraphWidget.h b/plugins/flake/textshape/dialogs/SimpleParagraphWidget.h
deleted file mode 100644
index 56d256b90a..0000000000
--- a/plugins/flake/textshape/dialogs/SimpleParagraphWidget.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2010 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2011 Mojtaba Shahi Senobari <mojtaba.shahi3000@gmail.com>
- * Copyright (C) 2011-2012 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- *
- * 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 SIMPLEPARAGRAPHWIDGET_H
-#define SIMPLEPARAGRAPHWIDGET_H
-
-#include <ui_SimpleParagraphWidget.h>
-
-#include <QWidget>
-#include <QTextBlock>
-
-class TextTool;
-class KoStyleManager;
-class KoParagraphStyle;
-class KoStyleThumbnailer;
-
-class StylesModel;
-class DockerStylesComboModel;
-class StylesDelegate;
-
-class KisSignalMapper;
-
-class SimpleParagraphWidget : public QWidget
-{
- Q_OBJECT
-public:
- explicit SimpleParagraphWidget(TextTool *tool, QWidget *parent = 0);
- ~SimpleParagraphWidget() override;
-
- void setInitialUsedStyles(QVector<int> list);
-
-public Q_SLOTS:
- void setCurrentBlock(const QTextBlock &block);
- void setCurrentFormat(const QTextBlockFormat &format);
- void setStyleManager(KoStyleManager *sm);
- void slotShowStyleManager(int index);
- void slotParagraphStyleApplied(const KoParagraphStyle *style);
-
-Q_SIGNALS:
- void doneWithFocus();
- void paragraphStyleSelected(KoParagraphStyle *);
- void newStyleRequested(const QString &name);
- void showStyleManager(int styleId);
-
-private Q_SLOTS:
- void listStyleChanged(int id);
- void styleSelected(int index);
- void styleSelected(const QModelIndex &index);
- void changeListLevel(int level);
-
-private:
- enum DirectionButtonState {
- LTR,
- RTL,
- Auto
- };
-
- void updateDirection(DirectionButtonState state);
-
- void fillListButtons();
-
- Ui::SimpleParagraphWidget widget;
- KoStyleManager *m_styleManager;
- bool m_blockSignals;
- QTextBlock m_currentBlock;
- QTextBlockFormat m_currentBlockFormat;
- TextTool *m_tool;
- DirectionButtonState m_directionButtonState;
- KoStyleThumbnailer *m_thumbnailer;
- KisSignalMapper *m_mapper;
-
- StylesModel *m_stylesModel;
- DockerStylesComboModel *m_sortedStylesModel;
- StylesDelegate *m_stylesDelegate;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/SimpleParagraphWidget.ui b/plugins/flake/textshape/dialogs/SimpleParagraphWidget.ui
deleted file mode 100644
index b2a84a892f..0000000000
--- a/plugins/flake/textshape/dialogs/SimpleParagraphWidget.ui
+++ /dev/null
@@ -1,228 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>SimpleParagraphWidget</class>
- <widget class="QWidget" name="SimpleParagraphWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>358</width>
- <height>163</height>
- </rect>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <layout class="QGridLayout" name="gridLayout_2" columnstretch="0">
- <property name="sizeConstraint">
- <enum>QLayout::SetMinAndMaxSize</enum>
- </property>
- <property name="margin">
- <number>0</number>
- </property>
- <property name="spacing">
- <number>0</number>
- </property>
- <item row="0" column="0">
- <widget class="QWidget" name="SpecialSpacer">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <layout class="QGridLayout" name="gridLayout" columnstretch="0,0,0,0,0,0,0,0,0,0,0">
- <property name="spacing">
- <number>2</number>
- </property>
- <item row="2" column="5" colspan="2">
- <spacer name="horizontalSpacer_3">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Fixed</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="0" colspan="11">
- <widget class="StylesCombo" name="paragraphStyleCombo"/>
- </item>
- <item row="2" column="0" colspan="2">
- <widget class="FormattingButton" name="bulletListButton">
- <property name="text">
- <string>...</string>
- </property>
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="3">
- <widget class="QToolButton" name="increaseIndent">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="7">
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QToolButton" name="alignLeft">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="alignCenter">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="alignRight">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="alignBlock">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>0</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item row="2" column="4">
- <widget class="QToolButton" name="changeTextDirection">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="2">
- <widget class="QToolButton" name="decreaseIndent">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="9">
- <widget class="QToolButton" name="moreOptions">
- <property name="text">
- <string>...</string>
- </property>
- </widget>
- </item>
- <item row="2" column="8">
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>100</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>FormattingButton</class>
- <extends>QToolButton</extends>
- <header>dialogs/FormattingButton.h</header>
- </customwidget>
- <customwidget>
- <class>StylesCombo</class>
- <extends>QComboBox</extends>
- <header>dialogs/StylesCombo.h</header>
- <container>1</container>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/SimpleTableWidget.cpp b/plugins/flake/textshape/dialogs/SimpleTableWidget.cpp
deleted file mode 100644
index da56d5ddb3..0000000000
--- a/plugins/flake/textshape/dialogs/SimpleTableWidget.cpp
+++ /dev/null
@@ -1,211 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2010 C. Boemann <cbo@boemann.dk>
- *
- * 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 "SimpleTableWidget.h"
-#include "TextTool.h"
-
-#include <KoTableCellStyle.h>
-#include <KoTextLayoutCellHelper.h>
-#include <KoZoomHandler.h>
-#include <KoColorPopupAction.h>
-#include <KoColor.h>
-#include <KoIcon.h>
-
-#include <QAction>
-#include <QDebug>
-
-#include <QWidget>
-#include <QPixmap>
-
-SimpleTableWidget::SimpleTableWidget(TextTool *tool, QWidget *parent)
- : QWidget(parent)
- , m_blockSignals(false)
- , m_tool(tool)
- , m_lastStyleEmitted(2)
-{
- widget.setupUi(this);
- widget.addRowAbove->setDefaultAction(tool->action("insert_tablerow_above"));
- widget.addRowBelow->setDefaultAction(tool->action("insert_tablerow_below"));
- widget.addColumnLeft->setDefaultAction(tool->action("insert_tablecolumn_left"));
- widget.addColumnRight->setDefaultAction(tool->action("insert_tablecolumn_right"));
- widget.deleteRow->setDefaultAction(tool->action("delete_tablerow"));
- widget.deleteColumn->setDefaultAction(tool->action("delete_tablecolumn"));
- widget.mergeCells->setDefaultAction(tool->action("merge_tablecells"));
- widget.splitCells->setDefaultAction(tool->action("split_tablecells"));
-
- connect(tool->action("activate_borderpainter"), SIGNAL(triggered(bool)), this, SLOT(restartPainting()));
- widget.border->setDefaultAction(tool->action("activate_borderpainter"));
-
- widget.border->setNumColumns(9);
-
- fillBorderButton(QColor(0, 0, 0));
-
- KoColorPopupAction *actionBorderColor = new KoColorPopupAction(this);
- actionBorderColor->setIcon(koIcon("format-fill-color"));
- actionBorderColor->setText(i18n("Set Border Color..."));
- widget.border->addAction(actionBorderColor);
- connect(actionBorderColor, SIGNAL(colorChanged(KoColor)), this, SLOT(setBorderColor(KoColor)));
-
- connect(widget.addRowAbove, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.addRowBelow, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.addColumnLeft, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.addColumnRight, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.deleteRow, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.deleteColumn, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.mergeCells, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.splitCells, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.border, SIGNAL(itemTriggered(int)), this, SLOT(emitTableBorderDataUpdated(int)));
- connect(widget.border, SIGNAL(clicked(bool)), this, SIGNAL(doneWithFocus()));
- connect(widget.border, SIGNAL(doneWithFocus()), this, SIGNAL(doneWithFocus()));
-}
-
-void SimpleTableWidget::restartPainting()
-{
- emitTableBorderDataUpdated(m_lastStyleEmitted);
-}
-
-void SimpleTableWidget::emitTableBorderDataUpdated(int i)
-{
- m_lastStyleEmitted = i;
- emit tableBorderDataUpdated(m_cellStyles[i - 1]->getEdge(KoBorder::TopBorder));
-}
-
-void SimpleTableWidget::setStyleManager(KoStyleManager *sm)
-{
- m_styleManager = sm;
-}
-
-void SimpleTableWidget::setBorderColor(const KoColor &koColor)
-{
- fillBorderButton(koColor.toQColor());
-}
-
-void SimpleTableWidget::fillBorderButton(const QColor &color)
-{
- qDeleteAll(m_cellStyles);
- m_cellStyles.clear();
-
- qreal thickness[9] = {0.25, 0.5, 0.75, 1.0, 1.5, 2.25, 3.0, 4.5, 6.0};
-
- KoTableCellStyle cellStyle;
- qDeleteAll(m_cellStyles);
- m_cellStyles.append(KoTableCellStyle().clone());
- for (int i = 8; i < 9; i++) {
- cellStyle.setEdge(KoBorder::TopBorder, KoBorder::BorderDoubleWave, thickness[i], color);
- m_cellStyles.append(cellStyle.clone());
- }
- for (int i = 6; i < 8; i++) {
- cellStyle.setEdge(KoBorder::TopBorder, KoBorder::BorderWave, thickness[i], color);
- m_cellStyles.append(cellStyle.clone());
- }
- for (int i = 4; i < 9; i++) {
- cellStyle.setEdge(KoBorder::TopBorder, KoBorder::BorderDouble, thickness[i] * 1.5, color);
- cellStyle.setEdgeDoubleBorderValues(KoBorder::TopBorder, thickness[i], thickness[i] / 4);
- m_cellStyles.append(cellStyle.clone());
- }
- for (int i = 6; i < 7; i++) {
- cellStyle.setEdge(KoBorder::TopBorder, KoBorder::BorderSlash, thickness[i], color);
- m_cellStyles.append(cellStyle.clone());
- }
- m_cellStyles.append(0);
- for (int i = 0; i < 7; i++) {
- cellStyle.setEdge(KoBorder::TopBorder, KoBorder::BorderDouble, thickness[i] * 3, color);
- m_cellStyles.append(cellStyle.clone());
- }
- for (int i = 0; i < 9; i++) {
- cellStyle.setEdge(KoBorder::TopBorder, KoBorder::BorderDouble, thickness[i] * 2, color);
- cellStyle.setEdgeDoubleBorderValues(KoBorder::TopBorder, thickness[i] / 2, thickness[i] / 2);
- m_cellStyles.append(cellStyle.clone());
- }
- for (int i = 0; i < 9; i++) {
- cellStyle.setEdge(KoBorder::TopBorder, KoBorder::BorderSolid, thickness[i], color);
- m_cellStyles.append(cellStyle.clone());
- }
- for (int i = 0; i < 9; i++) {
- cellStyle.setEdge(KoBorder::TopBorder, KoBorder::BorderDotted, thickness[i], color);
- m_cellStyles.append(cellStyle.clone());
- }
- for (int i = 0; i < 9; i++) {
- cellStyle.setEdge(KoBorder::TopBorder, KoBorder::BorderDashed, thickness[i], color);
- m_cellStyles.append(cellStyle.clone());
- }
- for (int i = 0; i < 9; i++) {
- cellStyle.setEdge(KoBorder::TopBorder, KoBorder::BorderDashedLong, thickness[i], color);
- m_cellStyles.append(cellStyle.clone());
- }
- for (int i = 0; i < 9; i++) {
- cellStyle.setEdge(KoBorder::TopBorder, KoBorder::BorderDashDot, thickness[i], color);
- m_cellStyles.append(cellStyle.clone());
- }
- for (int i = 0; i < 9; i++) {
- cellStyle.setEdge(KoBorder::TopBorder, KoBorder::BorderDashDotDot, thickness[i], color);
- m_cellStyles.append(cellStyle.clone());
- }
-
- int i = 1;
- KoZoomHandler zoomHandler;
- Q_FOREACH (KoTableCellStyle *style, m_cellStyles) {
- if (style == 0) {
- widget.border->addBlanks(1);
- i++;
- continue;
- }
- QPixmap pm(48, 16);
-
- pm.fill(Qt::transparent);
- QPainter p(&pm);
- p.setRenderHint(QPainter::Antialiasing);
-
- if (style->hasBorders()) {
- p.scale(zoomHandler.zoomedResolutionX(), zoomHandler.zoomedResolutionY());
- KoTextLayoutCellHelper cellStyleHelper(*style);
- qreal width = style->topBorderWidth();
- cellStyleHelper.drawTopHorizontalBorder(p, 0, 8 / zoomHandler.zoomedResolutionY() - width / 2, pm.width() / zoomHandler.zoomedResolutionX(), 0);
-
- widget.border->addItem(pm, i, KoUnit().toUserStringValue(style->topBorderWidth()) + "pt");
- } else {
- p.drawText(0, 0, 48, 16, Qt::AlignCenter, i18nc("No border - has to fit in 48pixels", "None"));
- widget.border->addItem(pm, i, i18n("No Border"));
- }
- i++;
- }
- widget.border->setItemsBackground(QColor(Qt::white));
-
- // widget.borderType->addItem("None");
-
- widget.border->addSeparator();
-
- /*
- //TODO: Uncomment the below line when the string freeze is over
- //action->setToolTip(i18n("Change the level the list is at"));
-
- QMenu *listLevelMenu = new QMenu();
- const int levelIndent = 13;
- for (int level = 0; level < 10; ++level) {
- QWidgetAction *wa = new QWidgetAction(listLevelMenu);
- ListLevelChooser *chooserWidget = new ListLevelChooser((levelIndent * level) + 5);
- wa->setDefaultWidget(chooserWidget);
- listLevelMenu->addAction(wa);
- m_mapper->setMapping(wa,level + 1);
- connect(chooserWidget, SIGNAL(clicked()), wa, SLOT(trigger()));
- connect(wa, SIGNAL(triggered()), m_mapper, SLOT(map()));
- }
-
- action->setMenu(listLevelMenu);
- */
-}
diff --git a/plugins/flake/textshape/dialogs/SimpleTableWidget.h b/plugins/flake/textshape/dialogs/SimpleTableWidget.h
deleted file mode 100644
index 4ccf21886f..0000000000
--- a/plugins/flake/textshape/dialogs/SimpleTableWidget.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2010 C. Boemann <cbo@boemann.dk>
- *
- * 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 SIMPLETABLEWIDGET_H
-#define SIMPLETABLEWIDGET_H
-
-#include <ui_SimpleTableWidget.h>
-#include <KoListStyle.h>
-#include <KoBorder.h>
-
-#include <QWidget>
-#include <QTextBlock>
-
-class TextTool;
-class KoStyleManager;
-class KoTableCellStyle;
-class KoColor;
-
-class SimpleTableWidget : public QWidget
-{
- Q_OBJECT
-public:
- explicit SimpleTableWidget(TextTool *tool, QWidget *parent = 0);
-
-public Q_SLOTS:
- void setStyleManager(KoStyleManager *sm);
- void emitTableBorderDataUpdated(int i = 0);
- void restartPainting();
- void setBorderColor(const KoColor &);
-
-Q_SIGNALS:
- void doneWithFocus();
- void tableBorderDataUpdated(const KoBorder::BorderData &);
-
-private:
- void fillBorderButton(const QColor &color);
-
- Ui::SimpleTableWidget widget;
- KoStyleManager *m_styleManager;
- bool m_blockSignals;
- bool m_comboboxHasBidiItems;
- QTextBlock m_currentBlock;
- TextTool *m_tool;
- QList<KoTableCellStyle *> m_cellStyles; // we only fill out the top borderdata for the previews
- int m_lastStyleEmitted;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/SimpleTableWidget.ui b/plugins/flake/textshape/dialogs/SimpleTableWidget.ui
deleted file mode 100644
index fd4701a49d..0000000000
--- a/plugins/flake/textshape/dialogs/SimpleTableWidget.ui
+++ /dev/null
@@ -1,236 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>SimpleTableWidget</class>
- <widget class="QWidget" name="SimpleTableWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>267</width>
- <height>62</height>
- </rect>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <layout class="QGridLayout" name="gridLayout_2" columnstretch="0,0,0">
- <property name="margin">
- <number>0</number>
- </property>
- <property name="spacing">
- <number>0</number>
- </property>
- <item row="0" column="0">
- <layout class="QGridLayout" name="gridLayout">
- <property name="spacing">
- <number>2</number>
- </property>
- <item row="0" column="0">
- <widget class="QToolButton" name="addRowAbove">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QToolButton" name="addColumnLeft">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="0" column="2">
- <widget class="QToolButton" name="addColumnRight">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QToolButton" name="addRowBelow">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QToolButton" name="deleteRow">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="2">
- <widget class="QToolButton" name="deleteColumn">
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="3" colspan="2">
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Fixed</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>4</width>
- <height>13</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="2" column="5">
- <widget class="QToolButton" name="splitCells">
- <property name="text">
- <string>...</string>
- </property>
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="0" column="5">
- <widget class="QToolButton" name="mergeCells">
- <property name="text">
- <string>...</string>
- </property>
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="6">
- <spacer name="horizontalSpacer_3">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Fixed</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>6</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="7">
- <widget class="FormattingButton" name="border">
- <property name="text">
- <string>...</string>
- </property>
- <property name="iconSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="popupMode">
- <enum>QToolButton::MenuButtonPopup</enum>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="1" column="0">
- <widget class="QWidget" name="SpecialSpacer">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- <item row="0" column="2">
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Preferred</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>0</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>FormattingButton</class>
- <extends>QToolButton</extends>
- <header>dialogs/FormattingButton.h</header>
- </customwidget>
- </customwidgets>
- <tabstops>
- <tabstop>addRowAbove</tabstop>
- <tabstop>addColumnLeft</tabstop>
- <tabstop>addColumnRight</tabstop>
- </tabstops>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/StyleManager.cpp b/plugins/flake/textshape/dialogs/StyleManager.cpp
deleted file mode 100644
index 8be45b446c..0000000000
--- a/plugins/flake/textshape/dialogs/StyleManager.cpp
+++ /dev/null
@@ -1,436 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2013 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 "StyleManager.h"
-
-#include "StylesManagerModel.h"
-#include "StylesSortFilterProxyModel.h"
-
-#include <KoStyleManager.h>
-#include <KoStyleThumbnailer.h>
-#include <KoParagraphStyle.h>
-#include <KoCharacterStyle.h>
-
-#include <QListView>
-#include <QModelIndex>
-#include <QTabWidget>
-#include <QInputDialog>
-#include <QMessageBox>
-
-#include <QDebug>
-
-StyleManager::StyleManager(QWidget *parent)
- : QWidget(parent)
- , m_styleManager(0)
- , m_paragraphStylesModel(new StylesManagerModel(this))
- , m_characterStylesModel(new StylesManagerModel(this))
- , m_paragraphProxyModel(new StylesSortFilterProxyModel(this))
- , m_characterProxyModel(new StylesSortFilterProxyModel(this))
- , m_thumbnailer(new KoStyleThumbnailer())
- , m_unappliedStyleChanges(false)
-{
- widget.setupUi(this);
- layout()->setMargin(0);
- widget.bNew->setToolTip(i18n("Create a new style inheriting the current style"));
-
- // Force "Base" background of the style listviews to white, so the background
- // is consistent with the one of the preview area. Also the usual document text colors
- // are dark, because made for a white paper background, so with a dark UI
- // color scheme they are hardly seen.
- // TODO: update to background color of currently selected/focused shape/page
- QPalette palette = this->palette();
- palette.setColor(QPalette::Base, QColor(Qt::white));
- widget.paragraphStylesListView->setPalette(palette);
- widget.characterStylesListView->setPalette(palette);
-
- m_paragraphStylesModel->setStyleThumbnailer(m_thumbnailer);
- m_characterStylesModel->setStyleThumbnailer(m_thumbnailer);
- m_paragraphProxyModel->setDynamicSortFilter(true);
- m_characterProxyModel->setDynamicSortFilter(true);
- m_paragraphProxyModel->invalidate();
- m_characterProxyModel->invalidate();
- m_paragraphProxyModel->setSourceModel(m_paragraphStylesModel);
- m_characterProxyModel->setSourceModel(m_characterStylesModel);
- m_paragraphProxyModel->sort(0);
- m_characterProxyModel->sort(0);
- //m_paragraphProxyModel->setSortRole(Qt::DisplayRole);
- //m_characterProxyModel->setSortRole(Qt::DisplayRole);
- widget.paragraphStylesListView->setModel(m_paragraphProxyModel);
- widget.characterStylesListView->setModel(m_characterProxyModel);
-
- connect(widget.paragraphStylesListView, SIGNAL(clicked(QModelIndex)), this, SLOT(slotParagraphStyleSelected(QModelIndex)));
- connect(widget.characterStylesListView, SIGNAL(clicked(QModelIndex)), this, SLOT(slotCharacterStyleSelected(QModelIndex)));
-
- connect(widget.bNew, SIGNAL(pressed()), this, SLOT(buttonNewPressed()));
- //connect(widget.bDelete, SIGNAL(pressed()), this, SLOT(buttonDeletePressed()));
- widget.bDelete->setVisible(false); // TODO make it visible when we can safely delete styles
-
- connect(widget.tabs, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
-
- connect(widget.paragraphStylePage, SIGNAL(styleChanged()), this, SLOT(currentParagraphStyleChanged()));
- connect(widget.characterStylePage, SIGNAL(styleChanged()), this, SLOT(currentCharacterStyleChanged()));
- connect(widget.paragraphStylePage, SIGNAL(nameChanged(QString)), this, SLOT(currentParagraphNameChanged(QString)));
- connect(widget.characterStylePage, SIGNAL(nameChanged(QString)), this, SLOT(currentCharacterNameChanged(QString)));
-}
-
-StyleManager::~StyleManager()
-{
- qDeleteAll(m_modifiedParagraphStyles.keys());
- qDeleteAll(m_modifiedCharacterStyles.keys());
-}
-
-void StyleManager::setStyleManager(KoStyleManager *sm)
-{
- Q_ASSERT(sm);
- m_styleManager = sm;
-
- widget.paragraphStylePage->setStyleManager(m_styleManager); //also updates style combos
- widget.characterStylePage->setStyleManager(m_styleManager); //also updates style combos
- widget.tabs->setCurrentIndex(widget.tabs->indexOf(widget.paragraphStylesListView));
- connect(sm, SIGNAL(styleAdded(KoParagraphStyle*)), this, SLOT(addParagraphStyle(KoParagraphStyle*)));
- connect(sm, SIGNAL(styleAdded(KoCharacterStyle*)), this, SLOT(addCharacterStyle(KoCharacterStyle*)));
- connect(sm, SIGNAL(styleRemoved(KoParagraphStyle*)), this, SLOT(removeParagraphStyle(KoParagraphStyle*)));
- connect(sm, SIGNAL(styleRemoved(KoCharacterStyle*)), this, SLOT(removeCharacterStyle(KoCharacterStyle*)));
-
- QList<KoCharacterStyle *> styles;
- QList<KoParagraphStyle *> paragraphStyles = m_styleManager->paragraphStyles();
- KoParagraphStyle *defaultParagraphStyle = m_styleManager->defaultParagraphStyle();
- foreach (KoParagraphStyle *style, paragraphStyles) {
- if (style != defaultParagraphStyle) {
- styles.append(style);
- }
- }
- m_paragraphStylesModel->setStyles(styles);
- styles = m_styleManager->characterStyles();
- styles.removeOne(m_styleManager->defaultCharacterStyle());
- m_characterStylesModel->setStyles(styles);
- if (!paragraphStyles.isEmpty()) {
- widget.paragraphStylesListView->setCurrentIndex(m_paragraphProxyModel->mapFromSource(m_paragraphStylesModel->index(0)));
- }
- if (!styles.isEmpty()) {
- widget.characterStylesListView->setCurrentIndex(m_characterProxyModel->mapFromSource(m_characterStylesModel->index(0)));
- }
-
- tabChanged(0);
-}
-
-void StyleManager::setParagraphStyle(KoParagraphStyle *style)
-{
- widget.characterStylePage->save();
- widget.paragraphStylePage->save();
- KoParagraphStyle *localStyle = 0;
-
- if (style) {
- QMap<KoParagraphStyle *, KoParagraphStyle *>::iterator it = m_modifiedParagraphStyles.find(style);
- if (it == m_modifiedParagraphStyles.end()) {
- localStyle = style->clone();
- m_modifiedParagraphStyles.insert(localStyle, style);
- m_paragraphStylesModel->replaceStyle(style, localStyle);
- } else {
- localStyle = dynamic_cast<KoParagraphStyle *>(it.key());
- }
-
- widget.paragraphStylesListView->setCurrentIndex(m_paragraphProxyModel->mapFromSource(m_paragraphStylesModel->styleIndex(localStyle)));
- }
- widget.paragraphStylePage->setStyle(localStyle);
- widget.stackedWidget->setCurrentWidget(widget.paragraphStylePage);
- widget.tabs->setCurrentIndex(widget.tabs->indexOf(widget.paragraphStylesListView));
- widget.paragraphStylesListView->setEnabled(style != 0);
-}
-
-void StyleManager::setCharacterStyle(KoCharacterStyle *style, bool canDelete)
-{
- Q_UNUSED(canDelete);
- widget.paragraphStylePage->save();
- widget.characterStylePage->save();
- KoCharacterStyle *localStyle = 0;
-
- if (style) {
- QMap<KoCharacterStyle *, KoCharacterStyle *>::iterator it = m_modifiedCharacterStyles.find(style);
- if (it == m_modifiedCharacterStyles.end()) {
- localStyle = style->clone();
- m_modifiedCharacterStyles.insert(localStyle, style);
- m_characterStylesModel->replaceStyle(style, localStyle);
- } else {
- localStyle = it.key();
- }
- widget.characterStylesListView->setCurrentIndex(m_characterProxyModel->mapFromSource(m_characterStylesModel->styleIndex(localStyle)));
- }
- widget.characterStylePage->setStyle(localStyle);
- widget.stackedWidget->setCurrentWidget(widget.characterStylePage);
- widget.tabs->setCurrentIndex(widget.tabs->indexOf(widget.characterStylesListView));
- widget.characterStylePage->setEnabled(style != 0);
-// widget.bDelete->setEnabled(canDelete);
-}
-
-void StyleManager::setUnit(const KoUnit &unit)
-{
- widget.paragraphStylePage->setUnit(unit);
-}
-
-void StyleManager::save()
-{
- if (!m_unappliedStyleChanges) {
- return;
- }
- widget.paragraphStylePage->save();
- widget.characterStylePage->save();
- widget.paragraphStylePage->setStyle(0);
- widget.characterStylePage->setStyle(0);
-
- m_styleManager->beginEdit();
-
- for (QMap<KoParagraphStyle *, KoParagraphStyle *>::iterator it(m_modifiedParagraphStyles.begin()); it != m_modifiedParagraphStyles.end(); ++it) {
- if (it.value() == 0) {
- m_styleManager->add(it.key());
- } else {
- KoParagraphStyle *altered = it.key();
- m_styleManager->alteredStyle(altered);
- m_paragraphStylesModel->replaceStyle(altered, it.value());
- delete altered;
- }
- }
- m_modifiedParagraphStyles.clear();
-
- for (QMap<KoCharacterStyle *, KoCharacterStyle *>::iterator it(m_modifiedCharacterStyles.begin()); it != m_modifiedCharacterStyles.end(); ++it) {
- if (it.value() == 0) {
- m_styleManager->add(it.key());
- } else {
- KoCharacterStyle *altered = it.key();
- m_styleManager->alteredStyle(altered);
- m_characterStylesModel->replaceStyle(altered, it.value());
- delete altered;
- }
- }
- m_modifiedCharacterStyles.clear();
-
- m_styleManager->endEdit();
-
- // set the paragraph and character style new so it has a cloned style to work on and we don't change the actual style.
- KoParagraphStyle *paragraphStyle = dynamic_cast<KoParagraphStyle *>(m_paragraphProxyModel->data(widget.paragraphStylesListView->currentIndex(),
- StylesManagerModel::StylePointer).value<KoCharacterStyle *>());
- if (paragraphStyle) {
- setParagraphStyle(paragraphStyle);
- }
-
- KoCharacterStyle *characterStyle = m_characterProxyModel->data(widget.characterStylesListView->currentIndex(),
- StylesManagerModel::StylePointer).value<KoCharacterStyle *>();
- if (characterStyle) {
- setCharacterStyle(characterStyle);
- }
-
- m_unappliedStyleChanges = false;
-}
-
-void StyleManager::currentParagraphStyleChanged()
-{
- KoParagraphStyle *style = dynamic_cast<KoParagraphStyle *>(m_paragraphProxyModel->data(widget.paragraphStylesListView->currentIndex(), StylesManagerModel::StylePointer).value<KoCharacterStyle *>());
- if (style) {
- widget.paragraphStylePage->save();
- m_paragraphStylesModel->updateStyle(style);
- m_unappliedStyleChanges = true;
- }
-}
-
-void StyleManager::currentParagraphNameChanged(const QString &name)
-{
- KoCharacterStyle *style = m_paragraphProxyModel->data(widget.paragraphStylesListView->currentIndex(), StylesManagerModel::StylePointer).value<KoCharacterStyle *>();
- if (style) {
- style->setName(name);
- currentParagraphStyleChanged();
- }
-}
-
-void StyleManager::currentCharacterStyleChanged()
-{
- KoCharacterStyle *style = m_characterProxyModel->data(widget.characterStylesListView->currentIndex(), StylesManagerModel::StylePointer).value<KoCharacterStyle *>();
- if (style) {
- widget.characterStylePage->save();
- m_characterStylesModel->updateStyle(style);
- m_unappliedStyleChanges = true;
- }
-}
-
-void StyleManager::currentCharacterNameChanged(const QString &name)
-{
- KoCharacterStyle *style = m_characterProxyModel->data(widget.characterStylesListView->currentIndex(), StylesManagerModel::StylePointer).value<KoCharacterStyle *>();
- if (style) {
- style->setName(name);
- currentCharacterStyleChanged();
- }
-}
-
-void StyleManager::addParagraphStyle(KoParagraphStyle *style)
-{
- widget.paragraphStylePage->setStyleManager(m_styleManager); //updates style combos
- m_paragraphStylesModel->addStyle(style);
- setParagraphStyle(style);
- m_unappliedStyleChanges = true;
-}
-
-void StyleManager::addCharacterStyle(KoCharacterStyle *style)
-{
- widget.characterStylePage->setStyleManager(m_styleManager); //updates style combos
- m_characterStylesModel->addStyle(style);
- setCharacterStyle(style);
- m_unappliedStyleChanges = true;
-}
-
-void StyleManager::removeParagraphStyle(KoParagraphStyle *style)
-{
- if (m_modifiedParagraphStyles.contains(style)) {
- m_modifiedParagraphStyles.remove(style);
- m_paragraphStylesModel->removeStyle(style);
- }
- widget.paragraphStylePage->setStyleManager(m_styleManager); //updates style combos
-}
-
-void StyleManager::removeCharacterStyle(KoCharacterStyle *style)
-{
- if (m_modifiedCharacterStyles.contains(style)) {
- m_modifiedCharacterStyles.remove(style);
- m_characterStylesModel->removeStyle(style);
- }
- widget.characterStylePage->setStyleManager(m_styleManager); //updates style combos
-}
-
-void StyleManager::slotParagraphStyleSelected(const QModelIndex &index)
-{
- if (checkUniqueStyleName()) {
- KoParagraphStyle *paragraphStyle = dynamic_cast<KoParagraphStyle *>(m_paragraphProxyModel->data(index, StylesManagerModel::StylePointer).value<KoCharacterStyle *>());
- if (paragraphStyle) {
- setParagraphStyle(paragraphStyle);
- return;
- }
- }
-}
-
-void StyleManager::slotCharacterStyleSelected(const QModelIndex &index)
-{
- if (checkUniqueStyleName()) {
- KoCharacterStyle *characterStyle = m_characterProxyModel->data(index, StylesManagerModel::StylePointer).value<KoCharacterStyle *>();
- if (characterStyle) {
- setCharacterStyle(characterStyle, false);
- return;
- }
- }
-}
-
-void StyleManager::buttonNewPressed()
-{
- if (checkUniqueStyleName()) {
- if (widget.tabs->indexOf(widget.paragraphStylesListView) == widget.tabs->currentIndex()) {
- KoParagraphStyle *newStyle = 0;
- KoParagraphStyle *style = dynamic_cast<KoParagraphStyle *>(m_paragraphProxyModel->data(widget.paragraphStylesListView->currentIndex(),
- StylesManagerModel::StylePointer).value<KoCharacterStyle *>());
- if (style) {
- newStyle = style->clone();
- } else {
- newStyle = new KoParagraphStyle();
- }
- newStyle->setName(i18n("New Style"));
- m_modifiedParagraphStyles.insert(newStyle, 0);
- addParagraphStyle(newStyle);
- widget.paragraphStylePage->selectName();
- } else {
- KoCharacterStyle *newStyle = 0;
- KoCharacterStyle *style = m_characterProxyModel->data(widget.characterStylesListView->currentIndex(), StylesManagerModel::StylePointer).value<KoCharacterStyle *>();
- if (style) {
- newStyle = style->clone();
- } else {
- newStyle = new KoCharacterStyle();
- }
- newStyle->setName(i18n("New Style"));
- m_modifiedCharacterStyles.insert(newStyle, 0);
- addCharacterStyle(newStyle);
- widget.characterStylePage->selectName();
- }
- }
-}
-
-void StyleManager::tabChanged(int index)
-{
- int paragraphIndex = widget.tabs->indexOf(widget.paragraphStylesListView);
- if (!checkUniqueStyleName(paragraphIndex == index ? widget.tabs->indexOf(widget.characterStylesListView) : paragraphIndex)) {
- // this is needed to not call tab changed during the resetting of the tab as this leads to en endless recursion.
- disconnect(widget.tabs, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
- if (widget.tabs->indexOf(widget.paragraphStylesListView) == widget.tabs->currentIndex()) {
- widget.tabs->setCurrentIndex(widget.tabs->indexOf(widget.characterStylesListView));
- } else {
- widget.tabs->setCurrentIndex(widget.tabs->indexOf(widget.paragraphStylesListView));
- }
- connect(widget.tabs, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
- } else {
- if (paragraphIndex == index) {
- KoParagraphStyle *style = dynamic_cast<KoParagraphStyle *>(m_paragraphProxyModel->data(widget.paragraphStylesListView->currentIndex(),
- StylesManagerModel::StylePointer).value<KoCharacterStyle *>());
- setParagraphStyle(style);
- widget.stackedWidget->setCurrentWidget(widget.paragraphStylePage);
- } else {
- KoCharacterStyle *style = m_characterProxyModel->data(widget.characterStylesListView->currentIndex(), StylesManagerModel::StylePointer).value<KoCharacterStyle *>();
- setCharacterStyle(style);
- widget.stackedWidget->setCurrentWidget(widget.characterStylePage);
- }
- }
-}
-
-bool StyleManager::unappliedStyleChanges()
-{
- return m_unappliedStyleChanges;
-}
-
-bool StyleManager::checkUniqueStyleName()
-{
- return checkUniqueStyleName(widget.tabs->currentIndex());
-}
-
-bool StyleManager::checkUniqueStyleName(int widgetIndex)
-{
- QModelIndex index;
- QString styleName;
- QListView *listView;
- if (widget.tabs->indexOf(widget.paragraphStylesListView) == widgetIndex) {
- styleName = widget.paragraphStylePage->styleName();
- listView = widget.paragraphStylesListView;
- index = m_paragraphProxyModel->mapFromSource(m_paragraphStylesModel->styleIndex(widget.paragraphStylePage->style()));
- } else {
- styleName = widget.characterStylePage->styleName();
- index = m_characterProxyModel->mapFromSource(m_characterStylesModel->styleIndex(widget.characterStylePage->style()));
- listView = widget.characterStylesListView;
- }
-
- QModelIndexList stylesByName;
- if (index.isValid()) {
- stylesByName.append(m_paragraphProxyModel->match(m_paragraphProxyModel->index(0, 0), Qt::DisplayRole, QVariant(styleName), -1, Qt::MatchFlags(Qt::MatchExactly | Qt::MatchWrap)));
- stylesByName.append(m_characterProxyModel->match(m_characterProxyModel->index(0, 0), Qt::DisplayRole, QVariant(styleName), -1, Qt::MatchFlags(Qt::MatchExactly | Qt::MatchWrap)));
- }
-
- bool unique = stylesByName.size() <= 1;
- if (!unique) {
- QMessageBox::critical(this, i18n("Warning"), i18n("Another style named '%1' already exist. Please choose another name.", styleName));
- listView->setCurrentIndex(index);
- if (widget.tabs->indexOf(widget.paragraphStylesListView) == widgetIndex) {
- widget.paragraphStylePage->selectName();
- } else {
- widget.characterStylePage->selectName();
- }
- }
- return unique;
-}
diff --git a/plugins/flake/textshape/dialogs/StyleManager.h b/plugins/flake/textshape/dialogs/StyleManager.h
deleted file mode 100644
index 1b36f2cb4d..0000000000
--- a/plugins/flake/textshape/dialogs/StyleManager.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2013 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 STYLEMANAGER_H
-#define STYLEMANAGER_H
-
-#include <ui_StyleManager.h>
-
-#include <QWidget>
-
-class StylesManagerModel;
-class StylesSortFilterProxyModel;
-class KoStyleManager;
-class KoStyleThumbnailer;
-class KoParagraphStyle;
-class KoCharacterStyle;
-
-class QModelIndex;
-
-class StyleManager : public QWidget
-{
- Q_OBJECT
-public:
- explicit StyleManager(QWidget *parent = 0);
- ~StyleManager() override;
-
- void setStyleManager(KoStyleManager *sm);
-
- void setUnit(const KoUnit &unit);
-
- //Check that the new name of style is unique or not
- bool checkUniqueStyleName();
-
-public Q_SLOTS:
- void save();
- void setParagraphStyle(KoParagraphStyle *style);
- void setCharacterStyle(KoCharacterStyle *style, bool canDelete = false);
- bool unappliedStyleChanges();
-
-private Q_SLOTS:
- void slotParagraphStyleSelected(const QModelIndex &index);
- void slotCharacterStyleSelected(const QModelIndex &index);
- void addParagraphStyle(KoParagraphStyle *);
- void addCharacterStyle(KoCharacterStyle *);
- void removeParagraphStyle(KoParagraphStyle *);
- void removeCharacterStyle(KoCharacterStyle *);
- void currentParagraphStyleChanged();
- void currentParagraphNameChanged(const QString &name);
- void currentCharacterStyleChanged();
- void currentCharacterNameChanged(const QString &name);
- void buttonNewPressed();
- void tabChanged(int index);
-
-private:
- bool checkUniqueStyleName(int widgetIndex);
-
- Ui::StyleManager widget;
- KoStyleManager *m_styleManager;
-
- QMap<KoParagraphStyle *, KoParagraphStyle *> m_modifiedParagraphStyles;
- QMap<KoCharacterStyle *, KoCharacterStyle *> m_modifiedCharacterStyles;
-
- StylesManagerModel *m_paragraphStylesModel;
- StylesManagerModel *m_characterStylesModel;
- StylesSortFilterProxyModel *m_paragraphProxyModel;
- StylesSortFilterProxyModel *m_characterProxyModel;
- KoStyleThumbnailer *m_thumbnailer;
- bool m_unappliedStyleChanges;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/StyleManager.ui b/plugins/flake/textshape/dialogs/StyleManager.ui
deleted file mode 100644
index 50b8f0e41f..0000000000
--- a/plugins/flake/textshape/dialogs/StyleManager.ui
+++ /dev/null
@@ -1,121 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>StyleManager</class>
- <widget class="QWidget" name="StyleManager">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>419</width>
- <height>318</height>
- </rect>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
- <horstretch>1</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="0" column="0">
- <widget class="QSplitter" name="splitter">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <widget class="QWidget" name="">
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0" colspan="2">
- <widget class="QTabWidget" name="tabs">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
- <horstretch>99</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <widget class="QListView" name="paragraphStylesListView">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
- <horstretch>14</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="horizontalScrollBarPolicy">
- <enum>Qt::ScrollBarAlwaysOff</enum>
- </property>
- <attribute name="title">
- <string>Paragraph</string>
- </attribute>
- </widget>
- <widget class="QListView" name="characterStylesListView">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
- <horstretch>14</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="horizontalScrollBarPolicy">
- <enum>Qt::ScrollBarAlwaysOff</enum>
- </property>
- <attribute name="title">
- <string>Character</string>
- </attribute>
- </widget>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QPushButton" name="bNew">
- <property name="text">
- <string>&amp;New</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QPushButton" name="bDelete">
- <property name="text">
- <string>Delete</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <widget class="QStackedWidget" name="stackedWidget">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="currentIndex">
- <number>2</number>
- </property>
- <widget class="StyleManagerWelcome" name="welcomePage"/>
- <widget class="ParagraphGeneral" name="paragraphStylePage"/>
- <widget class="CharacterGeneral" name="characterStylePage"/>
- </widget>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>ParagraphGeneral</class>
- <extends>QWidget</extends>
- <header>dialogs/ParagraphGeneral.h</header>
- <container>1</container>
- </customwidget>
- <customwidget>
- <class>CharacterGeneral</class>
- <extends>QWidget</extends>
- <header>dialogs/CharacterGeneral.h</header>
- <container>1</container>
- </customwidget>
- <customwidget>
- <class>StyleManagerWelcome</class>
- <extends>QWidget</extends>
- <header>dialogs/StyleManagerWelcome.h</header>
- <container>1</container>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/StyleManagerDialog.cpp b/plugins/flake/textshape/dialogs/StyleManagerDialog.cpp
deleted file mode 100644
index 0b5d476001..0000000000
--- a/plugins/flake/textshape/dialogs/StyleManagerDialog.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 "StyleManagerDialog.h"
-#include "StyleManager.h"
-
-#include <KoCharacterStyle.h>
-#include <KoParagraphStyle.h>
-#include <QMessageBox>
-
-StyleManagerDialog::StyleManagerDialog(QWidget *parent)
- : KoDialog(parent)
-{
- setButtons(Ok | Cancel | Apply);
- m_styleManagerWidget = new StyleManager(this);
- setMainWidget(m_styleManagerWidget);
- setWindowTitle(i18n("Style Manager"));
-
- connect(this, SIGNAL(applyClicked()), this, SLOT(applyClicked()));
-}
-
-StyleManagerDialog::~StyleManagerDialog()
-{
-}
-
-void StyleManagerDialog::applyClicked()
-{
- if (m_styleManagerWidget->checkUniqueStyleName()) {
- m_styleManagerWidget->save();
- }
-}
-
-void StyleManagerDialog::accept()
-{
- if (!m_styleManagerWidget->checkUniqueStyleName()) {
- return;
- }
- m_styleManagerWidget->save();
- KoDialog::accept();
- deleteLater();
-}
-
-void StyleManagerDialog::reject()
-{
- if (m_styleManagerWidget->unappliedStyleChanges()) {
- int ans = QMessageBox::warning(this, i18n("Save Changes"), i18n("You have changes that are not applied. "
- "What do you want to do with those changes?"), QMessageBox::Apply, QMessageBox::Discard, QMessageBox::Cancel);
- switch (ans) {
- case QMessageBox::Apply :
- if (m_styleManagerWidget->checkUniqueStyleName()) {
- m_styleManagerWidget->save();
- break;
- }
- return;
- case QMessageBox::Discard :
- break;
- case QMessageBox::Cancel :
- return;
- }
- }
- KoDialog::reject();
- deleteLater();
-}
-
-void StyleManagerDialog::closeEvent(QCloseEvent *e)
-{
- e->ignore();
- reject();
-}
-
-void StyleManagerDialog::setStyleManager(KoStyleManager *sm)
-{
- m_styleManagerWidget->setStyleManager(sm);
-}
-
-void StyleManagerDialog::setUnit(const KoUnit &unit)
-{
- m_styleManagerWidget->setUnit(unit);
-}
-
-void StyleManagerDialog::setCharacterStyle(KoCharacterStyle *style, bool canDelete)
-{
- m_styleManagerWidget->setCharacterStyle(style, canDelete);
-}
-
-void StyleManagerDialog::setParagraphStyle(KoParagraphStyle *style)
-{
- m_styleManagerWidget->setParagraphStyle(style);
-}
diff --git a/plugins/flake/textshape/dialogs/StyleManagerDialog.h b/plugins/flake/textshape/dialogs/StyleManagerDialog.h
deleted file mode 100644
index 0ecaf8e545..0000000000
--- a/plugins/flake/textshape/dialogs/StyleManagerDialog.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 STYLEMANAGERDIALOG_H
-#define STYLEMANAGERDIALOG_H
-
-#include <KoDialog.h>
-#include <QCloseEvent>
-
-class StyleManager;
-
-class KoCharacterStyle;
-class KoParagraphStyle;
-class KoStyleManager;
-class KoUnit;
-
-class StyleManagerDialog : public KoDialog
-{
- Q_OBJECT
-public:
- explicit StyleManagerDialog(QWidget *parent);
- ~StyleManagerDialog() override;
-
- void setStyleManager(KoStyleManager *sm);
-
- void setUnit(const KoUnit &unit);
-
-public Q_SLOTS:
- void setParagraphStyle(KoParagraphStyle *style);
- void setCharacterStyle(KoCharacterStyle *style, bool canDelete = false);
-
-private Q_SLOTS:
- void applyClicked();
-
-protected:
- void closeEvent(QCloseEvent *e) override;
-
-private:
- void accept() override;
- void reject() override;
-
- StyleManager *m_styleManagerWidget;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/StyleManagerWelcome.cpp b/plugins/flake/textshape/dialogs/StyleManagerWelcome.cpp
deleted file mode 100644
index e59ce36422..0000000000
--- a/plugins/flake/textshape/dialogs/StyleManagerWelcome.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2008 Pierre Stirnweiss <pstirnweiss@googlemail.com>
-
- 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 "StyleManagerWelcome.h"
-
-StyleManagerWelcome::StyleManagerWelcome(QWidget *parent)
- : QWidget(parent)
-{
- widget.setupUi(this);
-}
-
diff --git a/plugins/flake/textshape/dialogs/StyleManagerWelcome.h b/plugins/flake/textshape/dialogs/StyleManagerWelcome.h
deleted file mode 100644
index e69ff7dd5d..0000000000
--- a/plugins/flake/textshape/dialogs/StyleManagerWelcome.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2008 Pierre Stirnweiss <pstirnweiss@googlemail.com>
-
- 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 STYLEMANAGERWELCOME_H
-#define STYLEMANAGERWELCOME_H
-
-#include <QWidget>
-
-#include <ui_StyleManagerWelcome.h>
-
-class StyleManagerWelcome : public QWidget
-{
- Q_OBJECT
-public:
- explicit StyleManagerWelcome(QWidget *parent = 0);
-
-private:
- Ui::StyleManagerWelcome widget;
-};
-
-#endif // STYLEMANAGERWELCOME_H
diff --git a/plugins/flake/textshape/dialogs/StyleManagerWelcome.ui b/plugins/flake/textshape/dialogs/StyleManagerWelcome.ui
deleted file mode 100644
index 7c928b4452..0000000000
--- a/plugins/flake/textshape/dialogs/StyleManagerWelcome.ui
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>StyleManagerWelcome</class>
- <widget class="QWidget" name="StyleManagerWelcome">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>377</width>
- <height>249</height>
- </rect>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <property name="margin">
- <number>0</number>
- </property>
- <item row="0" column="0">
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QLabel" name="label">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Ignored" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="mouseTracking">
- <bool>true</bool>
- </property>
- <property name="text">
- <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
-&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
-p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;It is possible to assign a named style to text and alter the style properties to change all text with that style.&lt;/p&gt;
-&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Applying a style change will reformat all text that previously got the named style assigned to it. Use the Styles docker to apply styles to text.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- <property name="textFormat">
- <enum>Qt::RichText</enum>
- </property>
- <property name="wordWrap">
- <bool>true</bool>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/StylesCombo.cpp b/plugins/flake/textshape/dialogs/StylesCombo.cpp
deleted file mode 100644
index f6e8ad7bf1..0000000000
--- a/plugins/flake/textshape/dialogs/StylesCombo.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011-2012 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- *
- * 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 "StylesCombo.h"
-#include <KoStyleThumbnailer.h>
-
-#include "AbstractStylesModel.h"
-#include "StylesComboPreview.h"
-#include "StylesDelegate.h"
-
-#include <QListView>
-#include <QMouseEvent>
-#include <QStyleOptionViewItem>
-
-#include <QDebug>
-
-StylesCombo::StylesCombo(QWidget *parent)
- : QComboBox(parent)
- , m_stylesModel(0)
- , m_view(new QListView())
- , m_selectedItem(-1)
- , m_originalStyle(true)
-{
- // Force "Base" background to white, so the background is consistent with the one
- // of the preview area in the style manager. Also the usual document text colors
- // are dark, because made for a white paper background, so with a dark UI
- // color scheme they are hardly seen.
- // Force palette entry "Text" to black as contrast, as the pop-up button
- // symbol is often drawn with this palette entry
- // TODO: update to background color of currently selected/focused shape/page
- QPalette palette = this->palette();
- palette.setColor(QPalette::Base, QColor(Qt::white));
- palette.setColor(QPalette::Text, QColor(Qt::black));
- setPalette(palette);
-
- setMinimumSize(50, 32);
-
- m_view->setMinimumWidth(250);
- m_view->setMouseTracking(true);
- setView(m_view);
- view()->viewport()->installEventFilter(this);
-
- StylesDelegate *delegate = new StylesDelegate();
- connect(delegate, SIGNAL(needsUpdate(QModelIndex)), m_view, SLOT(update(QModelIndex)));
- connect(delegate, SIGNAL(styleManagerButtonClicked(QModelIndex)), this, SLOT(slotShowDia(QModelIndex)));
- connect(delegate, SIGNAL(deleteStyleButtonClicked(QModelIndex)), this, SLOT(slotDeleteStyle(QModelIndex)));
- connect(delegate, SIGNAL(clickedInItem(QModelIndex)), this, SLOT(slotItemClicked(QModelIndex)));
- setItemDelegate(delegate);
-
-// connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(slotSelectionChanged(int)));
-
- QComboBox::setEditable(true);
- setIconSize(QSize(0, 0));
-
- StylesComboPreview *preview = new StylesComboPreview(this);
- QComboBox::setEditable(true);
- setLineEdit(preview);
-}
-
-StylesCombo::~StylesCombo()
-{
-}
-
-void StylesCombo::setStyleIsOriginal(bool original)
-{
- m_originalStyle = original;
- if (!original) {
- m_preview->setAddButtonShown(true);
- } else {
- m_preview->setAddButtonShown(false);
- }
-}
-
-void StylesCombo::setStylesModel(AbstractStylesModel *model)
-{
- m_stylesModel = model;
- setModel(model);
-}
-
-void StylesCombo::setEditable(bool editable)
-{
- if (editable) {
- // Create a StylesComboPreview instead of a QLineEdit
- // Compared to QComboBox::setEditable, we might be missing the SH_ComboBox_Popup code though...
- // If a style needs this, then we'll need to call QComboBox::setEditable and then setLineEdit again
- StylesComboPreview *edit = new StylesComboPreview(this);
- setLineEdit(edit);
- } else {
- QComboBox::setEditable(editable);
- }
-}
-
-void StylesCombo::setLineEdit(QLineEdit *edit)
-{
- if (!isEditable() && edit && !qstrcmp(edit->metaObject()->className(), "QLineEdit")) {
- // uic generates code that creates a read-only StylesCombo and then
- // calls combo->setEditable( true ), which causes QComboBox to set up
- // a dumb QLineEdit instead of our nice StylesComboPreview.
- // As some StylesCombo features rely on the StylesComboPreview, we reject
- // this order here.
- delete edit;
- StylesComboPreview *preview = new StylesComboPreview(this);
- edit = preview;
- }
-
- QComboBox::setLineEdit(edit);
- m_preview = qobject_cast<StylesComboPreview *>(edit);
-
- if (m_preview) {
- connect(m_preview, SIGNAL(resized()), this, SLOT(slotUpdatePreview()));
- connect(m_preview, SIGNAL(newStyleRequested(QString)), this, SIGNAL(newStyleRequested(QString)));
- connect(m_preview, SIGNAL(clicked()), this, SLOT(slotPreviewClicked()));
- }
-
-}
-
-void StylesCombo::slotSelectionChanged(int index)
-{
- m_selectedItem = index;
- m_preview->setPreview(m_stylesModel->stylePreview(index, m_preview->availableSize()));
- update();
-// emit selectionChanged(index);
-}
-
-void StylesCombo::slotItemClicked(const QModelIndex &index)
-{
- //this slot allows us to emit a selected signal. There is a bit of redundancy if the item clicked was indeed a new selection, where we also emit the selectionChanged signal from the slot above.
- m_selectedItem = index.row();
- m_preview->setPreview(m_stylesModel->stylePreview(m_selectedItem, m_preview->availableSize()));
- m_currentIndex = index;
- update();
- emit selected(m_selectedItem);
- emit selected(index);
- hidePopup(); //the editor event has accepted the mouseReleased event. Call hidePopup ourselves then.
-}
-
-void StylesCombo::slotUpdatePreview()
-{
- if (!m_stylesModel) {
- return;
- }
- m_preview->setPreview(m_stylesModel->stylePreview(currentIndex(), m_preview->availableSize()));
- update();
-}
-
-void StylesCombo::slotPreviewClicked()
-{
- if (!view()->isVisible()) {
- showPopup();
- }
-}
-
-bool StylesCombo::eventFilter(QObject *object, QEvent *event)
-{
- if (event->type() == QEvent::MouseButtonRelease && object == view()->viewport()) {
- QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
- //If what follows isn't a HACK then I have no clue what is!!!!
- //The item delegate editorEvent method is not sent MouseButtonRelease events.
- //This is because the QComboBox installs an event filter on the view and calls
- //popup->hide() on MouseButtonRelease to dismiss the view. Since we installed an event filter on the view
- //ourselves, we can prevent hiding the popup. We have to call itemDelegate->editorEvent
- //manually though.
- QModelIndex index = view()->indexAt(mouseEvent->pos());
- QModelIndex buddy = m_stylesModel->buddy(index);
- QStyleOptionViewItem options;
- options.rect = view()->visualRect(buddy);
- options.widget = m_view;
- options.state |= (buddy == view()->currentIndex() ? QStyle::State_HasFocus : QStyle::State_None);
- return view()->itemDelegate()->editorEvent(mouseEvent, m_stylesModel, options, index);
- }
- return false;
-}
-
-void StylesCombo::slotShowDia(const QModelIndex &index)
-{
- emit showStyleManager(index.row());
-}
-
-void StylesCombo::slotDeleteStyle(const QModelIndex &index)
-{
- emit deleteStyle(index.row());
-}
-
-void StylesCombo::slotModelReset()
-{
- m_view->reset();
-}
-
-void StylesCombo::showEditIcon(bool show)
-{
- StylesDelegate *delegate = dynamic_cast<StylesDelegate *>(itemDelegate());
- Q_ASSERT(delegate);
- if (!delegate) { //the following should never get called as we are creating a StylesDelegate on the constructor;
- StylesDelegate *delegate = new StylesDelegate();
- connect(delegate, SIGNAL(needsUpdate(QModelIndex)), m_view, SLOT(update(QModelIndex)));
- connect(delegate, SIGNAL(styleManagerButtonClicked(QModelIndex)), this, SLOT(slotShowDia(QModelIndex)));
- connect(delegate, SIGNAL(deleteStyleButtonClicked(QModelIndex)), this, SLOT(slotDeleteStyle(QModelIndex)));
- connect(delegate, SIGNAL(clickedInItem(QModelIndex)), this, SLOT(slotItemClicked(QModelIndex)));
- setItemDelegate(delegate);
- }
- delegate->setEditButtonEnable(show);
-}
diff --git a/plugins/flake/textshape/dialogs/StylesCombo.h b/plugins/flake/textshape/dialogs/StylesCombo.h
deleted file mode 100644
index effb666743..0000000000
--- a/plugins/flake/textshape/dialogs/StylesCombo.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011-2012 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- *
- * 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 STYLESCOMBO_H
-#define STYLESCOMBO_H
-
-#include <QComboBox>
-
-class QListView;
-
-class AbstractStylesModel;
-class StylesComboPreview;
-
-/** This combo is specifically designed to allow choosing a text style, be it a character style or a paragraph style.
- * The combo itself does not know what type of style it is dealing with. In that respect it follows pretty much the normal QComboBox paradigm.
- * This is achieved by setting a @class StylesModel to the combo.
- * The combo also creates and uses a @class StylesDelegate in order to paint the items as preview in the dropdown menu. This delegate also provide a button to call the style manager dialog directly.
- * Additionally the combo display the style as a preview in its main area.
- * The combo allows its user to specify if the current selected style should be considered as original or not. If the style has been modified, a + button appears in the main area. Pressing it will allow to change the name of the style. Focusing out, or pressing enter will send a signal for creating a new style. Escaping will prevent this signal to be sent and return to the preview.
-*/
-
-class StylesCombo : public QComboBox
-{
- Q_OBJECT
-public:
- explicit StylesCombo(QWidget *parent);
- ~StylesCombo() override;
-
- /** Use this method to set the @param model of the combo. */
- void setStylesModel(AbstractStylesModel *model);
-
- /** This method is an override of QComboBox setLineEdit. We need to make it public since its Qt counterpart is public. However, this method is not supposed to be used (unless you know what you are doing). The StylesCombo relies on its own internal QLineEdit subclass for quite a lot of its functionality. There is no guarantee that the whole thing will work in case the line edit is replaced */
- void setLineEdit(QLineEdit *lineEdit);
- /** Same as above */
- void setEditable(bool editable);
-
- /** This method is used to specify if the currently selected style is in its original state or is considered modified. In the later case, the + button will appear (see the class description) */
- void setStyleIsOriginal(bool original);
-
- bool eventFilter(QObject *, QEvent *) override;
-
- /** When we don't want edit icon for our items in combo */
- void showEditIcon(bool show);
-
-public Q_SLOTS:
- /** This slot needs to be called if the preview in the main area needs to be updated for some reason */
- void slotUpdatePreview();
-
-Q_SIGNALS:
- /** This is emitted when a selection is made (programmatically or by user interaction). It is
- * to be noted that this signal is also emitted when an item is selected again.
- * @param index: the index of the selected item. */
- void selected(int index);
- void selected(const QModelIndex &index);
-
- /** This is emitted when a selection is changed (programmatically or by user interaction). It is
- * to be noted that this signal is _not_ emitted when an item is selected again. Not even if it
- * had been modified.
- * @param index: the index of the selected item. */
- void selectionChanged(int index);
-
- /** This signal is emitted on validation of the name of a modified style (after pressing the + button). This validation happens on focus out or pressed enter key.
- * @param name: the name by which the new style should be called */
- void newStyleRequested(const QString &name);
-
- /** This signal is emitted when the "show style manager" button is pressed in the dropdown list.
- * @param index: the index of the item on which the button was pressed */
- void showStyleManager(int index);
-
- /** This signal is emitted when the "delete style" button is pressed in the dropdown list.
- * @param index: the index of the item on which the button was pressed
- * This is currently disabled */
- void deleteStyle(int index);
-
-private Q_SLOTS:
- void slotDeleteStyle(const QModelIndex &);
- void slotShowDia(const QModelIndex &);
- void slotSelectionChanged(int index);
- void slotItemClicked(const QModelIndex &);
- void slotPreviewClicked();
- void slotModelReset();
-
-private:
- AbstractStylesModel *m_stylesModel;
- StylesComboPreview *m_preview;
- QListView *m_view;
- int m_selectedItem;
- bool m_originalStyle;
- QModelIndex m_currentIndex;
-};
-
-#endif //STYLESCOMBO_H
diff --git a/plugins/flake/textshape/dialogs/StylesComboPreview.cpp b/plugins/flake/textshape/dialogs/StylesComboPreview.cpp
deleted file mode 100644
index 08d280eb10..0000000000
--- a/plugins/flake/textshape/dialogs/StylesComboPreview.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- *
- * 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.
-*/
-
-/*
- * This class is heavily inspired by QLineEdit, so here goes credit because credit is due (from klineedit.h):
- * This class was originally inspired by Torben Weis'
- * fileentry.cpp for KFM II.
-
- * Sven Radej <sven.radej@iname.com>
- * Patrick Ward <PAT_WARD@HP-USA-om5.om.hp.com>
- * Preston Brown <pbrown@kde.org>
-
- * Completely re-designed:
- * Dawit Alemayehu <adawit@kde.org>
-
-*/
-
-#include "StylesComboPreview.h"
-
-#include <KoIcon.h>
-
-#include <QImage>
-#include <QLineEdit>
-#include <QModelIndex>
-#include <QPainter>
-#include <QPaintEvent>
-#include <QFocusEvent>
-#include <QMouseEvent>
-#include <QKeyEvent>
-#include <QPushButton>
-#include <QString>
-
-#include <klocalizedstring.h>
-
-#include <QDebug>
-
-StylesComboPreview::StylesComboPreview(QWidget *parent)
- : QLineEdit(parent)
- , m_renamingNewStyle(false)
- , m_shouldAddNewStyle(false)
- , m_addButton(0)
-{
- init();
-}
-
-StylesComboPreview::~StylesComboPreview()
-{
- delete m_addButton;
- m_addButton = 0;
-}
-
-void StylesComboPreview::init()
-{
- setReadOnly(true);
- if (m_addButton) {
- return;
- }
-
- m_addButton = new QPushButton(this);
- m_addButton->setCursor(Qt::ArrowCursor);
- m_addButton->setIcon(koIcon("list-add"));
- m_addButton->setFlat(true);
- m_addButton->setMinimumSize(16, 16);
- m_addButton->setMaximumSize(16, 16);
- m_addButton->setToolTip(i18n("Create a new style with the current properties"));
- connect(m_addButton, SIGNAL(clicked()), this, SLOT(addNewStyle()));
-
- updateAddButton();
-}
-
-void StylesComboPreview::updateAddButton()
-{
- if (!m_addButton) {
- return;
- }
-
- const QSize geom = size();
- const int buttonWidth = m_addButton->size().width();
- m_addButton->move(geom.width() - buttonWidth, (geom.height() - m_addButton->size().height()) / 2);
-}
-
-void StylesComboPreview::setAddButtonShown(bool show)
-{
- m_addButton->setVisible(show);
-}
-
-QSize StylesComboPreview::availableSize() const
-{
- return QSize(contentsRect().width() - m_addButton->width(), contentsRect().height()); ///TODO dynamic resizing when button shown/hidden.
-}
-
-void StylesComboPreview::setPreview(const QImage &image)
-{
- m_stylePreview = image;
-}
-
-bool StylesComboPreview::isAddButtonShown() const
-{
- return m_addButton != 0;
-}
-
-void StylesComboPreview::resizeEvent(QResizeEvent *ev)
-{
- QLineEdit::resizeEvent(ev);
- emit resized();
- updateAddButton();
-}
-
-void StylesComboPreview::keyPressEvent(QKeyEvent *e)
-{
- if (m_shouldAddNewStyle && e->key() == Qt::Key_Escape) {
- m_renamingNewStyle = false;
- m_shouldAddNewStyle = false;
- setReadOnly(true);
- setText(QString());
- e->accept();
- } else if (m_shouldAddNewStyle && (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return)) {
- m_renamingNewStyle = false;
- m_shouldAddNewStyle = false;
- emit newStyleRequested(text());
- setReadOnly(true);
- setText(QString());
- e->accept();
- } else {
- QLineEdit::keyPressEvent(e);
- }
-}
-
-void StylesComboPreview::focusOutEvent(QFocusEvent *e)
-{
- if (e->reason() != Qt::ActiveWindowFocusReason && e->reason() != Qt::PopupFocusReason) {
- if (m_shouldAddNewStyle) {
- m_renamingNewStyle = false;
- m_shouldAddNewStyle = false;
- emit newStyleRequested(text());
- setReadOnly(true);
- setText(QString());
- e->accept();
- }
- setReadOnly(true);
- m_renamingNewStyle = false;
- setText(QString());
- } else {
- QLineEdit::focusOutEvent(e);
- }
-}
-
-void StylesComboPreview::mouseReleaseEvent(QMouseEvent *event)
-{
- Q_UNUSED(event);
- if (!m_renamingNewStyle) {
- emit clicked();
- }
-}
-
-void StylesComboPreview::paintEvent(QPaintEvent *ev)
-{
- if (!m_renamingNewStyle) {
- QLineEdit::paintEvent(ev);
- QPainter p(this);
- p.setClipRect(ev->rect());
- p.drawImage(contentsRect().topLeft(), m_stylePreview);
- } else {
- QLineEdit::paintEvent(ev);
- }
-}
-
-void StylesComboPreview::addNewStyle()
-{
- m_renamingNewStyle = true;
- m_shouldAddNewStyle = true;
- setText(i18n("New style"));
- selectAll();
- setReadOnly(false);
- this->setFocus();
-}
diff --git a/plugins/flake/textshape/dialogs/StylesComboPreview.h b/plugins/flake/textshape/dialogs/StylesComboPreview.h
deleted file mode 100644
index f44a84a0fa..0000000000
--- a/plugins/flake/textshape/dialogs/StylesComboPreview.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- *
- * 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 STYLESCOMBOPREVIEW_H
-#define STYLESCOMBOPREVIEW_H
-
-#include <QLineEdit>
-
-class QImage;
-class QPushButton;
-class QSize;
-class QString;
-
-/** This is an internal class, used for the preview of styles in the main area of the @class StylesCombo. */
-
-class StylesComboPreview : public QLineEdit
-{
- Q_OBJECT
-
- Q_PROPERTY(bool showAddButton READ isAddButtonShown WRITE setAddButtonShown)
-
-public:
- explicit StylesComboPreview(QWidget *parent = 0);
- ~StylesComboPreview() override;
-
- QSize availableSize() const;
- void setAddButtonShown(bool show);
- bool isAddButtonShown() const;
-
- void setPreview(const QImage &image);
-
-Q_SIGNALS:
- void resized();
- void newStyleRequested(const QString &name);
- void clicked();
-
-protected:
- void resizeEvent(QResizeEvent *event) override;
- void keyPressEvent(QKeyEvent *event) override;
- void focusOutEvent(QFocusEvent *) override;
- void mouseReleaseEvent(QMouseEvent *event) override;
- void paintEvent(QPaintEvent *event) override;
-
-private Q_SLOTS:
- void addNewStyle();
-
-private:
- void init();
- void updateAddButton();
-
- bool m_renamingNewStyle;
- bool m_shouldAddNewStyle;
-
- QImage m_stylePreview;
-
- QPushButton *m_addButton;
-};
-
-#endif // STYLESCOMBOPREVIEW_H
diff --git a/plugins/flake/textshape/dialogs/StylesDelegate.cpp b/plugins/flake/textshape/dialogs/StylesDelegate.cpp
deleted file mode 100644
index 3dcf5defd8..0000000000
--- a/plugins/flake/textshape/dialogs/StylesDelegate.cpp
+++ /dev/null
@@ -1,303 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2011-2012 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- *
- * 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 "StylesDelegate.h"
-
-#include "AbstractStylesModel.h"
-
-#include <KoIcon.h>
-
-#include <QAbstractItemView>
-#include <QApplication>
-#include <QColor>
-#include <QEvent>
-#include <QMouseEvent>
-#include <QPainter>
-#include <QPen>
-#include <QRect>
-#include <QScrollBar>
-#include <QStyle>
-#include <QStyleOptionButton>
-#include <QStyleOptionViewItem>
-
-#include <QDebug>
-
-StylesDelegate::StylesDelegate()
- : QStyledItemDelegate()
- , m_editButtonPressed(false)
- , m_deleteButtonPressed(false)
- , m_enableEditButton(true)
-{
- m_buttonSize = 16;
- m_buttonDistance = 2;
-}
-
-void StylesDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optionV1,
- const QModelIndex &index) const
-{
- QStyleOptionViewItem option = optionV1;
- initStyleOption(&option, index);
- if (!index.data(AbstractStylesModel::isTitleRole).toBool()) {
- QStyledItemDelegate::paint(painter, option, index);
-
- //the following is needed to find out if the view has vertical scrollbars. If there is no view just paint and do not attempt to draw the control buttons.
- //this is needed because it seems that the option.rect given does not exclude the vertical scrollBar. This means that we can draw the button in an area that is going to be covered by the vertical scrollBar.
- const QAbstractItemView *view = static_cast<const QAbstractItemView *>(option.widget);
- if (!view) {
- return;
- }
- QScrollBar *scrollBar = view->verticalScrollBar();
- int scrollBarWidth = 0;
- if (scrollBar->isVisible()) {
- scrollBarWidth = scrollBar->width();
- }
-
- if (!index.isValid() || !(option.state & QStyle::State_MouseOver)) {
- return;
- }
- // Delete style button.
- int dx1 = option.rect.width() - qMin(option.rect.height() - 2, m_buttonSize) - m_buttonSize - m_buttonDistance - 2;
- int dy1 = 1 + (option.rect.height() - qMin(option.rect.height(), m_buttonSize)) / 2;
- int dx2 = -m_buttonSize - m_buttonDistance - 2;
- int dy2 = -1 - (option.rect.height() - qMin(option.rect.height(), m_buttonSize)) / 2;
- /* TODO: when we can safely delete styles, re-enable this
- QStyleOptionButton optDel;
- if (!m_deleteButtonPressed) {
- optDel.state |= QStyle::State_Enabled;
- }
- optDel.icon = koIcon("edit-delete");
- optDel.features |= QStyleOptionButton::Flat;
- optDel.rect = option.rect.adjusted(dx1 - scrollBarWidth, dy1, dx2 - scrollBarWidth, dy2);
- view->style()->drawControl(QStyle::CE_PushButton, &optDel, painter, 0);
- */
- // Open style manager dialog button.
- if (!m_enableEditButton) { // when we don't want edit icon
- return;
- }
- dx1 = option.rect.width() - qMin(option.rect.height() - 2, m_buttonSize) - 2;
- dy1 = 1 + (option.rect.height() - qMin(option.rect.height(), m_buttonSize)) / 2;
- dx2 = -2;
- dy2 = -1 - (option.rect.height() - qMin(option.rect.height(), m_buttonSize)) / 2;
- QStyleOptionButton optEdit;
- if (!m_editButtonPressed) {
- optEdit.state |= QStyle::State_Enabled;
- }
- optEdit.icon = koIcon("configure");
- optEdit.features |= QStyleOptionButton::Flat;
- optEdit.rect = option.rect.adjusted(dx1 - scrollBarWidth, dy1, dx2 - scrollBarWidth, dy2);
- view->style()->drawControl(QStyle::CE_PushButton, &optEdit, painter, 0);
- } else {
- const QString category = index.data().toString();
- const QRect optRect = option.rect;
- QFont font(QApplication::font());
- font.setBold(true);
- const QFontMetrics fontMetrics = QFontMetrics(font);
- QColor outlineColor = option.palette.text().color();
- outlineColor.setAlphaF(0.35);
- //BEGIN: top left corner
- {
- painter->save();
- painter->setPen(outlineColor);
- const QPointF topLeft(optRect.topLeft());
- QRectF arc(topLeft, QSizeF(4, 4));
- arc.translate(0.5, 0.5);
- painter->drawArc(arc, 1440, 1440);
- painter->restore();
- }
- //END: top left corner
- //BEGIN: left vertical line
- {
- QPoint start(optRect.topLeft());
- start.ry() += 3;
- QPoint verticalGradBottom(optRect.topLeft());
- verticalGradBottom.ry() += fontMetrics.height() + 5;
- QLinearGradient gradient(start, verticalGradBottom);
- gradient.setColorAt(0, outlineColor);
- gradient.setColorAt(1, Qt::transparent);
- painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient);
- }
- //END: left vertical line
- //BEGIN: horizontal line
- {
- QPoint start(optRect.topLeft());
- start.rx() += 3;
- QPoint horizontalGradTop(optRect.topLeft());
- horizontalGradTop.rx() += optRect.width() - 6;
- painter->fillRect(QRect(start, QSize(optRect.width() - 6, 1)), outlineColor);
- }
- //END: horizontal line
- //BEGIN: top right corner
- {
- painter->save();
- painter->setPen(outlineColor);
- QPointF topRight(optRect.topRight());
- topRight.rx() -= 4;
- QRectF arc(topRight, QSizeF(4, 4));
- arc.translate(0.5, 0.5);
- painter->drawArc(arc, 0, 1440);
- painter->restore();
- }
- //END: top right corner
- //BEGIN: right vertical line
- {
- QPoint start(optRect.topRight());
- start.ry() += 3;
- QPoint verticalGradBottom(optRect.topRight());
- verticalGradBottom.ry() += fontMetrics.height() + 5;
- QLinearGradient gradient(start, verticalGradBottom);
- gradient.setColorAt(0, outlineColor);
- gradient.setColorAt(1, Qt::transparent);
- painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient);
- }
- //END: right vertical line
- //BEGIN: text
- {
- QRect textRect(option.rect);
- textRect.setTop(textRect.top() + 7);
- textRect.setLeft(textRect.left() + 7);
- textRect.setHeight(fontMetrics.height());
- textRect.setRight(textRect.right() - 7);
- painter->save();
- painter->setFont(font);
- QColor penColor(option.palette.text().color());
- penColor.setAlphaF(0.6);
- painter->setPen(penColor);
- painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, category);
- painter->restore();
- }
- //END: text
- }
-}
-
-QSize StylesDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
-{
- Q_UNUSED(option);
- return index.data(Qt::SizeHintRole).toSize();
-}
-
-bool StylesDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &optionV1, const QModelIndex &index)
-{
- Q_UNUSED(model);
- QStyleOptionViewItem option = optionV1;
- initStyleOption(&option, index);
-
- //the following is needed to find out if the view has vertical scrollbars. If not just paint and do not attempt to draw the control buttons.
- //this is needed because it seems that the option.rect given does not exclude the vertical scrollBar. This means that we can draw the button in an area that is going to be covered by the vertical scrollBar.
-
- const QAbstractItemView *view = static_cast<const QAbstractItemView *>(option.widget);
- if (!view) {
- return false;
- }
- QScrollBar *scrollBar = view->verticalScrollBar();
- int scrollBarWidth = 0;
- if (scrollBar->isVisible()) {
- scrollBarWidth = scrollBar->width();
- }
-
- if (event->type() == QEvent::MouseButtonPress) {
- QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
- int dx1 = option.rect.width() - qMin(option.rect.height() - 2, m_buttonSize) - m_buttonSize - m_buttonDistance - 2;
- int dy1 = 1 + (option.rect.height() - qMin(option.rect.height(), m_buttonSize)) / 2;
- int dx2 = - m_buttonSize - m_buttonDistance - 2;
- int dy2 = -1 - (option.rect.height() - qMin(option.rect.height(), m_buttonSize)) / 2;
- /*TODO: when we can safely delete styles, re-enable this
- QRect delRect = option.rect.adjusted(dx1 - scrollBarWidth, dy1, dx2 - scrollBarWidth, dy2);
- if (delRect.contains(mouseEvent->pos())) {
- m_deleteButtonPressed = true;
- }
- else {
- m_deleteButtonPressed = false;
- }
- */
- dx1 = option.rect.width() - qMin(option.rect.height() - 2, m_buttonSize) - 2;
- dy1 = 1 + (option.rect.height() - qMin(option.rect.height(), m_buttonSize)) / 2;
- dx2 = -2;
- dy2 = -1 - (option.rect.height() - qMin(option.rect.height(), m_buttonSize)) / 2;
- QRect editRect = option.rect.adjusted(dx1 - scrollBarWidth, dy1, dx2 - scrollBarWidth, dy2);
- if (editRect.contains(mouseEvent->pos())) {
- m_editButtonPressed = true;
- } else {
- m_editButtonPressed = false;
- }
- emit needsUpdate(index);
- }
- if (event->type() == QEvent::MouseButtonRelease) {
- m_deleteButtonPressed = false;
- m_editButtonPressed = false;
- emit needsUpdate(index);
-
- if (index.flags() == Qt::NoItemFlags) { //if the item is NoItemFlagged, it means it is a separator in the view. In that case, we should not close the combo's drop down.
- return true;
- }
-
- QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
- int dx1 = option.rect.width() - qMin(option.rect.height() - 2, m_buttonSize) - m_buttonSize - m_buttonDistance - 2;
- int dy1 = 1 + (option.rect.height() - qMin(option.rect.height(), m_buttonSize)) / 2;
- int dx2 = - m_buttonSize - m_buttonDistance - 2;
- int dy2 = -1 - (option.rect.height() - qMin(option.rect.height(), m_buttonSize)) / 2;
- /*TODO: when we can safely delete styles, re-enable this
- QRect delRect = option.rect.adjusted(dx1 - scrollBarWidth, dy1, dx2 - scrollBarWidth, dy2);
- if (delRect.contains(mouseEvent->pos())) {
- emit deleteStyleButtonClicked(index);
- return true;
- }
- */
- dx1 = option.rect.width() - qMin(option.rect.height() - 2, m_buttonSize) - 2;
- dy1 = 1 + (option.rect.height() - qMin(option.rect.height(), m_buttonSize)) / 2;
- dx2 = -2;
- dy2 = -1 - (option.rect.height() - qMin(option.rect.height(), m_buttonSize)) / 2;
- QRect editRect = option.rect.adjusted(dx1 - scrollBarWidth, dy1, dx2 - scrollBarWidth, dy2);
- if (editRect.contains(mouseEvent->pos())) {
- emit styleManagerButtonClicked(index);
- return true;
- }
- emit clickedInItem(index);
- return true; //returning true here means the QComboBox mouseRelease code will not get called. The effect of it is that hidePopup will not get called. StylesCombo calls it in the corresponding slot.
- }
- if (event->type() == QEvent::MouseMove) {
- QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
- int dx1 = option.rect.width() - qMin(option.rect.height() - 2, m_buttonSize) - m_buttonSize - m_buttonDistance - 2;
- int dy1 = 1 + (option.rect.height() - qMin(option.rect.height(), m_buttonSize)) / 2;
- int dx2 = - m_buttonSize - m_buttonDistance - 2;
- int dy2 = -1 - (option.rect.height() - qMin(option.rect.height(), m_buttonSize)) / 2;
- /*TODO: when we can safely delete styles, re-enable this
- QRect delRect = option.rect.adjusted(dx1 - scrollBarWidth, dy1, dx2 - scrollBarWidth, dy2);
- if (!delRect.contains(mouseEvent->pos())) {
- m_deleteButtonPressed = false;
- }
- */
- dx1 = option.rect.width() - qMin(option.rect.height() - 2, m_buttonSize) - 2;
- dy1 = 1 + (option.rect.height() - qMin(option.rect.height(), m_buttonSize)) / 2;
- dx2 = -2;
- dy2 = -1 - (option.rect.height() - qMin(option.rect.height(), m_buttonSize)) / 2;
- QRect editRect = option.rect.adjusted(dx1 - scrollBarWidth, dy1, dx2 - scrollBarWidth, dy2);
- if (!editRect.contains(mouseEvent->pos())) {
- m_editButtonPressed = false;
- }
- emit needsUpdate(index);
- return false;
- }
- return false;
-}
-
-void StylesDelegate::setEditButtonEnable(bool enable)
-{
- m_enableEditButton = enable;
-}
diff --git a/plugins/flake/textshape/dialogs/StylesDelegate.h b/plugins/flake/textshape/dialogs/StylesDelegate.h
deleted file mode 100644
index 82b07a72f8..0000000000
--- a/plugins/flake/textshape/dialogs/StylesDelegate.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2011-2012 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- *
- * 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 STYLESDELEGATE_H
-#define STYLESDELEGATE_H
-
-#include <QStyledItemDelegate>
-
-/** This is an internal class, used for the preview of styles in the dropdown of the @class StylesCombo.
- * This class is also responsible for drawing and handling the buttons to call the style manager or to delete a style.
- * NB. Deleting a style is currently not supported, therefore the button has been disabled. */
-
-class StylesDelegate : public QStyledItemDelegate
-{
- Q_OBJECT
-
-public:
- StylesDelegate();
-
- void paint(QPainter *painter, const QStyleOptionViewItem &option,
- const QModelIndex &index) const override;
- QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
-
- bool editorEvent(QEvent *event, QAbstractItemModel *model,
- const QStyleOptionViewItem &option, const QModelIndex &index) override;
- void setEditButtonEnable(bool enable);
-
-Q_SIGNALS:
- void styleManagerButtonClicked(const QModelIndex &index);
- void deleteStyleButtonClicked(const QModelIndex &index);
- void needsUpdate(const QModelIndex &index);
- void clickedInItem(const QModelIndex &index);
-
-private:
- bool m_editButtonPressed;
- bool m_deleteButtonPressed;
- bool m_enableEditButton;
-
- int m_buttonSize;
- int m_buttonDistance;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/StylesFilteredModelBase.cpp b/plugins/flake/textshape/dialogs/StylesFilteredModelBase.cpp
deleted file mode 100644
index 165ad054ae..0000000000
--- a/plugins/flake/textshape/dialogs/StylesFilteredModelBase.cpp
+++ /dev/null
@@ -1,251 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2012 Pierre Stirnweiss <pstirnweiss@googlemail.org>
- *
- * 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 "StylesFilteredModelBase.h"
-
-#include <KoCharacterStyle.h>
-#include <KoParagraphStyle.h>
-
-#include <QDebug>
-
-StylesFilteredModelBase::StylesFilteredModelBase(QObject *parent)
- : AbstractStylesModel(parent)
- , m_sourceModel(0)
-{
-}
-
-QModelIndex StylesFilteredModelBase::index(int row, int column, const QModelIndex &parent) const
-{
- if (row < 0 || column != 0) {
- return QModelIndex();
- }
-
- if (!parent.isValid()) {
- if (row >= m_proxyToSource.count()) {
- return QModelIndex();
- }
- return createIndex(row, column, int(m_sourceModel->index(m_proxyToSource.at(row), 0, QModelIndex()).internalId()));
- }
- return QModelIndex();
-}
-
-QModelIndex StylesFilteredModelBase::parent(const QModelIndex &child) const
-{
- Q_UNUSED(child);
- return QModelIndex();
-}
-
-int StylesFilteredModelBase::columnCount(const QModelIndex &parent) const
-{
- Q_UNUSED(parent);
- return 1;
-}
-
-int StylesFilteredModelBase::rowCount(const QModelIndex &parent) const
-{
- if (!parent.isValid()) {
- return m_proxyToSource.size();
- }
- return 0;
-}
-
-QVariant StylesFilteredModelBase::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid()) {
- return QVariant();
- }
-
- switch (role) {
- case Qt::DisplayRole: {
- return QVariant();
- }
- case Qt::DecorationRole: {
- return m_sourceModel->data(m_sourceModel->index(m_proxyToSource.at(index.row()), 0, QModelIndex()), role);
- break;
- }
- case Qt::SizeHintRole: {
- return QVariant(QSize(250, 48));
- }
- default: break;
- };
- return QVariant();
-}
-
-Qt::ItemFlags StylesFilteredModelBase::flags(const QModelIndex &index) const
-{
- if (!index.isValid()) {
- return 0;
- }
- return (Qt::ItemIsSelectable | Qt::ItemIsEnabled);
-}
-
-void StylesFilteredModelBase::setStyleThumbnailer(KoStyleThumbnailer *thumbnailer)
-{
- Q_UNUSED(thumbnailer);
-}
-
-QModelIndex StylesFilteredModelBase::indexOf(const KoCharacterStyle *style) const
-{
- QModelIndex sourceIndex(m_sourceModel->indexOf(style));
-
- if (!style || !sourceIndex.isValid() || m_sourceToProxy.at(sourceIndex.row()) < 0) {
- return QModelIndex();
- }
- return createIndex(m_sourceToProxy.at(sourceIndex.row()), 0, style->styleId());
-}
-
-QImage StylesFilteredModelBase::stylePreview(int row, const QSize &size)
-{
- if (row < 0) {
- return QImage();
- }
- return m_sourceModel->stylePreview(m_proxyToSource.at(row), size);
-
-}
-/*
-QImage StylesFilteredModelBase::stylePreview(QModelIndex &index, const QSize &size)
-{
- if (!index.isValid()) {
- return QImage();
- }
- return m_sourceModel->stylePreview(index, size); //TODO be careful there. this is assuming the sourceModel is only using the internalId, and the index's internalId matches the model's
-
-}
-*/
-void StylesFilteredModelBase::setStylesModel(AbstractStylesModel *sourceModel)
-{
- if (m_sourceModel == sourceModel) {
- return;
- }
- if (m_sourceModel) {
- disconnect(m_sourceModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(rowsAboutToBeInserted(QModelIndex,int,int)));
- disconnect(m_sourceModel, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
- disconnect(m_sourceModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
- disconnect(m_sourceModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowsInserted(QModelIndex,int,int)));
- disconnect(m_sourceModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(rowsMoved(QModelIndex,int,int,QModelIndex,int)));
- disconnect(m_sourceModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(rowsRemoved(QModelIndex,int,int)));
- disconnect(m_sourceModel, SIGNAL(modelAboutToBeReset()), this, SLOT(modelAboutToBeReset()));
- disconnect(m_sourceModel, SIGNAL(modelReset()), this, SLOT(modelReset()));
- }
-
- m_sourceModel = sourceModel;
- connect(m_sourceModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(rowsAboutToBeInserted(QModelIndex,int,int)));
- connect(m_sourceModel, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
- connect(m_sourceModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
- connect(m_sourceModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowsInserted(QModelIndex,int,int)));
- connect(m_sourceModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(rowsMoved(QModelIndex,int,int,QModelIndex,int)));
- connect(m_sourceModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(rowsRemoved(QModelIndex,int,int)));
- connect(m_sourceModel, SIGNAL(modelAboutToBeReset()), this, SLOT(modelAboutToBeReset()));
- connect(m_sourceModel, SIGNAL(modelReset()), this, SLOT(modelReset()));
-
- beginResetModel();
- createMapping();
- endResetModel();
-}
-
-AbstractStylesModel::Type StylesFilteredModelBase::stylesType() const
-{
- Q_ASSERT(m_sourceModel);
- return m_sourceModel->stylesType();
-}
-
-void StylesFilteredModelBase::modelAboutToBeReset()
-{
- beginResetModel();
-}
-
-void StylesFilteredModelBase::modelReset()
-{
- createMapping();
- endResetModel();
-}
-
-void StylesFilteredModelBase::rowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
-{
- Q_UNUSED(parent);
- Q_UNUSED(start);
- Q_UNUSED(end);
- beginResetModel(); //TODO instead of resetting the whole thing, implement proper logic. this will do for a start, there shouldn't be too many styles anyway
-}
-
-void StylesFilteredModelBase::rowsInserted(const QModelIndex &parent, int start, int end)
-{
- Q_UNUSED(parent);
- Q_UNUSED(start);
- Q_UNUSED(end);
- createMapping();
- endResetModel();
-}
-
-void StylesFilteredModelBase::rowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
-{
- Q_UNUSED(sourceParent);
- Q_UNUSED(sourceStart);
- Q_UNUSED(sourceEnd);
- Q_UNUSED(destinationParent);
- Q_UNUSED(destinationRow);
- beginResetModel(); //TODO instead of resetting the whole thing, implement proper logic. this will do for a start, there shouldn't be too many styles anyway
-}
-
-void StylesFilteredModelBase::rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
-{
- Q_UNUSED(sourceParent);
- Q_UNUSED(sourceStart);
- Q_UNUSED(sourceEnd);
- Q_UNUSED(destinationParent);
- Q_UNUSED(destinationRow);
- createMapping();
- endResetModel();
-}
-
-void StylesFilteredModelBase::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
-{
- Q_UNUSED(parent);
- Q_UNUSED(start);
- Q_UNUSED(end);
- beginResetModel(); //TODO instead of resetting the whole thing, implement proper logic. this will do for a start, there shouldn't be too many styles anyway
-}
-
-void StylesFilteredModelBase::rowsRemoved(const QModelIndex &parent, int start, int end)
-{
- Q_UNUSED(parent);
- Q_UNUSED(start);
- Q_UNUSED(end);
- createMapping();
- endResetModel();
-}
-
-void StylesFilteredModelBase::createMapping()
-{
- Q_ASSERT(m_sourceModel);
- if (!m_sourceModel) {
- return;
- }
- m_sourceToProxy.clear();
- m_proxyToSource.clear();
-
- for (int i = 0; i < m_sourceModel->rowCount(QModelIndex()); ++i) {
- m_proxyToSource.append(i);
- }
-
- m_sourceToProxy.fill(-1, m_sourceModel->rowCount(QModelIndex()));
- for (int i = 0; i < m_proxyToSource.count(); ++i) {
- m_sourceToProxy[m_proxyToSource.at(i)] = i;
- }
-}
diff --git a/plugins/flake/textshape/dialogs/StylesFilteredModelBase.h b/plugins/flake/textshape/dialogs/StylesFilteredModelBase.h
deleted file mode 100644
index 8ae4b56a81..0000000000
--- a/plugins/flake/textshape/dialogs/StylesFilteredModelBase.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2012 Pierre Stirnweiss <pstirnweiss@googlemail.org>
- *
- * 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 STYLESFILTEREDMODELBASE_H
-#define STYLESFILTEREDMODELBASE_H
-
-#include "AbstractStylesModel.h"
-
-#include <QVector>
-
-/** This class serves as a base for filtering an @class AbstractStylesmodel. The base class implements a one to one mapping of the model.
- * Reimplementing the method createMapping is sufficient for basic sorting/filtering.
- *
- * QSortFilterProxyModel implementation was a great source of inspiration.
- *
- * It is to be noted that this is in no way a full proxyModel. It is built with several assumptions:
- * - it is used to filter a StylesModel which in turn is a flat list of items. There is only one level of items. (this also means that "parent" QModelIndexes are always invalid)
- * - there is no header in the model.
- * - the model has only one column
- * - only the following methods are used when updating the underlying model's data: resetModel, insertRows, moveRows, removeRows (cf QAbstractItemModel)
-*/
-
-class StylesFilteredModelBase : public AbstractStylesModel
-{
- Q_OBJECT
-public:
- explicit StylesFilteredModelBase(QObject *parent = 0);
-
- /** Re-implement from QAbstractItemModel. */
-
- QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const override;
-
- QModelIndex parent(const QModelIndex &child) const override;
-
- int columnCount(const QModelIndex &parent) const override;
-
- int rowCount(const QModelIndex &parent) const override;
-
- QVariant data(const QModelIndex &index, int role) const override;
-
- Qt::ItemFlags flags(const QModelIndex &index) const override;
-
- /** Specific methods of the AbstractStylesModel */
-
- /** Sets the @class KoStyleThumbnailer of the model. It is required that a @param thumbnailer is set before using the model. */
- void setStyleThumbnailer(KoStyleThumbnailer *thumbnailer) override;
-
- /** Return a @class QModelIndex for the specified @param style.
- * @param style may be either a character or paragraph style.
- */
- QModelIndex indexOf(const KoCharacterStyle *style) const override;
-
- /** Returns a QImage which is a preview of the style specified by @param row of the given @param size.
- * If size isn't specified, the default size of the given @class KoStyleThumbnailer is used.
- */
- QImage stylePreview(int row, const QSize &size = QSize()) override;
-// virtual QImage stylePreview(QModelIndex &index, const QSize &size = QSize());
-
- AbstractStylesModel::Type stylesType() const override;
-
- /** Specific methods of the StylesFiltermodelBase */
-
- /** Sets the sourceModel. Setting the model will trigger the mapping.
- */
- void setStylesModel(AbstractStylesModel *sourceModel);
-
-protected Q_SLOTS:
- void modelAboutToBeReset();
- void modelReset();
- void rowsAboutToBeInserted(const QModelIndex &parent, int start, int end);
- void rowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow);
- void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
- void rowsInserted(const QModelIndex &parent, int start, int end);
- void rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow);
- void rowsRemoved(const QModelIndex &parent, int start, int end);
-
-protected:
- virtual void createMapping();
-
- AbstractStylesModel *m_sourceModel;
-
- QVector<int> m_sourceToProxy;
- QVector<int> m_proxyToSource;
-};
-
-#endif // STYLESFILTEREDMODELBASE_H
diff --git a/plugins/flake/textshape/dialogs/StylesManagerModel.cpp b/plugins/flake/textshape/dialogs/StylesManagerModel.cpp
deleted file mode 100644
index 02853064e4..0000000000
--- a/plugins/flake/textshape/dialogs/StylesManagerModel.cpp
+++ /dev/null
@@ -1,140 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2013 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 "StylesManagerModel.h"
-
-#include <KoCharacterStyle.h>
-#include <KoStyleThumbnailer.h>
-
-#include <QDebug>
-
-StylesManagerModel::StylesManagerModel(QObject *parent)
- : QAbstractListModel(parent)
- , m_styleThumbnailer(0)
-{
-}
-
-QVariant StylesManagerModel::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid()) {
- return QVariant();
- }
-
- int row = index.row();
- if (row < 0 || row >= m_styles.size()) {
- return QVariant();
- }
- //qDebug() << Q_FUNC_INFO << row << role;
-
- QVariant retval;
- switch (role) {
- case Qt::DisplayRole:
- retval = m_styles[row]->name();
- break;
- case Qt::DecorationRole:
- if (!m_styleThumbnailer) {
- retval = QPixmap();
- } else {
- retval = m_styleThumbnailer->thumbnail(m_styles[row]);
- }
- break;
- case StylePointer:
- retval = QVariant::fromValue(m_styles[row]);
- break;
- case Qt::SizeHintRole:
- retval = QVariant(QSize(250, 48));
- break;
- default:
- break;
- };
- return retval;
-}
-
-int StylesManagerModel::rowCount(const QModelIndex &parent) const
-{
- Q_UNUSED(parent);
- return m_styles.size();
-}
-
-void StylesManagerModel::setStyleThumbnailer(KoStyleThumbnailer *thumbnailer)
-{
- m_styleThumbnailer = thumbnailer;
-}
-
-void StylesManagerModel::setStyles(const QList<KoCharacterStyle *> &styles)
-{
- beginResetModel();
- m_styles = styles;
- endResetModel();
-}
-
-void StylesManagerModel::addStyle(KoCharacterStyle *style)
-{
- if (m_styles.indexOf(style) == -1) {
- beginInsertRows(QModelIndex(), m_styles.size(), m_styles.size());
- m_styles.append(style);
- endInsertRows();
- }
-}
-
-void StylesManagerModel::removeStyle(KoCharacterStyle *style)
-{
- int row = m_styles.indexOf(style);
- Q_ASSERT(row != -1);
- if (row != -1) {
- beginRemoveRows(QModelIndex(), row, row);
- m_styles.removeAt(row);
- endRemoveRows();
- }
-}
-
-void StylesManagerModel::replaceStyle(KoCharacterStyle *oldStyle, KoCharacterStyle *newStyle)
-{
- qDebug() << Q_FUNC_INFO << oldStyle << "->" << newStyle;
- int row = m_styles.indexOf(oldStyle);
- Q_ASSERT(row != -1);
- if (row != -1) {
- m_styles[row] = newStyle;
- QModelIndex index = this->index(row);
- emit dataChanged(index, index);
- }
-}
-
-void StylesManagerModel::updateStyle(KoCharacterStyle *style)
-{
- int row = m_styles.indexOf(style);
- Q_ASSERT(row != -1);
- if (row != -1) {
- qDebug() << Q_FUNC_INFO << style << style->name();
- m_styleThumbnailer->removeFromCache(style);
- QModelIndex index = this->index(row);
- emit dataChanged(index, index);
- }
-}
-
-QModelIndex StylesManagerModel::styleIndex(KoCharacterStyle *style)
-{
- QModelIndex index;
- int row = m_styles.indexOf(style);
- if (row != -1) {
- index = this->index(row);
- }
- return index;
-}
-
diff --git a/plugins/flake/textshape/dialogs/StylesManagerModel.h b/plugins/flake/textshape/dialogs/StylesManagerModel.h
deleted file mode 100644
index 6d585bb3ae..0000000000
--- a/plugins/flake/textshape/dialogs/StylesManagerModel.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2013 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 STYLESMODELNEW_H
-#define STYLESMODELNEW_H
-
-#include <QAbstractListModel>
-#include <QList>
-
-class KoCharacterStyle;
-class KoStyleThumbnailer;
-
-class StylesManagerModel : public QAbstractListModel
-{
-public:
- enum Roles {
- StylePointer = Qt::UserRole + 1,
- };
-
- explicit StylesManagerModel(QObject *parent = 0);
-
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
- int rowCount(const QModelIndex &parent = QModelIndex()) const override;
-
- void setStyleThumbnailer(KoStyleThumbnailer *thumbnailer);
- void setStyles(const QList<KoCharacterStyle *> &styles);
- void addStyle(KoCharacterStyle *style);
- void removeStyle(KoCharacterStyle *style);
- void replaceStyle(KoCharacterStyle *oldStyle, KoCharacterStyle *newStyle);
- void updateStyle(KoCharacterStyle *style);
-
- QModelIndex styleIndex(KoCharacterStyle *style);
-
-private:
- QList<KoCharacterStyle *> m_styles;
- KoStyleThumbnailer *m_styleThumbnailer;
-};
-
-#endif /* STYLESMODELNEW_H */
diff --git a/plugins/flake/textshape/dialogs/StylesModel.cpp b/plugins/flake/textshape/dialogs/StylesModel.cpp
deleted file mode 100644
index b678f6e126..0000000000
--- a/plugins/flake/textshape/dialogs/StylesModel.cpp
+++ /dev/null
@@ -1,584 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Thomas Zander <zander@kde.org>
- * Copyright (C) 2011 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2011-2012 Pierre Stirnweiss <pstirnweiss@googlemail.org>
- *
- * 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 "StylesModel.h"
-
-#include <KoStyleThumbnailer.h>
-#include <KoStyleManager.h>
-#include <KoParagraphStyle.h>
-#include <KoCharacterStyle.h>
-
-#include <QImage>
-#include <QList>
-#include <QSharedPointer>
-#include <KisSignalMapper.h>
-#include <QCollator>
-
-#include <klocalizedstring.h>
-#include <QDebug>
-
-StylesModel::StylesModel(KoStyleManager *manager, AbstractStylesModel::Type modelType, QObject *parent)
- : AbstractStylesModel(parent)
- , m_styleManager(0)
- , m_currentParagraphStyle(0)
- , m_defaultCharacterStyle(0)
- , m_styleMapper(new KisSignalMapper(this))
- , m_provideStyleNone(false)
-{
- m_modelType = modelType;
- setStyleManager(manager);
- //Create a default characterStyle for the preview of "None" character style
- if (m_modelType == StylesModel::CharacterStyle) {
- m_defaultCharacterStyle = new KoCharacterStyle();
- m_defaultCharacterStyle->setStyleId(NoneStyleId);
- m_defaultCharacterStyle->setName(i18n("None"));
- m_defaultCharacterStyle->setFontPointSize(12);
-
- m_provideStyleNone = true;
- }
-
- connect(m_styleMapper, SIGNAL(mapped(int)), this, SLOT(updateName(int)));
-}
-
-StylesModel::~StylesModel()
-{
- delete m_currentParagraphStyle;
- delete m_defaultCharacterStyle;
-}
-
-QModelIndex StylesModel::index(int row, int column, const QModelIndex &parent) const
-{
- if (row < 0 || column != 0) {
- return QModelIndex();
- }
-
- if (!parent.isValid()) {
- if (row >= m_styleList.count()) {
- return QModelIndex();
- }
- return createIndex(row, column, m_styleList[row]);
- }
- return QModelIndex();
-}
-
-QModelIndex StylesModel::parent(const QModelIndex &child) const
-{
- Q_UNUSED(child);
- return QModelIndex();
-}
-
-int StylesModel::rowCount(const QModelIndex &parent) const
-{
- if (!parent.isValid()) {
- return m_styleList.count();
- }
- return 0;
-}
-
-int StylesModel::columnCount(const QModelIndex &parent) const
-{
- Q_UNUSED(parent);
- return 1;
-}
-
-QVariant StylesModel::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid()) {
- return QVariant();
- }
-
- int id = (int)index.internalId();
- switch (role) {
- case Qt::DisplayRole: {
- return QVariant();
- }
- case Qt::DecorationRole: {
- if (!m_styleThumbnailer) {
- return QPixmap();
- }
- if (m_modelType == StylesModel::ParagraphStyle) {
- KoParagraphStyle *paragStyle = m_styleManager->paragraphStyle(id);
- if (paragStyle) {
- return m_styleThumbnailer->thumbnail(paragStyle);
- }
- if (!paragStyle && m_draftParStyleList.contains(id)) {
- return m_styleThumbnailer->thumbnail(m_draftParStyleList[id]);
- }
- } else {
- KoCharacterStyle *usedStyle = 0;
- if (id == NoneStyleId) {
- usedStyle = static_cast<KoCharacterStyle *>(m_currentParagraphStyle);
- if (!usedStyle) {
- usedStyle = m_defaultCharacterStyle;
- }
- usedStyle->setName(i18n("None"));
- if (usedStyle->styleId() >= 0) { //if the styleId is NoneStyleId, we are using the default character style
- usedStyle->setStyleId(-usedStyle->styleId()); //this style is not managed by the styleManager but its styleId will be used in the thumbnail cache as part of the key.
- }
- return m_styleThumbnailer->thumbnail(usedStyle);
- } else {
- usedStyle = m_styleManager->characterStyle(id);
- if (usedStyle) {
- return m_styleThumbnailer->thumbnail(usedStyle, m_currentParagraphStyle);
- }
- if (!usedStyle && m_draftCharStyleList.contains(id)) {
- return m_styleThumbnailer->thumbnail(m_draftCharStyleList[id]);
- }
- }
- }
- break;
- }
- case Qt::SizeHintRole: {
- return QVariant(QSize(250, 48));
- }
- default: break;
- };
- return QVariant();
-}
-
-Qt::ItemFlags StylesModel::flags(const QModelIndex &index) const
-{
- if (!index.isValid()) {
- return 0;
- }
- return (Qt::ItemIsSelectable | Qt::ItemIsEnabled);
-}
-
-void StylesModel::setCurrentParagraphStyle(int styleId)
-{
- if (!m_styleManager || m_currentParagraphStyle == m_styleManager->paragraphStyle(styleId) || !m_styleManager->paragraphStyle(styleId)) {
- return; //TODO do we create a default paragraphStyle? use the styleManager default?
- }
- if (m_currentParagraphStyle) {
- delete m_currentParagraphStyle;
- m_currentParagraphStyle = 0;
- }
- m_currentParagraphStyle = m_styleManager->paragraphStyle(styleId)->clone();
-}
-
-void StylesModel::setProvideStyleNone(bool provide)
-{
- if (m_modelType == StylesModel::CharacterStyle) {
- m_provideStyleNone = provide;
- }
-}
-
-QModelIndex StylesModel::indexOf(const KoCharacterStyle *style) const
-{
- if (style) {
- return createIndex(m_styleList.indexOf(style->styleId()), 0, style->styleId());
- }
- else {
- return QModelIndex();
- }
-}
-
-QImage StylesModel::stylePreview(int row, const QSize &size)
-{
- if (!m_styleManager || !m_styleThumbnailer) {
- return QImage();
- }
- if (m_modelType == StylesModel::ParagraphStyle) {
- KoParagraphStyle *usedStyle = 0;
- usedStyle = m_styleManager->paragraphStyle(index(row).internalId());
- if (usedStyle) {
- return m_styleThumbnailer->thumbnail(usedStyle, size);
- }
- if (!usedStyle && m_draftParStyleList.contains(index(row).internalId())) {
- return m_styleThumbnailer->thumbnail(m_draftParStyleList[index(row).internalId()], size);
- }
- } else {
- KoCharacterStyle *usedStyle = 0;
- if (index(row).internalId() == (quintptr)NoneStyleId) {
- usedStyle = static_cast<KoCharacterStyle *>(m_currentParagraphStyle);
- if (!usedStyle) {
- usedStyle = m_defaultCharacterStyle;
- }
- usedStyle->setName(i18n("None"));
- if (usedStyle->styleId() >= 0) {
- usedStyle->setStyleId(-usedStyle->styleId()); //this style is not managed by the styleManager but its styleId will be used in the thumbnail cache as part of the key.
- }
- return m_styleThumbnailer->thumbnail(usedStyle, m_currentParagraphStyle, size);
- } else {
- usedStyle = m_styleManager->characterStyle(index(row).internalId());
- if (usedStyle) {
- return m_styleThumbnailer->thumbnail(usedStyle, m_currentParagraphStyle, size);
- }
- if (!usedStyle && m_draftCharStyleList.contains(index(row).internalId())) {
- return m_styleThumbnailer->thumbnail(m_draftCharStyleList[index(row).internalId()], m_currentParagraphStyle, size);
- }
- }
- }
- return QImage();
-}
-/*
-QImage StylesModel::stylePreview(QModelIndex &index, const QSize &size)
-{
- if (!m_styleManager || !m_styleThumbnailer) {
- return QImage();
- }
- if (m_modelType == StylesModel::ParagraphStyle) {
- KoParagraphStyle *usedStyle = 0;
- usedStyle = m_styleManager->paragraphStyle(index.internalId());
- if (usedStyle) {
- return m_styleThumbnailer->thumbnail(usedStyle, size);
- }
- if (!usedStyle && m_draftParStyleList.contains(index.internalId())) {
- return m_styleThumbnailer->thumbnail(m_draftParStyleList[index.internalId()], size);
- }
- }
- else {
- KoCharacterStyle *usedStyle = 0;
- if (index.internalId() == NoneStyleId) {
- usedStyle = static_cast<KoCharacterStyle*>(m_currentParagraphStyle);
- if (!usedStyle) {
- usedStyle = m_defaultCharacterStyle;
- }
- usedStyle->setName(i18n("None"));
- if (usedStyle->styleId() >= 0) {
- usedStyle->setStyleId(-usedStyle->styleId()); //this style is not managed by the styleManager but its styleId will be used in the thumbnail cache as part of the key.
- }
- return m_styleThumbnailer->thumbnail(usedStyle, m_currentParagraphStyle, size);
- }
- else {
- usedStyle = m_styleManager->characterStyle(index.internalId());
- if (usedStyle) {
- return m_styleThumbnailer->thumbnail(usedStyle, m_currentParagraphStyle, size);
- }
- if (!usedStyle && m_draftCharStyleList.contains(index.internalId())) {
- return m_styleThumbnailer->thumbnail(m_draftCharStyleList[index.internalId()],m_currentParagraphStyle, size);
- }
- }
- }
- return QImage();
-}
-*/
-void StylesModel::setStyleManager(KoStyleManager *sm)
-{
- if (sm == m_styleManager) {
- return;
- }
- if (m_styleManager) {
- disconnect(sm, SIGNAL(styleAdded(KoParagraphStyle*)), this, SLOT(addParagraphStyle(KoParagraphStyle*)));
- disconnect(sm, SIGNAL(styleAdded(KoCharacterStyle*)), this, SLOT(addCharacterStyle(KoCharacterStyle*)));
- disconnect(sm, SIGNAL(styleRemoved(KoParagraphStyle*)), this, SLOT(removeParagraphStyle(KoParagraphStyle*)));
- disconnect(sm, SIGNAL(styleRemoved(KoCharacterStyle*)), this, SLOT(removeCharacterStyle(KoCharacterStyle*)));
- }
- m_styleManager = sm;
- if (m_styleManager == 0) {
- return;
- }
-
- if (m_modelType == StylesModel::ParagraphStyle) {
- updateParagraphStyles();
- connect(sm, SIGNAL(styleAdded(KoParagraphStyle*)), this, SLOT(addParagraphStyle(KoParagraphStyle*)));
- connect(sm, SIGNAL(styleRemoved(KoParagraphStyle*)), this, SLOT(removeParagraphStyle(KoParagraphStyle*)));
- } else {
- updateCharacterStyles();
- connect(sm, SIGNAL(styleAdded(KoCharacterStyle*)), this, SLOT(addCharacterStyle(KoCharacterStyle*)));
- connect(sm, SIGNAL(styleRemoved(KoCharacterStyle*)), this, SLOT(removeCharacterStyle(KoCharacterStyle*)));
- }
-}
-
-void StylesModel::setStyleThumbnailer(KoStyleThumbnailer *thumbnailer)
-{
- m_styleThumbnailer = thumbnailer;
-}
-
-// called when the stylemanager adds a style
-void StylesModel::addParagraphStyle(KoParagraphStyle *style)
-{
- Q_ASSERT(style);
- QCollator collator;
- QList<int>::iterator begin = m_styleList.begin();
- int index = 0;
- for (; begin != m_styleList.end(); ++begin) {
- KoParagraphStyle *s = m_styleManager->paragraphStyle(*begin);
- if (!s && m_draftParStyleList.contains(*begin)) {
- s = m_draftParStyleList[*begin];
- }
- // s should be found as the manager and the m_styleList should be in sync
- Q_ASSERT(s);
- if (collator.compare(style->name(), s->name()) < 0) {
- break;
- }
- ++index;
- }
- beginInsertRows(QModelIndex(), index, index);
- m_styleList.insert(begin, style->styleId());
- m_styleMapper->setMapping(style, style->styleId());
- connect(style, SIGNAL(nameChanged(QString)), m_styleMapper, SLOT(map()));
- endInsertRows();
-}
-
-bool sortParagraphStyleByName(KoParagraphStyle *style1, KoParagraphStyle *style2)
-{
- Q_ASSERT(style1);
- Q_ASSERT(style2);
- return QCollator().compare(style1->name(), style2->name()) < 0;
-}
-
-void StylesModel::updateParagraphStyles()
-{
- Q_ASSERT(m_styleManager);
-
- beginResetModel();
- m_styleList.clear();
-
- QList<KoParagraphStyle *> styles = m_styleManager->paragraphStyles();
- std::sort(styles.begin(), styles.end(), sortParagraphStyleByName);
-
- Q_FOREACH (KoParagraphStyle *style, styles) {
- if (style != m_styleManager->defaultParagraphStyle()) { //The default character style is not user selectable. It only provides individual property defaults and is not a style per say.
- m_styleList.append(style->styleId());
- m_styleMapper->setMapping(style, style->styleId());
- connect(style, SIGNAL(nameChanged(QString)), m_styleMapper, SLOT(map()));
- }
- }
-
- endResetModel();
-}
-
-// called when the stylemanager adds a style
-void StylesModel::addCharacterStyle(KoCharacterStyle *style)
-{
- Q_ASSERT(style);
- // find the place where we need to insert the style
- QCollator collator;
- QList<int>::iterator begin = m_styleList.begin();
- int index = 0;
- // the None style should also be the first one so only start after it
- if (begin != m_styleList.end() && *begin == NoneStyleId) {
- ++begin;
- ++index;
- }
- for (; begin != m_styleList.end(); ++begin) {
- KoCharacterStyle *s = m_styleManager->characterStyle(*begin);
- if (!s && m_draftCharStyleList.contains(*begin)) {
- s = m_draftCharStyleList[*begin];
- }
- // s should be found as the manager and the m_styleList should be in sync
- Q_ASSERT(s);
- if (collator.compare(style->name(), s->name()) < 0) {
- break;
- }
- ++index;
- }
- beginInsertRows(QModelIndex(), index, index);
- m_styleList.insert(index, style->styleId());
- endInsertRows();
- m_styleMapper->setMapping(style, style->styleId());
- connect(style, SIGNAL(nameChanged(QString)), m_styleMapper, SLOT(map()));
-}
-
-bool sortCharacterStyleByName(KoCharacterStyle *style1, KoCharacterStyle *style2)
-{
- Q_ASSERT(style1);
- Q_ASSERT(style2);
- return QCollator().compare(style1->name(), style2->name()) < 0;
-}
-
-void StylesModel::updateCharacterStyles()
-{
- Q_ASSERT(m_styleManager);
-
- beginResetModel();
- m_styleList.clear();
-
- if (m_provideStyleNone && m_styleManager->paragraphStyles().count()) {
- m_styleList.append(NoneStyleId);
- }
-
- QList<KoCharacterStyle *> styles = m_styleManager->characterStyles();
- std::sort(styles.begin(), styles.end(), sortCharacterStyleByName);
-
- Q_FOREACH (KoCharacterStyle *style, styles) {
- if (style != m_styleManager->defaultCharacterStyle()) { //The default character style is not user selectable. It only provides individual property defaults and is not a style per say.
- m_styleList.append(style->styleId());
- m_styleMapper->setMapping(style, style->styleId());
- connect(style, SIGNAL(nameChanged(QString)), m_styleMapper, SLOT(map()));
- }
- }
-
- endResetModel();
-}
-
-// called when the stylemanager removes a style
-void StylesModel::removeParagraphStyle(KoParagraphStyle *style)
-{
- int row = m_styleList.indexOf(style->styleId());
- beginRemoveRows(QModelIndex(), row, row);
- m_styleMapper->removeMappings(style);
- disconnect(style, SIGNAL(nameChanged(QString)), m_styleMapper, SLOT(map()));
- m_styleList.removeAt(row);
- endRemoveRows();
-}
-
-// called when the stylemanager removes a style
-void StylesModel::removeCharacterStyle(KoCharacterStyle *style)
-{
- int row = m_styleList.indexOf(style->styleId());
- beginRemoveRows(QModelIndex(), row, row);
- m_styleMapper->removeMappings(style);
- disconnect(style, SIGNAL(nameChanged(QString)), m_styleMapper, SLOT(map()));
- m_styleList.removeAt(row);
- endRemoveRows();
-}
-
-void StylesModel::updateName(int styleId)
-{
- // updating the name of a style can mean that the style needs to be moved inside the list to keep the sort order.
- QCollator collator;
- int oldIndex = m_styleList.indexOf(styleId);
- if (oldIndex >= 0) {
- int newIndex = 0;
- if (m_modelType == StylesModel::ParagraphStyle) {
- KoParagraphStyle *paragStyle = m_styleManager->paragraphStyle(styleId);
- if (!paragStyle && m_draftParStyleList.contains(styleId)) {
- paragStyle = m_draftParStyleList.value(styleId);
- }
- if (paragStyle) {
- m_styleThumbnailer->removeFromCache(paragStyle);
-
- QList<int>::iterator begin = m_styleList.begin();
- for (; begin != m_styleList.end(); ++begin) {
- // don't test again the same style
- if (*begin == styleId) {
- continue;
- }
- KoParagraphStyle *s = m_styleManager->paragraphStyle(*begin);
- if (!s && m_draftParStyleList.contains(*begin)) {
- s = m_draftParStyleList[*begin];
- }
- // s should be found as the manager and the m_styleList should be in sync
- Q_ASSERT(s);
- if (collator.compare(paragStyle->name(), s->name()) < 0) {
- break;
- }
- ++newIndex;
- }
- if (oldIndex != newIndex) {
- // beginMoveRows needs the index where it would be placed when it is still in the old position
- // so add one when newIndex > oldIndex
- beginMoveRows(QModelIndex(), oldIndex, oldIndex, QModelIndex(), newIndex > oldIndex ? newIndex + 1 : newIndex);
- m_styleList.removeAt(oldIndex);
- m_styleList.insert(newIndex, styleId);
- endMoveRows();
- }
- }
- } else {
- KoCharacterStyle *characterStyle = m_styleManager->characterStyle(styleId);
- if (!characterStyle && m_draftCharStyleList.contains(styleId)) {
- characterStyle = m_draftCharStyleList[styleId];
- }
- if (characterStyle) {
- m_styleThumbnailer->removeFromCache(characterStyle);
-
- QList<int>::iterator begin = m_styleList.begin();
- if (begin != m_styleList.end() && *begin == NoneStyleId) {
- ++begin;
- ++newIndex;
- }
- for (; begin != m_styleList.end(); ++begin) {
- // don't test again the same style
- if (*begin == styleId) {
- continue;
- }
- KoCharacterStyle *s = m_styleManager->characterStyle(*begin);
- if (!s && m_draftCharStyleList.contains(*begin)) {
- s = m_draftCharStyleList[*begin];
- }
- // s should be found as the manager and the m_styleList should be in sync
- Q_ASSERT(s);
- if (collator.compare(characterStyle->name(), s->name()) < 0) {
- break;
- }
- ++newIndex;
- }
- if (oldIndex != newIndex) {
- // beginMoveRows needs the index where it would be placed when it is still in the old position
- // so add one when newIndex > oldIndex
- beginMoveRows(QModelIndex(), oldIndex, oldIndex, QModelIndex(), newIndex > oldIndex ? newIndex + 1 : newIndex);
- m_styleList.removeAt(oldIndex);
- m_styleList.insert(newIndex, styleId);
- endMoveRows();
- }
- }
- }
- }
-}
-
-QModelIndex StylesModel::firstStyleIndex()
-{
- if (!m_styleList.count()) {
- return QModelIndex();
- }
- return createIndex(m_styleList.indexOf(m_styleList.at(0)), 0, m_styleList.at(0));
-}
-
-QList<int> StylesModel::StyleList()
-{
- return m_styleList;
-}
-
-QHash<int, KoParagraphStyle *> StylesModel::draftParStyleList()
-{
- return m_draftParStyleList;
-}
-
-QHash<int, KoCharacterStyle *> StylesModel::draftCharStyleList()
-{
- return m_draftCharStyleList;
-}
-
-void StylesModel::addDraftParagraphStyle(KoParagraphStyle *style)
-{
- style->setStyleId(-(m_draftParStyleList.count() + 1));
- m_draftParStyleList.insert(style->styleId(), style);
- addParagraphStyle(style);
-}
-
-void StylesModel::addDraftCharacterStyle(KoCharacterStyle *style)
-{
- if (m_draftCharStyleList.count() == 0) { // we have a character style "m_defaultCharacterStyle" with style id NoneStyleId in style model.
- style->setStyleId(-(m_draftCharStyleList.count() + 2));
- } else {
- style->setStyleId(-(m_draftCharStyleList.count() + 1));
- }
- m_draftCharStyleList.insert(style->styleId(), style);
- addCharacterStyle(style);
-}
-
-void StylesModel::clearDraftStyles()
-{
- Q_FOREACH (KoParagraphStyle *style, m_draftParStyleList.values()) {
- removeParagraphStyle(style);
- }
- m_draftParStyleList.clear();
- Q_FOREACH (KoCharacterStyle *style, m_draftCharStyleList.values()) {
- removeCharacterStyle(style);
- }
- m_draftCharStyleList.clear();
-}
-
-StylesModel::Type StylesModel::stylesType() const
-{
- return m_modelType;
-}
diff --git a/plugins/flake/textshape/dialogs/StylesModel.h b/plugins/flake/textshape/dialogs/StylesModel.h
deleted file mode 100644
index 3b9d9086c9..0000000000
--- a/plugins/flake/textshape/dialogs/StylesModel.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Thomas Zander <zander@kde.org>
- * Copyright (C) 2011 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2011-2012 Pierre Stirnweiss <pstirnweiss@googlemail.org>
- *
- * 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 MODEL_H
-#define MODEL_H
-
-#include "AbstractStylesModel.h"
-
-#include <QAbstractListModel>
-
-#include <QSize>
-
-class KoStyleThumbnailer;
-
-class KoStyleManager;
-class KoParagraphStyle;
-class KoCharacterStyle;
-
-class QImage;
-class KisSignalMapper;
-
-/** This class is used to provide widgets (like the @class StylesCombo) the styles available to the document being worked on. The @class StylesModel can be of two types: character styles or paragraph styles type. This allows the widget to ignore the type of style it is handling.
- * Character styles in ODF can be specified in two ways. First, a named character style, specifying character formatting properties. It is meant to be used on a couple of individual characters. Secondely, a paragraph style also specifies character formatting properties, which are to be considered the default for that particular paragraph.
- * For this reason, the @class Stylesmodel, when of the type @value characterStyle, do not list the paragraph style names. Only the specific named character styles are listed. Additionally, as the first item, a virtual style "As paragraph" is provided. Selecting this "style" will set the character properties as specified by the paragraph style currently applied to the selection.
- * This class requires that a @class KoStyleManager and a @class KoStyleThumbnailer be set. See below methods.
- *
- * The StylesModel re-implement the AbstractStylesModel interface. Several components assume the following properties:
- * - the StylesModel is a flat list of items (this also means that "parent" QModelIndexes are always invalid)
- * - the StylesModel has only one column
- * - there is no header in the model
- * - only the following methods are used when updating the underlying model's data: resetModel, insertRows, moveRows, removeRows
-*/
-
-class StylesModel : public AbstractStylesModel
-{
- Q_OBJECT
-
-public:
- enum CategoriesInternalIds {
- NoneStyleId = -1
- };
-
- explicit StylesModel(KoStyleManager *styleManager, AbstractStylesModel::Type modelType, QObject *parent = 0);
- ~StylesModel() override;
-
- /** Re-implemented from QAbstractItemModel. */
-
- QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const override;
-
- int rowCount(const QModelIndex &parent) const override;
-
- QVariant data(const QModelIndex &index, int role) const override;
-
- Qt::ItemFlags flags(const QModelIndex &index) const override;
-
- QModelIndex parent(const QModelIndex &child) const override;
-
- int columnCount(const QModelIndex &parent) const override;
-
- /** *********************************** */
- /** Specific methods of the StylesModel */
-
- /** ************************* */
- /** Initialising of the model */
-
- /** Specify if the combo should provide the virtual style None. This style is a virtual style which equates to no style. It is only relevant for character styles.
- In case the "None" character style is selected, the character formatting properties of the paragraph style are used.
- A @class StylesModel of the @enum Type ParagraphStyle always has this property set to false.
- On the other hand, the default for a @class StylesModel of the @enum Type CharacterStyle is true.
-
- It is important to set this before setting the stylemanager on the model. The flag is used when populating the styles from the KoStyleManager.
- */
- void setProvideStyleNone(bool provide);
-
- /** Sets the @class KoStyleManager of the model. Setting this will populate the styles. It is required that a @param manager is set before using the model.
- * CAUTION: Populating the style will select the first inserted item. If this model is already set on a view, this might cause the view to emit an item selection changed signal.
- */
- void setStyleManager(KoStyleManager *manager);
-
- /** Sets the @class KoStyleThumbnailer of the model. It is required that a @param thumbnailer is set before using the model. */
- void setStyleThumbnailer(KoStyleThumbnailer *thumbnailer) override;
-
- /** *************** */
- /** Using the model */
-
- /** Return a @class QModelIndex for the specified @param style.
- * @param style may be either a character or paragraph style.
- */
- QModelIndex indexOf(const KoCharacterStyle *style) const override;
-
- /** Returns a QImage which is a preview of the style specified by @param row of the given @param size.
- * If size isn't specified, the default size of the given @class KoStyleThumbnailer is used.
- */
- QImage stylePreview(int row, const QSize &size = QSize()) override;
-// QImage stylePreview(QModelIndex &index, const QSize &size = QSize());
-
- /** Specifies which paragraph style is currently the active one (on the current paragraph). This is used in order to properly preview the "As paragraph" virtual character style. */
- void setCurrentParagraphStyle(int styleId);
-
- /** Return the first index at list. */
- QModelIndex firstStyleIndex();
-
- /** Return style id list. */
- QList<int> StyleList();
-
- /** Return new styles and their ids. */
- QHash<int, KoParagraphStyle *> draftParStyleList();
- QHash<int, KoCharacterStyle *> draftCharStyleList();
-
- /** Add a paragraph style to pargraph style list but this style is not applied. */
- void addDraftParagraphStyle(KoParagraphStyle *style);
-
- /** Add a character style to character style list but this style is not applied. */
- void addDraftCharacterStyle(KoCharacterStyle *style);
-
- /** we call this when we apply our unapplied styles and we clear our list. */
- void clearDraftStyles();
-
- /** We call this when we want a clear style model. */
- void clearStyleModel();
-
- /** Returns the type of styles in the model */
- AbstractStylesModel::Type stylesType() const override;
-
-private Q_SLOTS:
- void removeParagraphStyle(KoParagraphStyle *);
- void removeCharacterStyle(KoCharacterStyle *);
- void updateName(int styleId);
-
-public Q_SLOTS:
- void addParagraphStyle(KoParagraphStyle *);
- void addCharacterStyle(KoCharacterStyle *);
-
-private:
- void updateParagraphStyles();
- void updateCharacterStyles();
-
-protected:
- QList<int> m_styleList; // list of style IDs
- QHash<int, KoParagraphStyle *> m_draftParStyleList; // list of new styles that are not applied
- QHash<int, KoCharacterStyle *> m_draftCharStyleList;
-
-private:
- KoStyleManager *m_styleManager;
-
- KoParagraphStyle *m_currentParagraphStyle;
- KoCharacterStyle *m_defaultCharacterStyle;
-
- KisSignalMapper *m_styleMapper;
-
- bool m_provideStyleNone;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/StylesSortFilterProxyModel.cpp b/plugins/flake/textshape/dialogs/StylesSortFilterProxyModel.cpp
deleted file mode 100644
index 0bd330613a..0000000000
--- a/plugins/flake/textshape/dialogs/StylesSortFilterProxyModel.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2013 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 "StylesSortFilterProxyModel.h"
-
-#include <QDebug>
-
-StylesSortFilterProxyModel::StylesSortFilterProxyModel(QObject *parent)
- : QSortFilterProxyModel(parent)
-{
-}
-
-bool StylesSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
-{
- QVariant leftData = sourceModel()->data(left, Qt::DisplayRole);
- QVariant rightData = sourceModel()->data(right, Qt::DisplayRole);
-
- QString leftName = leftData.toString();
- QString rightName = rightData.toString();
- return QString::localeAwareCompare(leftName, rightName) < 0;
-}
diff --git a/plugins/flake/textshape/dialogs/StylesSortFilterProxyModel.h b/plugins/flake/textshape/dialogs/StylesSortFilterProxyModel.h
deleted file mode 100644
index 36114ef679..0000000000
--- a/plugins/flake/textshape/dialogs/StylesSortFilterProxyModel.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2013 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 STYLESSORTFILTERPROXYMODEL_H
-#define STYLESSORTFILTERPROXYMODEL_H
-
-#include <QSortFilterProxyModel>
-
-class StylesSortFilterProxyModel : public QSortFilterProxyModel
-{
-public:
- explicit StylesSortFilterProxyModel(QObject *parent = 0);
-
-protected:
- bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
-};
-
-#endif /* STYLESSORTFILTERPROXYMODEL_H */
diff --git a/plugins/flake/textshape/dialogs/TableDialog.cpp b/plugins/flake/textshape/dialogs/TableDialog.cpp
deleted file mode 100644
index f460796091..0000000000
--- a/plugins/flake/textshape/dialogs/TableDialog.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- *
- * 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 "TableDialog.h"
-
-#include <klocalizedstring.h>
-
-TableDialog::TableDialog(QWidget *parent)
- : KoDialog(parent)
-{
- setCaption(i18n("Insert Table"));
- setButtons(KoDialog::Ok | KoDialog::Cancel);
- showButtonSeparator(true);
- QWidget *form = new QWidget;
- widget.setupUi(form);
- setMainWidget(form);
-
- /* disable stuff not done yet */
- widget.groupPhysical->setVisible(false);
-}
-
-int TableDialog::columns()
-{
- return widget.intColumns->value();
-}
-
-int TableDialog::rows()
-{
- return widget.intRows->value();
-}
diff --git a/plugins/flake/textshape/dialogs/TableDialog.h b/plugins/flake/textshape/dialogs/TableDialog.h
deleted file mode 100644
index 0013452cb6..0000000000
--- a/plugins/flake/textshape/dialogs/TableDialog.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- *
- * 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 TABLEDIALOG_H
-#define TABLEDIALOG_H
-
-#include <ui_TableDialog.h>
-
-#include <KoDialog.h>
-
-class TableDialog : public KoDialog
-{
- Q_OBJECT
-public:
- explicit TableDialog(QWidget *parent);
-
- int columns();
- int rows();
-
-Q_SIGNALS:
-
-private:
- Ui::TableForm widget;
-};
-
-#endif
diff --git a/plugins/flake/textshape/dialogs/TableDialog.ui b/plugins/flake/textshape/dialogs/TableDialog.ui
deleted file mode 100644
index fe0d2469f6..0000000000
--- a/plugins/flake/textshape/dialogs/TableDialog.ui
+++ /dev/null
@@ -1,185 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>TableForm</class>
- <widget class="QWidget" name="TableForm">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>285</width>
- <height>239</height>
- </rect>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QGroupBox" name="groupLogical">
- <property name="title">
- <string>Columns and rows</string>
- </property>
- <property name="flat">
- <bool>true</bool>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0">
- <widget class="QLabel" name="labelColumns">
- <property name="text">
- <string>Number of columns:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QSpinBox" name="intColumns">
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- <property name="value">
- <number>2</number>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="labelRows">
- <property name="text">
- <string>Number of rows:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QSpinBox" name="intRows">
- <property name="frame">
- <bool>true</bool>
- </property>
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>999</number>
- </property>
- <property name="value">
- <number>2</number>
- </property>
- </widget>
- </item>
- <item row="0" column="2">
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="groupPhysical">
- <property name="title">
- <string>Width strategy</string>
- </property>
- <property name="flat">
- <bool>true</bool>
- </property>
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="0" column="0">
- <widget class="QRadioButton" name="radioFixed">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>Fixed column width:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QRadioButton" name="radioFitContents">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>Fit to contents</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QRadioButton" name="radioFitAvail">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>Fit to available surrounding</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QSpinBox" name="spinBox">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- <item row="0" column="2">
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="spacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>68</width>
- <height>1</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/TableOfContentsConfigure.cpp b/plugins/flake/textshape/dialogs/TableOfContentsConfigure.cpp
deleted file mode 100644
index b8ca0ad4ab..0000000000
--- a/plugins/flake/textshape/dialogs/TableOfContentsConfigure.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 "TableOfContentsConfigure.h"
-#include "TableOfContentsStyleConfigure.h"
-#include "TableOfContentsEntryDelegate.h"
-#include "TableOfContentsEntryModel.h"
-#include "TableOfContentsStyleModel.h"
-#include "KoTableOfContentsGeneratorInfo.h"
-#include "KoTextDocument.h"
-
-#include <KoTextEditor.h>
-#include <KoParagraphStyle.h>
-
-TableOfContentsConfigure::TableOfContentsConfigure(KoTextEditor *editor, QTextBlock block, QWidget *parent)
- : QDialog(parent)
- , m_textEditor(editor)
- , m_tocStyleConfigure(0)
- , m_tocInfo(0)
- , m_block(block)
- , m_document(0)
- , m_tocEntryStyleModel(0)
- , m_tocEntryConfigureDelegate(0)
-{
- init();
-
- KoTableOfContentsGeneratorInfo *info = block.blockFormat().property(KoParagraphStyle::TableOfContentsData).value<KoTableOfContentsGeneratorInfo *>();
- m_tocInfo = info->clone();
-
- setDisplay();
-}
-
-TableOfContentsConfigure::TableOfContentsConfigure(KoTextEditor *editor, KoTableOfContentsGeneratorInfo *info, QWidget *parent)
- : QDialog(parent)
- , m_textEditor(editor)
- , m_tocStyleConfigure(0)
- , m_tocInfo(0)
- , m_document(0)
- , m_tocEntryStyleModel(0)
- , m_tocEntryConfigureDelegate(0)
-{
- init();
- m_tocInfo = info->clone();
- setDisplay();
-}
-
-TableOfContentsConfigure::~TableOfContentsConfigure()
-{
- if (m_tocInfo) {
- delete m_tocInfo;
- }
-}
-
-void TableOfContentsConfigure::init()
-{
- ui.setupUi(this);
-
- setWindowTitle(i18n("Table of Contents - Configure"));
-
- ui.lineEditTitle->setText(i18n("Table Title"));
- ui.useOutline->setText(i18n("Use outline"));
- ui.useStyles->setText(i18n("Use styles"));
- ui.configureStyles->setText(i18n("Configure"));
- ui.tabWidget->setTabText(0, i18n("Index"));
- ui.tabWidget->setTabText(1, i18n("Styles"));
- ui.tabWidget->setCurrentIndex(0);
-
- ui.tocPreview->setStyleManager(KoTextDocument(m_textEditor->document()).styleManager());
-
- connect(this, SIGNAL(accepted()), this, SLOT(save()));
- connect(this, SIGNAL(rejected()), this, SLOT(cleanUp()));
- connect(ui.configureStyles, SIGNAL(clicked(bool)), this, SLOT(showStyleConfiguration()));
- connect(ui.lineEditTitle, SIGNAL(returnPressed()), this, SLOT(updatePreview()));
-}
-
-void TableOfContentsConfigure::setDisplay()
-{
- setVisible(true);
-
- ui.lineEditTitle->setText(m_tocInfo->m_indexTitleTemplate.text);
- ui.useOutline->setCheckState(m_tocInfo->m_useOutlineLevel ? Qt::Checked : Qt::Unchecked);
- ui.useStyles->setCheckState(m_tocInfo->m_useIndexSourceStyles ? Qt::Checked : Qt::Unchecked);
-
- connect(ui.lineEditTitle, SIGNAL(textChanged(QString)), this, SLOT(titleTextChanged(QString)));
- connect(ui.useOutline, SIGNAL(stateChanged(int)), this, SLOT(useOutline(int)));
- connect(ui.useStyles, SIGNAL(stateChanged(int)), this, SLOT(useIndexSourceStyles(int)));
-
- m_tocEntryStyleModel = new TableOfContentsEntryModel(KoTextDocument(m_textEditor->document()).styleManager(), m_tocInfo);
- connect(m_tocEntryStyleModel, SIGNAL(tocEntryDataChanged()), this, SLOT(updatePreview()));
-
- m_tocEntryConfigureDelegate = new TableOfContentsEntryDelegate(KoTextDocument(m_textEditor->document()).styleManager());
-
- ui.configureToCEntryStyle->setModel(m_tocEntryStyleModel);
-
- ui.configureToCEntryStyle->setItemDelegateForColumn(1, m_tocEntryConfigureDelegate);
-
- ui.configureToCEntryStyle->setShowGrid(false);
- ui.configureToCEntryStyle->verticalHeader()->hide();
- ui.configureToCEntryStyle->setEditTriggers(QAbstractItemView::CurrentChanged | QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked);
- ui.configureToCEntryStyle->setSelectionBehavior(QAbstractItemView::SelectRows);
- ui.configureToCEntryStyle->horizontalHeader()->setResizeMode(0, QHeaderView::ResizeToContents);
- ui.configureToCEntryStyle->horizontalHeader()->setResizeMode(1, QHeaderView::Stretch);
-
- connect(this, SIGNAL(accepted()), this, SLOT(save()));
- connect(this, SIGNAL(rejected()), this, SLOT(cleanUp()));
-
- updatePreview();
-}
-
-void TableOfContentsConfigure::save()
-{
- m_tocInfo->m_name = ui.lineEditTitle->text();
- m_tocInfo->m_indexTitleTemplate.text = ui.lineEditTitle->text();
- m_tocInfo->m_useOutlineLevel = (ui.useOutline->checkState() == Qt::Checked);
- m_tocInfo->m_useIndexSourceStyles = (ui.useStyles->checkState() == Qt::Checked);
-
- if (m_tocEntryStyleModel) {
- m_tocEntryStyleModel->saveData();
- }
-
- if (m_block.isValid()) {
- m_textEditor->setTableOfContentsConfig(m_tocInfo, m_block);
- }
- cleanUp();
-}
-
-void TableOfContentsConfigure::showStyleConfiguration()
-{
- if (!m_tocStyleConfigure) {
- m_tocStyleConfigure = new TableOfContentsStyleConfigure(KoTextDocument(m_textEditor->document()).styleManager(), this);
- }
- m_tocStyleConfigure->initializeUi(m_tocInfo);
-
-}
-
-void TableOfContentsConfigure::titleTextChanged(const QString &text)
-{
- m_tocInfo->m_indexTitleTemplate.text = text;
- updatePreview();
-}
-
-void TableOfContentsConfigure::useOutline(int state)
-{
- m_tocInfo->m_useOutlineLevel = (state == Qt::Checked);
- updatePreview();
-}
-
-void TableOfContentsConfigure::useIndexSourceStyles(int state)
-{
- m_tocInfo->m_useIndexSourceStyles = (state == Qt::Checked);
- updatePreview();
-}
-
-void TableOfContentsConfigure::updatePreview()
-{
- ui.tocPreview->updatePreview(m_tocInfo);
-}
-
-void TableOfContentsConfigure::cleanUp()
-{
- disconnect(ui.lineEditTitle, SIGNAL(textChanged(QString)), this, SLOT(titleTextChanged(QString)));
- disconnect(ui.useOutline, SIGNAL(stateChanged(int)), this, SLOT(useOutline(int)));
- disconnect(ui.useStyles, SIGNAL(stateChanged(int)), this, SLOT(useIndexSourceStyles(int)));
-
- disconnect(this, SIGNAL(accepted()), this, SLOT(save()));
- disconnect(this, SIGNAL(rejected()), this, SLOT(cleanUp()));
-
- if (m_tocEntryStyleModel) {
- delete m_tocEntryStyleModel;
- m_tocEntryStyleModel = 0;
- }
-
- if (m_tocEntryConfigureDelegate) {
- delete m_tocEntryConfigureDelegate;
- m_tocEntryConfigureDelegate = 0;
- }
-}
-
-KoTableOfContentsGeneratorInfo *TableOfContentsConfigure::currentToCData()
-{
- return m_tocInfo;
-}
diff --git a/plugins/flake/textshape/dialogs/TableOfContentsConfigure.h b/plugins/flake/textshape/dialogs/TableOfContentsConfigure.h
deleted file mode 100644
index bc035583ca..0000000000
--- a/plugins/flake/textshape/dialogs/TableOfContentsConfigure.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 TABLEOFCONTENTSCONFIGURE_H
-#define TABLEOFCONTENTSCONFIGURE_H
-
-#include "ui_TableOfContentsConfigure.h"
-
-#include <KoZoomHandler.h>
-
-#include <QDialog>
-#include <QTextBlock>
-
-namespace Ui
-{
-class TableOfContentsConfigure;
-}
-
-class QTextBlock;
-class TableOfContentsStyleConfigure;
-class TableOfContentsEntryModel;
-class TableOfContentsEntryDelegate;
-class KoTableOfContentsGeneratorInfo;
-class KoTextEditor;
-
-class TableOfContentsConfigure : public QDialog
-{
- Q_OBJECT
-
-public:
- explicit TableOfContentsConfigure(KoTextEditor *editor, QTextBlock block, QWidget *parent = 0);
- TableOfContentsConfigure(KoTextEditor *editor, KoTableOfContentsGeneratorInfo *info, QWidget *parent = 0);
- ~TableOfContentsConfigure() override;
- KoTableOfContentsGeneratorInfo *currentToCData();
-
-public Q_SLOTS:
- void setDisplay();
- void save();
- void cleanUp();
- void updatePreview();
-
-private Q_SLOTS:
- void showStyleConfiguration();
- void titleTextChanged(const QString &text);
- void useOutline(int state);
- void useIndexSourceStyles(int state);
-
-private:
-
- Ui::TableOfContentsConfigure ui;
- KoTextEditor *m_textEditor;
- TableOfContentsStyleConfigure *m_tocStyleConfigure;
- KoTableOfContentsGeneratorInfo *m_tocInfo;
- QTextBlock m_block;
- QTextDocument *m_document;
- TableOfContentsEntryModel *m_tocEntryStyleModel;
- TableOfContentsEntryDelegate *m_tocEntryConfigureDelegate;
-
- void init();
-};
-
-Q_DECLARE_METATYPE(QTextBlock)
-#endif // TABLEOFCONTENTSCONFIGURE_H
diff --git a/plugins/flake/textshape/dialogs/TableOfContentsConfigure.ui b/plugins/flake/textshape/dialogs/TableOfContentsConfigure.ui
deleted file mode 100644
index 776d8a2762..0000000000
--- a/plugins/flake/textshape/dialogs/TableOfContentsConfigure.ui
+++ /dev/null
@@ -1,186 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>TableOfContentsConfigure</class>
- <widget class="QDialog" name="TableOfContentsConfigure">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>655</width>
- <height>458</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>Dialog</string>
- </property>
- <property name="modal">
- <bool>true</bool>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0">
- <widget class="TableOfContentsPreview" name="tocPreview">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
- <property name="frameShape">
- <enum>QFrame::StyledPanel</enum>
- </property>
- <property name="frameShadow">
- <enum>QFrame::Raised</enum>
- </property>
- </widget>
- </item>
- <item row="0" column="2">
- <widget class="QTabWidget" name="tabWidget">
- <property name="currentIndex">
- <number>0</number>
- </property>
- <widget class="QWidget" name="tab">
- <attribute name="title">
- <string>Tab 1</string>
- </attribute>
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="0" column="0">
- <layout class="QHBoxLayout" name="horizontalLayout_3">
- <item>
- <widget class="QLabel" name="labelTitle">
- <property name="text">
- <string>Title</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLineEdit" name="lineEditTitle"/>
- </item>
- </layout>
- </item>
- <item row="1" column="0">
- <widget class="QCheckBox" name="useOutline">
- <property name="text">
- <string>CheckBox</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <widget class="QCheckBox" name="useStyles">
- <property name="text">
- <string>CheckBox</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="configureStyles">
- <property name="text">
- <string>PushButton</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="3" column="0">
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>262</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <widget class="QWidget" name="tab_2">
- <attribute name="title">
- <string>Tab 2</string>
- </attribute>
- <layout class="QGridLayout" name="gridLayout_3">
- <item row="0" column="0">
- <widget class="QTableView" name="configureToCEntryStyle"/>
- </item>
- </layout>
- </widget>
- </widget>
- </item>
- <item row="1" column="0">
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>319</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="2">
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>TableOfContentsPreview</class>
- <extends>QFrame</extends>
- <header>dialogs/TableOfContentsPreview.h</header>
- <container>1</container>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections>
- <connection>
- <sender>buttonBox</sender>
- <signal>accepted()</signal>
- <receiver>TableOfContentsConfigure</receiver>
- <slot>accept()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>248</x>
- <y>254</y>
- </hint>
- <hint type="destinationlabel">
- <x>157</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>buttonBox</sender>
- <signal>rejected()</signal>
- <receiver>TableOfContentsConfigure</receiver>
- <slot>reject()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>316</x>
- <y>260</y>
- </hint>
- <hint type="destinationlabel">
- <x>286</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- </connections>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/TableOfContentsEntryDelegate.cpp b/plugins/flake/textshape/dialogs/TableOfContentsEntryDelegate.cpp
deleted file mode 100644
index fb59b42459..0000000000
--- a/plugins/flake/textshape/dialogs/TableOfContentsEntryDelegate.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 "TableOfContentsEntryDelegate.h"
-
-#include <klocalizedstring.h>
-#include <KoStyleManager.h>
-#include <KoParagraphStyle.h>
-#include <KoStyleThumbnailer.h>
-
-#include <QComboBox>
-#include <QPainter>
-
-TableOfContentsEntryDelegate::TableOfContentsEntryDelegate(KoStyleManager *manager)
- : QStyledItemDelegate()
- , m_styleManager(manager)
-{
- Q_ASSERT(manager);
-}
-
-QSize TableOfContentsEntryDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
-{
- Q_UNUSED(option);
- Q_UNUSED(index);
- return QSize(250, 48);
-}
-
-QWidget *TableOfContentsEntryDelegate::createEditor(QWidget *parent,
- const QStyleOptionViewItem &/* option */,
- const QModelIndex &/* index */) const
-{
- QComboBox *editor = new QComboBox(parent);
- return editor;
-}
-
-void TableOfContentsEntryDelegate::setEditorData(QWidget *editor,
- const QModelIndex &index) const
-{
- int value = index.model()->data(index, Qt::EditRole).toInt();
- QComboBox *comboBox = static_cast<QComboBox *>(editor);
-
- QList<KoParagraphStyle *> paragraphStyles = m_styleManager->paragraphStyles();
- int count = 0;
- int indexCount = 0;
- foreach (const KoParagraphStyle *style, paragraphStyles) {
- comboBox->addItem(style->name());
- comboBox->setItemData(count, style->styleId());
-
- if (style->styleId() == value) {
- indexCount = count;
- }
-
- count++;
- }
-
- comboBox->setCurrentIndex(indexCount);
-}
-
-void TableOfContentsEntryDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
- const QModelIndex &index) const
-{
- QComboBox *comboBox = static_cast<QComboBox *>(editor);
- int value = comboBox->itemData(comboBox->currentIndex()).toInt();
-
- model->setData(index, value, Qt::EditRole);
-}
-
-void TableOfContentsEntryDelegate::updateEditorGeometry(QWidget *editor,
- const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
-{
- editor->setGeometry(option.rect);
-}
diff --git a/plugins/flake/textshape/dialogs/TableOfContentsEntryDelegate.h b/plugins/flake/textshape/dialogs/TableOfContentsEntryDelegate.h
deleted file mode 100644
index 55fe4981b5..0000000000
--- a/plugins/flake/textshape/dialogs/TableOfContentsEntryDelegate.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 TABLEOFCONTENTSENTRYDELEGATE_H
-#define TABLEOFCONTENTSENTRYDELEGATE_H
-
-#include <QStyledItemDelegate>
-
-class KoStyleManager;
-
-class TableOfContentsEntryDelegate: public QStyledItemDelegate
-{
-public:
- explicit TableOfContentsEntryDelegate(KoStyleManager *manager);
-
- QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
-
- QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
- const QModelIndex &index) const override;
-
- void setEditorData(QWidget *editor, const QModelIndex &index) const override;
- void setModelData(QWidget *editor, QAbstractItemModel *model,
- const QModelIndex &index) const override;
-
- void updateEditorGeometry(QWidget *editor,
- const QStyleOptionViewItem &option, const QModelIndex &index) const override;
-private:
- KoStyleManager *m_styleManager;
-
-};
-
-#endif // TABLEOFCONTENTSENTRYDELEGATE_H
diff --git a/plugins/flake/textshape/dialogs/TableOfContentsEntryModel.cpp b/plugins/flake/textshape/dialogs/TableOfContentsEntryModel.cpp
deleted file mode 100644
index 30d954cc2a..0000000000
--- a/plugins/flake/textshape/dialogs/TableOfContentsEntryModel.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 "TableOfContentsEntryModel.h"
-#include <KoTableOfContentsGeneratorInfo.h>
-#include <KoStyleManager.h>
-#include <KoParagraphStyle.h>
-#include <klocalizedstring.h>
-
-TableOfContentsEntryModel::TableOfContentsEntryModel(KoStyleManager *manager, KoTableOfContentsGeneratorInfo *info)
- : m_styleManager(manager)
- , m_tocInfo(info)
-{
- Q_ASSERT(manager);
- Q_ASSERT(info);
-
- int titleStyleId = 0;
- if (m_styleManager->paragraphStyle(m_tocInfo->m_indexTitleTemplate.styleId)) {
- titleStyleId = m_tocInfo->m_indexTitleTemplate.styleId;
- } else {
- titleStyleId = m_styleManager->defaultParagraphStyle()->styleId();
- }
-
- m_tocEntries.append(qMakePair(i18n("Title"), titleStyleId));
-
- for (int i = 1; i <= m_tocInfo->m_outlineLevel; i++) {
- m_tocEntries.append(qMakePair(i18n("Level %1", QString("%1").arg(i)), m_styleManager->defaultTableOfContentsEntryStyle(i)->styleId()));
- }
-
- for (int j = 0; j < m_tocInfo->m_entryTemplate.count(); j++) {
- if (m_tocInfo->m_entryTemplate.at(j).outlineLevel <= 0 || m_tocInfo->m_entryTemplate.at(j).outlineLevel > m_tocInfo->m_outlineLevel) {
- continue; //ignore entries with outline level less than 0 and greater than the max outline level
- }
- if (m_styleManager->paragraphStyle(m_tocInfo->m_entryTemplate.at(j).styleId)) {
- m_tocEntries[m_tocInfo->m_entryTemplate.at(j).outlineLevel].second = m_tocInfo->m_entryTemplate.at(j).styleId;
- }
- }
-}
-
-int TableOfContentsEntryModel::rowCount(const QModelIndex &parent) const
-{
- if (!parent.isValid()) {
- return m_tocEntries.count();
- }
-
- return 0;
-}
-
-int TableOfContentsEntryModel::columnCount(const QModelIndex &parent) const
-{
- if (!parent.isValid()) {
- return 2;
- }
-
- return 0;
-}
-
-QModelIndex TableOfContentsEntryModel::index(int row, int column, const QModelIndex &parent) const
-{
- if (row < 0 || column < 0 || column > 1) {
- return QModelIndex();
- }
-
- if (!parent.isValid()) {
- if (row >= m_tocEntries.count()) {
- return QModelIndex();
- }
- return createIndex(row, column, new QPair<QString, int>(m_tocEntries[row].first, m_tocEntries[row].second));
- }
- return QModelIndex();
-}
-
-QVariant TableOfContentsEntryModel::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid()) {
- return QVariant();
- }
-
- if (index.column() == Levels) {
- switch (role) {
- case Qt::DisplayRole:
- case Qt::DecorationRole:
- return QVariant(static_cast< QPair<QString, int> *>(index.internalPointer())->first);
- default: break;
- }
- } else {
- switch (role) {
- case Qt::DisplayRole:
- case Qt::DecorationRole:
- return QVariant(m_styleManager->paragraphStyle(static_cast< QPair<QString, int> *>(index.internalPointer())->second)->name());
- //break
- case Qt::EditRole:
- return QVariant(static_cast< QPair<QString, int> *>(index.internalPointer())->second);
- default: break;
- }
- }
- return QVariant();
-}
-
-bool TableOfContentsEntryModel::setData(const QModelIndex &index, const QVariant &value, int role)
-{
- if (!index.isValid()) {
- return false;
- }
-
- static_cast< QPair<int, int> *>(index.internalPointer())->second = value.toInt();
- QAbstractTableModel::setData(index, value, role);
- m_tocEntries[index.row()].second = value.toInt();
-
- //show data in preview
- saveData();
- emit tocEntryDataChanged();
-
- return true;
-}
-
-Qt::ItemFlags TableOfContentsEntryModel::flags(const QModelIndex &index) const
-{
- if (!index.isValid()) {
- return 0;
- }
- if (index.column() == Levels) {
- return (Qt::ItemIsSelectable | Qt::ItemIsEnabled);
- }
- if (index.column() == Styles) {
- return (Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
- }
- return 0;
-}
-
-QVariant TableOfContentsEntryModel::headerData(int section, Qt::Orientation orientation, int role) const
-{
- if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
- if (section == Levels) {
- return i18n("Level");
- } else if (section == Styles) {
- return i18n("Style");
- } else {
- return QAbstractTableModel::headerData(section, orientation, role);
- }
- } else {
- return QAbstractTableModel::headerData(section, orientation, role);
- }
-
-}
-
-void TableOfContentsEntryModel::saveData()
-{
- //index 0 of m_tocEntries is for title information
- m_tocInfo->m_indexTitleTemplate.styleName = m_styleManager->paragraphStyle(m_tocEntries.at(0).second)->name();
- m_tocInfo->m_indexTitleTemplate.styleId = m_tocEntries.at(0).second;
-
- for (int i = 1; i <= m_tocInfo->m_outlineLevel; i++) {
- m_tocInfo->m_entryTemplate[i - 1].styleName = m_styleManager->paragraphStyle(m_tocEntries.at(i).second)->name();
- m_tocInfo->m_entryTemplate[i - 1].styleId = m_tocEntries.at(i).second;
- }
-}
diff --git a/plugins/flake/textshape/dialogs/TableOfContentsEntryModel.h b/plugins/flake/textshape/dialogs/TableOfContentsEntryModel.h
deleted file mode 100644
index 18dcb3b76c..0000000000
--- a/plugins/flake/textshape/dialogs/TableOfContentsEntryModel.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 TABLEOFCONTENTSENTYMODEL_H
-#define TABLEOFCONTENTSENTYMODEL_H
-
-#include <QAbstractTableModel>
-#include <QStringList>
-#include <QPair>
-
-class KoStyleManager;
-class KoTableOfContentsGeneratorInfo;
-
-class TableOfContentsEntryModel : public QAbstractTableModel
-{
- Q_OBJECT
-public:
- enum ModelColumns { Levels = 0, Styles = 1 };
- TableOfContentsEntryModel(KoStyleManager *manager, KoTableOfContentsGeneratorInfo *info);
-
- int rowCount(const QModelIndex &parent) const override;
- int columnCount(const QModelIndex &parent) const override;
- QVariant data(const QModelIndex &index, int role) const override;
- bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
- Qt::ItemFlags flags(const QModelIndex &index) const override;
- QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const override;
- QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
-
- void saveData();
-
-Q_SIGNALS:
- void tocEntryDataChanged();
-
-private:
-
- QList <QPair <QString, int> > m_tocEntries; //first contains the text that will appear in table view, and second one is the styleId
- KoStyleManager *m_styleManager;
- KoTableOfContentsGeneratorInfo *m_tocInfo;
-};
-
-#endif // TABLEOFCONTENTSENTYMODEL_H
diff --git a/plugins/flake/textshape/dialogs/TableOfContentsPreview.cpp b/plugins/flake/textshape/dialogs/TableOfContentsPreview.cpp
deleted file mode 100644
index 2af5662e4b..0000000000
--- a/plugins/flake/textshape/dialogs/TableOfContentsPreview.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 "TableOfContentsPreview.h"
-
-#include "KoTableOfContentsGeneratorInfo.h"
-#include "KoZoomHandler.h"
-#include "KoTextDocumentLayout.h"
-#include "TextTool.h"
-
-#include <KoInlineTextObjectManager.h>
-#include <KoParagraphStyle.h>
-#include <KoPageProvider.h>
-#include <KoShapePaintingContext.h>
-
-TableOfContentsPreview::TableOfContentsPreview(QWidget *parent)
- : QFrame(parent)
- , m_textShape(0)
- , m_pm(0)
- , m_styleManager(0)
- , m_previewPixSize(QSize(0, 0))
-{
-}
-
-TableOfContentsPreview::~TableOfContentsPreview()
-{
- deleteTextShape();
-
- if (m_pm) {
- delete m_pm;
- m_pm = 0;
- }
-}
-
-void TableOfContentsPreview::setStyleManager(KoStyleManager *styleManager)
-{
- m_styleManager = styleManager;
-}
-
-void TableOfContentsPreview::paintEvent(QPaintEvent *event)
-{
- Q_UNUSED(event);
-
- QPainter *p = new QPainter(this);
- p->save();
- p->translate(5.5, 1.5);
- p->setRenderHint(QPainter::Antialiasing);
- QRect rectang = rect();
- rectang.adjust(-4, -4, -4, -4);
-
- if (m_pm) {
- p->drawPixmap(rectang, *m_pm, m_pm->rect());
- } else {
- p->fillRect(rectang, QBrush(QColor(Qt::white)));
- }
-
- p->restore();
-
- delete p;
-}
-
-void TableOfContentsPreview::updatePreview(KoTableOfContentsGeneratorInfo *newToCInfo)
-{
- QTextBlockFormat tocFormat;
- QTextDocument *tocDocument = new QTextDocument(this);
- KoTextDocument(tocDocument).setStyleManager(m_styleManager);
- KoTableOfContentsGeneratorInfo *info = newToCInfo->clone();
- // info->m_indexTitleTemplate.text = newToCInfo->m_indexTitleTemplate.text;
- // info->m_useOutlineLevel = newToCInfo->m_useOutlineLevel;
-
- tocFormat.setProperty(KoParagraphStyle::TableOfContentsData, QVariant::fromValue<KoTableOfContentsGeneratorInfo *>(info));
- tocFormat.setProperty(KoParagraphStyle::GeneratedDocument, QVariant::fromValue<QTextDocument *>(tocDocument));
-
- deleteTextShape();
-
- m_textShape = new TextShape(&m_itom, &m_tlm);
- if (m_previewPixSize.isEmpty()) {
- m_textShape->setSize(size());
- } else {
- m_textShape->setSize(m_previewPixSize);
- }
- QTextCursor cursor(m_textShape->textShapeData()->document());
-
- QTextCharFormat textCharFormat = cursor.blockCharFormat();
- textCharFormat.setFontPointSize(11);
- textCharFormat.setFontWeight(QFont::Normal);
-
- //the brush is set to the background colour so that the actual text block(Heading 1,Heading 1.1 etc.) does not appear in the preview
- textCharFormat.setProperty(QTextCharFormat::ForegroundBrush, QBrush(Qt::white));
- cursor.setCharFormat(textCharFormat);
-
- cursor.insertBlock(tocFormat);
- cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
-
- //insert text for different heading styles
- QTextBlockFormat blockFormat;
- blockFormat.setProperty(KoParagraphStyle::OutlineLevel, 1);
- cursor.insertBlock(blockFormat, textCharFormat);
- cursor.insertText("Header 1");
-
- QTextBlockFormat blockFormat1;
- blockFormat1.setProperty(KoParagraphStyle::OutlineLevel, 2);
- cursor.insertBlock(blockFormat1, textCharFormat);
- cursor.insertText("Header 1.1");
-
- QTextBlockFormat blockFormat2;
- blockFormat2.setProperty(KoParagraphStyle::OutlineLevel, 2);
- cursor.insertBlock(blockFormat2, textCharFormat);
- cursor.insertText("Header 1.2");
-
- QTextBlockFormat blockFormat3;
- blockFormat3.setProperty(KoParagraphStyle::OutlineLevel, 1);
- cursor.insertBlock(blockFormat3, textCharFormat);
- cursor.insertText("Header 2");
-
- KoTextDocument(m_textShape->textShapeData()->document()).setStyleManager(m_styleManager);
-
- KoTextDocumentLayout *lay = dynamic_cast<KoTextDocumentLayout *>(m_textShape->textShapeData()->document()->documentLayout());
- connect(lay, SIGNAL(finishedLayout()), this, SLOT(finishedPreviewLayout()));
- if (lay) {
- lay->layout();
- }
-}
-
-void TableOfContentsPreview::finishedPreviewLayout()
-{
- if (m_pm) {
- delete m_pm;
- m_pm = 0;
- }
-
- if (m_previewPixSize.isEmpty()) {
- m_pm = new QPixmap(size());
- } else {
- m_pm = new QPixmap(m_previewPixSize);
- }
- m_pm->fill(Qt::white);
- m_zoomHandler.setZoom(0.9);
- m_zoomHandler.setDpi(72, 72);
- QPainter p(m_pm);
-
- if (m_textShape) {
- if (m_previewPixSize.isEmpty()) {
- m_textShape->setSize(size());
- } else {
- m_textShape->setSize(m_previewPixSize);
- }
- KoShapePaintingContext paintContext; //FIXME
- m_textShape->paintComponent(p, paintContext);
- }
- emit pixmapGenerated();
- update();
-}
-
-QPixmap TableOfContentsPreview::previewPixmap()
-{
- return QPixmap(*m_pm);
-}
-
-void TableOfContentsPreview::deleteTextShape()
-{
- if (m_textShape) {
- KoTextDocumentLayout *lay = dynamic_cast<KoTextDocumentLayout *>(m_textShape->textShapeData()->document()->documentLayout());
- if (lay) {
- lay->setContinuousLayout(false);
- lay->setBlockLayout(true);
- }
- delete m_textShape;
- m_textShape = 0;
- }
-}
-
-void TableOfContentsPreview::setPreviewSize(const QSize &size)
-{
- m_previewPixSize = size;
-}
diff --git a/plugins/flake/textshape/dialogs/TableOfContentsPreview.h b/plugins/flake/textshape/dialogs/TableOfContentsPreview.h
deleted file mode 100644
index 2675bf8586..0000000000
--- a/plugins/flake/textshape/dialogs/TableOfContentsPreview.h
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef TABLEOFCONTENTSPREVIEW_H
-#define TABLEOFCONTENTSPREVIEW_H
-/* This file is part of the KDE project
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 <KoZoomHandler.h>
-#include <KoInlineTextObjectManager.h>
-#include <KoTextRangeManager.h>
-
-#include <QFrame>
-#include <QPixmap>
-
-class TextShape;
-class KoTableOfContentsGeneratorInfo;
-class KoStyleManager;
-
-class TableOfContentsPreview : public QFrame
-{
- Q_OBJECT
-public:
- explicit TableOfContentsPreview(QWidget *parent = 0);
- ~TableOfContentsPreview() override;
- void setStyleManager(KoStyleManager *styleManager);
- /// sets the size of the generated preview pixmap if not set then it takes the widget's size
- void setPreviewSize(const QSize &size);
- QPixmap previewPixmap();
-
-protected:
- void paintEvent(QPaintEvent *event) override;
-
-Q_SIGNALS:
- void pixmapGenerated();
-public Q_SLOTS:
- void updatePreview(KoTableOfContentsGeneratorInfo *info);
-
-private Q_SLOTS:
- void finishedPreviewLayout();
-
-private:
- TextShape *m_textShape;
- QPixmap *m_pm;
- KoZoomHandler m_zoomHandler;
- KoStyleManager *m_styleManager;
- KoInlineTextObjectManager m_itom;
- KoTextRangeManager m_tlm;
- QSize m_previewPixSize;
-
- void deleteTextShape();
-
-};
-
-#endif // TABLEOFCONTENTSPREVIEW_H
diff --git a/plugins/flake/textshape/dialogs/TableOfContentsStyleConfigure.cpp b/plugins/flake/textshape/dialogs/TableOfContentsStyleConfigure.cpp
deleted file mode 100644
index 892d525834..0000000000
--- a/plugins/flake/textshape/dialogs/TableOfContentsStyleConfigure.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 "TableOfContentsStyleConfigure.h"
-#include "ui_TableOfContentsStyleConfigure.h"
-
-#include "KoStyleManager.h"
-#include "KoParagraphStyle.h"
-
-#include <QTableView>
-#include <QHeaderView>
-
-TableOfContentsStyleConfigure::TableOfContentsStyleConfigure(KoStyleManager *manager, QWidget *parent)
- : QDialog(parent)
- , ui(new Ui::TableOfContentsStyleConfigure)
- , m_stylesTree(0)
- , m_styleManager(manager)
- , m_tocInfo(0)
- , m_stylesModel(0)
-{
- ui->setupUi(this);
- setWindowTitle(i18n("Table of Contents - Configure Styles"));
-
- Q_ASSERT(manager);
-
- ui->stylesAvailableLabel->setText(i18n("Styles available"));
- connect(this, SIGNAL(accepted()), this, SLOT(save()));
-}
-
-TableOfContentsStyleConfigure::~TableOfContentsStyleConfigure()
-{
- delete ui;
-}
-
-void TableOfContentsStyleConfigure::initializeUi(KoTableOfContentsGeneratorInfo *info)
-{
- Q_ASSERT(info);
-
- m_tocInfo = info;
-
- connect(this, SIGNAL(accepted()), this, SLOT(save()));
- connect(this, SIGNAL(rejected()), this, SLOT(discardChanges()));
-
- m_stylesModel = new TableOfContentsStyleModel(m_styleManager, m_tocInfo);
- ui->tableView->setModel(m_stylesModel);
-
- ui->tableView->setItemDelegateForColumn(1, &m_delegate);
-
- ui->tableView->setShowGrid(false);
- ui->tableView->verticalHeader()->hide();
- ui->tableView->setEditTriggers(QAbstractItemView::CurrentChanged | QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked);
- ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
- ui->tableView->horizontalHeader()->setResizeMode(0, QHeaderView::Stretch);
- ui->tableView->horizontalHeader()->resizeSection(1, 100);
-
- this->setVisible(true);
-}
-
-void TableOfContentsStyleConfigure::save()
-{
- if (m_stylesModel) {
- m_stylesModel->saveData();
- delete m_stylesModel;
- m_stylesModel = 0;
- }
-
- disconnect(this, SIGNAL(accepted()), this, SLOT(save()));
- disconnect(this, SIGNAL(rejected()), this, SLOT(discardChanges()));
-}
-
-void TableOfContentsStyleConfigure::discardChanges()
-{
- if (m_stylesModel) {
- delete m_stylesModel;
- m_stylesModel = 0;
- }
-
- disconnect(this, SIGNAL(accepted()), this, SLOT(save()));
- disconnect(this, SIGNAL(rejected()), this, SLOT(discardChanges()));
-}
diff --git a/plugins/flake/textshape/dialogs/TableOfContentsStyleConfigure.h b/plugins/flake/textshape/dialogs/TableOfContentsStyleConfigure.h
deleted file mode 100644
index b9530c54c2..0000000000
--- a/plugins/flake/textshape/dialogs/TableOfContentsStyleConfigure.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 TABLEOFCONTENTSSTYLECONFIGURE_H
-#define TABLEOFCONTENTSSTYLECONFIGURE_H
-
-#include "TableOfContentsStyleModel.h"
-#include "TableOfContentsStyleDelegate.h"
-
-#include <QDialog>
-
-namespace Ui
-{
-class TableOfContentsStyleConfigure;
-}
-
-class QStandardItemModel;
-class KoStyleManager;
-class TableOfContentsStyleModel;
-class KoTableOfContentsGeneratorInfo;
-
-class TableOfContentsStyleConfigure : public QDialog
-{
- Q_OBJECT
-
-public:
- explicit TableOfContentsStyleConfigure(KoStyleManager *manager, QWidget *parent = 0);
- ~TableOfContentsStyleConfigure() override;
- void initializeUi(KoTableOfContentsGeneratorInfo *info);
-
-public Q_SLOTS:
- void save();
- void discardChanges();
-
-private:
- Ui::TableOfContentsStyleConfigure *ui;
- QStandardItemModel *m_stylesTree;
- KoStyleManager *m_styleManager;
- KoTableOfContentsGeneratorInfo *m_tocInfo;
- TableOfContentsStyleModel *m_stylesModel;
- TableOfContentsStyleDelegate m_delegate;
-};
-
-#endif // TABLEOFCONTENTSSTYLECONFIGURE_H
diff --git a/plugins/flake/textshape/dialogs/TableOfContentsStyleConfigure.ui b/plugins/flake/textshape/dialogs/TableOfContentsStyleConfigure.ui
deleted file mode 100644
index 9059eefb3e..0000000000
--- a/plugins/flake/textshape/dialogs/TableOfContentsStyleConfigure.ui
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>TableOfContentsStyleConfigure</class>
- <widget class="QDialog" name="TableOfContentsStyleConfigure">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>557</width>
- <height>437</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>Dialog</string>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0">
- <widget class="QLabel" name="stylesAvailableLabel">
- <property name="text">
- <string>TextLabel</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QTableView" name="tableView"/>
- </item>
- <item row="2" column="0">
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections>
- <connection>
- <sender>buttonBox</sender>
- <signal>accepted()</signal>
- <receiver>TableOfContentsStyleConfigure</receiver>
- <slot>accept()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>248</x>
- <y>254</y>
- </hint>
- <hint type="destinationlabel">
- <x>157</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>buttonBox</sender>
- <signal>rejected()</signal>
- <receiver>TableOfContentsStyleConfigure</receiver>
- <slot>reject()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>316</x>
- <y>260</y>
- </hint>
- <hint type="destinationlabel">
- <x>286</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- </connections>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/TableOfContentsStyleDelegate.cpp b/plugins/flake/textshape/dialogs/TableOfContentsStyleDelegate.cpp
deleted file mode 100644
index b42326ce36..0000000000
--- a/plugins/flake/textshape/dialogs/TableOfContentsStyleDelegate.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 "TableOfContentsStyleDelegate.h"
-
-#include <klocalizedstring.h>
-
-#include <QSpinBox>
-
-TableOfContentsStyleDelegate::TableOfContentsStyleDelegate()
- : QStyledItemDelegate()
-{
-}
-
-QSize TableOfContentsStyleDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
-{
- Q_UNUSED(option);
- Q_UNUSED(index);
- return QSize(250, 48);
-}
-
-QWidget *TableOfContentsStyleDelegate::createEditor(QWidget *parent,
- const QStyleOptionViewItem &/* option */,
- const QModelIndex &/* index */) const
-{
- QSpinBox *editor = new QSpinBox(parent);
- editor->setMinimum(0);
- editor->setMaximum(100);
-
- return editor;
-}
-
-void TableOfContentsStyleDelegate::setEditorData(QWidget *editor,
- const QModelIndex &index) const
-{
- int value = index.model()->data(index, Qt::EditRole).toInt();
- QSpinBox *spinBox = static_cast<QSpinBox *>(editor);
- spinBox->setMinimum(0);
- spinBox->setMaximum(10);
- spinBox->setSpecialValueText(i18n("Disabled"));
- spinBox->setValue(value);
-}
-
-void TableOfContentsStyleDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
- const QModelIndex &index) const
-{
- QSpinBox *spinBox = static_cast<QSpinBox *>(editor);
- spinBox->interpretText();
- int value = spinBox->value();
-
- model->setData(index, value, Qt::EditRole);
-}
-
-void TableOfContentsStyleDelegate::updateEditorGeometry(QWidget *editor,
- const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
-{
- editor->setGeometry(option.rect);
-}
diff --git a/plugins/flake/textshape/dialogs/TableOfContentsStyleDelegate.h b/plugins/flake/textshape/dialogs/TableOfContentsStyleDelegate.h
deleted file mode 100644
index fd70bc2507..0000000000
--- a/plugins/flake/textshape/dialogs/TableOfContentsStyleDelegate.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 TABLEOFCONTENTSSTYLEDELEGATE_H
-#define TABLEOFCONTENTSSTYLEDELEGATE_H
-
-#include <QStyledItemDelegate>
-
-class TableOfContentsStyleDelegate: public QStyledItemDelegate
-{
-public:
- TableOfContentsStyleDelegate();
-
- QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
-
- QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
- const QModelIndex &index) const override;
-
- void setEditorData(QWidget *editor, const QModelIndex &index) const override;
- void setModelData(QWidget *editor, QAbstractItemModel *model,
- const QModelIndex &index) const override;
-
- void updateEditorGeometry(QWidget *editor,
- const QStyleOptionViewItem &option, const QModelIndex &index) const override;
-};
-
-#endif // TABLEOFCONTENTSSTYLEDELEGATE_H
diff --git a/plugins/flake/textshape/dialogs/TableOfContentsStyleModel.cpp b/plugins/flake/textshape/dialogs/TableOfContentsStyleModel.cpp
deleted file mode 100644
index 0e28e48921..0000000000
--- a/plugins/flake/textshape/dialogs/TableOfContentsStyleModel.cpp
+++ /dev/null
@@ -1,264 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 "TableOfContentsStyleModel.h"
-
-#include "KoStyleManager.h"
-#include <KoStyleThumbnailer.h>
-#include "KoParagraphStyle.h"
-#include "ToCBibGeneratorInfo.h"
-#include "KoTableOfContentsGeneratorInfo.h"
-#include "kis_assert.h"
-
-#include <QPair>
-
-#include <klocalizedstring.h>
-
-TableOfContentsStyleModel::TableOfContentsStyleModel(const KoStyleManager *manager, KoTableOfContentsGeneratorInfo *info)
- : QAbstractTableModel()
- , m_styleManager(manager)
- , m_styleThumbnailer(new KoStyleThumbnailer())
- , m_tocInfo(info)
-{
- Q_ASSERT(manager);
- Q_ASSERT(info);
-
- m_styleThumbnailer->setThumbnailSize(QSize(250, 48));
-
- Q_FOREACH (const KoParagraphStyle *style, m_styleManager->paragraphStyles()) {
- m_styleList.append(style->styleId());
- m_outlineLevel.append(getOutlineLevel(style->styleId()));
- }
-
-}
-
-TableOfContentsStyleModel::~TableOfContentsStyleModel()
-{
- delete m_styleThumbnailer;
-}
-
-QModelIndex TableOfContentsStyleModel::index(int row, int column, const QModelIndex &parent) const
-{
- if (row < 0 || column < 0 || column > 1) {
- return QModelIndex();
- }
-
- if (!parent.isValid()) {
- if (row >= m_styleList.count()) {
- return QModelIndex();
- }
-
- QPair<int, int> *modelValue = new QPair<int, int>(m_styleList[row], m_outlineLevel[row]);
- return createIndex(row, column, modelValue);
- }
- return QModelIndex();
-}
-
-int TableOfContentsStyleModel::rowCount(const QModelIndex &parent) const
-{
- if (!parent.isValid()) {
- return m_styleList.count();
- }
- return 0;
-}
-
-int TableOfContentsStyleModel::columnCount(const QModelIndex &parent) const
-{
- if (!parent.isValid()) {
- return 2;
- }
- return 0;
-}
-
-QVariant TableOfContentsStyleModel::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid()) {
- return QVariant();
- }
-
- int id = static_cast< QPair<int, int> *>(index.internalPointer())->first;
- if (index.column() == 0) {
- switch (role) {
- case Qt::DisplayRole: {
- return QVariant();
- }
- case Qt::DecorationRole: {
- if (!m_styleThumbnailer) {
- return QPixmap();
- }
- KoParagraphStyle *paragStyle = m_styleManager->paragraphStyle(id);
- if (paragStyle) {
- return m_styleThumbnailer->thumbnail(paragStyle);
- }
- break;
- }
- default: break;
- }
- } else {
- KoParagraphStyle *paragStyle = m_styleManager->paragraphStyle(id);
- KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paragStyle, QVariant());
-
- switch (role) {
- case Qt::DisplayRole: {
- if (QVariant(static_cast< QPair<int, int> *>(index.internalPointer())->second).value<int>() == 0) {
- return QVariant(i18n("Disabled"));
- } else {
- return QVariant(static_cast< QPair<int, int> *>(index.internalPointer())->second);
- }
- }
- case Qt::EditRole: {
- return QVariant(static_cast< QPair<int, int> *>(index.internalPointer())->second);
- }
- default: break;
- }
- }
- return QVariant();
-}
-
-Qt::ItemFlags TableOfContentsStyleModel::flags(const QModelIndex &index) const
-{
- if (!index.isValid()) {
- return 0;
- }
- if (index.column() == 0) {
- return (Qt::ItemIsSelectable | Qt::ItemIsEnabled);
- }
- if (index.column() == 1) {
- return (Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
- }
- return 0;
-}
-
-bool TableOfContentsStyleModel::setData(const QModelIndex &index, const QVariant &value, int role)
-{
- if (!index.isValid()) {
- return false;
- }
-
- static_cast< QPair<int, int> *>(index.internalPointer())->second = value.toInt();
- QAbstractTableModel::setData(index, value, role);
- m_outlineLevel[index.row()] = value.toInt();
- return true;
-}
-
-void TableOfContentsStyleModel::saveData()
-{
- int row = 0;
-
- Q_FOREACH (const int styleId, m_styleList) {
- KoParagraphStyle *paragStyle = m_styleManager->paragraphStyle(styleId);
- if (paragStyle) {
- setOutlineLevel(styleId, m_outlineLevel[row]);
- }
- row++;
- }
-}
-
-int TableOfContentsStyleModel::getOutlineLevel(int styleId)
-{
- foreach (const IndexSourceStyles &indexSourceStyles, m_tocInfo->m_indexSourceStyles) {
- foreach (const IndexSourceStyle &indexStyle, indexSourceStyles.styles) {
- if (m_styleManager->paragraphStyle(indexStyle.styleId) && styleId == indexStyle.styleId) {
- return indexSourceStyles.outlineLevel;
- }
- }
- }
- return 0;
-}
-
-void TableOfContentsStyleModel::setOutlineLevel(int styleId, int outLineLevel)
-{
- //ignore changes to paragraph styles with KoParagraphStyle::OutlineLevel property set.
- //i.e. those considered by KoTableOfContentsGeneratorInfo::m_useOutlineLevel==true
- if (m_styleManager->paragraphStyle(styleId)->hasProperty(KoParagraphStyle::OutlineLevel)) {
- return;
- }
-
- //check if the outlineLevel has changed
- if (getOutlineLevel(styleId) == outLineLevel) {
- return;
- }
-
- //now insert the style at the correct place( remove from the old place first and then insert at the new level)
- IndexSourceStyle indexStyleMoved;
- bool styleFound = false;
- int sourceStyleIndex = 0;
- foreach (const IndexSourceStyles &indexSourceStyles, m_tocInfo->m_indexSourceStyles) {
- int index = 0;
- foreach (const IndexSourceStyle &indexStyle, indexSourceStyles.styles) {
- if (styleId == indexStyle.styleId) {
- styleFound = true;
- indexStyleMoved = m_tocInfo->m_indexSourceStyles[sourceStyleIndex].styles.takeAt(index);
- break;
- }
- index++;
-
- if (styleFound == true) {
- break;
- }
- }
- sourceStyleIndex++;
- }
-
- //this style is not in the IndexSourceStyles list so fill it
- if (!styleFound) {
- indexStyleMoved.styleId = styleId;
- indexStyleMoved.styleName = m_styleManager->paragraphStyle(styleId)->name();
- }
-
- //check if IndexSourceStyles are there for this outlineLevel, if not create it
- bool sourceStylePresent = false;
- foreach (const IndexSourceStyles &indexSourceStyles, m_tocInfo->m_indexSourceStyles) {
- if (outLineLevel == indexSourceStyles.outlineLevel) {
- sourceStylePresent = true;
- break;
- }
- }
-
- if (!sourceStylePresent) {
- IndexSourceStyles indexStyles;
- indexStyles.outlineLevel = outLineLevel;
- m_tocInfo->m_indexSourceStyles.append(indexStyles);
- }
-
- sourceStyleIndex = 0;
- foreach (const IndexSourceStyles &indexSourceStyles, m_tocInfo->m_indexSourceStyles) {
- if (outLineLevel == indexSourceStyles.outlineLevel) {
- m_tocInfo->m_indexSourceStyles[sourceStyleIndex].styles.append(indexStyleMoved);
- break;
- }
- sourceStyleIndex++;
- }
-
-}
-
-QVariant TableOfContentsStyleModel::headerData(int section, Qt::Orientation orientation, int role) const
-{
- if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
- if (section == 0) {
- return i18n("Styles");
- } else if (section == 1) {
- return i18n("Level");
- } else {
- return QAbstractTableModel::headerData(section, orientation, role);
- }
- } else {
- return QAbstractTableModel::headerData(section, orientation, role);
- }
-}
diff --git a/plugins/flake/textshape/dialogs/TableOfContentsStyleModel.h b/plugins/flake/textshape/dialogs/TableOfContentsStyleModel.h
deleted file mode 100644
index 9bcd8e2f3c..0000000000
--- a/plugins/flake/textshape/dialogs/TableOfContentsStyleModel.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 TABLEOFCONTENTSSTYLEMODEL_H
-#define TABLEOFCONTENTSSTYLEMODEL_H
-
-#include <QAbstractTableModel>
-
-class KoStyleManager;
-class KoStyleThumbnailer;
-class KoTableOfContentsGeneratorInfo;
-
-class TableOfContentsStyleModel : public QAbstractTableModel
-{
-public:
- TableOfContentsStyleModel(const KoStyleManager *manager, KoTableOfContentsGeneratorInfo *info);
- ~TableOfContentsStyleModel() override;
- int rowCount(const QModelIndex &parent) const override;
- int columnCount(const QModelIndex &parent) const override;
- QVariant data(const QModelIndex &index, int role) const override;
- bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
- Qt::ItemFlags flags(const QModelIndex &index) const override;
- QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const override;
- QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
-
- void saveData();
-
-protected:
- QList<int> m_styleList; // list of style IDs
- QList<int> m_outlineLevel;
-
-private:
- const KoStyleManager *m_styleManager;
- KoStyleThumbnailer *m_styleThumbnailer;
- KoTableOfContentsGeneratorInfo *m_tocInfo;
-
- int getOutlineLevel(int styleId);
- void setOutlineLevel(int styleId, int outLineLevel);
-};
-
-#endif // TABLEOFCONTENTSSTYLEMODEL_H
-
diff --git a/plugins/flake/textshape/dialogs/TableOfContentsTemplate.cpp b/plugins/flake/textshape/dialogs/TableOfContentsTemplate.cpp
deleted file mode 100644
index 4755d2a472..0000000000
--- a/plugins/flake/textshape/dialogs/TableOfContentsTemplate.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 "TableOfContentsTemplate.h"
-
-#include <KoTableOfContentsGeneratorInfo.h>
-#include <KoStyleManager.h>
-#include <KoParagraphStyle.h>
-#include <klocalizedstring.h>
-
-TableOfContentsTemplate::TableOfContentsTemplate(KoStyleManager *manager)
- : m_manager(manager)
-{
- Q_ASSERT(manager);
-}
-
-QList<KoTableOfContentsGeneratorInfo *> TableOfContentsTemplate::templates()
-{
- //if you are adding your own custom styles specifically for ToC, add it as an unused style in KoStyleManager
- // when the ToC is used the style will be automatically move to the usedStyle section
-
- QList<KoTableOfContentsGeneratorInfo *> predefinedTemplates;
- KoTableOfContentsGeneratorInfo *firstTemplate = new KoTableOfContentsGeneratorInfo();
- firstTemplate->m_indexTitleTemplate.text = i18n("Table Of Contents");
-
- firstTemplate->m_indexTitleTemplate.styleId = m_manager->defaultTableOfcontentsTitleStyle()->styleId();
- firstTemplate->m_indexTitleTemplate.styleName = m_manager->defaultTableOfcontentsTitleStyle()->name();
-
- for (int level = 1; level <= firstTemplate->m_outlineLevel; ++level) {
- firstTemplate->m_entryTemplate[level - 1].styleId = m_manager->defaultTableOfContentsEntryStyle(level)->styleId();
- firstTemplate->m_entryTemplate[level - 1].styleName = m_manager->defaultTableOfContentsEntryStyle(level)->name();
- }
-
- KoTableOfContentsGeneratorInfo *secondTemplate = new KoTableOfContentsGeneratorInfo();
- secondTemplate->m_indexTitleTemplate.text = i18n("Contents");
-
- secondTemplate->m_indexTitleTemplate.styleId = m_manager->defaultTableOfcontentsTitleStyle()->styleId();
- secondTemplate->m_indexTitleTemplate.styleName = m_manager->defaultTableOfcontentsTitleStyle()->name();
-
- for (int level = 1; level <= firstTemplate->m_outlineLevel; ++level) {
- secondTemplate->m_entryTemplate[level - 1].styleId = m_manager->defaultTableOfContentsEntryStyle(level)->styleId();
- secondTemplate->m_entryTemplate[level - 1].styleName = m_manager->defaultTableOfContentsEntryStyle(level)->name();
- }
-
- predefinedTemplates.append(firstTemplate);
- predefinedTemplates.append(secondTemplate);
- return predefinedTemplates;
-}
-
-void TableOfContentsTemplate::moveTemplateToUsed(KoTableOfContentsGeneratorInfo *info)
-{
- if (m_manager->unusedStyle(info->m_indexTitleTemplate.styleId)) {
- m_manager->moveToUsedStyles(info->m_indexTitleTemplate.styleId);
- }
-
- for (int level = 1; level <= info->m_outlineLevel; level++) {
- if (m_manager->unusedStyle(info->m_entryTemplate[level - 1].styleId)) {
- m_manager->moveToUsedStyles(info->m_entryTemplate[level - 1].styleId);
- }
- }
-}
diff --git a/plugins/flake/textshape/dialogs/TableOfContentsTemplate.h b/plugins/flake/textshape/dialogs/TableOfContentsTemplate.h
deleted file mode 100644
index f98f6f9aab..0000000000
--- a/plugins/flake/textshape/dialogs/TableOfContentsTemplate.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 TABLEOFCONTENTSTEMPLATE_H
-#define TABLEOFCONTENTSTEMPLATE_H
-
-#include <QList>
-
-class KoTableOfContentsGeneratorInfo;
-class KoStyleManager;
-
-class TableOfContentsTemplate
-{
-public:
- explicit TableOfContentsTemplate(KoStyleManager *manager);
-
- QList<KoTableOfContentsGeneratorInfo *> templates();
-
- /// this method moves the styles used in info ToC from unused styles list to used
- void moveTemplateToUsed(KoTableOfContentsGeneratorInfo *info);
-
-private:
- KoStyleManager *m_manager;
-};
-
-#endif // TABLEOFCONTENTSTEMPLATE_H
diff --git a/plugins/flake/textshape/dialogs/TrackedChangeManager.cpp b/plugins/flake/textshape/dialogs/TrackedChangeManager.cpp
deleted file mode 100644
index b482f4f6cd..0000000000
--- a/plugins/flake/textshape/dialogs/TrackedChangeManager.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/* This file is part of the KDE project
-* Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
-*
-* 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 "TrackedChangeManager.h"
-
-#include "TrackedChangeModel.h"
-
-#include <klocalizedstring.h>
-
-#include <QModelIndex>
-#include <QTreeView>
-
-#include <QDebug>
-
-TrackedChangeManager::TrackedChangeManager(QWidget *parent)
- : QWidget(parent)
- , m_model(0)
-{
- widget.setupUi(this);
-}
-
-TrackedChangeManager::~TrackedChangeManager()
-{
-}
-
-void TrackedChangeManager::setModel(TrackedChangeModel *model)
-{
- m_model = model;
- widget.treeView->setModel(m_model);
- widget.treeView->reset();
- connect(widget.treeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(currentChanged(QModelIndex,QModelIndex)));
-}
-
-void TrackedChangeManager::currentChanged(const QModelIndex &newIndex, const QModelIndex &previousIndex)
-{
- Q_UNUSED(previousIndex);
- emit currentChanged(newIndex);
-}
-
-void TrackedChangeManager::selectItem(const QModelIndex &newIndex)
-{
- QModelIndex currentIndex = widget.treeView->currentIndex();
- widget.treeView->setCurrentIndex(newIndex);
- currentChanged(newIndex, currentIndex);
-}
diff --git a/plugins/flake/textshape/dialogs/TrackedChangeManager.h b/plugins/flake/textshape/dialogs/TrackedChangeManager.h
deleted file mode 100644
index c5ca791edd..0000000000
--- a/plugins/flake/textshape/dialogs/TrackedChangeManager.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* This file is part of the KDE project
-* Copyright (C) 2009-2010 Pierre Stirnweiss <pstirnweiss@googlemail.com>
-*
-* 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 TRACKEDCHANGEMANAGER_H
-#define TRACKEDCHANGEMANAGER_H
-
-#include <ui_TrackedChangeManager.h>
-
-//#include <KoDialog.h>
-#include <QWidget>
-
-class TrackedChangeModel;
-
-class QModelIndex;
-
-class TrackedChangeManager : public QWidget
-{
- Q_OBJECT
-public:
- explicit TrackedChangeManager(QWidget *parent = 0);
- ~TrackedChangeManager() override;
-
- void setModel(TrackedChangeModel *model);
-
- void selectItem(const QModelIndex &newIndex);
-
-Q_SIGNALS:
- void currentChanged(const QModelIndex &newIndex);
-
-private Q_SLOTS:
- void currentChanged(const QModelIndex &newIndex, const QModelIndex &previousIndex);
-
-private:
- Ui::trackedChange widget;
- TrackedChangeModel *m_model;
-};
-
-#endif // TRACKEDCHANGEMANAGER_H
diff --git a/plugins/flake/textshape/dialogs/TrackedChangeManager.ui b/plugins/flake/textshape/dialogs/TrackedChangeManager.ui
deleted file mode 100644
index 0f2b62c9a4..0000000000
--- a/plugins/flake/textshape/dialogs/TrackedChangeManager.ui
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>trackedChange</class>
- <widget class="QWidget" name="trackedChange">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>400</width>
- <height>300</height>
- </rect>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QTreeView" name="treeView"/>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/flake/textshape/dialogs/TrackedChangeModel.cpp b/plugins/flake/textshape/dialogs/TrackedChangeModel.cpp
deleted file mode 100644
index 7690e01485..0000000000
--- a/plugins/flake/textshape/dialogs/TrackedChangeModel.cpp
+++ /dev/null
@@ -1,341 +0,0 @@
-/* This file is part of the KDE project
-* Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
-*
-* 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 "TrackedChangeModel.h"
-
-#include <KoTextDocument.h>
-#include <KoTextDocumentLayout.h>
-#include <KoGenChange.h>
-#include <KoInlineTextObjectManager.h>
-#include <changetracker/KoChangeTracker.h>
-#include <changetracker/KoChangeTrackerElement.h>
-#include <styles/KoCharacterStyle.h>
-
-#include <kundo2magicstring.h>
-
-#include <QHash>
-#include <QModelIndex>
-#include <QStack>
-#include <QTextBlock>
-#include <QTextCharFormat>
-#include <QTextCursor>
-#include <QTextDocument>
-#include <QTextFragment>
-
-////ModelItem
-
-ModelItem::ModelItem(ModelItem *parent)
-{
- m_parentItem = parent;
- m_data.changeId = 0;
-}
-
-ModelItem::~ModelItem()
-{
- qDeleteAll(m_childItems);
-}
-
-void ModelItem::setChangeId(int changeId)
-{
- m_data.changeId = changeId;
-}
-
-void ModelItem::setChangeType(KoGenChange::Type type)
-{
- m_data.changeType = type;
-}
-
-void ModelItem::setChangeTitle(const QString &title)
-{
- m_data.title = title;
-}
-
-void ModelItem::setChangeAuthor(const QString &author)
-{
- m_data.author = author;
-}
-
-void ModelItem::appendChild(ModelItem *child)
-{
- m_childItems.append(child);
-}
-
-ModelItem *ModelItem::child(int row)
-{
- return m_childItems.value(row);
-}
-
-QList< ModelItem * > ModelItem::children()
-{
- return m_childItems;
-}
-
-int ModelItem::childCount() const
-{
- return m_childItems.count();
-}
-
-ModelItem *ModelItem::parent()
-{
- return m_parentItem;
-}
-
-int ModelItem::row() const
-{
- if (m_parentItem) {
- return m_parentItem->m_childItems.indexOf(const_cast<ModelItem *>(this));
- }
- return 0;
-}
-
-void ModelItem::setChangeRange(int start, int end)
-{
- m_data.changeRanges.append(QPair<int, int>(start, end));
-}
-
-ItemData ModelItem::itemData()
-{
- return m_data;
-}
-
-void ModelItem::removeChildren()
-{
- qDeleteAll(m_childItems);
- m_childItems.clear();
-}
-
-////TrackedChangeModel
-
-TrackedChangeModel::TrackedChangeModel(QTextDocument *document, QObject *parent)
- : QAbstractItemModel(parent)
- , m_document(document)
-{
- m_rootItem = new ModelItem(0);
- setupModelData(m_document, m_rootItem);
-}
-
-TrackedChangeModel::~TrackedChangeModel()
-{
- delete m_rootItem;
-}
-
-QModelIndex TrackedChangeModel::index(int row, int column, const QModelIndex &parent) const
-{
- if (!hasIndex(row, column, parent)) {
- return QModelIndex();
- }
-
- ModelItem *parentItem;
-
- if (!parent.isValid()) {
- parentItem = m_rootItem;
- } else {
- parentItem = static_cast<ModelItem *>(parent.internalPointer());
- }
-
- ModelItem *childItem = parentItem->child(row);
- if (childItem) {
- return createIndex(row, column, childItem);
- } else {
- return QModelIndex();
- }
-}
-
-QModelIndex TrackedChangeModel::indexForChangeId(int changeId)
-{
- ModelItem *item = m_changeItems.value(changeId);
- if (!item) {
- return QModelIndex();
- }
- return createIndex(item->row(), 0, item);
-}
-
-QModelIndex TrackedChangeModel::parent(const QModelIndex &index) const
-{
- if (!index.isValid()) {
- return QModelIndex();
- }
-
- ModelItem *childItem = static_cast<ModelItem *>(index.internalPointer());
- ModelItem *parentItem = childItem->parent();
-
- if (parentItem == m_rootItem) {
- return QModelIndex();
- }
-
- return createIndex(parentItem->row(), 0, parentItem);
-}
-
-int TrackedChangeModel::rowCount(const QModelIndex &parent) const
-{
- ModelItem *parentItem;
- if (parent.column() > 0) {
- return 0;
- }
-
- if (!parent.isValid()) {
- parentItem = m_rootItem;
- } else {
- parentItem = static_cast<ModelItem *>(parent.internalPointer());
- }
-
- return parentItem->childCount();
-}
-
-int TrackedChangeModel::columnCount(const QModelIndex &parent) const
-{
- Q_UNUSED(parent);
- return 3;
-}
-
-ItemData TrackedChangeModel::changeItemData(const QModelIndex &index, int role) const
-{
- if (!index.isValid()) {
- return ItemData();
- }
-
- if (role != Qt::DisplayRole) {
- return ItemData();
- }
-
- ModelItem *item = static_cast<ModelItem *>(index.internalPointer());
-
- return item->itemData();
-}
-
-QVariant TrackedChangeModel::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid()) {
- return QVariant();
- }
-
- if (role != Qt::DisplayRole) {
- return QVariant();
- }
-
- ModelItem *item = static_cast<ModelItem *>(index.internalPointer());
-
- ItemData data = item->itemData();
-
- switch (index.column()) {
- case 0:
- return QVariant(item->itemData().changeId);
- case 1:
- return QVariant(item->itemData().title);
- case 2:
- return QVariant(item->itemData().author);
- default:
- break;
- }
- return QVariant();
-}
-
-Qt::ItemFlags TrackedChangeModel::flags(const QModelIndex &index) const
-{
- if (!index.isValid()) {
- return 0;
- }
-
- return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
-}
-
-QVariant TrackedChangeModel::headerData(int section, Qt::Orientation orientation, int role) const
-{
- Q_UNUSED(section);
-
- if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
- switch (section) {
- case 0:
- return QVariant(QString("changeId"));
- break;
- case 1:
- return QVariant(QString("title"));
- break;
- case 2:
- return QVariant(QString("author"));
- break;
- }
- }
-
- return QVariant();
-}
-
-void TrackedChangeModel::setupModel()
-{
- beginRemoveRows(QModelIndex(), 0, rowCount() - 1);
- m_rootItem->removeChildren();
- endRemoveRows();
- setupModelData(m_document, m_rootItem);
- beginInsertRows(QModelIndex(), 0, m_rootItem->childCount() - 1);
- endInsertRows();
-}
-
-void TrackedChangeModel::setupModelData(QTextDocument *document, ModelItem *parent)
-{
- m_changeTracker = KoTextDocument(document).changeTracker();
- m_layout = dynamic_cast<KoTextDocumentLayout *>(document->documentLayout());
-
- QStack<ModelItem *> itemStack;
- itemStack.push(parent);
- m_changeItems.clear();
-
- QTextBlock block = document->begin();
- while (block.isValid()) {
- QTextBlock::iterator it;
- for (it = block.begin(); !(it.atEnd()); ++it) {
- QTextFragment fragment = it.fragment();
- QTextCharFormat format = fragment.charFormat();
- int changeId = format.property(KoCharacterStyle::ChangeTrackerId).toInt();
-// if (m_changeTracker->elementById(changeId) && m_changeTracker->elementById(changeId)->getChangeType() == KoGenChange::deleteChange)
-// continue;
- if (changeId) {
- if (changeId != itemStack.top()->itemData().changeId) {
- while (itemStack.top() != parent) {
- if (!m_changeTracker->isParent(itemStack.top()->itemData().changeId, changeId)) {
- itemStack.pop();
- } else {
- break;
- }
- }
- }
- ModelItem *item = m_changeItems.value(changeId);
- if (!item) {
- item = new ModelItem(itemStack.top());
- item->setChangeId(changeId);
- item->setChangeType(m_changeTracker->elementById(changeId)->getChangeType());
- item->setChangeTitle(m_changeTracker->elementById(changeId)->getChangeTitle().toString());
- item->setChangeAuthor(m_changeTracker->elementById(changeId)->getCreator());
- itemStack.top()->appendChild(item);
- m_changeItems.insert(changeId, item);
- }
- item->setChangeRange(fragment.position(), fragment.position() + fragment.length());
- ModelItem *parentItem = item->parent();
- while (parentItem->itemData().changeId) {
- parentItem->setChangeRange(fragment.position(), fragment.position() + fragment.length());
- parentItem = parentItem->parent();
- }
- itemStack.push(item);
-
- } else {
- itemStack.push(parent);
- }
- }
- block = block.next();
- }
-}
diff --git a/plugins/flake/textshape/dialogs/TrackedChangeModel.h b/plugins/flake/textshape/dialogs/TrackedChangeModel.h
deleted file mode 100644
index c7047aa3c3..0000000000
--- a/plugins/flake/textshape/dialogs/TrackedChangeModel.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* This file is part of the KDE project
-* Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
-*
-* 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 TRACKEDCHANGEMODEL_H
-#define TRACKEDCHANGEMODEL_H
-
-#include <KoGenChange.h>
-
-#include <QAbstractItemModel>
-#include <QHash>
-#include <QList>
-#include <QMetaType>
-#include <QObject>
-#include <QPair>
-
-class KoChangeTracker;
-class KoTextDocumentLayout;
-
-class QTextDocument;
-
-struct ItemData {
- int changeId;
- QList<QPair<int, int> > changeRanges;
- KoGenChange::Type changeType;
- QString title;
- QString author;
-};
-
-Q_DECLARE_METATYPE(ItemData)
-
-class ModelItem
-{
-public:
- explicit ModelItem(ModelItem *parent = 0);
- ~ModelItem();
-
- void setChangeId(int changeId);
- void setChangeType(KoGenChange::Type type);
- void setChangeTitle(const QString &title);
- void setChangeAuthor(const QString &author);
-
- void appendChild(ModelItem *child);
-
- ModelItem *child(int row);
- QList<ModelItem *> children();
- int childCount() const;
- int row() const;
- ModelItem *parent();
-
- ItemData itemData();
-
- void setChangeRange(int start, int end);
-
- void removeChildren();
-
-private:
- QList<ModelItem *> m_childItems;
- ModelItem *m_parentItem;
- ItemData m_data;
-};
-
-class TrackedChangeModel : public QAbstractItemModel
-{
- Q_OBJECT
-
-public:
- explicit TrackedChangeModel(QTextDocument *document, QObject *parent = 0);
- ~TrackedChangeModel() override;
-
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
- Qt::ItemFlags flags(const QModelIndex &index) const override;
- QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
- QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
- QModelIndex indexForChangeId(int changeId);
- QModelIndex parent(const QModelIndex &index) const override;
- int rowCount(const QModelIndex &parent = QModelIndex()) const override;
- int columnCount(const QModelIndex &parent = QModelIndex()) const override;
-
- ItemData changeItemData(const QModelIndex &index, int role = Qt::DisplayRole) const;
-
-public Q_SLOTS:
- void setupModel();
-
-private:
- void setupModelData(QTextDocument *document, ModelItem *parent);
-
- QTextDocument *m_document;
- ModelItem *m_rootItem;
- KoChangeTracker *m_changeTracker;
- KoTextDocumentLayout *m_layout;
-
- QHash<int, int> m_changeOccurenceCounter;
- QHash<int, ModelItem *> m_changeItems;
-};
-
-#endif // TRACKEDCHANGEMODEL_H
diff --git a/plugins/flake/textshape/dialogs/UnifiedLinkInsertionDialog.h b/plugins/flake/textshape/dialogs/UnifiedLinkInsertionDialog.h
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/plugins/flake/textshape/dialogs/ValidParentStylesProxyModel.cpp b/plugins/flake/textshape/dialogs/ValidParentStylesProxyModel.cpp
deleted file mode 100644
index 43df0b3071..0000000000
--- a/plugins/flake/textshape/dialogs/ValidParentStylesProxyModel.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2012 Pierre Stirnweiss <pstirnweiss@googlemail.org>
- *
- * 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 "ValidParentStylesProxyModel.h"
-
-#include <QModelIndex>
-
-#include <KoParagraphStyle.h>
-#include <KoStyleManager.h>
-
-#include <QDebug>
-
-ValidParentStylesProxyModel::ValidParentStylesProxyModel(QObject *parent)
- : StylesFilteredModelBase(parent)
- , m_styleManager(0)
-{
-}
-
-void ValidParentStylesProxyModel::setStyleManager(KoStyleManager *sm)
-{
- Q_ASSERT(sm);
-
- m_styleManager = sm;
-}
-
-void ValidParentStylesProxyModel::createMapping()
-{
-
- if (!m_styleManager || !m_sourceModel) {
- return;
- }
- m_sourceToProxy.clear();
- m_proxyToSource.clear();
-
- for (int i = 0; i < m_sourceModel->rowCount(QModelIndex()); ++i) {
- QModelIndex index = m_sourceModel->index(i, 0, QModelIndex());
- int id = (int)index.internalId();
- KoParagraphStyle *paragraphStyle = m_styleManager->paragraphStyle(id);
- if (paragraphStyle) {
- bool ok = true;
- KoParagraphStyle *testStyle = paragraphStyle;
- while (testStyle && ok) {
- ok = testStyle->styleId() != m_currentChildStyleId;
- testStyle = testStyle->parentStyle();
- }
- if (!ok) {
- continue; //we cannot inherit ourself even indirectly through the parent chain
- }
- m_proxyToSource.append(i); //the style is ok for parenting
- } else {
- KoCharacterStyle *characterStyle = m_styleManager->characterStyle(id);
- if (characterStyle) {
- bool ok = true;
- KoCharacterStyle *testStyle = characterStyle;
- while (testStyle && ok) {
- ok = testStyle->styleId() != m_currentChildStyleId;
- testStyle = testStyle->parentStyle();
- }
- if (!ok) {
- continue; //we cannot inherit ourself even indirectly through the parent chain
- }
- m_proxyToSource.append(i); //the style is ok for parenting
- }
- }
- }
- m_sourceToProxy.fill(-1, m_sourceModel->rowCount(QModelIndex()));
- for (int i = 0; i < m_proxyToSource.count(); ++i) {
- m_sourceToProxy[m_proxyToSource.at(i)] = i;
- }
-}
-
-void ValidParentStylesProxyModel::setCurrentChildStyleId(int styleId)
-{
- m_currentChildStyleId = styleId;
- emit layoutAboutToBeChanged();
- createMapping();
- emit layoutChanged();
-}
diff --git a/plugins/flake/textshape/dialogs/ValidParentStylesProxyModel.h b/plugins/flake/textshape/dialogs/ValidParentStylesProxyModel.h
deleted file mode 100644
index 277a88f168..0000000000
--- a/plugins/flake/textshape/dialogs/ValidParentStylesProxyModel.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2012 Pierre Stirnweiss <pstirnweiss@googlemail.org>
- *
- * 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 VALIDPARENTSTYLESPROXYMODEL_H
-#define VALIDPARENTSTYLESPROXYMODEL_H
-
-//#include "AbstractStylesModel.h"
-#include "StylesFilteredModelBase.h"
-
-#include <QVector>
-
-class KoStyleManager;
-
-class QModelIndex;
-
-/** This class is acting as a proxy between a "real" StylesModel and views. It is used to filter out styles which would not make a valid parent of the given childStyle (see void setCurrentChildStyleId(int styleId) ).
- *
- * In that matter, QSortFilterProxyModel implementation was a great source of inspiration.
- *
- * It is to be noted that this is in no way a full proxyModel. It is built with several assumptions:
- * - it is used to filter a StylesModel which in turn is a flat list of items. There is only one level of items. (this also means that "parent" QModelIndexes are always invalid)
- * - there is no header in the model.
- * - the model has only one column
- * - only the following methods are used when updating the underlying model's data: resetModel, insertRows, moveRows, removeRows (cf QAbstractItemModel)
-*/
-
-class ValidParentStylesProxyModel : public StylesFilteredModelBase
-{
- Q_OBJECT
-public:
- explicit ValidParentStylesProxyModel(QObject *parent = 0);
-
- void setStyleManager(KoStyleManager *manager); //it is needed to travel the style's parenting chain in order to assess if the currentChildStyle is suitable for being a parent
- void setCurrentChildStyleId(int styleId);
-
-protected:
- void createMapping() override;
-
-private:
- KoStyleManager *m_styleManager;
- int m_currentChildStyleId;
-};
-
-#endif // VALIDPARENTSTYLESPROXYMODEL_H
diff --git a/plugins/flake/textshape/kotext/AutoFormat b/plugins/flake/textshape/kotext/AutoFormat
deleted file mode 100644
index 2cc23903fb..0000000000
--- a/plugins/flake/textshape/kotext/AutoFormat
+++ /dev/null
@@ -1,52 +0,0 @@
-Autoformat feature:
-words and kpresenter have autoformat feature:
--> Simple autocorrection :
- -> Convert first letter of a sentence automatically to uppercase
- -> Convert two uppercase characters to one uppercase and one lowercase
- -> Auto format Url => when we write http://www.kde.org it is replaced
- by a link variable, we detect as an url all words started by http:// ftp://
- mailto: news:/
- -> Suppress double space
- -> Suppress space at the beginning and the end of a paragraph
- -> Automatically do bold and underline formatting => when we write
- *kde* => it replace by <bold>kde</bold> and when we write _kde_
- it replaces by <underline>kde</underline>
- -> Replace 1/2 to 1/2 => replace to fraction charactere it works for
- 1/2, 1/4 3/4
- -> Use auto-numbering for numbered paragraphs, when we start a paragraph
- with a <number>+<space>+<text> and we press enter this paragraph and
- next paragraph is replace by number style.
- -> use list-formatting for bulleted paragraph, when we write "* kde" and
- press enter style of paragraph is replaced by bullet style. We can
- configurate bullet.
--> Custom Quotes :
- -> we can replace double quotes and simple quotes by specific
- characters.
--> Advanced autocorrection:
- -> we can define a word which will be replaced by another word
- => for example calligras by calligra, or microsoft by linux
-->Exception:
- -> we can define list of exception word:
- =>Do not treat as the end of a sequence
- ==>don't upper case after specific word.
-
- =>there is a autoInclude. Autoformat analyse line and detect
- when we force lower case after a '.'
-
- =>Accept to uppercase letters :
- => there is a autoinclude. Autoformat analyse line and detect
- when we force 2 uppercase letters.
-->Auto Completion:
- ->When have a manual completion by default it's CTRL+E (we can configurate
- it into words or kpresenter.
- ->we can save list of completion word
- ->define min word length : min equals 5
- ->define max number of completion word ( max = 500 )
- ->Append space after completion.
-
--2002-03-27- calligra 1.1post.
-Laurent Montel <lmontel@mandrakesoft.com>
-Be careful my English is not good, so you can change all you want in this file.
-
-
-
diff --git a/plugins/flake/textshape/kotext/CMakeLists.txt b/plugins/flake/textshape/kotext/CMakeLists.txt
deleted file mode 100644
index 4c93537505..0000000000
--- a/plugins/flake/textshape/kotext/CMakeLists.txt
+++ /dev/null
@@ -1,134 +0,0 @@
-include_directories(${FONTCONFIG_INCLUDE_DIR}
- ${FREETYPE_INCLUDE_DIRS})
-
-set(kritatext_LIB_SRCS
- KoDocumentRdfBase.cpp
- KoText.cpp
- KoTextBlockData.cpp
- KoTextBlockBorderData.cpp
- KoTextBlockPaintStrategyBase.cpp
- KoTextOdfSaveHelper.cpp
- KoTextDocument.cpp
- KoTextEditor.cpp
- KoTextEditor_undo.cpp
- KoTextEditor_format.cpp
- KoList.cpp
-
- KoTextEditingRegistry.cpp
- KoTextEditingFactory.cpp
- KoTextEditingPlugin.cpp
-
- KoTextRangeManager.cpp
- KoInlineTextObjectManager.cpp
- KoInlineObjectFactoryBase.cpp
- KoInlineObjectRegistry.cpp
- InsertInlineObjectActionBase_p.cpp
- InsertVariableAction.cpp
- InsertNamedVariableAction.cpp
- InsertTextReferenceAction.cpp
- InsertTextLocator.cpp
- KoInlineObject.cpp
- KoTextRange.cpp
- KoVariable.cpp
- KoVariableManager.cpp
- KoNamedVariable.cpp
- KoSection.cpp
- KoSectionEnd.cpp
- KoSectionUtils.cpp
- KoSectionModel.cpp
- KoTextLocator.cpp
- KoTextReference.cpp
- KoAnchorInlineObject.cpp
- KoAnchorTextRange.cpp
- KoTextShapeSavingContext.cpp
- KoAnnotation.cpp
- KoAnnotationManager.cpp
- KoBookmark.cpp
- KoBookmarkManager.cpp
- KoInlineNote.cpp
- KoInlineCite.cpp
- KoTextSoftPageBreak.cpp
- KoTextDebug.cpp
- KoTextPage.cpp
- KoPageProvider.cpp
- KoTableColumnAndRowStyleManager.cpp
- KoTextInlineRdf.cpp
- KoTextMeta.cpp
- KoTextTableTemplate.cpp
-
- OdfTextTrackStyles.cpp
-
- ToCBibGeneratorInfo.cpp
- KoTableOfContentsGeneratorInfo.cpp
- KoBibliographyInfo.cpp
-
- styles/Styles_p.cpp
- styles/KoCharacterStyle.cpp
- styles/KoParagraphStyle.cpp
- styles/KoStyleManager.cpp
- styles/KoListStyle.cpp
- styles/KoListLevelProperties.cpp
- styles/KoTableStyle.cpp
- styles/KoTableColumnStyle.cpp
- styles/KoTableRowStyle.cpp
- styles/KoTableCellStyle.cpp
- styles/KoSectionStyle.cpp
- opendocument/KoTextSharedLoadingData.cpp
- opendocument/KoTextSharedSavingData.cpp
- opendocument/KoTextLoader.cpp
- opendocument/KoTextWriter_p.cpp
- opendocument/KoTextWriter.cpp
-
- changetracker/KoChangeTracker.cpp
- changetracker/KoChangeTrackerElement.cpp
- changetracker/KoFormatChangeInformation.cpp
- changetracker/KoDeletedRowColumnDataStore.cpp
- changetracker/KoDeletedRowData.cpp
- changetracker/KoDeletedColumnData.cpp
- changetracker/KoDeletedCellData.cpp
-
- commands/ChangeAnchorPropertiesCommand.cpp
- commands/ChangeListCommand.cpp
- commands/ChangeStylesCommand.cpp
- commands/ChangeStylesMacroCommand.cpp
- commands/DeleteAnchorsCommand.cpp
- commands/DeleteAnnotationsCommand.cpp
- commands/DeleteCommand.cpp
- commands/DeleteTableColumnCommand.cpp
- commands/DeleteTableRowCommand.cpp
- commands/InsertNoteCommand.cpp
- commands/InsertTableColumnCommand.cpp
- commands/InsertTableRowCommand.cpp
- commands/ResizeTableCommand.cpp
- commands/InsertInlineObjectCommand.cpp
- commands/ListItemNumberingCommand.cpp
- commands/TextPasteCommand.cpp
- commands/AddTextRangeCommand.cpp
- commands/AddAnnotationCommand.cpp
- commands/ParagraphFormattingCommand.cpp
- commands/RenameSectionCommand.cpp
- commands/NewSectionCommand.cpp
- commands/SplitSectionsCommand.cpp
-
- KoTextDrag.cpp
- KoTextCommandBase.cpp
-
- TextDebug.cpp
-)
-
-add_library(kritatext SHARED ${kritatext_LIB_SRCS})
-generate_export_header(kritatext BASE_NAME kritatext)
-
-target_link_libraries(kritatext kritaflake Qt5::Gui kritawidgetutils )
-target_link_libraries(kritatext LINK_INTERFACE_LIBRARIES kritaflake Qt5::Gui )
-
-target_include_directories(kritatext
- PUBLIC
- $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/opendocument>
- $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/changetracker>
- $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/styles>
-)
-set_target_properties(kritatext PROPERTIES
- VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION}
-)
-install(TARGETS kritatext ${INSTALL_TARGETS_DEFAULT_ARGS})
diff --git a/plugins/flake/textshape/kotext/Documentation/Howto-undoRedoCommands.txt b/plugins/flake/textshape/kotext/Documentation/Howto-undoRedoCommands.txt
deleted file mode 100644
index 444fa3e03b..0000000000
--- a/plugins/flake/textshape/kotext/Documentation/Howto-undoRedoCommands.txt
+++ /dev/null
@@ -1,106 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2012 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- *
- * 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.
- */
-
-There are 3 ways to use the undo/redo framework. 1 is only accessible from within the KoTextEditor. The other 2 are publicly available.
-
-------------------------
-1. using the updateState method of the KoTextEditor::Private. (internal to KoTextEditor).
-
- At the beginning of an editing method in KoTextEditor, the updateState method should be called setting the proper state and a command title (see KoTextEditor_undo.cpp).
- A head command which will be pushed on the stack will be created when we first receive a signal from the QTextDocument. All edtiting actions on the QTextCursor will then create UndoTextCommands (in reaction to the QTextDocument's signal), which will be parented to the head command.
- When the editing method is finished, the state of the editor should be put back to NoOp, unless the editing method is an "open ended" one (key press or delete).
- Important notices:
- - When setting the new state, both the state and the command title are used to determine if we are in a new command. If both the state and the command title are identical to the current ones, the framework will not create a new head command. Example: the current state is "Format" with a command title "Format text". setting it again to "Foramt" state with "Fornat text" title will not create a new command on the application's undo stack. Setting it to "Format" state with "Bold" title will however create a new command on the application's stack.
- - This method should be used for low level editing methods, using QTextCursor to edit directly the document. Using KoTextEditor::addCommand or KoTextEditor::beginEditBlock from within this editing method might cause undesired behaviour (especially if no editing action occurred on the QTextCursor yet).
- - The only actions which will be undone/redone are the ones affecting the QTextDocument. Any Calligra actions will not get undone/redone here (eg. any maintenance in some high level manager like KoStyleManager, KoInlineObjectManager, shapes,....). If you need such things, this is not the method to do it, use a full blown KUndo2Command pushed with KoTextEditor::addCommand for this (see below).
-
-------------------------
-2. using KoTextEditor::addCommand method.
-
- This method allows to push a full self contained KUndo2Command. The method will be pushed on the KoTextEditor's commandStack. This means that this method will parent all UndoTextCommands created in reaction to the QTextDocument's signal, until the redo method of the command returns. At which point, it will be removed from the KoTextEditor's commandStack. If the KUndo2Command has a parent, it will not be pushed onto the application's undo stack. Equally if the KoTextEditor's commandStack isn't empty, the pushed KUndo2Command will not be pushed onto the application's undo stack (nested commands).
- It is important to note that only while the KUndo2Command's redo method is being executed is the command on the KoTextEditor's commandStack and is therefore parenting the QTextDocument's triggered UndoTextCommands, as well as any nested pushed KUndo2Commands.
- This means that ALL actions are to be implemented in the command's redo and undo methods. This includes any creation and push of a child KUndo2Command.
- Below is an example of how such a command should be constructed:
-
-class MyCommand : public KUndo2Command
-{
-public:
-
- MyCommand(MyCommandParameters, KUndo2Command* parent = 0);
- virtual ~MyCommand();
-
- virtual void undo();
- virtual void redo();
-
-//The following 2 methods are optional. Check Qt's documentation to see how to use these.
- virtual int id() const;
- virtual bool mergeWith ( const KUndo2Command *command);
-
-private:
- bool m_first;
-};
-
-MyCommand::MyCommand(MyCommandParameters, KUndo2Command *parent):
- KUndo2Command(parent),
- m_first(true),
- m_deleteAnchors(false)
-{
- Here you can do some initialisations, collect information, ...
- No "active" stuff can go in the constructor because:
- - anything happening in the constructor will be called only on construction,
- - if a change to the QTextDocument happens, an UndoTextCommand will be created and get either parented to the wrong KUndo2Command, or create an unwanted command on the application's undo stack.
-}
-
-MyCommand::~MyCommand()
-{
- Well, you know what you have to do in here...
-}
-
-void MyCommand::redo()
-{
- if (m_first) {
- m_first = false;
-
- Do your editing and actions in here.
- This is also where children KUndo2Commands should be created and pushed on the KoTextEditor using KoTextEditor::addCommand. These children should be passed this command as parent (mandatory). A parent command is responsible for deleting its children KUndo2Commands.
-
- }
- else {
- KUndo2Command::redo();
- This will ensure that all children commands (either the KUndo2Commands we created or the auto-generated UndoTextCommands) are redone. This means that all the changes done to the QTextDocument will be redone by Qt automattically.
- In here you would also redo anything that is not linked to editing the QTextDocument directly, like update status in the managers (StyleManager, ObjectManagers,...)
- }
-}
-
-void MyCommand::undo()
-{
- KUndo2Command::undo();
- This will ensure that all children commands (either the KUndo2Commands we created or the auto-generated UndoTextCommands) are undone. This means that all the changes done to the QTextDocument will be undone by Qt automattically.
- In here you would also undo anything that is not linked to editing the QTextDocument directly, like update status in the managers (StyleManager, ObjectManagers,...)
-}
-
-------------------------
-3. using KoTextEditor::beginEditBlock/endEditBlock method
-
-This method can be used to group several editions of a QTextDocument through a QTextEditor within one KUndo2Command. The KUndo2Command will be created (if none is currently present on the commandStack), a pointer to it (or to the commandStack's top command) is returned by beginEditBlock. All editions done before the call to endEditBlock will belong to the same KUndo2Command.
-
-It is safe do call this from within a redo method of a custom KUndo2Command which has been pushed by the KoTextEditor::addCommand. However, it is NOT safe to push such a command from within a beginEditBlock/endEditBlock. This is because addCommand will put the KUndo2Command on the commandStack, call redo and remove it from commandStack. However, since we are in a beginEditBlock/endEditBlock, QTextDocument will not send any signal (they are all sent when we call endEditBlock). This means that by the time these signals are sent, the custom KUndo2Command will not be on the commandStack anymore and the auto generated UndoTextCommands will not be properly parented.
-
-This method is also not suitable for undo/redo actions which also need to act outside the QTextDocument (like doing stuff with the managers,....). This method will push an auto generated KUndo2Command on the application stack, which will serve as parent for all the UndoTextCommand (generated because of QTextDocument's signals).
-The only actions which will be undone/redone are the ones affecting the QTextDocument. Any Calligra actions will not get undone/redone here (eg. any maintenance in some high level manager like KoStyleManager, KoInlineObjectManager, shapes,....). If you need such things, this is not the method to do it, use a full blown KUndo2Command pushed with KoTextEditor::addCommand for this (see above: method 2).
diff --git a/plugins/flake/textshape/kotext/InsertInlineObjectActionBase_p.cpp b/plugins/flake/textshape/kotext/InsertInlineObjectActionBase_p.cpp
deleted file mode 100644
index 9d0dc5490d..0000000000
--- a/plugins/flake/textshape/kotext/InsertInlineObjectActionBase_p.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 "InsertInlineObjectActionBase_p.h"
-#include "KoInlineObject.h"
-#include "KoTextEditor.h"
-
-#include <KoCanvasBase.h>
-
-#include "TextDebug.h"
-
-InsertInlineObjectActionBase::InsertInlineObjectActionBase(KoCanvasBase *canvas, const QString &name)
- : QAction(name, canvas->canvasWidget()),
- m_canvas(canvas)
-{
- connect(this, SIGNAL(triggered(bool)), this, SLOT(activated()));
-}
-
-InsertInlineObjectActionBase::~InsertInlineObjectActionBase()
-{
-}
-
-void InsertInlineObjectActionBase::activated()
-{
- Q_ASSERT(m_canvas);
- KoTextEditor *editor = KoTextEditor::getTextEditorFromCanvas(m_canvas);
- if (editor) {
- KoInlineObject *obj = createInlineObject();
- if (obj) {
- editor->insertInlineObject(obj);
- }
- }
-}
diff --git a/plugins/flake/textshape/kotext/InsertInlineObjectActionBase_p.h b/plugins/flake/textshape/kotext/InsertInlineObjectActionBase_p.h
deleted file mode 100644
index fd4542b133..0000000000
--- a/plugins/flake/textshape/kotext/InsertInlineObjectActionBase_p.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 INSERTINLINEOBJECTACTIONBASE_H
-#define INSERTINLINEOBJECTACTIONBASE_H
-
-#include <QAction>
-#include <QPointer>
-
-#include <KoCanvasBase.h>
-
-class KoInlineObject;
-
-/**
- * helper class
- */
-class InsertInlineObjectActionBase : public QAction
-{
- Q_OBJECT
-public:
- InsertInlineObjectActionBase(KoCanvasBase *canvas, const QString &name);
- ~InsertInlineObjectActionBase() override;
-
-private Q_SLOTS:
- void activated();
-
-protected:
- virtual KoInlineObject *createInlineObject() = 0;
-
- QPointer<KoCanvasBase> m_canvas;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/InsertNamedVariableAction.cpp b/plugins/flake/textshape/kotext/InsertNamedVariableAction.cpp
deleted file mode 100644
index 7f4d13c281..0000000000
--- a/plugins/flake/textshape/kotext/InsertNamedVariableAction.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 "InsertNamedVariableAction_p.h"
-#include "KoInlineTextObjectManager.h"
-
-#include "KoVariable.h"
-
-InsertNamedVariableAction::InsertNamedVariableAction(KoCanvasBase *canvas, const KoInlineTextObjectManager *manager, const QString &name)
- : InsertInlineObjectActionBase(canvas, name),
- m_manager(manager),
- m_name(name)
-{
-}
-
-KoInlineObject *InsertNamedVariableAction::createInlineObject()
-{
- return m_manager->variableManager()->createVariable(m_name);
-}
diff --git a/plugins/flake/textshape/kotext/InsertNamedVariableAction_p.h b/plugins/flake/textshape/kotext/InsertNamedVariableAction_p.h
deleted file mode 100644
index aa562f70a6..0000000000
--- a/plugins/flake/textshape/kotext/InsertNamedVariableAction_p.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 INSERTNAMEDVARIABLEACTION_H
-#define INSERTNAMEDVARIABLEACTION_H
-
-#include "InsertInlineObjectActionBase_p.h"
-
-class KoInlineTextObjectManager;
-
-/**
- * helper class
- */
-class InsertNamedVariableAction : public InsertInlineObjectActionBase
-{
-public:
- InsertNamedVariableAction(KoCanvasBase *canvas, const KoInlineTextObjectManager *manager, const QString &name);
-
-private:
- KoInlineObject *createInlineObject() override;
-
- const KoInlineTextObjectManager *m_manager;
- QString m_name;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/InsertTextLocator.cpp b/plugins/flake/textshape/kotext/InsertTextLocator.cpp
deleted file mode 100644
index 2371f84d15..0000000000
--- a/plugins/flake/textshape/kotext/InsertTextLocator.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2010 Thomas Zander <zander@kde.org>
- *
- * 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 "InsertTextLocator_p.h"
-#include "KoTextEditor.h"
-
-#include <KoCanvasBase.h>
-
-
-InsertTextLocator::InsertTextLocator(KoCanvasBase *canvas)
- : InsertInlineObjectActionBase(canvas, i18n("Index Reference"))
-{
-}
-
-KoInlineObject *InsertTextLocator::createInlineObject()
-{
- Q_ASSERT(m_canvas);
- KoTextEditor *editor = KoTextEditor::getTextEditorFromCanvas(m_canvas);
- if (editor) {
- KoInlineObject *obj = editor->insertIndexMarker();
- Q_UNUSED(obj); // intentionally unused: if we return it, it gets inserted again
- }
- return 0;
-}
diff --git a/plugins/flake/textshape/kotext/InsertTextLocator_p.h b/plugins/flake/textshape/kotext/InsertTextLocator_p.h
deleted file mode 100644
index 35cd3a6ae1..0000000000
--- a/plugins/flake/textshape/kotext/InsertTextLocator_p.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 INSERTTEXTLOCATOR_H
-#define INSERTNAMEDVARIABLEACTION_H
-
-#include "InsertInlineObjectActionBase_p.h"
-
-/**
- * helper class
- */
-class InsertTextLocator : public InsertInlineObjectActionBase
-{
-public:
- explicit InsertTextLocator(KoCanvasBase *canvas);
-
-private:
- KoInlineObject *createInlineObject() override;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/InsertTextReferenceAction.cpp b/plugins/flake/textshape/kotext/InsertTextReferenceAction.cpp
deleted file mode 100644
index a4d0c00bba..0000000000
--- a/plugins/flake/textshape/kotext/InsertTextReferenceAction.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 "InsertTextReferenceAction_p.h"
-#include "KoTextLocator.h"
-#include "KoTextReference.h"
-#include "KoInlineTextObjectManager.h"
-
-#include <KoCanvasBase.h>
-
-#include <klocalizedstring.h>
-#include <kmessagebox.h>
-#include <kpagedialog.h>
-#include <QVBoxLayout>
-#include <QListWidget>
-#include <QLabel>
-
-InsertTextReferenceAction::InsertTextReferenceAction(KoCanvasBase *canvas, const KoInlineTextObjectManager *manager)
- : InsertInlineObjectActionBase(canvas, i18n("Text Reference")),
- m_manager(manager)
-{
-}
-
-KoInlineObject *InsertTextReferenceAction::createInlineObject()
-{
- const QList<KoTextLocator*> textLocators = m_manager->textLocators();
- if (textLocators.isEmpty()) {
- KMessageBox::information(m_canvas->canvasWidget(), i18n("Please create an index to reference first."));
- return 0;
- }
-
- QWidget *widget = new QWidget();
- QVBoxLayout *lay = new QVBoxLayout(widget);
- widget->setLayout(lay);
- lay->setMargin(0);
-
- QLabel *label = new QLabel(i18n("Select the index you want to reference"), widget);
- lay->addWidget(label);
- QStringList selectionList;
- Q_FOREACH (KoTextLocator* locator, textLocators)
- selectionList << locator->word() + '(' + QString::number(locator->pageNumber()) + ')';
- QListWidget *list = new QListWidget(widget);
- lay->addWidget(list);
- list->addItems(selectionList);
-
- KPageDialog dialog(m_canvas->canvasWidget());
- dialog.setWindowTitle(i18n("%1 Options", i18n("Text Reference"))); // reuse the text passed in the constructor
- dialog.addPage(widget, QString());
-
- KoVariable *variable = 0;
- if (dialog.exec() == KPageDialog::Accepted && list->currentRow() >= 0) {
- KoTextLocator *locator = textLocators[list->currentRow()];
- Q_ASSERT(locator);
- variable = new KoTextReference(locator->id());
- }
- return variable;
-}
diff --git a/plugins/flake/textshape/kotext/InsertTextReferenceAction_p.h b/plugins/flake/textshape/kotext/InsertTextReferenceAction_p.h
deleted file mode 100644
index 0b66be6ef6..0000000000
--- a/plugins/flake/textshape/kotext/InsertTextReferenceAction_p.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 INSERTTEXTREFERENCEACTION_H
-#define INSERTTEXTREFERENCEACTION_H
-
-#include "InsertInlineObjectActionBase_p.h"
-
-class KoInlineTextObjectManager;
-
-/**
- * helper class
- */
-class InsertTextReferenceAction : public InsertInlineObjectActionBase
-{
-public:
- InsertTextReferenceAction(KoCanvasBase *canvas, const KoInlineTextObjectManager *manager);
-
-private:
- KoInlineObject *createInlineObject() override;
-
- const KoInlineTextObjectManager *m_manager;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/InsertVariableAction.cpp b/plugins/flake/textshape/kotext/InsertVariableAction.cpp
deleted file mode 100644
index 0f2040344e..0000000000
--- a/plugins/flake/textshape/kotext/InsertVariableAction.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 "InsertVariableAction_p.h"
-#include "KoVariable.h"
-#include "KoInlineObjectFactoryBase.h"
-#include "KoText.h"
-
-#include <KoCanvasBase.h>
-#include <KoShapeController.h>
-#include <KoInlineTextObjectManager.h>
-
-#include <kpagedialog.h>
-
-#include <klocalizedstring.h>
-#include <QLayout>
-
-InsertVariableAction::InsertVariableAction(KoCanvasBase *base, KoInlineObjectFactoryBase *factory, const KoInlineObjectTemplate &templ)
- : InsertInlineObjectActionBase(base, templ.name)
- , m_factory(factory)
- , m_templateId(templ.id)
- , m_properties(templ.properties)
- , m_templateName(templ.name)
-{
-}
-
-KoInlineObject *InsertVariableAction::createInlineObject()
-{
- KoInlineObject *io = m_factory->createInlineObject(m_properties);
- KoVariable *variable = dynamic_cast<KoVariable*>(io);
- Q_ASSERT(variable);
- KoInlineTextObjectManager *objManager = m_canvas->shapeController()->resourceManager()->resource(KoText::InlineTextObjectManager).value<KoInlineTextObjectManager*>();
- Q_ASSERT(objManager);
- variable->setManager(objManager);
- QWidget *widget = variable->createOptionsWidget();
- if (widget) {
- if (widget->layout()) {
- widget->layout()->setMargin(0);
- }
- KPageDialog *dialog = new KPageDialog(m_canvas->canvasWidget());
- dialog->setWindowTitle(i18n("%1 Options", m_templateName));
- dialog->addPage(widget, QString());
- if (dialog->exec() != KPageDialog::Accepted) {
- delete variable;
- variable = 0;
- }
- delete dialog;
- }
- return variable;
-}
diff --git a/plugins/flake/textshape/kotext/InsertVariableAction_p.h b/plugins/flake/textshape/kotext/InsertVariableAction_p.h
deleted file mode 100644
index 93e893ec28..0000000000
--- a/plugins/flake/textshape/kotext/InsertVariableAction_p.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 INSERTVARIABLEACTION_H
-#define INSERTVARIABLEACTION_H
-
-#include "InsertInlineObjectActionBase_p.h"
-
-class KoProperties;
-class KoInlineObjectFactoryBase;
-struct KoInlineObjectTemplate;
-
-/// \internal
-class InsertVariableAction : public InsertInlineObjectActionBase
-{
-public:
- InsertVariableAction(KoCanvasBase *base, KoInlineObjectFactoryBase *factory, const KoInlineObjectTemplate &templ);
-
-private:
- KoInlineObject *createInlineObject() override;
-
- KoInlineObjectFactoryBase *const m_factory;
- const QString m_templateId;
- const KoProperties *const m_properties;
- QString m_templateName;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoAnchorInlineObject.cpp b/plugins/flake/textshape/kotext/KoAnchorInlineObject.cpp
deleted file mode 100644
index 806aa37a84..0000000000
--- a/plugins/flake/textshape/kotext/KoAnchorInlineObject.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007, 2009-2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2010 Ko Gmbh <cbo@kogmbh.com>
- * Copyright (C) 2011 Matus Hanzes <matus.hanzes@ixonos.com>
- * Copyright (C) 2013 C. Boemann <cbo@boemann.dk>
- *
- * 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 "KoAnchorInlineObject.h"
-#include "KoInlineObject_p.h"
-#include "KoShapeAnchor.h"
-
-#include <KoShapeSavingContext.h>
-#include <KoShapeLoadingContext.h>
-#include <KoShape.h>
-
-#include <QTextInlineObject>
-#include <QFontMetricsF>
-#include "TextDebug.h"
-
-// #define DEBUG_PAINTING
-
-class KoAnchorInlineObjectPrivate : public KoInlineObjectPrivate
-{
-public:
- KoAnchorInlineObjectPrivate(KoShapeAnchor *p)
- : parent(p)
- , document(0)
- , position(-1)
- , inlineObjectAscent(0)
- , inlineObjectDescent(0)
- {
- }
-
- KoShapeAnchor *parent;
- const QTextDocument *document;
- int position;
- QTextCharFormat format;
- qreal inlineObjectAscent;
- qreal inlineObjectDescent;
-};
-
-KoAnchorInlineObject::KoAnchorInlineObject(KoShapeAnchor *parent)
- : KoInlineObject(*(new KoAnchorInlineObjectPrivate(parent)), false)
-{
- Q_ASSERT(parent);
- parent->setTextLocation(this);
-}
-
-KoAnchorInlineObject::~KoAnchorInlineObject()
-{
-}
-
-KoShapeAnchor *KoAnchorInlineObject::anchor() const
-{
- Q_D(const KoAnchorInlineObject);
- return d->parent;
-}
-
-void KoAnchorInlineObject::updatePosition(const QTextDocument *document, int posInDocument, const QTextCharFormat &format)
-{
- Q_D(KoAnchorInlineObject);
- d->document = document;
- d->position = posInDocument;
- d->format = format;
- if (d->parent->placementStrategy() != 0) {
- d->parent->placementStrategy()->updateContainerModel();
- }
-}
-
-void KoAnchorInlineObject::resize(const QTextDocument *document, QTextInlineObject &object, int posInDocument, const QTextCharFormat &format, QPaintDevice *pd)
-{
- Q_UNUSED(document);
- Q_UNUSED(posInDocument);
- Q_D(KoAnchorInlineObject);
-
- if (!d->parent->shape()->isVisible()) {
- // Per default the shape this anchor presents is hidden and we only make it visible once an explicit resize-request
- // was made. This prevents shapes that are anchored at e.g. hidden textboxes to not become visible as long as they
- // are not asked to resize.
- d->parent->shape()->setVisible(true);
- }
-
- // important detail; top of anchored shape is at the baseline.
- QFontMetricsF fm(format.font(), pd);
- if (d->parent->anchorType() == KoShapeAnchor::AnchorAsCharacter) {
- QPointF offset = d->parent->offset();
- offset.setX(0);
- d->parent->setOffset(offset);
- object.setWidth(d->parent->shape()->size().width());
- if (d->parent->verticalRel() == KoShapeAnchor::VBaseline) {
- // baseline implies special meaning of the position attribute:
- switch (d->parent->verticalPos()) {
- case KoShapeAnchor::VFromTop:
- object.setAscent(qMax((qreal) 0, -offset.y()));
- object.setDescent(qMax((qreal) 0, d->parent->shape()->size().height() + offset.y()));
- break;
- case KoShapeAnchor::VTop:
- object.setAscent(d->parent->shape()->size().height());
- object.setDescent(0);
- break;
- case KoShapeAnchor::VMiddle:
- object.setAscent(d->parent->shape()->size().height()/2);
- object.setDescent(d->parent->shape()->size().height()/2);
- break;
- case KoShapeAnchor::VBottom:
- object.setAscent(0);
- object.setDescent(d->parent->shape()->size().height());
- break;
- default:
- break;
- }
- } else {
- qreal boundTop = fm.ascent();
- switch (d->parent->verticalPos()) {
- case KoShapeAnchor::VFromTop:
- object.setAscent(qMax((qreal) 0, -offset.y()));
- object.setDescent(qMax((qreal) 0, d->parent->shape()->size().height() + offset.y()));
- break;
- case KoShapeAnchor::VTop:
- object.setAscent(boundTop);
- object.setDescent(qMax((qreal) 0, d->parent->shape()->size().height() - boundTop));
- break;
- case KoShapeAnchor::VMiddle:
- object.setAscent(d->parent->shape()->size().height()/2);
- object.setDescent(d->parent->shape()->size().height()/2);
- break;
- case KoShapeAnchor::VBottom:
- object.setAscent(0);
- object.setDescent(d->parent->shape()->size().height());
- break;
- default:
- break;
- }
- }
- d->inlineObjectAscent = object.ascent();
- d->inlineObjectDescent = object.descent();
- } else {
- object.setWidth(0);
- object.setAscent(0);
- object.setDescent(0);
- }
-}
-
-void KoAnchorInlineObject::paint(QPainter &, QPaintDevice *, const QTextDocument *, const QRectF &, const QTextInlineObject &, int , const QTextCharFormat &)
-{
-}
-
-int KoAnchorInlineObject::position() const
-{
- Q_D(const KoAnchorInlineObject);
- return d->position;
-}
-
-const QTextDocument *KoAnchorInlineObject::document() const
-{
- Q_D(const KoAnchorInlineObject);
- return d->document;
-}
-
-qreal KoAnchorInlineObject::inlineObjectAscent() const
-{
- Q_D(const KoAnchorInlineObject);
- return d->inlineObjectAscent;
-}
-
-qreal KoAnchorInlineObject::inlineObjectDescent() const
-{
- Q_D(const KoAnchorInlineObject);
- return d->inlineObjectDescent;
-}
-
-bool KoAnchorInlineObject::loadOdf(const KoXmlElement &, KoShapeLoadingContext &)
-{
- // do nothing
- return true;
-}
-
-void KoAnchorInlineObject::saveOdf(KoShapeSavingContext &context)
-{
- Q_D(KoAnchorInlineObject);
- d->parent->saveOdf(context);
-}
diff --git a/plugins/flake/textshape/kotext/KoAnchorInlineObject.h b/plugins/flake/textshape/kotext/KoAnchorInlineObject.h
deleted file mode 100644
index e2a3bea8ff..0000000000
--- a/plugins/flake/textshape/kotext/KoAnchorInlineObject.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007, 2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2011 Matus Hanzes <matus.hanzes@ixonos.com>
- * Copyright (C) 2013 C. Boemann <cbo@boemann.dk>
- *
- * 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 KOANCHORINLINEOBJECT_H
-#define KOANCHORINLINEOBJECT_H
-
-#include "KoInlineObject.h"
-
-#include "KoShapeAnchor.h"
-
-#include "kritatext_export.h"
-
-class KoAnchorInlineObjectPrivate;
-
-/**
- * This class connects KoShapeAnchor to an inline character in the text document.
- *
- * This class is used when the shape anchor is of type: as-char
- *
- * It has to be registered to the inlineobjectmanager and thus forms the connection between the text
- * and the KoShapeAnchor and by extension the so called 'anchored-shape' (any kind of shape)
- *
- * The KoAnchorInlineObject is placed as a character in text. As such it will move and be
- * editable like any other character, including deletion.
- *
- * Since this is a real character it will be positioned by the textlayout engine and anything that
- * will change the position of the text will thus also change the KoAnchorInlineObject character.
- *
- * The anchored-shape can be repositioned on the canvas if the text is relayouted (for example after
- * editing the text. This is dependent on how the text layout is implemented.
- *
- * Steps to use a KoAnchorInlineObject are
- * <ol>
- * <li> Create KoShapeAnchor *anchor = new KoShapeAnchor(shape);
- * <li> Use anchor->loadOdf() to load additional attributes like the "text:anchor-type"
- * <li> if type is as-char create KoAnchorInlineObject *anchorObj = new KoAnchorInlineObject(anchor);
- * </ol>
- */
-class KRITATEXT_EXPORT KoAnchorInlineObject : public KoInlineObject, public KoShapeAnchor::TextLocation
-{
- Q_OBJECT
-public:
- /**
- * Constructor for an as-char anchor.
- * @param parent the shapeanchor.
- */
- explicit KoAnchorInlineObject(KoShapeAnchor *parent);
- ~KoAnchorInlineObject() override;
-
- /// returns the parent anchor
- KoShapeAnchor *anchor() const;
-
- /// returns the cursor position in the document where this anchor is positioned.
- int position() const override;
-
- /// returns the document that this anchor is associated with.
- const QTextDocument *document() const override;
-
- /// reimplemented from KoInlineObject
- void updatePosition(const QTextDocument *document,
- int posInDocument, const QTextCharFormat &format) override;
- /// reimplemented from KoInlineObject
- void resize(const QTextDocument *document, QTextInlineObject &object,
- int posInDocument, const QTextCharFormat &format, QPaintDevice *pd) override;
- /// reimplemented from KoInlineObject
- void paint(QPainter &painter, QPaintDevice *pd, const QTextDocument *document,
- const QRectF &rect, const QTextInlineObject &object, int posInDocument, const QTextCharFormat &format) override;
-
- qreal inlineObjectAscent() const;
-
- qreal inlineObjectDescent() const;
-
- /// reimplemented from KoInlineObject - should not do anything
- bool loadOdf(const KoXmlElement &, KoShapeLoadingContext &) override;
-
- /// reimplemented from KoInlineObject
- void saveOdf(KoShapeSavingContext &context) override;
-
-
-private:
- Q_DECLARE_PRIVATE(KoAnchorInlineObject)
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoAnchorTextRange.cpp b/plugins/flake/textshape/kotext/KoAnchorTextRange.cpp
deleted file mode 100644
index 2befe407e7..0000000000
--- a/plugins/flake/textshape/kotext/KoAnchorTextRange.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007, 2009-2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2010 Ko Gmbh <cbo@kogmbh.com>
- * Copyright (C) 2011 Matus Hanzes <matus.hanzes@ixonos.com>
- * Copyright (C) 2013 C. Boemann <cbo@boemann.dk>
- *
- * 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 "KoAnchorTextRange.h"
-#include "KoShapeAnchor.h"
-
-#include <KoShapeSavingContext.h>
-#include <KoShape.h>
-
-#include "TextDebug.h"
-
-
-class KoAnchorTextRangePrivate
-{
-public:
- KoAnchorTextRangePrivate(KoShapeAnchor *p)
- : parent(p)
- {
- }
-
- KoShapeAnchor *parent;
-};
-
-KoAnchorTextRange::KoAnchorTextRange(KoShapeAnchor *parent, const QTextCursor &cursor)
- : KoTextRange(cursor)
- , d_ptr(new KoAnchorTextRangePrivate(parent))
-{
- Q_ASSERT(parent);
- parent->setTextLocation(this);
-}
-
-KoAnchorTextRange::~KoAnchorTextRange()
-{
- delete d_ptr;
-}
-
-KoShapeAnchor *KoAnchorTextRange::anchor() const
-{
- Q_D(const KoAnchorTextRange);
- return d->parent;
-}
-
-const QTextDocument *KoAnchorTextRange::document() const
-{
- return KoTextRange::document();
-}
-
-int KoAnchorTextRange::position() const
-{
- return rangeStart();
-}
-
-void KoAnchorTextRange::updateContainerModel()
-{
- Q_D(KoAnchorTextRange);
-
- if (!d->parent->shape()->isVisible()) {
- // Per default the shape this anchor presents is hidden and we only make it visible once an
- // explicit placement is made. This prevents shapes that are anchored at e.g. hidden
- // textboxes to not become visible.
- d->parent->shape()->setVisible(true);
- }
-
- if (d->parent->placementStrategy() != 0) {
- d->parent->placementStrategy()->updateContainerModel();
- }
-}
-
-bool KoAnchorTextRange::loadOdf(const KoXmlElement &, KoShapeLoadingContext &)
-{
- return true;
-}
-
-void KoAnchorTextRange::saveOdf(KoShapeSavingContext &context, int position, KoTextRange::TagType tagType) const
-{
- Q_UNUSED(position);
- Q_UNUSED(tagType);
-
- Q_D(const KoAnchorTextRange);
- if (tagType == KoTextRange::StartTag) {
- d->parent->saveOdf(context);
- }
-}
diff --git a/plugins/flake/textshape/kotext/KoAnchorTextRange.h b/plugins/flake/textshape/kotext/KoAnchorTextRange.h
deleted file mode 100644
index 35b441680c..0000000000
--- a/plugins/flake/textshape/kotext/KoAnchorTextRange.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007, 2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2011 Matus Hanzes <matus.hanzes@ixonos.com>
- * Copyright (C) 2013 C. Boemann <cbo@boemann.dk>
- *
- * 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 KOANCHORTEXTRANGE_H
-#define KOANCHORTEXTRANGE_H
-
-#include "KoTextRange.h"
-
-#include "KoShapeAnchor.h"
-
-#include "kritatext_export.h"
-
-class KoAnchorTextRangePrivate;
-class QTextCursor;
-
-/**
- * This class connects KoShapeAnchor to a position in the text document.
- *
- * This class is used when the shape anchor is of type: char or paragraph
- *
- * It has to be registered to the textrange manager and thus forms the connection between the text
- * and the KoShapeAnchor and by extension the so called 'anchored-shape' (any kind of shape)
- *
- * The KoAnchorTextRange is placed at a position in text. As with all KoTextRange it will change
- * it's position in the text when the user edits text before it. The user is also able to delete it if
- * deleting the text where it is positioned.
- *
- * The anchored-shape can be repositioned on the canvas if the text is relayouted (for example after
- * editing the text. This is dependent on how the text layout is implemented.
- *
- * Steps to use a KoAnchorTextRange are
- * <ol>
- * <li> Create KoShapeAnchor *anchor = new KoShapeAnchor(shape);
- * <li> Use anchor->loadOdf() to load additional attributes like the "text:anchor-type"
- * <li> if type is char or paragraph create KoAnchorTextRange *anchorRange = new KoAnchorTextRange(anchor);
- * </ol>
- */
-class KRITATEXT_EXPORT KoAnchorTextRange : public KoTextRange, public KoShapeAnchor::TextLocation
-{
- Q_OBJECT
-public:
- /**
- * Constructor for a char or paragraph anchor.
- * @param parent the shape anchor.
- * @param cursor the text cursor.
- */
- KoAnchorTextRange(KoShapeAnchor *parent, const QTextCursor &cursor);
- ~KoAnchorTextRange() override;
-
- /// returns the parent anchor
- KoShapeAnchor *anchor() const;
-
- /// reimplemented from KoShapeAnchor::TextLocation
- const QTextDocument *document() const override;
-
- /// reimplemented from KoShapeAnchor::TextLocation
- int position() const override;
-
- void updateContainerModel();
-
- /// reimplemented from KoTextRange - should not do anything
- bool loadOdf(const KoXmlElement &, KoShapeLoadingContext &) override;
-
- /// reimplemented from KoTextRange
- void saveOdf(KoShapeSavingContext &context, int position, KoTextRange::TagType tagType) const override;
-
-private:
- KoAnchorTextRangePrivate * const d_ptr;
- Q_DECLARE_PRIVATE(KoAnchorTextRange)
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoAnnotation.cpp b/plugins/flake/textshape/kotext/KoAnnotation.cpp
deleted file mode 100644
index 6aa514b618..0000000000
--- a/plugins/flake/textshape/kotext/KoAnnotation.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007-2008 Fredy Yanardi <fyanardi@gmail.com>
- * Copyright (C) 2011 Boudewijn Rempt <boud@valdyas.org>
- * Copyright (C) 2012 Inge Wallin <inge@lysator.liu.se>
- *
- * 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 "KoAnnotation.h"
-
-#include <KoShapeSavingContext.h>
-#include <KoXmlWriter.h>
-#include <KoXmlReader.h>
-#include <KoTextInlineRdf.h>
-#include <KoTextRangeManager.h>
-#include <KoXmlNS.h>
-#include <KoShape.h>
-
-#include <QTextDocument>
-#include <QTextBlock>
-#include <QTextCursor>
-#include "TextDebug.h"
-
-// Include Q_UNSUSED classes, for building on Windows
-#include <KoShapeLoadingContext.h>
-
-class Q_DECL_HIDDEN KoAnnotation::Private
-{
-public:
- Private(const QTextDocument *doc):
- document(doc),
- posInDocument(0) { }
- const QTextDocument *document;
- int posInDocument;
-
- // Name of this annotation. It is used to tie together the annotation and annotation-end tags
- QString name;
-
- KoShape *shape;
-};
-
-KoAnnotation::KoAnnotation(const QTextCursor &cursor)
- : KoTextRange(cursor),
- d(new Private(cursor.block().document()))
-{
-}
-
-KoAnnotation::~KoAnnotation()
-{
- delete d;
-}
-
-
-void KoAnnotation::setName(const QString &name)
-{
- d->name = name;
-}
-
-QString KoAnnotation::name() const
-{
- return d->name;
-}
-
-void KoAnnotation::setAnnotationShape(KoShape *shape)
-{
- d->shape = shape;
-}
-
-KoShape *KoAnnotation::annotationShape() const
-{
- return d->shape;
-}
-
-bool KoAnnotation::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- Q_UNUSED(context);
-
- if (element.localName() != "annotation") {
- return false;
- }
-
- //debugText << "****** Start Load odf ******";
- QString annotationName = element.attribute("name");
-
- if (manager()) {
- // For cut and paste, make sure that the name is unique.
- d->name = createUniqueAnnotationName(manager()->annotationManager(), annotationName, false);
-
- // When loading an annotation we must assume that it is for a point rather than
- // a range. If we encounter an <annotation-end> tag later, we will change that.
- setPositionOnlyMode(true);
-
- // Add inline Rdf to the annotation.
- if (element.hasAttributeNS(KoXmlNS::xhtml, "property") || element.hasAttribute("id")) {
- KoTextInlineRdf* inlineRdf = new KoTextInlineRdf(const_cast<QTextDocument*>(d->document), this);
- if (inlineRdf->loadOdf(element)) {
- setInlineRdf(inlineRdf);
- }
- else {
- delete inlineRdf;
- inlineRdf = 0;
- }
- }
- //debugText << "****** End Load ******";
-
- return true;
- }
-
- return false;
-}
-
-void KoAnnotation::saveOdf(KoShapeSavingContext &context, int position, TagType tagType) const
-{
- KoXmlWriter *writer = &context.xmlWriter();
-
- if (!hasRange()) {
-
- if (tagType == StartTag) {
- writer->startElement("office:annotation", false);
- writer->addAttribute("text:name", d->name.toUtf8());
- if (inlineRdf()) {
- inlineRdf()->saveOdf(context, writer);
- }
-
- d->shape->saveOdf(context);
-
- writer->endElement(); //office:annotation
- }
-
- } else if ((tagType == StartTag) && (position == rangeStart())) {
- writer->startElement("office:annotation", false);
- writer->addAttribute("text:name", d->name.toUtf8());
- if (inlineRdf()) {
- inlineRdf()->saveOdf(context, writer);
- }
-
- d->shape->saveOdf(context);
-
- writer->endElement(); //office:annotation
- } else if ((tagType == EndTag) && (position == rangeEnd())) {
- writer->startElement("office:annotation-end", false);
- writer->addAttribute("text:name", d->name.toUtf8());
- writer->endElement();
- }
- // else nothing
-
-}
-
-QString KoAnnotation::createUniqueAnnotationName(const KoAnnotationManager* kam,
- const QString &annotationName, bool isEndMarker)
-{
- QString ret = annotationName;
- int uniqID = 0;
-
- while (true) {
- if (kam->annotation(ret)) {
- ret = QString("%1_%2").arg(annotationName).arg(++uniqID);
- } else {
- if (isEndMarker) {
- --uniqID;
- if (!uniqID)
- ret = annotationName;
- else
- ret = QString("%1_%2").arg(annotationName).arg(uniqID);
- }
- break;
- }
- }
- return ret;
-}
diff --git a/plugins/flake/textshape/kotext/KoAnnotation.h b/plugins/flake/textshape/kotext/KoAnnotation.h
deleted file mode 100644
index 26c9026e1a..0000000000
--- a/plugins/flake/textshape/kotext/KoAnnotation.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007-2008 Fredy Yanardi <fyanardi@gmail.com>
- * Copyright (C) 2011 Boudewijn Rempt <boud@valdyas.org>
- * Copyright (C) 2012 Inge Wallin <inge@lysator.liu.se>
- *
- * 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 KOANNOTATION_H
-#define KOANNOTATION_H
-
-#include "KoTextRange.h"
-#include "kritatext_export.h"
-
-class KoShape;
-class KoAnnotationManager;
-
-/**
- * An annotation is a note made by the user regarding a part of the
- * text. The annotation refers to either a position or a range of
- * text. The annotation location will be automatically updated if user
- * alters the text in the document.
-
- * An annotation is identified by it's name, and all annotations are
- * managed by KoAnnotationManager. An annotation can be retrieved from
- * the annotation manager by using name as identifier.
- *
- * @see KoAnnotationManager
- */
-class KRITATEXT_EXPORT KoAnnotation : public KoTextRange
-{
- Q_OBJECT
-public:
- /**
- * Constructor.
- *
- * By default an annotation has the SinglePosition type and an empty name.
- * The name is set when the annotation is inserted into the annotation manager.
- *
- * @param document the text document where this annotation is located
- */
- explicit KoAnnotation(const QTextCursor &);
-
- ~KoAnnotation() override;
-
- /// reimplemented from super
- void saveOdf(KoShapeSavingContext &context, int position, TagType tagType) const override;
-
- /**
- * Set the new name for this annotation
- * @param name the new name of the annotation
- */
- void setName(const QString &name);
-
- /// @return the name of this annotation
- QString name() const;
-
-
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
-
- /**
- * This is called to allow Cut and Paste of annotations. This
- * method gives a correct, unique, name
- */
- static QString createUniqueAnnotationName(const KoAnnotationManager* kam,
- const QString &annotationName, bool isEndMarker);
-
- void setAnnotationShape(KoShape *shape);
-
- KoShape *annotationShape() const;
-
-private:
-
- class Private;
- Private *const d;
-};
-
-#endif
-
diff --git a/plugins/flake/textshape/kotext/KoAnnotationManager.cpp b/plugins/flake/textshape/kotext/KoAnnotationManager.cpp
deleted file mode 100644
index 136321187f..0000000000
--- a/plugins/flake/textshape/kotext/KoAnnotationManager.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Fredy Yanardi <fyanardi@gmail.com>
- * Copyright (c) 2011 Boudewijn Rempt <boud@valdyas.org>
- * Copyright (C) 2012 Inge Wallin <inge@lysator.liu.se>
- *
- * 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 "KoAnnotationManager.h"
-#include "KoAnnotation.h"
-
-#include "TextDebug.h"
-#include <QHash>
-
-class KoAnnotationManagerPrivate
-{
-public:
- KoAnnotationManagerPrivate() { }
- QHash<QString, KoAnnotation*> annotationHash;
- QList<QString> annotationNameList;
- int lastId;
-};
-
-KoAnnotationManager::KoAnnotationManager()
- : d(new KoAnnotationManagerPrivate)
-{
-}
-
-KoAnnotationManager::~KoAnnotationManager()
-{
- delete d;
-}
-
-void KoAnnotationManager::insert(const QString &name, KoAnnotation *annotation)
-{
- annotation->setName(name);
- d->annotationHash[name] = annotation;
- d->annotationNameList.append(name);
-}
-
-void KoAnnotationManager::remove(const QString &name)
-{
- d->annotationHash.remove(name);
- d->annotationNameList.removeAt(d->annotationNameList.indexOf(name));
-}
-
-void KoAnnotationManager::rename(const QString &oldName, const QString &newName)
-{
- QHash<QString, KoAnnotation*>::iterator i = d->annotationHash.begin();
-
- while (i != d->annotationHash.end()) {
- if (i.key() == oldName) {
- KoAnnotation *annotation = d->annotationHash.take(i.key());
- annotation->setName(newName);
- d->annotationHash.insert(newName, annotation);
- int listPos = d->annotationNameList.indexOf(oldName);
- d->annotationNameList.replace(listPos, newName);
- return;
- }
- ++i;
- }
-}
-
-KoAnnotation *KoAnnotationManager::annotation(const QString &name) const
-{
- KoAnnotation *annotation = d->annotationHash.value(name);
- return annotation;
-}
-
-QList<QString> KoAnnotationManager::annotationNameList() const
-{
- return d->annotationNameList;
-}
diff --git a/plugins/flake/textshape/kotext/KoAnnotationManager.h b/plugins/flake/textshape/kotext/KoAnnotationManager.h
deleted file mode 100644
index 9d3df698a2..0000000000
--- a/plugins/flake/textshape/kotext/KoAnnotationManager.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Fredy Yanardi <fyanardi@gmail.com>
- * Copyright (C) 2012 Inge Wallin <inge@lysator.liu.se>
- *
- * 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 KOANNOTATIONMANAGER_H
-#define KOANNOTATIONMANAGER_H
-
-#include "kritatext_export.h"
-
-#include <QObject>
-#include <QList>
-
-class KoAnnotation;
-class KoAnnotationManagerPrivate;
-
-/**
- * A manager for all annotations in a document. Every annotation is identified by a unique name.
- * Note that only SinglePosition and StartAnnotation annotations can be retrieved from this
- * manager. An end annotation should be retrieved from it's parent (StartAnnotation) using
- * KoAnnotation::endAnnotation()
- * This class also maintains a list of annotation names so that it can be easily used to
- * show all available annotation.
- */
-class KRITATEXT_EXPORT KoAnnotationManager : public QObject
-{
- Q_OBJECT
-public:
- /// constructor
- KoAnnotationManager();
- ~KoAnnotationManager() override;
-
- /// @return an annotation with the specified name, or 0 if there is none
- KoAnnotation *annotation(const QString &name) const;
-
- /// @return a list of QString containing all annotation names
- QList<QString> annotationNameList() const;
-
-public Q_SLOTS:
- /**
- * Insert a new annotation to this manager. The name of the annotation
- * will be set to @p name, no matter what name has been set on
- * it.
- * @param name the name of the annotation
- * @param annotation the annotation object to insert
- */
- void insert(const QString &name, KoAnnotation *annotation);
-
- /**
- * Remove an annotation from this manager.
- * @param name the name of the annotation to remove
- */
- void remove(const QString &name);
-
- /**
- * Rename an annotation
- * @param oldName the old name of the annotation
- * @param newName the new name of the annotation
- */
- void rename(const QString &oldName, const QString &newName);
-
-private:
- KoAnnotationManagerPrivate * const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoBibliographyInfo.cpp b/plugins/flake/textshape/kotext/KoBibliographyInfo.cpp
deleted file mode 100644
index 270fd932e2..0000000000
--- a/plugins/flake/textshape/kotext/KoBibliographyInfo.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Smit Patel <smitpatel24@gmail.com>
- *
- * 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 "KoBibliographyInfo.h"
-
-#include <KoXmlReader.h>
-#include <KoXmlWriter.h>
-#include <KoXmlNS.h>
-#include <KoTextSharedLoadingData.h>
-#include <KoParagraphStyle.h>
-#include <KoOdfBibliographyConfiguration.h>
-
-int KoBibliographyInfo::styleNameToStyleId(KoTextSharedLoadingData *sharedLoadingData, const QString &styleName)
-{
- KoParagraphStyle * style = sharedLoadingData->paragraphStyle(styleName, true);
- if (style) {
- return style->styleId();
- }
-
- return 0;
-}
-
-KoBibliographyInfo::KoBibliographyInfo()
- : m_generator(0)
-{
-}
-
-KoBibliographyInfo::~KoBibliographyInfo()
-{
- foreach (const BibliographyEntryTemplate &entryTemplate, m_entryTemplate.values()) {
- qDeleteAll(entryTemplate.indexEntries);
- }
- delete m_generator;
- m_generator = 0; // just to be safe
-}
-
-void KoBibliographyInfo::loadOdf(KoTextSharedLoadingData *sharedLoadingData, const KoXmlElement& element)
-{
- Q_ASSERT(element.localName() == "bibliography-source" && element.namespaceURI() == KoXmlNS::text);
-
- KoXmlElement p;
- forEachElement(p, element) {
- if (p.namespaceURI() != KoXmlNS::text) {
- continue;
- }
-
- // first child
- if (p.localName() == "index-title-template") {
- m_indexTitleTemplate.styleName = p.attribute("style-name");
- m_indexTitleTemplate.styleId = styleNameToStyleId(sharedLoadingData, m_indexTitleTemplate.styleName);
- m_indexTitleTemplate.text = p.text();
- // second child
- } else if (p.localName() == "bibliography-entry-template") {
- BibliographyEntryTemplate bibEntryTemplate;
- bibEntryTemplate.styleName = p.attribute("style-name");
- bibEntryTemplate.bibliographyType = p.attribute("bibliography-type");
- bibEntryTemplate.styleId = styleNameToStyleId(sharedLoadingData, bibEntryTemplate.styleName );
-
- KoXmlElement indexEntry;
- forEachElement(indexEntry, p) {
- if (indexEntry.namespaceURI() != KoXmlNS::text) {
- continue;
- }
-
- if (indexEntry.localName() == "index-entry-bibliography") {
- // use null String if the style name is not present, it means that we inherit it from the parent
- IndexEntryBibliography * entryBibliography = new IndexEntryBibliography(
- indexEntry.attribute("style-name", QString())
- );
-
- entryBibliography->dataField = indexEntry.attribute("bibliography-data-field", "article");
- bibEntryTemplate.indexEntries.append(static_cast<IndexEntry*>(entryBibliography));
-
- } else if (indexEntry.localName() == "index-entry-span") {
- IndexEntrySpan * entrySpan = new IndexEntrySpan(indexEntry.attribute("style-name", QString()));
- entrySpan->text = indexEntry.text();
- bibEntryTemplate.indexEntries.append(static_cast<IndexEntry*>(entrySpan));
-
- } else if (indexEntry.localName() == "index-entry-tab-stop") {
- IndexEntryTabStop * entryTabStop = new IndexEntryTabStop(indexEntry.attribute("style-name", QString()));
-
- QString type = indexEntry.attribute("type","right"); // left or right
- if (type == "left") {
- entryTabStop->tab.type = QTextOption::LeftTab;
- } else {
- entryTabStop->tab.type = QTextOption::RightTab;
- }
- entryTabStop->setPosition(indexEntry.attribute("position", QString()));
- entryTabStop->tab.leaderText = indexEntry.attribute("leader-char",".");
- bibEntryTemplate.indexEntries.append(static_cast<IndexEntry*>(entryTabStop));
- }
- }
- m_entryTemplate[bibEntryTemplate.bibliographyType] = bibEntryTemplate;
-
- // third child
- }
- }// forEachElement
-}
-
-void KoBibliographyInfo::saveOdf(KoXmlWriter * writer) const
-{
- writer->startElement("text:bibliography-source");
-
- m_indexTitleTemplate.saveOdf(writer);
-
- foreach (const BibliographyEntryTemplate &entry, m_entryTemplate.values()) {
- entry.saveOdf(writer);
- }
-
- writer->endElement();
-}
-
-void KoBibliographyInfo::setGenerator(BibliographyGeneratorInterface *generator)
-{
- delete m_generator;
- m_generator = generator;
-}
-
-void KoBibliographyInfo::setEntryTemplates(QMap<QString, BibliographyEntryTemplate> &entryTemplates)
-{
- m_entryTemplate = entryTemplates;
-}
-
-KoBibliographyInfo *KoBibliographyInfo::clone()
-{
- KoBibliographyInfo *newBibInfo = new KoBibliographyInfo();
- newBibInfo->m_entryTemplate.clear();
- newBibInfo->m_name = QString(m_name);
- newBibInfo->m_styleName = QString(m_name);
- newBibInfo->m_indexTitleTemplate = m_indexTitleTemplate;
-
- for (int i = 0; i < m_entryTemplate.size() ; i++) {
- newBibInfo->m_entryTemplate.insert(KoOdfBibliographyConfiguration::bibTypes.at(i),
- m_entryTemplate[KoOdfBibliographyConfiguration::bibTypes.at(i)]);
- }
-
- return newBibInfo;
-}
-
-BibliographyGeneratorInterface *KoBibliographyInfo::generator() const
-{
- return m_generator;
-}
diff --git a/plugins/flake/textshape/kotext/KoBibliographyInfo.h b/plugins/flake/textshape/kotext/KoBibliographyInfo.h
deleted file mode 100644
index d66c00c160..0000000000
--- a/plugins/flake/textshape/kotext/KoBibliographyInfo.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Smit Patel <smitpatel24@gmail.com>
- *
- * 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 KOBIBLIOGRAPHYINFO_H
-#define KOBIBLIOGRAPHYINFO_H
-
-#include "kritatext_export.h"
-#include <KoXmlReaderForward.h>
-#include "ToCBibGeneratorInfo.h"
-
-class KoTextSharedLoadingData;
-class KoXmlWriter;
-
-class KRITATEXT_EXPORT BibliographyGeneratorInterface {
-public:
- BibliographyGeneratorInterface() {}
- virtual ~BibliographyGeneratorInterface() {}
- //virtual void setMaxTabPosition(qreal maxTabPosition) = 0;
-};
-
-class KRITATEXT_EXPORT KoBibliographyInfo
-{
-public:
- KoBibliographyInfo();
-
- ~KoBibliographyInfo();
-
- void loadOdf(KoTextSharedLoadingData *sharedLoadingData, const KoXmlElement &element);
- void saveOdf(KoXmlWriter *writer) const;
-
- void setGenerator(BibliographyGeneratorInterface *generator);
- void setEntryTemplates(QMap<QString, BibliographyEntryTemplate> &entryTemplates);
-
- KoBibliographyInfo *clone();
- BibliographyGeneratorInterface *generator() const;
-
- QString m_name;
- QString m_styleName;
- IndexTitleTemplate m_indexTitleTemplate;
- QMap<QString, BibliographyEntryTemplate> m_entryTemplate;
-
-private:
- int styleNameToStyleId(KoTextSharedLoadingData *sharedLoadingData, const QString &styleName);
- BibliographyGeneratorInterface *m_generator;
-};
-
-Q_DECLARE_METATYPE(KoBibliographyInfo *)
-
-#endif // KOBIBLIOGRAPHYINFO_H
diff --git a/plugins/flake/textshape/kotext/KoBookmark.cpp b/plugins/flake/textshape/kotext/KoBookmark.cpp
deleted file mode 100644
index 4fde2ac869..0000000000
--- a/plugins/flake/textshape/kotext/KoBookmark.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007-2008 Fredy Yanardi <fyanardi@gmail.com>
- * Copyright (C) 2011 Boudewijn Rempt <boud@valdyas.org>
- * Copyright (C) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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 "KoBookmark.h"
-
-#include <KoShapeSavingContext.h>
-#include <KoXmlWriter.h>
-#include <KoXmlReader.h>
-#include <KoTextInlineRdf.h>
-#include <KoTextRangeManager.h>
-#include <KoXmlNS.h>
-
-#include <QTextDocument>
-#include <QTextBlock>
-#include <QTextCursor>
-#include "TextDebug.h"
-
-// Include Q_UNSUSED classes, for building on Windows
-#include <KoShapeLoadingContext.h>
-
-class Q_DECL_HIDDEN KoBookmark::Private
-{
-public:
- Private(const QTextDocument *doc)
- : document(doc)
- {
- }
- const QTextDocument *document;
- QString name;
-};
-
-KoBookmark::KoBookmark(const QTextCursor &cursor)
- : KoTextRange(cursor),
- d(new Private(cursor.block().document()))
-{
-}
-
-KoBookmark::~KoBookmark()
-{
- delete d;
-}
-
-void KoBookmark::setName(const QString &name)
-{
- d->name = name;
-}
-
-QString KoBookmark::name() const
-{
- return d->name;
-}
-
-bool KoBookmark::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- Q_UNUSED(context);
-
- QString bookmarkName = element.attribute("name");
- const QString localName(element.localName());
-
- if (manager()) {
- // For cut and paste, make sure that the name is unique.
- d->name = createUniqueBookmarkName(manager()->bookmarkManager(), bookmarkName, false);
-
- if (localName == "bookmark" || localName == "bookmark-start") {
- setPositionOnlyMode(localName == "bookmark");
-
- // Add inline Rdf to the bookmark.
- if (element.hasAttributeNS(KoXmlNS::xhtml, "property") || element.hasAttribute("id")) {
- KoTextInlineRdf* inlineRdf = new KoTextInlineRdf(const_cast<QTextDocument*>(d->document), this);
- if (inlineRdf->loadOdf(element)) {
- setInlineRdf(inlineRdf);
- }
- else {
- delete inlineRdf;
- inlineRdf = 0;
- }
- }
- }
- else {
- // NOTE: "bookmark-end" is handled in KoTextLoader
- // if we ever come here then something pretty weird is going on...
- return false;
- }
- return true;
- }
- return false;
-}
-
-void KoBookmark::saveOdf(KoShapeSavingContext &context, int position, TagType tagType) const
-{
- KoXmlWriter *writer = &context.xmlWriter();
-
- if (!hasRange()) {
- if (tagType == StartTag) {
- writer->startElement("text:bookmark", false);
- writer->addAttribute("text:name", d->name.toUtf8());
- if (inlineRdf()) {
- inlineRdf()->saveOdf(context, writer);
- }
- writer->endElement();
- }
- } else if ((tagType == StartTag) && (position == rangeStart())) {
- writer->startElement("text:bookmark-start", false);
- writer->addAttribute("text:name", d->name.toUtf8());
- if (inlineRdf()) {
- inlineRdf()->saveOdf(context, writer);
- }
- writer->endElement();
- } else if ((tagType == EndTag) && (position == rangeEnd())) {
- writer->startElement("text:bookmark-end", false);
- writer->addAttribute("text:name", d->name.toUtf8());
- writer->endElement();
- }
- // else nothing
-}
-
-QString KoBookmark::createUniqueBookmarkName(const KoBookmarkManager* bmm, QString bookmarkName, bool isEndMarker)
-{
- QString ret = bookmarkName;
- int uniqID = 0;
-
- while (true) {
- if (bmm->bookmark(ret)) {
- ret = QString("%1_%2").arg(bookmarkName).arg(++uniqID);
- } else {
- if (isEndMarker) {
- --uniqID;
- if (!uniqID)
- ret = bookmarkName;
- else
- ret = QString("%1_%2").arg(bookmarkName).arg(uniqID);
- }
- break;
- }
- }
- return ret;
-}
-
diff --git a/plugins/flake/textshape/kotext/KoBookmark.h b/plugins/flake/textshape/kotext/KoBookmark.h
deleted file mode 100644
index 6101a3d59f..0000000000
--- a/plugins/flake/textshape/kotext/KoBookmark.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007-2008 Fredy Yanardi <fyanardi@gmail.com>
- * Copyright (C) 2011 Boudewijn Rempt <boud@valdyas.org>
- * Copyright (C) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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 KOBOOKMARK_H
-#define KOBOOKMARK_H
-
-#include "KoTextRange.h"
-#include "kritatext_export.h"
-
-class KoBookmarkManager;
-
-/**
- * A document can store a set of cursor positions/selected cursor locations which can be
- * retrieved again later to go to those locations from any location in the document.
- * The bookmark location will be automatically updated if user alters the text in the document.
- * A bookmark is identified by it's name, and all bookmarks are managed by KoBookmarkManager. A
- * bookmark can be retrieved from the bookmark manager by using name as identifier.
- * @see KoBookmarkManager
- */
-class KRITATEXT_EXPORT KoBookmark : public KoTextRange
-{
- Q_OBJECT
-public:
- /**
- * Constructor.
- *
- * By default a bookmark has the SinglePosition type and an empty name.
- * The name is set when the book is inserted into the bookmark manager.
- *
- * @param document the text document where this bookmark is located
- */
- explicit KoBookmark(const QTextCursor &);
-
- ~KoBookmark() override;
-
- /// reimplemented from super
- void saveOdf(KoShapeSavingContext &context, int position, TagType tagType) const override;
-
- /**
- * Set the new name for this bookmark
- * @param name the new name of the bookmark
- */
- void setName(const QString &name);
-
- /// @return the name of this bookmark
- QString name() const;
-
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
-
- /**
- * This is called to allow Cut and Paste of bookmarks. This
- * method gives a correct, unique, name
- */
- static QString createUniqueBookmarkName(const KoBookmarkManager* bmm, QString bookmarkName, bool isEndMarker);
-private:
-
- class Private;
- Private *const d;
-};
-
-#endif
-
diff --git a/plugins/flake/textshape/kotext/KoBookmarkManager.cpp b/plugins/flake/textshape/kotext/KoBookmarkManager.cpp
deleted file mode 100644
index 1dd12c0801..0000000000
--- a/plugins/flake/textshape/kotext/KoBookmarkManager.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Fredy Yanardi <fyanardi@gmail.com>
- * Copyright (c) 2011 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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 "KoBookmarkManager.h"
-#include "KoBookmark.h"
-
-#include "TextDebug.h"
-#include <QHash>
-
-class KoBookmarkManagerPrivate
-{
-public:
- KoBookmarkManagerPrivate() { }
- QHash<QString, KoBookmark*> bookmarkHash;
- QList<QString> bookmarkNameList;
- int lastId;
-};
-
-KoBookmarkManager::KoBookmarkManager()
- : d(new KoBookmarkManagerPrivate)
-{
-}
-
-KoBookmarkManager::~KoBookmarkManager()
-{
- delete d;
-}
-
-void KoBookmarkManager::insert(const QString &name, KoBookmark *bookmark)
-{
- bookmark->setName(name);
- d->bookmarkHash[name] = bookmark;
- d->bookmarkNameList.append(name);
-}
-
-void KoBookmarkManager::remove(const QString &name)
-{
- d->bookmarkHash.remove(name);
- d->bookmarkNameList.removeAt(d->bookmarkNameList.indexOf(name));
-}
-
-void KoBookmarkManager::rename(const QString &oldName, const QString &newName)
-{
- QHash<QString, KoBookmark*>::iterator i = d->bookmarkHash.begin();
-
- while (i != d->bookmarkHash.end()) {
- if (i.key() == oldName) {
- KoBookmark *bookmark = d->bookmarkHash.take(i.key());
- bookmark->setName(newName);
- d->bookmarkHash.insert(newName, bookmark);
- int listPos = d->bookmarkNameList.indexOf(oldName);
- d->bookmarkNameList.replace(listPos, newName);
- return;
- }
- ++i;
- }
-}
-
-KoBookmark *KoBookmarkManager::bookmark(const QString &name) const
-{
- KoBookmark *bookmark = d->bookmarkHash.value(name);
- return bookmark;
-}
-
-QList<QString> KoBookmarkManager::bookmarkNameList() const
-{
- return d->bookmarkNameList;
-}
diff --git a/plugins/flake/textshape/kotext/KoBookmarkManager.h b/plugins/flake/textshape/kotext/KoBookmarkManager.h
deleted file mode 100644
index 5ec4a2efde..0000000000
--- a/plugins/flake/textshape/kotext/KoBookmarkManager.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Fredy Yanardi <fyanardi@gmail.com>
- * Copyright (C) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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 KOBOOKMARKMANAGER_H
-#define KOBOOKMARKMANAGER_H
-
-#include "kritatext_export.h"
-
-#include <QObject>
-#include <QList>
-#include <QString>
-
-class KoBookmark;
-class KoBookmarkManagerPrivate;
-
-/**
- * A manager for all bookmarks in a document. Every bookmark is identified by a unique name.
- * Note that only SinglePosition and StartBookmark bookmarks can be retrieved from this
- * manager. An end bookmark should be retrieved from it's parent (StartBookmark) using
- * KoBookmark::endBookmark()
- * This class also maintains a list of bookmark names so that it can be easily used to
- * show all available bookmark.
- */
-class KRITATEXT_EXPORT KoBookmarkManager : public QObject
-{
- Q_OBJECT
-public:
- /// constructor
- KoBookmarkManager();
- ~KoBookmarkManager() override;
-
- /// @return a bookmark with the specified name, or 0 if there is none
- KoBookmark *bookmark(const QString &name) const;
-
- /// @return a list of QString containing all bookmark names
- QList<QString> bookmarkNameList() const;
-
-public Q_SLOTS:
- /**
- * Insert a new bookmark to this manager. The name of the bookmark
- * will be set to @p name, no matter what name has been set on
- * it.
- * @param name the name of the bookmark
- * @param bookmark the bookmark object to insert
- */
- void insert(const QString &name, KoBookmark *bookmark);
-
- /**
- * Remove a bookmark from this manager.
- * @param name the name of the bookmark to remove
- */
- void remove(const QString &name);
-
- /**
- * Rename a bookmark
- * @param oldName the old name of the bookmark
- * @param newName the new name of the bookmark
- */
- void rename(const QString &oldName, const QString &newName);
-
-private:
- KoBookmarkManagerPrivate * const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoDocumentRdfBase.cpp b/plugins/flake/textshape/kotext/KoDocumentRdfBase.cpp
deleted file mode 100644
index 0bec963942..0000000000
--- a/plugins/flake/textshape/kotext/KoDocumentRdfBase.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2010 KO GmbH <ben.martin@kogmbh.com>
-
- 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 "KoDocumentRdfBase.h"
-
-#include <KoDocumentResourceManager.h>
-#include <KoText.h>
-
-#ifdef SHOULD_BUILD_RDF
-#include <Soprano/Soprano>
-#endif
-
-#include "TextDebug.h"
-
-KoDocumentRdfBase::KoDocumentRdfBase(QObject *parent)
- : QObject(parent)
-{
-}
-
-KoDocumentRdfBase::~KoDocumentRdfBase()
-{
-}
-
-#ifdef SHOULD_BUILD_RDF
-QSharedPointer<Soprano::Model> KoDocumentRdfBase::model() const
-{
- return QSharedPointer<Soprano::Model>(0);
-}
-#endif
-
-void KoDocumentRdfBase::linkToResourceManager(KoDocumentResourceManager *rm)
-{
- QVariant variant;
- variant.setValue<QObject*>(this);
- rm->setResource(KoText::DocumentRdf, variant);
-}
-
-void KoDocumentRdfBase::updateInlineRdfStatements(const QTextDocument *qdoc)
-{
- Q_UNUSED(qdoc);
-}
-
-void KoDocumentRdfBase::updateXmlIdReferences(const QMap<QString, QString> &m)
-{
- Q_UNUSED(m);
-}
-
-bool KoDocumentRdfBase::loadOasis(KoStore *store)
-{
- Q_UNUSED(store);
- return true;
-}
-
-bool KoDocumentRdfBase::saveOasis(KoStore *store, KoXmlWriter *manifestWriter)
-{
- Q_UNUSED(store);
- Q_UNUSED(manifestWriter);
- return true;
-}
-
-bool KoDocumentRdfBase::completeLoading(KoStore */*store*/)
-{
- return false;
-}
-
-bool KoDocumentRdfBase::completeSaving(KoStore */*store*/, KoXmlWriter */*manifestWriter*/, KoShapeSavingContext */*context*/)
-{
- return false;
-}
-
-QStringList KoDocumentRdfBase::idrefList() const
-{
- return QStringList();
-}
diff --git a/plugins/flake/textshape/kotext/KoDocumentRdfBase.h b/plugins/flake/textshape/kotext/KoDocumentRdfBase.h
deleted file mode 100644
index 8549d44346..0000000000
--- a/plugins/flake/textshape/kotext/KoDocumentRdfBase.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2010 KO GmbH <ben.martin@kogmbh.com>
-
- 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_DOCUMENT_Rdf_Base_H
-#define KO_DOCUMENT_Rdf_Base_H
-
-#include "kritatext_export.h"
-
-#include <QObject>
-#include <QMap>
-#include <QString>
-#include <QMetaType>
-#include <QSharedPointer>
-
-#include <KoDataCenterBase.h>
-
-class KoDocumentResourceManager;
-class QTextDocument;
-class KoStore;
-class KoXmlWriter;
-
-
-///**
-// * Dummy definition in case Soprano is not available.
-// */
-namespace Soprano
-{
- class Model;
-}
-
-/**
- * A base class that provides the interface to many RDF features
- * but will not do anything if Soprano support is not built.
- * By having this "Base" class, code can call methods at points
- * where RDF handling is desired and can avoid \#ifdef conditionals
- * because the base class interface is here and will be valid, even
- * if impotent when Soprano support is not built.
- */
-class KRITATEXT_EXPORT KoDocumentRdfBase : public QObject, public KoDataCenterBase
-{
- Q_OBJECT
-
-public:
- explicit KoDocumentRdfBase(QObject *parent = 0);
- ~KoDocumentRdfBase() override;
-
- /**
- * Get the Soprano::Model that contains all the Rdf
- * You do not own the model, do not delete it.
- */
-#ifdef SHOULD_BUILD_RDF
- virtual QSharedPointer<Soprano::Model> model() const;
-#endif
- virtual void linkToResourceManager(KoDocumentResourceManager *rm);
-
- virtual void updateInlineRdfStatements(const QTextDocument *qdoc);
- virtual void updateXmlIdReferences(const QMap<QString, QString> &m);
-
- /**
- * idrefList queries soprano after loading and creates a list of all rdfid's that
- * where found in the manifest.rdf document. This list is used to make sure we do not
- * create more inline rdf objects than necessary
- * @return a list of xml-id's
- */
- virtual QStringList idrefList() const;
-
-
- virtual bool loadOasis(KoStore *store);
- virtual bool saveOasis(KoStore *store, KoXmlWriter *manifestWriter);
-
- // reimplemented in komain/rdf/KoDocumentRdf
- bool completeLoading(KoStore *store) override;
- bool completeSaving(KoStore *store, KoXmlWriter *manifestWriter, KoShapeSavingContext *context) override;
-};
-
-Q_DECLARE_METATYPE(KoDocumentRdfBase*)
-
-#endif
-
diff --git a/plugins/flake/textshape/kotext/KoInlineCite.cpp b/plugins/flake/textshape/kotext/KoInlineCite.cpp
deleted file mode 100644
index e078eb66d9..0000000000
--- a/plugins/flake/textshape/kotext/KoInlineCite.cpp
+++ /dev/null
@@ -1,753 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Smit Patel <smitpatel24@gmail.com>
- *
- * 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 "KoInlineCite.h"
-
-#include "KoInlineTextObjectManager.h"
-#include <KoXmlWriter.h>
-#include <KoXmlNS.h>
-#include <KoShapeSavingContext.h>
-#include <KoTextDocument.h>
-#include <KoOdfBibliographyConfiguration.h>
-#include <KoStyleManager.h>
-#include "TextDebug.h"
-
-#include <QTextDocument>
-#include <QTextInlineObject>
-#include <QFontMetricsF>
-#include <QTextOption>
-
-// Include Q_UNSUSED classes, for building on Windows
-#include <KoShapeLoadingContext.h>
-
-class Q_DECL_HIDDEN KoInlineCite::Private
-{
-public:
- Private(KoInlineCite::Type t)
- : type(t)
- {
- }
-
- KoInlineCite::Type type;
- int posInDocument;
- QString label;
-
- QString bibliographyType;
- QString identifier;
- QString address;
- QString annote;
- QString author;
- QString booktitle;
- QString chapter;
- QString edition;
- QString editor;
- QString publicationType;
- QString institution;
- QString journal;
- QString month;
- QString note;
- QString number;
- QString organisation;
- QString pages;
- QString publisher;
- QString school; //university in UI and saved under text:school tag in XML format
- QString series;
- QString title;
- QString reportType;
- QString volume;
- QString year;
- QString url;
- QString isbn;
- QString issn;
- QString custom1;
- QString custom2;
- QString custom3;
- QString custom4;
- QString custom5;
-};
-
-KoInlineCite::KoInlineCite(Type type)
- :KoInlineObject(true)
- ,d(new Private(type))
-{
-}
-
-KoInlineCite::~KoInlineCite()
-{
- delete d;
-}
-
-KoInlineCite::Type KoInlineCite::type() const
-{
- return d->type;
-}
-
-void KoInlineCite::setType(Type t)
-{
- d->type = t;
-}
-
-QString KoInlineCite::dataField(const QString &fieldName) const
-{
- if ( fieldName == "address" ) {
- return d->address;
- } else if ( fieldName == "annote" ) {
- return d->annote;
- } else if ( fieldName == "author" ) {
- return d->author;
- } else if ( fieldName == "bibliography-type" ) {
- return d->bibliographyType;
- } else if ( fieldName == "booktitle" ) {
- return d->booktitle;
- } else if ( fieldName == "chapter" ) {
- return d->chapter;
- } else if ( fieldName == "custom1" ) {
- return d->custom1;
- } else if ( fieldName == "custom2" ) {
- return d->custom2;
- } else if ( fieldName == "custom3" ) {
- return d->custom3;
- } else if ( fieldName == "custom4" ) {
- return d->custom4;
- } else if ( fieldName == "custom5" ) {
- return d->custom5;
- } else if ( fieldName == "edition" ) {
- return d->edition;
- } else if ( fieldName == "editor" ) {
- return d->editor;
- } else if ( fieldName == "howpublished" ) {
- return d->publicationType;
- } else if ( fieldName == "identifier" ) {
- return d->identifier;
- } else if ( fieldName == "institution" ) {
- return d->institution;
- } else if ( fieldName == "isbn" ) {
- return d->isbn;
- } else if ( fieldName == "issn" ) {
- return d->issn;
- } else if ( fieldName == "journal" ) {
- return d->journal;
- } else if ( fieldName == "month" ) {
- return d->month;
- } else if ( fieldName == "note" ) {
- return d->note;
- } else if ( fieldName == "number" ) {
- return d->number;
- } else if ( fieldName == "organisations" ) {
- return d->organisation;
- } else if ( fieldName == "pages" ) {
- return d->pages;
- } else if ( fieldName == "publisher" ) {
- return d->publisher;
- } else if ( fieldName == "report-type" ) {
- return d->reportType;
- } else if ( fieldName == "school" ) {
- return d->school;
- } else if ( fieldName == "series" ) {
- return d->series;
- } else if ( fieldName == "title" ) {
- return d->title;
- } else if ( fieldName == "url" ) {
- return d->url;
- } else if ( fieldName == "volume" ) {
- return d->volume;
- } else if ( fieldName == "year" ) {
- return d->year;
- } else {
- return QString();
- }
-}
-
-void KoInlineCite::setIdentifier(const QString &identifier)
-{
- d->identifier = identifier;
-}
-
-void KoInlineCite::setAddress(const QString &addr)
-{
- d->address = addr;
-}
-
-void KoInlineCite::setAnnotation(const QString &annotation)
-{
- d->annote = annotation;
-}
-
-void KoInlineCite::setAuthor(const QString &author)
-{
- d->author = author;
-}
-
-void KoInlineCite::setBibliographyType(const QString &bibliographyType)
-{
- d->bibliographyType = bibliographyType;
-}
-
-void KoInlineCite::setBookTitle(const QString &booktitle)
-{
- d->booktitle = booktitle;
-}
-
-void KoInlineCite::setChapter(const QString &chapter)
-{
- d->chapter = chapter;
-}
-
-void KoInlineCite::setCustom1(const QString &custom1)
-{
- d->custom1 = custom1;
-}
-
-void KoInlineCite::setCustom2(const QString &custom2)
-{
- d->custom2 = custom2;
-}
-
-void KoInlineCite::setCustom3(const QString &custom3)
-{
- d->custom3 = custom3;
-}
-
-void KoInlineCite::setCustom4(const QString &custom4)
-{
- d->custom4 = custom4;
-}
-
-void KoInlineCite::setCustom5(const QString &custom5)
-{
- d->custom5 = custom5;
-}
-
-void KoInlineCite::setEdition(const QString &edition)
-{
- d->edition = edition;
-}
-
-void KoInlineCite::setEditor(const QString &editor)
-{
- d->editor = editor;
-}
-
-void KoInlineCite::setInstitution(const QString &institution)
-{
- d->institution = institution;
-}
-
-void KoInlineCite::setISBN(const QString &isbn)
-{
- d->isbn = isbn;
-}
-
-void KoInlineCite::setISSN(const QString &issn)
-{
- d->issn = issn;
-}
-
-void KoInlineCite::setJournal(const QString &journal)
-{
- d->journal = journal;
-}
-
-void KoInlineCite::setLabel(const QString &label)
-{
- d->label = label;
-}
-
-void KoInlineCite::setMonth(const QString &month)
-{
- d->month = month;
-}
-
-void KoInlineCite::setNote(const QString &note)
-{
- d->note = note;
-}
-
-void KoInlineCite::setNumber(const QString &number)
-{
- d->number = number;
-}
-
-void KoInlineCite::setOrganisation(const QString &organisation)
-{
- d->organisation = organisation;
-}
-
-void KoInlineCite::setPages(const QString &pages)
-{
- d->pages = pages;
-}
-
-void KoInlineCite::setPublicationType(const QString &publicationType)
-{
- d->publicationType = publicationType;
-}
-
-void KoInlineCite::setPublisher(const QString &publisher)
-{
- d->publisher = publisher;
-}
-
-void KoInlineCite::setReportType(const QString &reportType)
-{
- d->reportType = reportType;
-}
-
-void KoInlineCite::setSchool(const QString &school)
-{
- d->school = school;
-}
-
-void KoInlineCite::setSeries(const QString &series)
-{
- d->series = series;
-}
-
-void KoInlineCite::setTitle(const QString &title)
-{
- d->title = title;
-}
-
-void KoInlineCite::setURL(const QString &url)
-{
- d->url = url;
-}
-
-void KoInlineCite::setVolume(const QString &volume)
-{
- d->volume = volume;
-}
-
-void KoInlineCite::setYear(const QString &year)
-{
- d->year = year;
-}
-
-QString KoInlineCite::identifier() const
-{
- return d->identifier;
-}
-
-QString KoInlineCite::address() const
-{
- return d->address;
-}
-
-QString KoInlineCite::annotation() const
-{
- return d->annote;
-}
-
-QString KoInlineCite::author() const
-{
- return d->author;
-}
-
-QString KoInlineCite::bibliographyType() const
-{
- return d->bibliographyType;
-}
-
-QString KoInlineCite::bookTitle() const
-{
- return d->booktitle;
-}
-
-QString KoInlineCite::chapter() const
-{
- return d->chapter;
-}
-
-QString KoInlineCite::custom1() const
-{
- return d->custom1;
-}
-
-QString KoInlineCite::custom2() const
-{
- return d->custom2;
-}
-
-QString KoInlineCite::custom3() const
-{
- return d->custom3;
-}
-
-QString KoInlineCite::custom4() const
-{
- return d->custom4;
-}
-
-QString KoInlineCite::custom5() const
-{
- return d->custom5;
-}
-
-QString KoInlineCite::edition() const
-{
- return d->edition;
-}
-
-QString KoInlineCite::editor() const
-{
- return d->editor;
-}
-
-QString KoInlineCite::institution() const
-{
- return d->institution;
-}
-
-QString KoInlineCite::isbn() const
-{
- return d->isbn;
-}
-
-QString KoInlineCite::issn() const
-{
- return d->issn;
-}
-
-QString KoInlineCite::journal() const
-{
- return d->journal;
-}
-
-QString KoInlineCite::month() const
-{
- return d->month;
-}
-
-QString KoInlineCite::note() const
-{
- return d->note;
-}
-
-QString KoInlineCite::number() const
-{
- return d->number;
-}
-
-QString KoInlineCite::organisations() const
-{
- return d->organisation;
-}
-
-QString KoInlineCite::pages() const
-{
- return d->pages;
-}
-
-QString KoInlineCite::publisher() const
-{
- return d->publisher;
-}
-
-QString KoInlineCite::publicationType() const
-{
- return d->publicationType;
-}
-
-QString KoInlineCite::reportType() const
-{
- return d->reportType;
-}
-
-QString KoInlineCite::school() const
-{
- return d->school;
-}
-
-QString KoInlineCite::series() const
-{
- return d->series;
-}
-
-QString KoInlineCite::title() const
-{
- return d->title;
-}
-
-QString KoInlineCite::volume() const
-{
- return d->volume;
-}
-
-QString KoInlineCite::year() const
-{
- return d->year;
-}
-
-QString KoInlineCite::url() const
-{
- return d->url;
-}
-
-int KoInlineCite::posInDocument() const
-{
- return d->posInDocument;
-}
-
-bool KoInlineCite::operator!= ( const KoInlineCite &cite ) const
-{
- return !(d->address == cite.address() && d->annote == cite.annotation() && d->author == cite.author() &&
- d->bibliographyType == cite.bibliographyType() && d->booktitle == cite.bookTitle() &&
- d->chapter == cite.chapter() && d->custom1 == cite.custom1() && d->custom2 == cite.custom2() &&
- d->custom3 == cite.custom3() && d->custom4 == cite.custom4() && d->custom5 == cite.custom5() &&
- d->edition == cite.edition() && d->editor == cite.editor() && d->identifier == cite.identifier() &&
- d->institution == cite.institution() && d->isbn == cite.isbn() && d->issn == cite.issn() &&
- d->journal == cite.journal() && d->month == cite.month() && d->note == cite.note() &&
- d->number == cite.number() && d->organisation == cite.organisations() && d->pages == cite.pages() &&
- d->publicationType == cite.publicationType() && d->publisher == cite.publisher() &&
- d->reportType == cite.reportType() && d->school == cite.school() && d->series == cite.series() &&
- d->title == cite.title() && d->url == cite.url() && d->volume == cite.volume() && d->year == cite.year());
-}
-
-KoInlineCite &KoInlineCite::operator =(const KoInlineCite &cite)
-{
- d->address = cite.address();
- d->annote = cite.annotation();
- d->author = cite.author();
- d->bibliographyType = cite.bibliographyType();
- d->booktitle = cite.bookTitle();
- d->chapter = cite.chapter();
- d->custom1 = cite.custom1();
- d->custom2 = cite.custom2();
- d->custom3 = cite.custom3();
- d->custom4 = cite.custom4();
- d->custom5 = cite.custom5();
- d->edition = cite.edition();
- d->editor = cite.editor();
- d->identifier = cite.identifier();
- d->institution = cite.institution();
- d->isbn = cite.isbn();
- d->issn = cite.issn();
- d->journal = cite.journal();
- d->month = cite.month();
- d->note = cite.note();
- d->number = cite.number();
- d->organisation = cite.organisations();
- d->pages = cite.pages();
- d->publicationType = cite.publicationType();
- d->publisher = cite.publisher();
- d->reportType = cite.reportType();
- d->school = cite.school();
- d->series = cite.series();
- d->title = cite.title();
- d->url = cite.url();
- d->volume = cite.volume();
- d->year = cite.year();
-
- return *this;
-}
-
-void KoInlineCite::updatePosition(const QTextDocument *document, int posInDocument, const QTextCharFormat &format)
-{
- Q_UNUSED(document);
- Q_UNUSED(format);
- d->posInDocument = posInDocument;
-}
-
-void KoInlineCite::resize(const QTextDocument *document, QTextInlineObject &object, int posInDocument, const QTextCharFormat &format, QPaintDevice *pd)
-{
- Q_UNUSED(document);
- Q_UNUSED(posInDocument);
- if (d->identifier.isEmpty())
- return;
-
- KoOdfBibliographyConfiguration *bibConfiguration = KoTextDocument(document).styleManager()->bibliographyConfiguration();
-
- if (!bibConfiguration->numberedEntries()) {
- d->label = QString("%1%2%3").arg(bibConfiguration->prefix())
- .arg(d->identifier)
- .arg(bibConfiguration->suffix());
- } else {
- d->label = QString("%1%2%3").arg(bibConfiguration->prefix())
- .arg(QString::number(manager()->citationsSortedByPosition(true).indexOf(this) + 1))
- .arg(bibConfiguration->suffix());
- }
-
- Q_ASSERT(format.isCharFormat());
- QFontMetricsF fm(format.font(), pd);
- object.setWidth(fm.width(d->label));
- object.setAscent(fm.ascent());
- object.setDescent(fm.descent());
-}
-
-void KoInlineCite::paint(QPainter &painter, QPaintDevice *pd, const QTextDocument *document, const QRectF &rect, const QTextInlineObject &object, int posInDocument, const QTextCharFormat &format)
-{
- Q_UNUSED(document);
- Q_UNUSED(object);
- Q_UNUSED(posInDocument);
-
- if (d->identifier.isEmpty())
- return;
-
- KoOdfBibliographyConfiguration *bibConfiguration = KoTextDocument(document).styleManager()->bibliographyConfiguration();
-
- if (!bibConfiguration->numberedEntries()) {
- d->label = QString("%1%2%3").arg(bibConfiguration->prefix())
- .arg(d->identifier)
- .arg(bibConfiguration->suffix());
- } else {
- d->label = QString("%1%2%3").arg(bibConfiguration->prefix())
- .arg(QString::number(manager()->citationsSortedByPosition(true, document->firstBlock()).indexOf(this) + 1))
- .arg(bibConfiguration->suffix());
- }
-
- QFont font(format.font(), pd);
- QTextLayout layout(d->label, font, pd);
- layout.setCacheEnabled(true);
- QList<QTextLayout::FormatRange> layouts;
- QTextLayout::FormatRange range;
- range.start = 0;
- range.length = d->label.length();
- range.format = format;
- range.format.setVerticalAlignment(QTextCharFormat::AlignNormal);
- layouts.append(range);
- layout.setAdditionalFormats(layouts);
-
- QTextOption option(Qt::AlignLeft | Qt::AlignAbsolute);
- option.setTextDirection(object.textDirection());
- layout.setTextOption(option);
- layout.beginLayout();
- layout.createLine();
- layout.endLayout();
- layout.draw(&painter, rect.topLeft());
-}
-
-bool KoInlineCite::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- Q_UNUSED(context);
- //KoTextLoader loader(context);
- if (element.namespaceURI() == KoXmlNS::text && element.localName() == "bibliography-mark") {
- d->identifier = element.attributeNS(KoXmlNS::text, "identifier");
- d->bibliographyType = element.attributeNS(KoXmlNS::text, "bibliography-type");
- d->address = element.attributeNS(KoXmlNS::text, "address");
- d->annote = element.attributeNS(KoXmlNS::text, "annote");
- d->author = element.attributeNS(KoXmlNS::text, "author");
- d->booktitle = element.attributeNS(KoXmlNS::text, "booktitle");
- d->chapter = element.attributeNS(KoXmlNS::text, "chapter");
- d->edition = element.attributeNS(KoXmlNS::text, "edition");
- d->editor = element.attributeNS(KoXmlNS::text, "editor");
- d->publicationType = element.attributeNS(KoXmlNS::text, "howpublished");
- d->institution = element.attributeNS(KoXmlNS::text, "institution");
- d->journal = element.attributeNS(KoXmlNS::text, "journal");
- d->month = element.attributeNS(KoXmlNS::text, "month");
- d->note = element.attributeNS(KoXmlNS::text, "note");
- d->number = element.attributeNS(KoXmlNS::text, "number");
- d->organisation = element.attributeNS(KoXmlNS::text, "organisations");
- d->pages = element.attributeNS(KoXmlNS::text, "pages");
- d->publisher = element.attributeNS(KoXmlNS::text, "publisher");
- d->school = element.attributeNS(KoXmlNS::text, "school");
- d->series = element.attributeNS(KoXmlNS::text, "series");
- d->title = element.attributeNS(KoXmlNS::text, "title");
- d->reportType = element.attributeNS(KoXmlNS::text, "report-type");
- d->volume = element.attributeNS(KoXmlNS::text, "volume");
- d->year = element.attributeNS(KoXmlNS::text, "year");
- d->url = element.attributeNS(KoXmlNS::text, "url");
- d->isbn = element.attributeNS(KoXmlNS::text, "isbn");
- d->issn = element.attributeNS(KoXmlNS::text, "issn");
- d->custom1 = element.attributeNS(KoXmlNS::text, "custom1");
- d->custom2 = element.attributeNS(KoXmlNS::text, "custom2");
- d->custom3 = element.attributeNS(KoXmlNS::text, "custom3");
- d->custom4 = element.attributeNS(KoXmlNS::text, "custom4");
- d->custom5 = element.attributeNS(KoXmlNS::text, "custom5");
-
- //Now checking for cloned citation (with same identifier)
- if (manager()->citations(true).keys().count(d->identifier) > 1) {
- this->setType(KoInlineCite::ClonedCitation);
- }
- }
- else {
- return false;
- }
- return true;
-}
-
-void KoInlineCite::saveOdf(KoShapeSavingContext &context)
-{
- KoXmlWriter *writer = &context.xmlWriter();
- writer->startElement("text:bibliography-mark", false);
-
- if (!d->identifier.isEmpty())
- writer->addAttribute("text:identifier", d->identifier); //can't be "" //to be changed later
- if (!d->bibliographyType.isEmpty())
- writer->addAttribute("text:bibliography-type", d->bibliographyType);
- if (!d->address.isEmpty())
- writer->addAttribute("text:address",d->identifier);
- if (!d->annote.isEmpty())
- writer->addAttribute("text:annote",d->annote);
- if (!d->author.isEmpty())
- writer->addAttribute("text:author",d->author);
- if (!d->booktitle.isEmpty())
- writer->addAttribute("text:booktitle",d->booktitle);
- if (!d->chapter.isEmpty())
- writer->addAttribute("text:chapter",d->chapter);
- if (!d->edition.isEmpty())
- writer->addAttribute("text:edition",d->edition);
- if (!d->editor.isEmpty())
- writer->addAttribute("text:editor",d->editor);
- if (!d->publicationType.isEmpty())
- writer->addAttribute("text:howpublished",d->publicationType);
- if (!d->institution.isEmpty())
- writer->addAttribute("text:institution",d->institution);
- if (!d->journal.isEmpty())
- writer->addAttribute("text:journal",d->journal);
- if (!d->month.isEmpty())
- writer->addAttribute("text:month",d->month);
- if (!d->note.isEmpty())
- writer->addAttribute("text:note",d->note);
- if (!d->number.isEmpty())
- writer->addAttribute("text:number",d->number);
- if (!d->pages.isEmpty())
- writer->addAttribute("text:pages",d->pages);
- if (!d->publisher.isEmpty())
- writer->addAttribute("text:publisher",d->publisher);
- if (!d->school.isEmpty())
- writer->addAttribute("text:school",d->school);
- if (!d->series.isEmpty())
- writer->addAttribute("text:series",d->series);
- if (!d->title.isEmpty())
- writer->addAttribute("text:title",d->title);
- if (!d->reportType.isEmpty())
- writer->addAttribute("text:report-type",d->reportType);
- if (!d->volume.isEmpty())
- writer->addAttribute("text:volume",d->volume);
- if (!d->year.isEmpty())
- writer->addAttribute("text:year",d->year);
- if (!d->url.isEmpty())
- writer->addAttribute("text:url",d->url);
- if (!d->isbn.isEmpty())
- writer->addAttribute("text:isbn",d->isbn);
- if (!d->issn.isEmpty())
- writer->addAttribute("text:issn",d->issn);
- if (!d->custom1.isEmpty())
- writer->addAttribute("text:custom1",d->custom1);
- if (!d->custom2.isEmpty())
- writer->addAttribute("text:custom2",d->custom2);
- if (!d->custom3.isEmpty())
- writer->addAttribute("text:custom3",d->custom3);
- if (!d->custom4.isEmpty())
- writer->addAttribute("text:custom4",d->custom4);
- if (!d->custom5.isEmpty())
- writer->addAttribute("text:custom5",d->custom5);
-
- writer->addTextNode(QString("[%1]").arg(d->identifier));
- writer->endElement();
-}
diff --git a/plugins/flake/textshape/kotext/KoInlineCite.h b/plugins/flake/textshape/kotext/KoInlineCite.h
deleted file mode 100644
index a0c538e0eb..0000000000
--- a/plugins/flake/textshape/kotext/KoInlineCite.h
+++ /dev/null
@@ -1,211 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Smit Patel <smitpatel24@gmail.com>
- *
- * 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 KOINLINECITE_H
-#define KOINLINECITE_H
-
-#include "KoInlineObject.h"
-#include "kritatext_export.h"
-
-/**
- * This object is an inline object, which means it is anchored in the text-flow and it can hold
- * bibliography-mark(citation).
- */
-class KRITATEXT_EXPORT KoInlineCite : public KoInlineObject
-{
- Q_OBJECT
-public:
- enum Type {
- Citation,
- ClonedCitation //cloned from other citation in document
- };
- /**
- * Construct a new cite to be inserted in the text using KoTextSelectionHandler::insertInlineObject() for example.
- */
- explicit KoInlineCite(Type type);
-
- ~KoInlineCite() override;
-
- bool operator!= (const KoInlineCite &cite) const;
-
- KoInlineCite &operator= (const KoInlineCite &cite);
-
- Type type() const; //return type of cite
-
- void setType(Type t);
-
- QString dataField(const QString &fieldName) const; //returns bibliography-data-field with name fieldName
-
- bool hasSameData(KoInlineCite *cite) const;
-
- void copyFrom(KoInlineCite *cite);
-
- void setIdentifier(const QString &identifier);
-
- void setBibliographyType(const QString &bibliographyType);
-
- void setAddress (const QString &addr);
-
- void setAnnotation (const QString &annotation);
-
- void setAuthor (const QString &author);
-
- void setBookTitle (const QString &booktitle);
-
- void setChapter (const QString &chapter);
-
- void setEdition (const QString &edition);
-
- void setEditor (const QString &editor);
-
- void setPublicationType (const QString &publicationType);
-
- void setInstitution (const QString &institution);
-
- void setJournal (const QString &journal);
-
- void setLabel(const QString &label);
-
- void setMonth (const QString &month);
-
- void setNote (const QString &note);
-
- void setNumber (const QString &number);
-
- void setOrganisation (const QString &organisation);
-
- void setPages (const QString &pages);
-
- void setPublisher (const QString &publisher);
-
- void setSchool (const QString &school);
-
- void setSeries (const QString &series);
-
- void setTitle (const QString &title);
-
- void setReportType (const QString &reportType);
-
- void setVolume (const QString &volume);
-
- void setYear (const QString &year);
-
- void setURL (const QString &url);
-
- void setISBN (const QString &isbn);
-
- void setISSN (const QString &issn);
-
- void setCustom1 (const QString &custom1);
-
- void setCustom2 (const QString &custom2);
-
- void setCustom3 (const QString &custom3);
-
- void setCustom4 (const QString &custom4);
-
- void setCustom5 (const QString &custom5);
-
- QString identifier() const;
-
- QString address() const;
-
- QString author() const;
-
- QString bibliographyType() const;
-
- QString annotation() const;
-
- QString bookTitle() const;
-
- QString chapter() const;
-
- QString edition() const;
-
- QString editor() const;
-
- QString publicationType() const;
-
- QString institution() const;
-
- QString journal() const;
-
- QString month() const;
-
- QString note() const;
-
- QString number() const;
-
- QString organisations() const;
-
- QString pages() const;
-
- QString publisher() const;
-
- QString school() const;
-
- QString series() const;
-
- QString title() const;
-
- QString reportType() const;
-
- QString volume() const;
-
- QString year() const;
-
- QString url() const;
-
- QString isbn() const;
-
- QString issn() const;
-
- QString custom1() const;
-
- QString custom2() const;
-
- QString custom3() const;
-
- QString custom4() const;
-
- QString custom5() const;
-
- int posInDocument() const;
-
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
-
- ///reimplemented
- void saveOdf(KoShapeSavingContext &context) override;
-
-protected:
- /// reimplemented
- void updatePosition(const QTextDocument *document, int posInDocument, const QTextCharFormat &format) override;
- /// reimplemented
- void resize(const QTextDocument *document, QTextInlineObject &object,
- int posInDocument, const QTextCharFormat &format, QPaintDevice *pd) override;
- /// reimplemented
- void paint(QPainter &painter, QPaintDevice *pd, const QTextDocument *document,
- const QRectF &rect, const QTextInlineObject &object, int posInDocument, const QTextCharFormat &format) override;
-
-private:
- class Private;
- Private * const d;
-
-};
-
-#endif // KOINLINECITE_H
diff --git a/plugins/flake/textshape/kotext/KoInlineNote.cpp b/plugins/flake/textshape/kotext/KoInlineNote.cpp
deleted file mode 100644
index 732c00c4e8..0000000000
--- a/plugins/flake/textshape/kotext/KoInlineNote.cpp
+++ /dev/null
@@ -1,310 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2010 KO Gmbh <boud@valdyas.org>
- *
- * 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 "KoInlineNote.h"
-
-#include <KoXmlWriter.h>
-#include <KoXmlNS.h>
-#include <KoShapeSavingContext.h>
-#include <KoOdfNumberDefinition.h>
-#include <KoTextLoader.h>
-#include <KoTextWriter.h>
-#include <KoTextDocument.h>
-#include <KoText.h>
-#include <KoStyleManager.h>
-#include <KoParagraphStyle.h>
-#include "TextDebug.h"
-
-#include <QTextDocument>
-#include <QTextFrame>
-#include <QTextCursor>
-#include <QTextInlineObject>
-#include <QFontMetricsF>
-#include <QTextOption>
-#include <QDateTime>
-
-class Q_DECL_HIDDEN KoInlineNote::Private
-{
-public:
- Private(KoInlineNote::Type t)
- : textFrame(0)
- , autoNumbering(false)
- , type(t)
- {
- }
-
- QTextDocument *document;
- QTextFrame *textFrame;
- QString label;
- QString author;
- QDateTime date;
- bool autoNumbering;
- KoInlineNote::Type type;
- int posInDocument;
-};
-
-KoInlineNote::KoInlineNote(Type type)
- : KoInlineObject(true)
- , d(new Private(type))
-{
-}
-
-KoInlineNote::~KoInlineNote()
-{
- delete d;
-}
-
-void KoInlineNote::setMotherFrame(QTextFrame *motherFrame)
-{
- d->document = motherFrame->document();
-
- // We create our own subframe
-
- QTextCursor cursor(motherFrame->lastCursorPosition());
- QTextFrameFormat format;
- format.setProperty(KoText::SubFrameType, KoText::NoteFrameType);
- d->textFrame = cursor.insertFrame(format);
-
- // Now let's make sure it has the right paragraph
- KoOdfNotesConfiguration *notesConfig = 0;
- if (d->type == KoInlineNote::Footnote) {
- notesConfig = KoTextDocument(d->document).styleManager()->notesConfiguration(KoOdfNotesConfiguration::Footnote);
- } else if (d->type == KoInlineNote::Endnote) {
- notesConfig = KoTextDocument(d->document).styleManager()->notesConfiguration(KoOdfNotesConfiguration::Endnote);
- }
-
- KoParagraphStyle *style = static_cast<KoParagraphStyle *>(notesConfig->defaultNoteParagraphStyle());
- if (style) {
- QTextBlockFormat bf;
- QTextCharFormat cf;
- style->applyStyle(bf);
- style->KoCharacterStyle::applyStyle(cf);
- cursor.setBlockFormat(bf);
- cursor.setBlockCharFormat(cf);
- }
-}
-
-void KoInlineNote::setLabel(const QString &text)
-{
- d->label = text;
-}
-
-void KoInlineNote::setAutoNumber(int autoNumber)
-{
- if (d->autoNumbering) {
- KoOdfNotesConfiguration *notesConfig = 0;
- if (d->type == KoInlineNote::Footnote) {
- notesConfig = KoTextDocument(d->document).styleManager()->notesConfiguration(KoOdfNotesConfiguration::Footnote);
- } else if (d->type == KoInlineNote::Endnote) {
- notesConfig = KoTextDocument(d->document).styleManager()->notesConfiguration(KoOdfNotesConfiguration::Endnote);
- }
- d->label = notesConfig->numberFormat().formattedNumber(autoNumber + notesConfig->startValue());
- }
-}
-
-QTextFrame *KoInlineNote::textFrame() const
-{
- return d->textFrame;
-}
-
-void KoInlineNote::setTextFrame(QTextFrame *textFrame)
-{
- d->textFrame = textFrame;
-}
-
-QString KoInlineNote::label() const
-{
- return d->label;
-}
-
-bool KoInlineNote::autoNumbering() const
-{
- return d->autoNumbering;
-}
-
-void KoInlineNote::setAutoNumbering(bool on)
-{
- d->autoNumbering = on;
-}
-
-KoInlineNote::Type KoInlineNote::type() const
-{
- return d->type;
-}
-
-void KoInlineNote::updatePosition(const QTextDocument *document, int posInDocument, const QTextCharFormat &format)
-{
- Q_UNUSED(document);
- Q_UNUSED(format);
-
- d->posInDocument = posInDocument;
-}
-
-void KoInlineNote::resize(const QTextDocument *document, QTextInlineObject &object, int posInDocument, const QTextCharFormat &format, QPaintDevice *pd)
-{
- Q_UNUSED(document);
- Q_UNUSED(posInDocument);
- if (d->label.isEmpty()) {
- object.setWidth(0);
- object.setAscent(0);
- object.setDescent(0);
- } else {
- Q_ASSERT(format.isCharFormat());
- QFontMetricsF fm(format.font(), pd);
- object.setWidth(fm.width(d->label));
- object.setAscent(fm.ascent());
- object.setDescent(fm.descent());
- }
-}
-
-void KoInlineNote::paint(QPainter &painter, QPaintDevice *pd, const QTextDocument *document, const QRectF &rect, const QTextInlineObject &object, int posInDocument, const QTextCharFormat &originalFormat)
-{
- Q_UNUSED(document);
- Q_UNUSED(posInDocument);
-
- if (d->label.isEmpty())
- return;
-
- QTextCharFormat format = originalFormat;
- KoOdfNotesConfiguration *notesConfig = 0;
- if (d->type == KoInlineNote::Footnote) {
- notesConfig = KoTextDocument(d->document).styleManager()->notesConfiguration(KoOdfNotesConfiguration::Footnote);
- } else if (d->type == KoInlineNote::Endnote) {
- notesConfig = KoTextDocument(d->document).styleManager()->notesConfiguration(KoOdfNotesConfiguration::Endnote);
- }
- KoCharacterStyle *style = static_cast<KoCharacterStyle *>(notesConfig->citationBodyTextStyle());
- if (style) {
- style->applyStyle(format);
- }
-
- QFont font(format.font(), pd);
- QTextLayout layout(d->label, font, pd);
- layout.setCacheEnabled(true);
- QList<QTextLayout::FormatRange> layouts;
- QTextLayout::FormatRange range;
- range.start = 0;
- range.length = d->label.length();
- range.format = format;
- layouts.append(range);
- layout.setAdditionalFormats(layouts);
-
- QTextOption option(Qt::AlignLeft | Qt::AlignAbsolute);
- option.setTextDirection(object.textDirection());
- layout.setTextOption(option);
- layout.beginLayout();
- layout.createLine();
- layout.endLayout();
- layout.draw(&painter, rect.topLeft());
-}
-
-bool KoInlineNote::loadOdf(const KoXmlElement & element, KoShapeLoadingContext &context)
-{
- KoTextLoader loader(context);
- QTextCursor cursor(d->textFrame);
-
- if (element.namespaceURI() == KoXmlNS::text && element.localName() == "note") {
-
- QString className = element.attributeNS(KoXmlNS::text, "note-class");
- if (className == "footnote") {
- d->type = Footnote;
- }
- else if (className == "endnote") {
- d->type = Endnote;
- }
- else {
- return false;
- }
-
- for (KoXmlNode node = element.firstChild(); !node.isNull(); node = node.nextSibling()) {
- KoXmlElement ts = node.toElement();
- if (ts.namespaceURI() != KoXmlNS::text)
- continue;
- if (ts.localName() == "note-body") {
- loader.loadBody(ts, cursor);
- } else if (ts.localName() == "note-citation") {
- d->label = ts.attributeNS(KoXmlNS::text, "label");
- if (d->label.isEmpty()) {
- setAutoNumbering(true);
- d->label = ts.text();
- }
- }
- }
- }
- else if (element.namespaceURI() == KoXmlNS::office && element.localName() == "annotation") {
- d->author = element.attributeNS(KoXmlNS::text, "dc-creator");
- d->date = QDateTime::fromString(element.attributeNS(KoXmlNS::text, "dc-date"), Qt::ISODate);
- loader.loadBody(element, cursor); // would skip author and date, and do just the <text-p> and <text-list> elements
- }
- else {
- return false;
- }
-
- return true;
-}
-
-void KoInlineNote::saveOdf(KoShapeSavingContext & context)
-{
- KoXmlWriter *writer = &context.xmlWriter();
-
- if (d->type == Footnote || d->type == Endnote) {
- writer->startElement("text:note", false);
- if (d->type == Footnote) {
- writer->addAttribute("text:note-class", "footnote");
- } else {
- writer->addAttribute("text:note-class", "endnote");
- }
-
- writer->startElement("text:note-citation", false);
- if (!autoNumbering()) {
- writer->addAttribute("text:label", d->label);
- }
- writer->addTextNode(d->label);
- writer->endElement();
-
- writer->startElement("text:note-body", false);
- KoTextWriter textWriter(context);
- textWriter.write(d->document, d->textFrame->firstPosition(), d->textFrame->lastPosition());
- writer->endElement();
-
- writer->endElement();
- }
- else if (d->type == Annotation) {
- writer->startElement("office:annotation");
- if (!d->author.isEmpty()) {
- writer->startElement("dc:creator");
- writer->addTextNode(d->author);
- writer->endElement();
- }
- if (d->date.isValid()) {
- writer->startElement("dc:date");
- writer->addTextSpan(d->date.toString(Qt::ISODate));
- writer->endElement();
- }
-
- KoTextWriter textWriter(context);
- textWriter.write(d->document, d->textFrame->firstPosition(),d->textFrame->lastPosition());
-
- writer->endElement();
- }
-}
-
-int KoInlineNote::getPosInDocument() const
-{
- return d->posInDocument;
-}
diff --git a/plugins/flake/textshape/kotext/KoInlineNote.h b/plugins/flake/textshape/kotext/KoInlineNote.h
deleted file mode 100644
index 8fd8806d73..0000000000
--- a/plugins/flake/textshape/kotext/KoInlineNote.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 KOINLINENOTE_H
-#define KOINLINENOTE_H
-
-#include "KoInlineObject.h"
-#include "kritatext_export.h"
-
-class QTextFrame;
-
-/**
- * This object is an inline object, which means it is anchored in the text-flow and it can hold note info.
- * Typical notes that use this are Footnotes, Endnotes and Annotations (also known as comments).
- */
-class KRITATEXT_EXPORT KoInlineNote : public KoInlineObject
-{
- Q_OBJECT
-public:
- /// The type of note specifies how the application will use the text from the note.
- enum Type {
- Footnote, ///< Notes of this type will have their text placed at the bottom of a shape.
- Endnote, ///< Notes of this type are used as endnotes in applications that support it.
- Annotation ///< Notes of this type will have their text placed in the document margin.
- };
-
- /**
- * Construct a new note to be inserted in the text using KoTextEditor::insertInlineObject() for example.
- * @param type the type of note, which specifies how the application will use the text from the new note.
- */
- explicit KoInlineNote(Type type);
- // destructor
- ~KoInlineNote() override;
-
- /**
- * Set the textframe where we will create our own textframe within
- * Our textframe is the one containing the real note contents.
- * @param text the new text
- */
- void setMotherFrame(QTextFrame *text);
-
- /**
- * Set the label that is shown at the spot this inline note is inserted.
- * @param text the new label
- */
- void setLabel(const QString &text);
-
- /**
- * Indirectly set the label that is shown at the spot this inline note is inserted.
- * @param autoNumber the number that the label will portray. 0 should be the first
- */
- void setAutoNumber(int autoNumber);
-
- /// return the current text
- QTextFrame *textFrame() const;
-
- /// return the current label
- QString label() const;
-
- /**
- * @return whether the label should be automatically recreated or if the label is static.
- */
- bool autoNumbering() const;
-
- /**
- * Set whether the label should be automatically recreated.
- * @param on if true then changes in footnote-ordering will recalcualte the label.
- */
- void setAutoNumbering(bool on);
-
- /// return the type of note.
- Type type() const;
-
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
-
- ///reimplemented
- void saveOdf(KoShapeSavingContext &context) override;
-
- int getPosInDocument() const;
-
-protected:
- /// reimplemented
- void updatePosition(const QTextDocument *document,
- int posInDocument, const QTextCharFormat &format) override;
- /// reimplemented
- void resize(const QTextDocument *document, QTextInlineObject &object,
- int posInDocument, const QTextCharFormat &format, QPaintDevice *pd) override;
- /// reimplemented
- void paint(QPainter &painter, QPaintDevice *pd, const QTextDocument *document,
- const QRectF &rect, const QTextInlineObject &object, int posInDocument, const QTextCharFormat &format) override;
-
-private:
- friend class InsertNoteCommand;
-
- // only to be used on subsequent redo of insertion
- void setTextFrame(QTextFrame *textFrame);
-
- class Private;
- Private * const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoInlineObject.cpp b/plugins/flake/textshape/kotext/KoInlineObject.cpp
deleted file mode 100644
index c3441e9cd6..0000000000
--- a/plugins/flake/textshape/kotext/KoInlineObject.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- *
- * 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 "KoInlineObject.h"
-#include "KoInlineObject_p.h"
-#include "KoInlineTextObjectManager.h"
-#include "KoTextInlineRdf.h"
-
-#include "TextDebug.h"
-
-QDebug KoInlineObjectPrivate::printDebug(QDebug dbg) const
-{
- dbg.nospace() << "KoInlineObject ManagerId: " << id;
- return dbg.space();
-}
-
-
-KoInlineObjectPrivate::~KoInlineObjectPrivate()
-{
- delete rdf;
-}
-
-KoInlineObject::KoInlineObject(bool propertyChangeListener)
- : d_ptr(new KoInlineObjectPrivate)
-{
- Q_D(KoInlineObject);
- d->propertyChangeListener = propertyChangeListener;
-}
-
-KoInlineObject::KoInlineObject(KoInlineObjectPrivate &priv, bool propertyChangeListener)
- : d_ptr(&priv)
-{
- Q_D(KoInlineObject);
- d->propertyChangeListener = propertyChangeListener;
-}
-
-KoInlineObject::~KoInlineObject()
-{
- if (d_ptr->manager) {
- d_ptr->manager->removeInlineObject(this);
- }
- delete d_ptr;
- d_ptr = 0;
-}
-
-void KoInlineObject::setManager(KoInlineTextObjectManager *manager)
-{
- Q_D(KoInlineObject);
- d->manager = manager;
-}
-
-KoInlineTextObjectManager *KoInlineObject::manager() const
-{
- Q_D(const KoInlineObject);
- return d->manager;
-}
-
-void KoInlineObject::propertyChanged(Property key, const QVariant &value)
-{
- Q_UNUSED(key);
- Q_UNUSED(value);
-}
-
-int KoInlineObject::id() const
-{
- Q_D(const KoInlineObject);
- return d->id;
-}
-
-void KoInlineObject::setId(int id)
-{
- Q_D(KoInlineObject);
- d->id = id;
-}
-
-bool KoInlineObject::propertyChangeListener() const
-{
- Q_D(const KoInlineObject);
- return d->propertyChangeListener;
-}
-
-QDebug operator<<(QDebug dbg, const KoInlineObject *o)
-{
- return o ? o->d_func()->printDebug(dbg) : dbg << "KoInlineObject 0";
-;
-}
-
-void KoInlineObject::setInlineRdf(KoTextInlineRdf* rdf)
-{
- Q_D(KoInlineObject);
- d->rdf = rdf;
-}
-
-KoTextInlineRdf* KoInlineObject::inlineRdf() const
-{
- Q_D(const KoInlineObject);
- return d->rdf;
-}
-
diff --git a/plugins/flake/textshape/kotext/KoInlineObject.h b/plugins/flake/textshape/kotext/KoInlineObject.h
deleted file mode 100644
index a7c9183cb4..0000000000
--- a/plugins/flake/textshape/kotext/KoInlineObject.h
+++ /dev/null
@@ -1,239 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- *
- * 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 KOINLINEOBJECTBASE_H
-#define KOINLINEOBJECTBASE_H
-
-#include "kritatext_export.h"
-#include <KoXmlReaderForward.h>
-
-#include <QObject>
-#include <QTextInlineObject>
-
-class QVariant;
-class QTextDocument;
-class QTextCharFormat;
-class QPaintDevice;
-class QPainter;
-class QRectF;
-
-class KoInlineTextObjectManager;
-class KoInlineObjectPrivate;
-class KoShapeSavingContext;
-class KoTextInlineRdf;
-class KoShapeLoadingContext;
-
-/**
- * Base class for all inline-text-objects.
- *
- * In a TextShape you can insert objects that move with the text.
- * They are essentially anchored to a specific position in the text, as
- * one character.
- *
- * @see KoInlineTextObjectManager
- */
-class KRITATEXT_EXPORT KoInlineObject : public QObject
-{
- Q_OBJECT
-public:
- enum Property {
- DocumentURL,
- PageCount,
- AuthorName,
- SenderEmail,
- SenderCompany,
- SenderPhoneWork,
- SenderPhonePrivate,
- SenderFax,
- SenderCountry,
- Title,
- Keywords,
- Subject,
- Description,
- Comments,
- SenderPostalCode,
- SenderCity,
- SenderStreet,
- SenderTitle,
- SenderFirstname,
- SenderLastname,
- SenderPosition,
- AuthorInitials,
- Chapter, ///< Chapter (number, name, number and name, plain number, plain number and name) variables.
-
- 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.
- WordsStart = 7000, ///< Base number for Words specific values.
- VariableManagerStart = 8000, ///< Start of numbers reserved for the KoVariableManager
- UserGet = 12000, ///< User defined variable user-field-get
- UserInput = 12001 ///< User defined variable user-field-input
- };
-
- /**
- * constructor
- * @param propertyChangeListener if set to true this instance will be notified of changes of properties.
- * @see KoInlineTextObjectManager::setProperty()
- * @see propertyChangeListener()
- */
- explicit KoInlineObject(bool propertyChangeListener = false);
- ~KoInlineObject() override;
-
- /**
- * Will be called by the manager when this variable is added.
- * Remember that inheriting classes should not use the manager() in the constructor, since it will be 0
- * @param manager the object manager for this object.
- */
- void setManager(KoInlineTextObjectManager *manager);
-
- /**
- * Return the object manager set on this inline object.
- */
- KoInlineTextObjectManager *manager() const;
-
- /**
- * Just prior to the first time this object will be shown this method will be called.
- * The object plugin should reimplement this to initialize the object after the manager
- * has been set, but before the text has been layouted.
- * The default implementation does nothing.
- */
- virtual void setup() {}
-
- /**
- * Save this inlineObject as ODF
- * @param context the context for saving.
- */
- virtual void saveOdf(KoShapeSavingContext &context) = 0;
-
- /**
- * Update position of the inline object.
- * This is called each time the paragraph this inline object is in is re-layouted giving you the opportunity
- * to reposition your object based on the new information.
- * @param document the text document this inline object is operating on.
- * @param posInDocument the character position in the document (param document) this inline object is at.
- * @param format the character format for the inline object.
- */
- virtual void updatePosition(const QTextDocument *document, int posInDocument, const QTextCharFormat &format) = 0;
-
- /**
- * Update the size of the inline object.
- * Each time the text is painted, as well as when the paragraph this variable is in, this method
- * is called. You should alter the size of the object if the content has changed.
- * Altering the size is done by altering the 'object' parameter using QTextInlineObject::setWidth(),
- * QTextInlineObject::setAscent() and QTextInlineObject::setDescent() methods.
- * Note that this method is called while painting; and thus is time sensitive; avoid doing anything time
- * consuming.
- * Note make sure that the width is 0 when there is nothing to be shown for the object.
- * @param document the text document this inline object is operating on.
- * @param object the inline object properties
- * @param posInDocument the character position in the document (param document) this inline object is at.
- * @param format the character format for the inline object.
- * @param pd the postscript-paintdevice that all text is rendered on. Use this for QFont and related
- * classes so the inline object can be reused on any paintdevice.
- */
- virtual void resize(const QTextDocument *document, QTextInlineObject &object,
- int posInDocument, const QTextCharFormat &format, QPaintDevice *pd) = 0;
-
- /**
- * Paint the inline-object-base using the provided painter within the rectangle specified by rect.
- * @param document the text document this inline object is operating on.
- * @param object the inline object properties
- * @param posInDocument the character position in the document (param document) this inline object is at.
- * @param format the character format for the inline object.
- * @param pd the postscript-paintdevice that all text is rendered on. Use this for QFont and related
- * classes so the inline object can be reused on any paintdevice.
- * @param painter the painting object to paint on. Note that unline many places in calligra painting
- * should happen at the position indicated by the rect, not at top-left.
- * @param rect the rectangle inside which the variable can paint itself. Painting outside the rect
- * will give various problems with regards to repainting issues.
- */
- virtual void paint(QPainter &painter, QPaintDevice *pd, const QTextDocument *document,
- const QRectF &rect, const QTextInlineObject &object, int posInDocument, const QTextCharFormat &format) = 0;
-
- /**
- * Overwrite this if you are interested in propertychanges.
- * @param property the property id that has been changed, one from the Property enum.
- * You should ignore all properties you don't use as new properties can be added at any time.
- * @param value the new value of the property wrapped in a QVariant. Properties can be a lot of
- * different class types. Ints, bools, QStrings etc.
- * example:
- * @code
- * void KoDateVariable::propertyChanged(Property key, const QVariant &value) {
- * if(key == KoInlineObject::PageCount)
- * setValue(QString::number(value.toInt()));
- * }
- * @endcode
- * @see propertyChangeListener()
- */
- virtual void propertyChanged(Property property, const QVariant &value);
-
- /// return the inline-object Id that is assigned for this object.
- int id() const;
-
- /// Set the inline-object Id that is assigned for this object by the KoInlineTextObjectManager.
- void setId(int id);
-
- /**
- * When true, notify this object of property changes.
- * Each inlineObject can use properties like the PageCount or the document name.
- * Only objects that actually have a need for such information be a listener to avoid unneeded
- * overhead.
- * When this returns true, the propertyChanged() method will be called.
- * @see KoInlineTextObjectManager::setProperty()
- */
- bool propertyChangeListener() const;
-
- /**
- * An inline object might have some Rdf metadata associated with it
- * in content.xml
- * Ownership of the rdf object is taken by this object, you should not
- * delete it.
- */
- void setInlineRdf(KoTextInlineRdf *rdf);
- /**
- * Get any Rdf which was stored in content.xml for this inline object
- * This object continues to own the object, do not delete it.
- */
- KoTextInlineRdf *inlineRdf() const;
-
- /**
- * Load a variable from odf.
- *
- * @param element element which represents the shape in odf
- * @param context the KoShapeLoadingContext used for loading
- *
- * @return false if loading failed
- */
- virtual bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) = 0;
-
-protected:
- explicit KoInlineObject(KoInlineObjectPrivate &, bool propertyChangeListener = false);
-
- KoInlineObjectPrivate *d_ptr;
-
-private:
- Q_DECLARE_PRIVATE(KoInlineObject)
- friend KRITATEXT_EXPORT QDebug operator<<(QDebug, const KoInlineObject *);
-};
-
-KRITATEXT_EXPORT QDebug operator<<(QDebug dbg, const KoInlineObject *o);
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoInlineObjectFactoryBase.cpp b/plugins/flake/textshape/kotext/KoInlineObjectFactoryBase.cpp
deleted file mode 100644
index b5e460176b..0000000000
--- a/plugins/flake/textshape/kotext/KoInlineObjectFactoryBase.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006 Thomas Zander <zander@kde.org>
- *
- * 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 "KoInlineObjectFactoryBase.h"
-#include <KoProperties.h>
-
-#include <QStringList>
-
-class InlineObjectFactoryPrivate
-{
-public:
- InlineObjectFactoryPrivate(const QString &identifier)
- : id(identifier) {
- }
-
- ~InlineObjectFactoryPrivate() {
- Q_FOREACH (const KoInlineObjectTemplate &t, templates)
- delete t.properties;
- templates.clear();
- }
-
- const QString id;
- QString iconName;
- QString odfNameSpace;
- QStringList odfElementNames;
- QList<KoInlineObjectTemplate> templates;
- KoInlineObjectFactoryBase::ObjectType type;
-};
-
-KoInlineObjectFactoryBase::KoInlineObjectFactoryBase(const QString &id, ObjectType type)
- : d(new InlineObjectFactoryPrivate(id))
-{
- d->type = type;
-}
-
-KoInlineObjectFactoryBase::~KoInlineObjectFactoryBase()
-{
- delete d;
-}
-
-QString KoInlineObjectFactoryBase::id() const
-{
- return d->id;
-}
-
-QList<KoInlineObjectTemplate> KoInlineObjectFactoryBase::templates() const
-{
- return d->templates;
-}
-
-void KoInlineObjectFactoryBase::addTemplate(const KoInlineObjectTemplate &params)
-{
- d->templates.append(params);
-}
-
-QStringList KoInlineObjectFactoryBase::odfElementNames() const
-{
- return d->odfElementNames;
-}
-
-QString KoInlineObjectFactoryBase::odfNameSpace() const
-{
- return d->odfNameSpace;
-}
-
-void KoInlineObjectFactoryBase::setOdfElementNames(const QString & nameSpace, const QStringList &names)
-{
- d->odfNameSpace = nameSpace;
- d->odfElementNames = names;
-}
-
-KoInlineObjectFactoryBase::ObjectType KoInlineObjectFactoryBase::type() const
-{
- return d->type;
-}
diff --git a/plugins/flake/textshape/kotext/KoInlineObjectFactoryBase.h b/plugins/flake/textshape/kotext/KoInlineObjectFactoryBase.h
deleted file mode 100644
index 0dd1339ac0..0000000000
--- a/plugins/flake/textshape/kotext/KoInlineObjectFactoryBase.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006 Thomas Zander <zander@kde.org>
- *
- * 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 KOINLINEOBJECTFACTORY_H
-#define KOINLINEOBJECTFACTORY_H
-
-#include <QString>
-
-#include "kritatext_export.h"
-
-class KoInlineObject;
-class InlineObjectFactoryPrivate;
-class KoProperties;
-
-/// A template used in the KoInlineObjectFactoryBase
-struct KRITATEXT_EXPORT KoInlineObjectTemplate {
- QString id; ///< The id of the inlineObject
- QString name; ///< The name to be shown for this template
- /**
- * The properties which, when passed to the KoInlineObjectFactoryBase::createInlineObject() method
- * result in the object this template represents.
- */
- const KoProperties *properties;
-};
-
-/**
- * A factory for inline text objects. There should be one for each plugin type to
- * allow the creation of the inlineObject from that plugin.
- * The factory additionally has information to allow showing a menu entry for user
- * access to the object-type.
- * @see KoInlineObjectRegistry
- */
-class KRITATEXT_EXPORT KoInlineObjectFactoryBase
-{
-public:
- /// The type of inlineObject this factory creates.
- enum ObjectType {
- TextVariable, ///< The factory creates KoVariable inherting objects.
- Other = 0x100 ///< The factory creates objects that should not be shown in any menu
- };
-
- /**
- * Create the new factory
- * @param id a string that will be used internally for referencing the variable-type.
- * @param type the object type for the new factory.
- */
- KoInlineObjectFactoryBase(const QString &id, ObjectType type);
- virtual ~KoInlineObjectFactoryBase();
-
- /**
- * Create a new instance of an inline object.
- */
- virtual KoInlineObject *createInlineObject(const KoProperties *properties = 0) const = 0;
-
- /**
- * return the id for the variable this factory creates.
- * @return the id for the variable this factory creates.
- */
- QString id() const;
-
- /**
- * Returns the type of object this factory creates.
- * The main purpose is to group plugins per type in, for example, a menu.
- */
- ObjectType type() const;
-
- /**
- * Return all the templates this factory knows about.
- * Each template shows a different way to create an object this factory is specialized in.
- */
- QList<KoInlineObjectTemplate> templates() const;
-
- QStringList odfElementNames() const;
-
- QString odfNameSpace() const;
-
- void setOdfElementNames(const QString &nameSpace, const QStringList &names);
-
-protected:
- /**
- * Add a template with the properties of a specific type of object this factory can generate
- * using the createInlineObject() method.
- * @param params The new template this factory knows to produce
- */
- void addTemplate(const KoInlineObjectTemplate &params);
-
-private:
- InlineObjectFactoryPrivate * const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoInlineObjectRegistry.cpp b/plugins/flake/textshape/kotext/KoInlineObjectRegistry.cpp
deleted file mode 100644
index f1db33e7b1..0000000000
--- a/plugins/flake/textshape/kotext/KoInlineObjectRegistry.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
- *
- * 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 "KoInlineObjectRegistry.h"
-#include "KoInlineObjectFactoryBase.h"
-#include "InsertVariableAction_p.h"
-
-#include <KoCanvasBase.h>
-#include <KoInlineObject.h>
-#include <KoXmlReader.h>
-#include <KoPluginLoader.h>
-
-#include <QGlobalStatic>
-
-#include "TextDebug.h"
-
-Q_GLOBAL_STATIC(KoInlineObjectRegistry, s_instance)
-
-
-class Q_DECL_HIDDEN KoInlineObjectRegistry::Private
-{
-public:
- void insertFactory(KoInlineObjectFactoryBase *factory);
- void init(KoInlineObjectRegistry *q);
-
- QHash<QPair<QString, QString>, KoInlineObjectFactoryBase *> factories;
-};
-
-void KoInlineObjectRegistry::Private::init(KoInlineObjectRegistry *q)
-{
- KoPluginLoader::PluginsConfig config;
- config.whiteList = "TextInlinePlugins";
- config.blacklist = "TextInlinePluginsDisabled";
- config.group = "krita";
- KoPluginLoader::instance()->load(QString::fromLatin1("Krita/Text-InlineObject"),
- QString::fromLatin1("[X-KoText-PluginVersion] == 28"), config);
-
- foreach (KoInlineObjectFactoryBase *factory, q->values()) {
- QString nameSpace = factory->odfNameSpace();
- if (nameSpace.isEmpty() || factory->odfElementNames().isEmpty()) {
- debugText << "Variable factory" << factory->id() << " does not have odfNameSpace defined, ignoring";
- } else {
- foreach (const QString &elementName, factory->odfElementNames()) {
- factories.insert(QPair<QString, QString>(nameSpace, elementName), factory);
-
- debugText << "Inserting variable factory" << factory->id() << " for"
- << nameSpace << ":" << elementName;
- }
- }
- }
-}
-
-KoInlineObjectRegistry* KoInlineObjectRegistry::instance()
-{
- if (!s_instance.exists()) {
- s_instance->d->init(s_instance);
- }
- return s_instance;
-}
-
-QList<QAction*> KoInlineObjectRegistry::createInsertVariableActions(KoCanvasBase *host) const
-{
- QList<QAction*> answer;
- foreach (const QString &key, keys()) {
- KoInlineObjectFactoryBase *factory = value(key);
- if (factory->type() == KoInlineObjectFactoryBase::TextVariable) {
- foreach (const KoInlineObjectTemplate &templ, factory->templates()) {
- answer.append(new InsertVariableAction(host, factory, templ));
- }
-#ifndef NDEBUG
- if (factory->templates().isEmpty()) {
- warnText << "Variable factory" << factory->id() << "has no templates, skipping.";
- }
-#endif
- }
- }
- return answer;
-}
-
-KoInlineObject *KoInlineObjectRegistry::createFromOdf(const KoXmlElement &element, KoShapeLoadingContext &context) const
-{
- KoInlineObjectFactoryBase *factory = d->factories.value(
- QPair<QString, QString>(element.namespaceURI(), element.tagName()));
- if (factory == 0) {
- debugText << "No factory for" << element.namespaceURI() << ":" << element.tagName();
- return 0;
- }
-
- KoInlineObject *object = factory->createInlineObject(0);
- if (object) {
- object->loadOdf(element, context);
- }
-
- return object;
-}
-
-KoInlineObjectRegistry::~KoInlineObjectRegistry()
-{
- qDeleteAll(doubleEntries());
- qDeleteAll(values());
- delete d;
-}
-
-KoInlineObjectRegistry::KoInlineObjectRegistry()
- : d(new Private())
-{
-}
diff --git a/plugins/flake/textshape/kotext/KoInlineObjectRegistry.h b/plugins/flake/textshape/kotext/KoInlineObjectRegistry.h
deleted file mode 100644
index 4007947c65..0000000000
--- a/plugins/flake/textshape/kotext/KoInlineObjectRegistry.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
- *
- * 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 KOINLINEOBJECTREGISTRY_H
-#define KOINLINEOBJECTREGISTRY_H
-
-#include <KoGenericRegistry.h>
-#include <KoInlineObjectFactoryBase.h>
-#include <KoXmlReaderForward.h>
-#include "kritatext_export.h"
-#include <QList>
-
-class KoCanvasBase;
-class QAction;
-class KoShapeLoadingContext;
-
-/**
- * This singleton class keeps a register of all available InlineObject factories.
- * @see KoInlineObjectFactoryBase
- * @see KoInlineTextObjectManager
- * @see KoInlineObject
- * @see KoVariable
- */
-class KRITATEXT_EXPORT KoInlineObjectRegistry : public KoGenericRegistry<KoInlineObjectFactoryBase*>
-{
-public:
- KoInlineObjectRegistry();
- ~KoInlineObjectRegistry() override;
-
- /**
- * Return an instance of the KoInlineObjectRegistry
- * Creates an instance if that has never happened before and returns the singleton instance.
- */
- static KoInlineObjectRegistry *instance();
-
- /**
- * Create a list of actions that can be used to plug into a menu, for example.
- * This method will find all the InlineObjectFactories that are installed in the system and
- * find out which object they provide. If a factory provides a variable, then all its
- * templates will be added to the response.
- * Each of these actions, when executed, will insert the relevant variable in the current text-position.
- * The actions assume that the text tool is selected, if that's not the case then they will silently fail.
- * @param host the canvas for which these actions are created. Note that the actions will get these
- * actions as a parent (for memory management purposes) as well.
- * @see KoInlineTextObjectManager::createInsertVariableActions()
- */
- QList<QAction*> createInsertVariableActions(KoCanvasBase *host) const;
-
- /**
- * Use the element to find out which variable plugin can load it, and returns the loaded
- * variable. The element expected is one of 'text:subject', 'text:date' / etc.
- *
- * @returns the variable or 0 if no variable could be created
- */
- KoInlineObject *createFromOdf(const KoXmlElement &element, KoShapeLoadingContext &context) const;
-
-private:
- KoInlineObjectRegistry(const KoInlineObjectRegistry&);
- KoInlineObjectRegistry operator=(const KoInlineObjectRegistry&);
-
- class Private;
- Private * const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoInlineObject_p.h b/plugins/flake/textshape/kotext/KoInlineObject_p.h
deleted file mode 100644
index f9b2490390..0000000000
--- a/plugins/flake/textshape/kotext/KoInlineObject_p.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- *
- * 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 KOINLINEOBJECT_P_H
-#define KOINLINEOBJECT_P_H
-
-#include "TextDebug.h"
-class KoTextInlineRdf;
-
-class KoInlineObjectPrivate
-{
-public:
- KoInlineObjectPrivate()
- : manager(0),
- id(-1),
- propertyChangeListener(0),
- rdf(0) {
- }
- virtual ~KoInlineObjectPrivate();
-
- KoInlineTextObjectManager *manager;
- int id;
- bool propertyChangeListener;
- KoTextInlineRdf *rdf; //< An inline object might have RDF, we own it.
-
- virtual QDebug printDebug(QDebug dbg) const;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoInlineTextObjectManager.cpp b/plugins/flake/textshape/kotext/KoInlineTextObjectManager.cpp
deleted file mode 100644
index 5c7164a9c5..0000000000
--- a/plugins/flake/textshape/kotext/KoInlineTextObjectManager.cpp
+++ /dev/null
@@ -1,296 +0,0 @@
- /* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (c) 2011 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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 "KoInlineTextObjectManager.h"
-
-#include "InsertNamedVariableAction_p.h"
-#include "InsertTextReferenceAction_p.h"
-#include "InsertTextLocator_p.h"
-#include "KoInlineObjectRegistry.h"
-#include "KoTextLocator.h"
-#include "KoInlineNote.h"
-#include "KoInlineCite.h"
-
-#include <QTextCursor>
-
-KoInlineTextObjectManager::KoInlineTextObjectManager(QObject *parent)
- : QObject(parent),
- m_lastObjectId(0),
- m_variableManager(this)
-{
-}
-
-KoInlineTextObjectManager::~KoInlineTextObjectManager()
-{
-}
-
-KoInlineObject *KoInlineTextObjectManager::inlineTextObject(const QTextCharFormat &format) const
-{
- int id = format.intProperty(InlineInstanceId);
- if (id <= 0)
- return 0;
- return m_objects.value(id, 0);
-}
-
-KoInlineObject *KoInlineTextObjectManager::inlineTextObject(const QTextCursor &cursor) const
-{
- return inlineTextObject(cursor.charFormat());
-}
-
-KoInlineObject *KoInlineTextObjectManager::inlineTextObject(int id) const
-{
- return m_objects.value(id);
-}
-
-void KoInlineTextObjectManager::insertInlineObject(QTextCursor& cursor, KoInlineObject *object)
-{
- QTextCharFormat oldCf = cursor.charFormat();
- // create a new format out of the old so that the current formatting is
- // also used for the inserted object. KoVariables render text too ;)
- QTextCharFormat cf(oldCf);
- cf.setObjectType(QTextFormat::UserObject + 1);
- cf.setProperty(InlineInstanceId, ++m_lastObjectId);
- cursor.insertText(QString(QChar::ObjectReplacementCharacter), cf);
- object->setId(m_lastObjectId);
- object->setManager(this);
- object->setup();
-
- insertObject(object);
-
- // reset to use old format so that the InlineInstanceId is no longer set.
- cursor.setCharFormat(oldCf);
-}
-
-void KoInlineTextObjectManager::insertObject(KoInlineObject *object)
-{
- m_objects.insert(object->id(), object);
- if (object->propertyChangeListener()) {
- m_listeners.append(object);
- QHash<int, QVariant>::iterator i;
- for (i = m_properties.begin(); i != m_properties.end(); ++i)
- object->propertyChanged((KoInlineObject::Property)(i.key()), i.value());
- }
-
- // reset to use old format so that the InlineInstanceId is no longer set.
-}
-
-void KoInlineTextObjectManager::addInlineObject(KoInlineObject* object)
-{
- if (!object) {
- return;
- }
-
- int id = object->id();
- if (id == -1) {
- object->setId(++m_lastObjectId);
- object->setManager(this);
- object->setup();
- }
- else {
- m_deletedObjects.remove(id);
- }
- insertObject(object);
-}
-
-void KoInlineTextObjectManager::removeInlineObject(KoInlineObject *object)
-{
- if (!object) {
- return;
- }
-
- int id = object->id();
- m_objects.remove(id);
- m_deletedObjects[id] = object;
- m_listeners.removeAll(object);
-}
-
-void KoInlineTextObjectManager::setProperty(KoInlineObject::Property key, const QVariant &value)
-{
- if (m_properties.contains(key)) {
- if (value == m_properties.value(key))
- return;
- m_properties.remove(key);
- }
- m_properties.insert(key, value);
- foreach (KoInlineObject *obj, m_listeners)
- obj->propertyChanged(key, value);
-}
-
-QVariant KoInlineTextObjectManager::property(KoInlineObject::Property key) const
-{
- return m_properties.value(key);
-}
-
-int KoInlineTextObjectManager::intProperty(KoInlineObject::Property key) const
-{
- if (!m_properties.contains(key))
- return 0;
- return m_properties.value(key).toInt();
-}
-
-bool KoInlineTextObjectManager::boolProperty(KoInlineObject::Property key) const
-{
- if (!m_properties.contains(key))
- return false;
- return m_properties.value(key).toBool();
-}
-
-QString KoInlineTextObjectManager::stringProperty(KoInlineObject::Property key) const
-{
- if (!m_properties.contains(key))
- return QString();
- return qvariant_cast<QString>(m_properties.value(key));
-}
-
-const KoVariableManager *KoInlineTextObjectManager::variableManager() const
-{
- return &m_variableManager;
-}
-
-KoVariableManager *KoInlineTextObjectManager::variableManager()
-{
- return &m_variableManager;
-}
-
-void KoInlineTextObjectManager::removeProperty(KoInlineObject::Property key)
-{
- m_properties.remove(key);
-}
-
-QList<QAction*> KoInlineTextObjectManager::createInsertVariableActions(KoCanvasBase *host) const
-{
- QList<QAction *> answer = KoInlineObjectRegistry::instance()->createInsertVariableActions(host);
- int i = 0;
- Q_FOREACH (const QString & name, m_variableManager.variables()) {
- answer.insert(i++, new InsertNamedVariableAction(host, this, name));
- }
-
- answer.append(new InsertTextLocator(host));
- answer.append(new InsertTextReferenceAction(host, this));
- return answer;
-}
-
-QList<KoTextLocator*> KoInlineTextObjectManager::textLocators() const
-{
- QList<KoTextLocator*> answers;
- Q_FOREACH (KoInlineObject *object, m_objects) {
- KoTextLocator *tl = dynamic_cast<KoTextLocator*>(object);
- if (tl)
- answers.append(tl);
- }
- return answers;
-}
-
-QList<KoInlineNote*> KoInlineTextObjectManager::endNotes() const
-{
- QList<KoInlineNote*> answers;
- Q_FOREACH (KoInlineObject* object, m_objects) {
- KoInlineNote* note = dynamic_cast<KoInlineNote*>(object);
- if (note && note->type() == KoInlineNote::Endnote) {
- answers.append(note);
- }
- }
- return answers;
-}
-
-QMap<QString, KoInlineCite*> KoInlineTextObjectManager::citations(bool duplicatesEnabled) const
-{
- QMap<QString, KoInlineCite*> answers;
- Q_FOREACH (KoInlineObject* object, m_objects) {
- KoInlineCite* cite = dynamic_cast<KoInlineCite*>(object);
- if (cite && (cite->type() == KoInlineCite::Citation ||
- (duplicatesEnabled && cite->type() == KoInlineCite::ClonedCitation))) {
- answers.insert(cite->identifier(), cite);
- }
- }
- return answers;
-}
-
-QList<KoInlineCite*> KoInlineTextObjectManager::citationsSortedByPosition(bool duplicatesEnabled, QTextBlock block) const
-{
- QList<KoInlineCite*> answers;
-
- while (block.isValid()) {
- QString text = block.text();
- int pos = text.indexOf(QChar::ObjectReplacementCharacter);
-
- while (pos >= 0 && pos <= block.length() ) {
- QTextCursor cursor(block);
- cursor.setPosition(block.position() + pos);
- cursor.setPosition(cursor.position() + 1, QTextCursor::KeepAnchor);
-
- KoInlineCite *cite = dynamic_cast<KoInlineCite*>(this->inlineTextObject(cursor));
-
- if (cite && (cite->type() == KoInlineCite::Citation ||
- (duplicatesEnabled && cite->type() == KoInlineCite::ClonedCitation))) {
- answers.append(cite);
- }
- pos = text.indexOf(QChar::ObjectReplacementCharacter, pos + 1);
- }
- block = block.next();
- }
-
- return answers;
-}
-
-void KoInlineTextObjectManager::documentInformationUpdated(const QString &info, const QString &data)
-{
- if (info == "title")
- setProperty(KoInlineObject::Title, data);
- else if (info == "description")
- setProperty(KoInlineObject::Description, data);
- else if (info == "abstract")
- setProperty(KoInlineObject::Comments, data);
- else if (info == "subject")
- setProperty(KoInlineObject::Subject, data);
- else if (info == "keyword")
- setProperty(KoInlineObject::Keywords, data);
- else if (info == "creator")
- setProperty(KoInlineObject::AuthorName, data);
- else if (info == "initial")
- setProperty(KoInlineObject::AuthorInitials, data);
-// else if (info == "title") // TODO: find a correct tag name
-// setProperty(KoInlineObject::SenderTitle, data);
- else if (info == "email")
- setProperty(KoInlineObject::SenderEmail, data);
- else if (info == "telephone")
- setProperty(KoInlineObject::SenderPhonePrivate, data);
- else if (info == "telephone-work")
- setProperty(KoInlineObject::SenderPhoneWork, data);
- else if (info == "fax")
- setProperty(KoInlineObject::SenderFax, data);
- else if (info == "country")
- setProperty(KoInlineObject::SenderCountry, data);
- else if (info == "postal-code")
- setProperty(KoInlineObject::SenderPostalCode, data);
- else if (info == "city")
- setProperty(KoInlineObject::SenderCity, data);
- else if (info == "street")
- setProperty(KoInlineObject::SenderStreet, data);
- else if (info == "position")
- setProperty(KoInlineObject::SenderPosition, data);
- else if (info == "company")
- setProperty(KoInlineObject::SenderCompany, data);
-}
-
-QList<KoInlineObject*> KoInlineTextObjectManager::inlineTextObjects() const
-{
- return m_objects.values();
-}
diff --git a/plugins/flake/textshape/kotext/KoInlineTextObjectManager.h b/plugins/flake/textshape/kotext/KoInlineTextObjectManager.h
deleted file mode 100644
index 64f1c83bb9..0000000000
--- a/plugins/flake/textshape/kotext/KoInlineTextObjectManager.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- *
- * 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 KOINLINETEXTOBJECTMANAGER_H
-#define KOINLINETEXTOBJECTMANAGER_H
-
-#include "KoInlineObject.h"
-#include "KoVariableManager.h"
-#include "kritatext_export.h"
-
-// Qt + kde
-#include <QHash>
-#include <QTextBlock>
-
-class KoCanvasBase;
-class KoTextLocator;
-class KoInlineNote;
-class KoInlineCite;
-
-class QTextCharFormat;
-class QAction;
-
-/**
- * A container to register all the inlineTextObjects with.
- * Inserting an inline-object in a QTextDocument should be done via this manager which will
- * insert a placeholder in the text and you should add the KoInlineTextObjectManager to the
- * KoTextDocument.
- */
-class KRITATEXT_EXPORT KoInlineTextObjectManager : public QObject
-{
- Q_OBJECT
-public:
- enum Properties {
- InlineInstanceId = 577297549 // If you change this, don't forget to change KoCharacterStyle.h
- };
-
- /// Constructor
- explicit KoInlineTextObjectManager(QObject *parent = 0);
- ~KoInlineTextObjectManager() override;
-
- /**
- * Retrieve a formerly added inline object based on the format.
- * @param format the textCharFormat
- */
- KoInlineObject *inlineTextObject(const QTextCharFormat &format) const;
-
- /**
- * Retrieve a formerly added inline object based on the cursor position.
- * @param cursor the cursor which position is used. The anchor is ignored.
- */
- KoInlineObject *inlineTextObject(const QTextCursor &cursor) const;
-
- /**
- * Retrieve a formerly added inline object based on the KoInlineObject::id() of the object.
- * @param id the id assigned to the inline text object when it was added.
- */
- KoInlineObject *inlineTextObject(int id) const;
-
- QList<KoInlineObject*> inlineTextObjects() const;
-
- /**
- * Insert a new inline object into the manager as well as the document.
- * This method will cause a placeholder to be inserted into the text at cursor position,
- * possibly replacing a selection. The object will then be used as an inline
- * character and painted at the specified location in the text.
- * @param cursor the cursor which indicated the document and the position in that document
- * where the inline object will be inserted.
- * @param object the inline object to insert.
- */
- void insertInlineObject(QTextCursor &cursor, KoInlineObject *object);
-
- /**
- * Add inline object into the manager.
- *
- * This methods add the inline object into the manager. This is useful if you have a command
- * that removes and adds a inline object to the manager. If the object already was inserted before
- * (the object id is already set) it keeps the old id, otherwise a new id will be generated.
- *
- * @param object the inline object to insert.
- */
- void addInlineObject(KoInlineObject* object);
-
- /**
- * Remove an inline object from this manager. The object will also be removed from
- * the bookmarkmanager if it is a bookmark. This is not done smart: you might end up
- * with dangling start or end bookmarks.
- * Should really only be called by KoTextEditor's delete commands
- * @param object the object to be removed
- */
- void removeInlineObject(KoInlineObject *object);
-
- /**
- * Set a property that may have changed which will be forwarded to all registered textObjects.
- * If the key has changed then all registered InlineObject instances that have stated to want
- * updates will get called with the change.
- * The property will be stored to allow it to be retrieved via the intProperty() and friends.
- * @see KoInlineObject::propertyChangeListener()
- */
- void setProperty(KoInlineObject::Property key, const QVariant &value);
-
- /// retrieve a property
- QVariant property(KoInlineObject::Property key) const;
-
- /// retrieve an int property
- int intProperty(KoInlineObject::Property key) const;
-
- /// retrieve a bool property
- bool boolProperty(KoInlineObject::Property key) const;
-
- /// retrieve a string property
- QString stringProperty(KoInlineObject::Property key) const;
-
- /// remove a property from the store.
- void removeProperty(KoInlineObject::Property key);
-
- /**
- * Return the variableManager.
- */
- const KoVariableManager *variableManager() const;
- /**
- * Return the variableManager.
- */
- KoVariableManager *variableManager();
-
- /**
- * Create a list of actions that can be used to plug into a menu, for example.
- * This method internally uses KoInlineObjectRegistry::createInsertVariableActions() but extends
- * the list with all registered variable-names.
- * Each of these actions, when executed, will insert the relevant variable in the current text-position.
- * The actions assume that the text tool is selected, if that's not the case then they will silently fail.
- * @param host the canvas for which these actions are created. Note that the actions will get these
- * actions as a parent (for memory management purposes) as well.
- * @see KoVariableManager
- */
- QList<QAction*> createInsertVariableActions(KoCanvasBase *host) const;
-
- QList<KoTextLocator*> textLocators() const;
-
- /**
- * It returns a list of all end notes in the document
- */
- QList<KoInlineNote*> endNotes() const;
-
- QMap<QString, KoInlineCite*> citations(bool duplicatesEnabled = true) const;
-
- QList<KoInlineCite*> citationsSortedByPosition(bool duplicatesEnabled = true,
- QTextBlock block = QTextBlock()) const;
-
-public Q_SLOTS:
- void documentInformationUpdated(const QString &info, const QString &data);
-
-Q_SIGNALS:
- /**
- * Emitted whenever a property is set and it turns out to be changed.
- */
- void propertyChanged(int, const QVariant &variant);
-
-private:
- void insertObject(KoInlineObject *object);
-
- QHash<int, KoInlineObject*> m_objects;
- QHash<int, KoInlineObject*> m_deletedObjects;
- QList<KoInlineObject*> m_listeners; // holds objects also in m_objects, but which want propertyChanges
- int m_lastObjectId;
- QHash<int, QVariant> m_properties;
-
- KoVariableManager m_variableManager;
-};
-
-Q_DECLARE_METATYPE(KoInlineTextObjectManager*)
-#endif
diff --git a/plugins/flake/textshape/kotext/KoList.cpp b/plugins/flake/textshape/kotext/KoList.cpp
deleted file mode 100644
index 43c13cd3e3..0000000000
--- a/plugins/flake/textshape/kotext/KoList.cpp
+++ /dev/null
@@ -1,249 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2010 Thomas Zander <zander@kde.org>
- *
- * 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 "KoList.h"
-#include "KoList_p.h"
-
-#include "KoTextDocument.h"
-#include "styles/KoListLevelProperties.h"
-#include "styles/KoParagraphStyle.h"
-#include "styles/KoStyleManager.h"
-
-#include "TextDebug.h"
-
-#include <QTextCursor>
-
-KoList::KoList(const QTextDocument *document, KoListStyle *style, KoList::Type type)
- : QObject(const_cast<QTextDocument *>(document)), d(new KoListPrivate(this, document))
-{
- Q_ASSERT(document);
- d->type = type;
- setStyle(style);
- KoTextDocument(document).addList(this);
-}
-
-KoList::~KoList()
-{
- KoTextDocument(d->document).removeList(this);
- delete d;
-}
-
-QVector<QWeakPointer<QTextList> > KoList::textLists() const
-{
- return d->textLists;
-}
-
-QVector<KoListStyle::ListIdType> KoList::textListIds() const
-{
- return d->textListIds;
-}
-
-KoList *KoList::applyStyle(const QTextBlock &block, KoListStyle *style, int level)
-{
- Q_ASSERT(style);
- KoTextDocument document(block.document());
- KoList *list = document.list(block);
- if (list && *list->style() == *style) {
- list->add(block, level);
- return list;
- }
-
- //the block was already another list but with a different style - remove block from list
- if (list)
- list->remove(block);
-
- // Ok, so we are now ready to add the block to another list, but which other list?
- // For headers we always want to continue from any previous header
- // For normal lists we either want to continue an adjacent list or create a new one
- if (block.blockFormat().hasProperty(KoParagraphStyle::OutlineLevel)) {
- for (QTextBlock b = block.previous();b.isValid(); b = b.previous()) {
- list = document.list(b);
- if (list && *list->style() == *style) {
- break;
- }
- }
- if (!list || *list->style() != *style) {
- list = new KoList(block.document(), style);
- }
- } else {
- list = document.list(block.previous());
- if (!list || *list->style() != *style) {
- list = document.list(block.next());
- if (!list || *list->style() != *style) {
- list = new KoList(block.document(), style);
- }
- }
- }
- list->add(block, level);
- return list;
-}
-
-void KoList::add(const QTextBlock &block, int level)
-{
- if (!block.isValid())
- return;
-
- Q_ASSERT(level >= 0 && level <= 10);
- if (level == 0) { // fetch the first proper level we have
- level = 1; // if nothing works...
- for (int i = 1; i <= 10; i++) {
- if (d->style->hasLevelProperties(i)) {
- level = i;
- break;
- }
- }
- }
- remove(block);
-
- QTextList *textList = d->textLists.value(level-1).data();
- if (!textList) {
- QTextCursor cursor(block);
- QTextListFormat format = d->style->listFormat(level);
- textList = cursor.createList(format);
- format.setProperty(KoListStyle::ListId, (KoListStyle::ListIdType)(textList));
- textList->setFormat(format);
- d->textLists[level-1] = textList;
- d->textListIds[level-1] = (KoListStyle::ListIdType)textList;
- } else {
- textList->add(block);
- }
-
- QTextCursor cursor(block);
- QTextBlockFormat blockFormat = cursor.blockFormat();
- if (d->style->styleId()) {
- blockFormat.setProperty(KoParagraphStyle::ListStyleId, d->style->styleId());
- } else {
- blockFormat.clearProperty(KoParagraphStyle::ListStyleId);
- }
- if (d->type == KoList::TextList) {
- blockFormat.clearProperty(KoParagraphStyle::ListLevel);
- } else {
- blockFormat.setProperty(KoParagraphStyle::ListLevel, level);
- }
- cursor.setBlockFormat(blockFormat);
-
- d->invalidate(block);
-}
-
-void KoList::remove(const QTextBlock &block)
-{
- //QTextLists are created with a blockIndent of 1. When a block is removed from a QTextList, it's blockIndent is set to (block.indent + list.indent).
- //Since we do not use Qt's indentation for lists, we need to clear the block's blockIndent, otherwise the block's style will appear as modified.
- bool clearIndent = !block.blockFormat().hasProperty(4160);
-
- if (QTextList *textList = block.textList()) {
- // invalidate the list before we remove the item
- // (since the list might disappear if the block is the only item)
- KoListPrivate::invalidateList(block);
- textList->remove(block);
- }
- KoListPrivate::invalidate(block);
-
- if (clearIndent) {
- QTextBlockFormat format = block.blockFormat();
- format.clearProperty(4160);
- QTextCursor cursor(block);
- cursor.setBlockFormat(format);
- }
-}
-
-void KoList::setStyle(KoListStyle *style)
-{
- if (style == 0) {
- KoStyleManager *styleManager = KoTextDocument(d->document).styleManager();
- Q_ASSERT(styleManager);
- style = styleManager->defaultListStyle();
- }
-
- if (style != d->style) {
- if (d->style)
- disconnect(d->style, 0, this, 0);
- d->style = style->clone(this);
- connect(d->style, SIGNAL(styleChanged(int)), this, SLOT(styleChanged(int)));
- }
-
- for (int i = 0; i < d->textLists.count(); i++) {
- QTextList *textList = d->textLists.value(i).data();
- if (!textList)
- continue;
- KoListLevelProperties properties = d->style->levelProperties(i+1);
- if (properties.listId())
- d->textListIds[i] = properties.listId();
- QTextListFormat format;
- properties.applyStyle(format);
- textList->setFormat(format);
- d->invalidate(textList->item(0));
- }
-
- //if this list is a heading list then update the style manager with the list proprerties
- if (KoTextDocument(d->document).headingList() == this) {
- if (KoStyleManager *styleManager = KoTextDocument(d->document).styleManager()) {
- if (styleManager->outlineStyle()) {
- styleManager->outlineStyle()->copyProperties(style);
- }
- }
- }
-}
-
-KoListStyle *KoList::style() const
-{
- return d->style;
-}
-
-void KoList::updateStoredList(const QTextBlock &block)
-{
- if (block.textList()) {
- int level = block.textList()->format().property(KoListStyle::Level).toInt();
- QTextList *textList = block.textList();
- textList->format().setProperty(KoListStyle::ListId, (KoListStyle::ListIdType)(textList));
- d->textLists[level-1] = textList;
- d->textListIds[level-1] = (KoListStyle::ListIdType)textList;
- }
-}
-
-bool KoList::contains(QTextList *list) const
-{
- return list && d->textLists.contains(list);
-}
-
-int KoList::level(const QTextBlock &block)
-{
- if (!block.textList())
- return 0;
- int l = block.blockFormat().intProperty(KoParagraphStyle::ListLevel);
- if (!l) { // not a numbered-paragraph
- QTextListFormat format = block.textList()->format();
- l = format.intProperty(KoListStyle::Level);
- }
- return l;
-}
-
-KoList *KoList::listContinuedFrom() const
-{
- return d->listToBeContinuedFrom;
-}
-
-void KoList::setListContinuedFrom(KoList *list)
-{
- d->listToBeContinuedFrom = list;
-}
-
-//have to include this because of Q_PRIVATE_SLOT
-#include "moc_KoList.cpp"
diff --git a/plugins/flake/textshape/kotext/KoList.h b/plugins/flake/textshape/kotext/KoList.h
deleted file mode 100644
index 3f05d8658a..0000000000
--- a/plugins/flake/textshape/kotext/KoList.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- *
- * 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 KOLIST_H
-#define KOLIST_H
-
-#include "styles/KoListStyle.h"
-
-#include <QMetaType>
-#include <QWeakPointer>
-#include <QVector>
-#include <QTextList>
-
-class KoListPrivate;
-
-/**
- * This class represents an ODF list. An ODF list may have upto 10 levels
- * Each of the levels is represented as a QTextList (QTextList does not support
- * embedded lists). There is always an associated KoListStyle that holds the
- * styling information for various level of the ODF list.
- */
-class KRITATEXT_EXPORT KoList : public QObject
-{
- Q_OBJECT
-public:
- enum Type {
- TextList,
- NumberedParagraph
- };
-
- /// Constructor
- KoList(const QTextDocument *document, KoListStyle *style, Type type = TextList);
-
- /// Destructor
- ~KoList() override;
-
- /// Adds \a block to \a level of this list
- void add(const QTextBlock &block, int level);
-
- /// Removes \a block from any KoList the block is a part of
- static void remove(const QTextBlock &block);
-
- /**
- * Adds \a block to a list that follows \a style at \a level. If the block is
- * already a part of a list, it is removed from that list. If the block before
- * or after this block is part of a list that follows \a style, this block is
- * added to that list. If required a new KoList is created.
- * Returns the KoList that this block was added to.
- */
- static KoList *applyStyle(const QTextBlock &block, KoListStyle *style, int level);
-
- /// Sets the style of this list
- void setStyle(KoListStyle *style);
-
- /// Returns the style of this list
- KoListStyle *style() const;
-
- /// Return true if this list contains \a textlist
- bool contains(QTextList *textList) const;
-
- /// Returns the QTextLists that form this list
- QVector<QWeakPointer<QTextList> > textLists() const;
-
- QVector<KoListStyle::ListIdType> textListIds() const;
-
- static int level(const QTextBlock &block);
-
- /// Update the stored QTextList pointer for the given block
- void updateStoredList(const QTextBlock &block);
-
- KoList *listContinuedFrom() const;
- void setListContinuedFrom(KoList *list);
-
-private:
- KoListPrivate * const d;
-
- Q_PRIVATE_SLOT(d, void styleChanged(int))
-};
-
-Q_DECLARE_METATYPE(KoList*)
-Q_DECLARE_METATYPE(QList<KoList*>)
-
-#endif // KOLIST_H
diff --git a/plugins/flake/textshape/kotext/KoList_p.h b/plugins/flake/textshape/kotext/KoList_p.h
deleted file mode 100644
index 2a15cc754e..0000000000
--- a/plugins/flake/textshape/kotext/KoList_p.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2008 Pierre Stirnweiss <pierre.stirnweiss_calligra@gadz.org>
- *
- * 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 KOLIST_P_H
-#define KOLIST_P_H
-
-
-#include "KoList.h"
-#include "styles/KoListStyle.h"
-#include "KoTextBlockData.h"
-
-#include <QTextDocument>
-#include <QTextBlock>
-#include <QVector>
-#include <QVariant>
-#include <QTextList>
-
-class KoListPrivate
-{
-public:
- KoListPrivate(KoList *q, const QTextDocument *document)
- : q(q), type(KoList::TextList), style(0), textLists(10), textListIds(10), document(document), listToBeContinuedFrom(0)
- {
- }
-
- ~KoListPrivate()
- {
- }
-
- static void invalidate(const QTextBlock &block)
- {
- QTextBlock currentBlock = block;
- KoTextBlockData data(currentBlock);
- data.setCounterWidth(-1.0);
- }
-
- static void invalidateList(const QTextBlock &block)
- {
- for (int i = 0; i < block.textList()->count(); i++) {
- if (block.textList()->item(i) != block) {
- invalidate(block.textList()->item(i));
- break;
- }
- }
- }
-
- void styleChanged(int level)
- {
- Q_UNUSED(level);
- q->setStyle(style);
- }
-
- KoList *q;
- KoList::Type type;
- KoListStyle *style;
- QVector<QWeakPointer<QTextList> > textLists;
- QVector<KoListStyle::ListIdType> textListIds;
- const QTextDocument *document;
- QMap<int, QVariant> properties;
- KoList *listToBeContinuedFrom;
-};
-
-#endif // KOLIST_P_H
diff --git a/plugins/flake/textshape/kotext/KoNamedVariable.cpp b/plugins/flake/textshape/kotext/KoNamedVariable.cpp
deleted file mode 100644
index e94446e827..0000000000
--- a/plugins/flake/textshape/kotext/KoNamedVariable.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 "KoNamedVariable.h"
-
-#include "KoInlineTextObjectManager.h"
-
-// Include Q_UNUSED classes, for building on Windows
-#include <KoShapeLoadingContext.h>
-#include <KoShapeSavingContext.h>
-#include <KoXmlReader.h>
-
-KoNamedVariable::KoNamedVariable(Property key, const QString &name)
- : KoVariable(true),
- m_name(name),
- m_key(key)
-{
-}
-
-void KoNamedVariable::propertyChanged(Property property, const QVariant &value)
-{
- if (property == m_key)
- setValue(qvariant_cast<QString>(value));
-}
-
-void KoNamedVariable::setup()
-{
- setValue(manager()->stringProperty(m_key));
-}
-
-bool KoNamedVariable::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- Q_UNUSED(element);
- Q_UNUSED(context);
- // TODO
- return false;
-}
-
-void KoNamedVariable::saveOdf(KoShapeSavingContext &context)
-{
- Q_UNUSED(context);
- // TODO
-}
diff --git a/plugins/flake/textshape/kotext/KoNamedVariable.h b/plugins/flake/textshape/kotext/KoNamedVariable.h
deleted file mode 100644
index 01994d25d8..0000000000
--- a/plugins/flake/textshape/kotext/KoNamedVariable.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 KONAMEDVARIABLE_H
-#define KONAMEDVARIABLE_H
-
-#include "KoVariable.h"
-#include "kritatext_export.h"
-
-/**
- * This inlineObject shows the current value of a variable as registered in the KoVariableManager.
- * The proper way to create a new class is to use KoVariableManager::createVariable()
- */
-class KoNamedVariable : public KoVariable
-{
-public:
- /// return the name of this named variable
- QString name() const {
- return m_name;
- }
-
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
- void saveOdf(KoShapeSavingContext &context) override;
-
-protected:
- friend class KoVariableManager;
- /**
- * Constructor
- * @param key the property that represents the named variable. As defined internally in the KoVariableManager
- * @param name the name of the variable.
- */
- KoNamedVariable(Property key, const QString &name);
-
-private:
- /// reimplemented method
- void propertyChanged(Property property, const QVariant &value) override;
- /// reimplemented method
- void setup() override;
-
- const QString m_name;
- const Property m_key;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoPageProvider.cpp b/plugins/flake/textshape/kotext/KoPageProvider.cpp
deleted file mode 100644
index e695613181..0000000000
--- a/plugins/flake/textshape/kotext/KoPageProvider.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/* This file is part of the KDE project
-
- Copyright (C) 2009 Thorsten Zachmann <zachmann@kde.org>
-
- 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 "KoPageProvider.h"
-
-KoPageProvider::KoPageProvider()
-{
-}
-
-KoPageProvider::~KoPageProvider()
-{
-}
diff --git a/plugins/flake/textshape/kotext/KoPageProvider.h b/plugins/flake/textshape/kotext/KoPageProvider.h
deleted file mode 100644
index bad158fdc7..0000000000
--- a/plugins/flake/textshape/kotext/KoPageProvider.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* This file is part of the KDE project
-
- Copyright (C) 2009 Thorsten Zachmann <zachmann@kde.org>
-
- 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 KOPAGEPROVIDER_H
-#define KOPAGEPROVIDER_H
-
-#include "kritatext_export.h"
-
-class KoShape;
-class KoTextPage;
-
-/// \internal this is a hack for kpresenter
-class KRITATEXT_EXPORT KoPageProvider
-{
-public:
- KoPageProvider();
- virtual ~KoPageProvider();
-
- /**
- * Get the page number for the given shape
- */
- virtual KoTextPage *page(const KoShape *shape) const = 0;
-};
-#endif // KOPAGEPROVIDER_H
diff --git a/plugins/flake/textshape/kotext/KoSection.cpp b/plugins/flake/textshape/kotext/KoSection.cpp
deleted file mode 100644
index 933af986f3..0000000000
--- a/plugins/flake/textshape/kotext/KoSection.cpp
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (c) 2011 Boudewijn Rempt <boud@valdyas.org>
- * Copyright (c) 2014-2015 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 "KoSection.h"
-
-#include <KoXmlNS.h>
-#include <KoXmlReader.h>
-#include <KoTextSharedLoadingData.h>
-#include <KoShapeSavingContext.h>
-#include <KoXmlWriter.h>
-#include <KoSectionStyle.h>
-#include <KoSectionModel.h>
-#include <KoSectionEnd.h>
-#include <KoTextDocument.h>
-#include <KoTextInlineRdf.h>
-
-#include <QTextBlock>
-
-#include "TextDebug.h"
-
-class KoSectionPrivate
-{
-public:
- explicit KoSectionPrivate(const QTextCursor &cursor, const QString &_name, KoSection *_parent)
- : document(cursor.block().document())
- , name(_name)
- , sectionStyle(0)
- , boundingCursorStart(cursor)
- , boundingCursorEnd(cursor)
- , parent(_parent)
- , inlineRdf(0)
- {
- }
-
- const QTextDocument *document;
-
- QString condition;
- QString display;
- QString name;
- QString text_protected;
- QString protection_key;
- QString protection_key_digest_algorithm;
- QString style_name;
- KoSectionStyle *sectionStyle;
-
- QScopedPointer<KoSectionEnd> sectionEnd; ///< pointer to the corresponding section end
- int level; ///< level of the section in document, root sections have 0 level
- QTextCursor boundingCursorStart; ///< This cursor points to the start of the section
- QTextCursor boundingCursorEnd; ///< This cursor points to the end of the section (excluding paragraph symbol)
-
- // Boundings explanation:
- //
- // |S|e|c|t|i|o|n|...|t|e|x|t|P|
- // ^ ^
- // |--- Start |-- End
-
- QVector<KoSection *> children; ///< List of the section's childrens
- KoSection *parent; ///< Parent of the section
-
- KoTextInlineRdf *inlineRdf; ///< Handling associated RDF
-};
-
-KoSection::KoSection(const QTextCursor &cursor, const QString &name, KoSection *parent)
- : d_ptr(new KoSectionPrivate(cursor, name, parent))
-{
- Q_D(KoSection);
-
- d->boundingCursorStart.setKeepPositionOnInsert(true); // Start cursor should stay on place
- d->boundingCursorEnd.setKeepPositionOnInsert(false); // and end one should move forward
-
- if (parent) {
- d->level = parent->level() + 1;
- } else {
- d->level = 0;
- }
-}
-
-KoSection::~KoSection()
-{
- // Here scoped pointer will delete sectionEnd
-}
-
-QString KoSection::name() const
-{
- Q_D(const KoSection);
- return d->name;
-}
-
-QPair<int, int> KoSection::bounds() const
-{
- Q_D(const KoSection);
- return QPair<int, int>(
- d->boundingCursorStart.position(),
- d->boundingCursorEnd.position()
- );
-}
-
-int KoSection::level() const
-{
- Q_D(const KoSection);
- return d->level;
-}
-
-bool KoSection::loadOdf(const KoXmlElement &element, KoTextSharedLoadingData *sharedData, bool stylesDotXml)
-{
- Q_D(KoSection);
- // check whether we really are a section
- if (element.namespaceURI() == KoXmlNS::text && element.localName() == "section") {
- // get all the attributes
- d->condition = element.attributeNS(KoXmlNS::text, "condition");
- d->display = element.attributeNS(KoXmlNS::text, "display");
-
- if (d->display == "condition" && d->condition.isEmpty()) {
- warnText << "Section display is set to \"condition\", but condition is empty.";
- }
-
- QString newName = element.attributeNS(KoXmlNS::text, "name");
- if (!KoTextDocument(d->document).sectionModel()->setName(this, newName)) {
- warnText << "Section name \"" << newName
- << "\" must be unique or is invalid. Resetting it to " << name();
- }
-
- d->text_protected = element.attributeNS(KoXmlNS::text, "text-protected");
- d->protection_key = element.attributeNS(KoXmlNS::text, "protection-key");
- d->protection_key_digest_algorithm = element.attributeNS(KoXmlNS::text, "protection-key-algorithm");
- d->style_name = element.attributeNS(KoXmlNS::text, "style-name", "");
-
- if (!d->style_name.isEmpty()) {
- d->sectionStyle = sharedData->sectionStyle(d->style_name, stylesDotXml);
- }
-
- // lets handle associated xml:id
- if (element.hasAttribute("id")) {
- KoTextInlineRdf* inlineRdf = new KoTextInlineRdf(const_cast<QTextDocument *>(d->document), this);
- if (inlineRdf->loadOdf(element)) {
- d->inlineRdf = inlineRdf;
- } else {
- delete inlineRdf;
- inlineRdf = 0;
- }
- }
-
- return true;
- }
- return false;
-}
-
-void KoSection::saveOdf(KoShapeSavingContext &context) const
-{
- Q_D(const KoSection);
- KoXmlWriter *writer = &context.xmlWriter();
- Q_ASSERT(writer);
- writer->startElement("text:section", false);
-
- if (!d->condition.isEmpty()) writer->addAttribute("text:condition", d->condition);
- if (!d->display.isEmpty()) writer->addAttribute("text:display", d->condition);
- if (!d->name.isEmpty()) writer->addAttribute("text:name", d->name);
- if (!d->text_protected.isEmpty()) writer->addAttribute("text:text-protected", d->text_protected);
- if (!d->protection_key.isEmpty()) writer->addAttribute("text:protection-key", d->protection_key);
- if (!d->protection_key_digest_algorithm.isEmpty()) {
- writer->addAttribute("text:protection-key-digest-algorithm", d->protection_key_digest_algorithm);
- }
- if (!d->style_name.isEmpty()) writer->addAttribute("text:style-name", d->style_name);
-
- if (d->inlineRdf) {
- d->inlineRdf->saveOdf(context, writer);
- }
-}
-
-void KoSection::setSectionEnd(KoSectionEnd* sectionEnd)
-{
- Q_D(KoSection);
- d->sectionEnd.reset(sectionEnd);
-}
-
-void KoSection::setName(const QString &name)
-{
- Q_D(KoSection);
- d->name = name;
-}
-
-void KoSection::setLevel(int level)
-{
- Q_D(KoSection);
- d->level = level;
-}
-
-void KoSection::setKeepEndBound(bool state)
-{
- Q_D(KoSection);
- d->boundingCursorEnd.setKeepPositionOnInsert(state);
-}
-
-KoSection *KoSection::parent() const
-{
- Q_D(const KoSection);
- return d->parent;
-}
-
-QVector<KoSection *> KoSection::children() const
-{
- Q_D(const KoSection);
- return d->children;
-}
-
-void KoSection::insertChild(int childIdx, KoSection *section)
-{
- Q_D(KoSection);
- d->children.insert(childIdx, section);
-}
-
-void KoSection::removeChild(int childIdx)
-{
- Q_D(KoSection);
- d->children.remove(childIdx);
-}
-
-KoTextInlineRdf *KoSection::inlineRdf() const
-{
- Q_D(const KoSection);
- return d->inlineRdf;
-}
-
-void KoSection::setInlineRdf(KoTextInlineRdf *inlineRdf)
-{
- Q_D(KoSection);
- d->inlineRdf = inlineRdf;
-}
diff --git a/plugins/flake/textshape/kotext/KoSection.h b/plugins/flake/textshape/kotext/KoSection.h
deleted file mode 100644
index 12dd9c2ded..0000000000
--- a/plugins/flake/textshape/kotext/KoSection.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (c) 2011 Boudewijn Rempt <boud@valdyas.org>
- * Copyright (c) 2014-2015 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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.
- */
-#ifndef KOSECTION_H
-#define KOSECTION_H
-
-#include "kritatext_export.h"
-
-#include <QMetaType>
-#include <QList>
-#include <QString>
-#include <QPair>
-#include <QScopedPointer>
-#include <QTextCursor>
-
-#include <KoXmlReaderForward.h>
-class KoShapeSavingContext;
-class KoTextSharedLoadingData;
-class KoSectionEnd;
-class KoElementReference;
-class KoTextInlineRdf;
-
-class KoSectionPrivate;
-/**
- * Contains the information about the current text:section.
- *
- * The <text:section> element has the following attributes:
- *
- * <ul>
- * <li>text:condition
- * <li>text:display
- * <li>text:name
- * <li>text:protected
- * <li>text:protection-key
- * <li>text:protection-key-digest-algorithm
- * <li>text:style-name
- * <li>xml:id
- * </ul>
- * (odf spec v.12)
- */
-class KRITATEXT_EXPORT KoSection
-{
-public:
- ~KoSection();
-
- /// Returns section name
- QString name() const;
- /// Returns starting and ending position of section in QTextDocument
- QPair<int, int> bounds() const;
- /// Returns section level. Root section has @c 0 level.
- int level() const;
-
- /** Returns inlineRdf associated with section
- * @return pointer to the KoTextInlineRdf for this section
- */
- KoTextInlineRdf *inlineRdf() const;
-
- /** Sets KoTextInlineRdf for this section
- * @param inlineRdf pointer to KoTextInlineRdf to set
- */
- void setInlineRdf(KoTextInlineRdf *inlineRdf);
-
- bool loadOdf(const KoXmlElement &element, KoTextSharedLoadingData *sharedData, bool stylesDotXml);
- void saveOdf(KoShapeSavingContext &context) const;
-
-protected:
- const QScopedPointer<KoSectionPrivate> d_ptr;
-
-private:
- Q_DISABLE_COPY(KoSection)
- Q_DECLARE_PRIVATE(KoSection)
-
- explicit KoSection(const QTextCursor &cursor, const QString &name, KoSection *parent);
-
- /// Changes section's name to @param name
- void setName(const QString &name);
-
- /// Sets paired KoSectionsEnd for this section.
- void setSectionEnd(KoSectionEnd *sectionEnd);
-
- /**
- * Sets level of section in section tree.
- * Root sections have @c 0 level.
- */
- void setLevel(int level);
-
- /// Returns a pointer to the parent of the section in tree.
- KoSection *parent() const;
-
- /// Returns a vector of pointers to the children of the section.
- QVector<KoSection *> children() const;
-
- /**
- * Specifies if end bound of section should stay on place when inserting text.
- * Used by KoTextLoader on document loading.
- * @see QTextCursor::setKeepPositionOnInsert(bool)
- */
- void setKeepEndBound(bool state);
-
- /**
- * Inserts @param section to position @param childIdx of children
- */
- void insertChild(int childIdx, KoSection *section);
-
- /**
- * Removes child on position @param childIdx
- */
- void removeChild(int childIdx);
-
- friend class KoSectionModel;
- friend class KoTextLoader; // accesses setKeepEndBound() function
- friend class KoSectionEnd;
- friend class TestKoTextEditor; // accesses setKeepEndBound() function
-};
-
-Q_DECLARE_METATYPE(KoSection *)
-Q_DECLARE_METATYPE(QList<KoSection *>)
-
-#endif // KOSECTION_H
diff --git a/plugins/flake/textshape/kotext/KoSectionEnd.cpp b/plugins/flake/textshape/kotext/KoSectionEnd.cpp
deleted file mode 100644
index c620a071a4..0000000000
--- a/plugins/flake/textshape/kotext/KoSectionEnd.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2011 Boudewijn Rempt <boud@valdyas.org>
- * Copyright (c) 2014 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 "KoSectionEnd.h"
-
-#include <KoShapeSavingContext.h>
-#include <KoXmlWriter.h>
-#include <KoSection.h>
-
-class KoSectionEndPrivate
-{
-public:
- KoSectionEndPrivate(KoSection *_section)
- : section(_section)
- {
- Q_ASSERT(section);
- }
-
- KoSection *section; //< pointer to the corresponding section
-};
-
-KoSectionEnd::KoSectionEnd(KoSection* section)
- : d_ptr(new KoSectionEndPrivate(section))
-{
- Q_D(KoSectionEnd);
- d->section->setSectionEnd(this);
-}
-
-KoSectionEnd::~KoSectionEnd()
-{
-}
-
-QString KoSectionEnd::name() const
-{
- Q_D(const KoSectionEnd);
- return d->section->name();
-}
-
-KoSection *KoSectionEnd::correspondingSection() const
-{
- Q_D(const KoSectionEnd);
- return d->section;
-}
-
-void KoSectionEnd::saveOdf(KoShapeSavingContext &context) const
-{
- KoXmlWriter *writer = &context.xmlWriter();
- Q_ASSERT(writer);
- writer->endElement();
-}
diff --git a/plugins/flake/textshape/kotext/KoSectionEnd.h b/plugins/flake/textshape/kotext/KoSectionEnd.h
deleted file mode 100644
index a0fbc7e137..0000000000
--- a/plugins/flake/textshape/kotext/KoSectionEnd.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2011 Boudewijn Rempt <boud@valdyas.org>
- * Copyright (c) 2014-2015 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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.
- */
-#ifndef KOSECTIONEND_H
-#define KOSECTIONEND_H
-
-#include "kritatext_export.h"
-
-#include <QMetaType>
-#include <QList>
-#include <QString>
-#include <QScopedPointer>
-
-class KoShapeSavingContext;
-class KoSection;
-
-class KoSectionEndPrivate;
-/**
- * Marks the end of the section
- */
-class KRITATEXT_EXPORT KoSectionEnd {
-public:
- ~KoSectionEnd(); // this is needed for QScopedPointer
-
- void saveOdf(KoShapeSavingContext &context) const;
-
- QString name() const;
- KoSection *correspondingSection() const;
-
-protected:
- const QScopedPointer<KoSectionEndPrivate> d_ptr;
-
-private:
- Q_DISABLE_COPY(KoSectionEnd)
- Q_DECLARE_PRIVATE(KoSectionEnd)
-
- explicit KoSectionEnd(KoSection *section);
-
- friend class KoSectionModel;
- friend class TestKoTextEditor;
-};
-
-Q_DECLARE_METATYPE(KoSectionEnd *)
-Q_DECLARE_METATYPE(QList<KoSectionEnd *>)
-
-#endif // KOSECTIONEND_H
diff --git a/plugins/flake/textshape/kotext/KoSectionModel.cpp b/plugins/flake/textshape/kotext/KoSectionModel.cpp
deleted file mode 100644
index 8b1b8769be..0000000000
--- a/plugins/flake/textshape/kotext/KoSectionModel.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-#include "KoSectionModel.h"
-
-#include <climits>
-#include <KoTextDocument.h>
-#include <KLocalizedString>
-
-KoSectionModel::KoSectionModel(QTextDocument *doc)
- : QAbstractItemModel()
- , m_doc(doc)
-{
- KoTextDocument(m_doc).setSectionModel(this);
-}
-
-KoSectionModel::~KoSectionModel()
-{
- Q_FOREACH (KoSection *sec, m_registeredSections) {
- delete sec; // This will delete associated KoSectionEnd in KoSection destructor
- }
-}
-
-KoSection *KoSectionModel::createSection(const QTextCursor &cursor, KoSection *parent, const QString &name)
-{
- if (!isValidNewName(name)) {
- return 0;
- }
-
- KoSection *result = new KoSection(cursor, name, parent);
-
- // Lets find our number in parent's children by cursor position
- QVector<KoSection *> children = (parent ? parent->children() : m_rootSections);
- int childrenId = children.size();
- for (int i = 0; i < children.size(); i++) {
- if (cursor.position() < children[i]->bounds().first) {
- childrenId = i;
- break;
- }
- }
- // We need to place link from parent to children in childId place
- // Also need to find corresponding index and declare operations in terms of model
- insertToModel(result, childrenId);
-
- return result;
-}
-
-KoSection *KoSectionModel::createSection(const QTextCursor &cursor, KoSection *parent)
-{
- return createSection(cursor, parent, possibleNewName());
-}
-
-KoSectionEnd *KoSectionModel::createSectionEnd(KoSection *section)
-{
- return new KoSectionEnd(section);
-}
-
-KoSection *KoSectionModel::sectionAtPosition(int pos)
-{
- // TODO: Rewrite it by traversing Model as tree
- KoSection *result = 0;
- int level = -1; // Seeking the section with maximum level
- QHash<QString, KoSection *>::iterator it = m_sectionNames.begin();
- for (; it != m_sectionNames.end(); it++) {
- QPair<int, int> bounds = it.value()->bounds();
- if (bounds.first > pos || bounds.second < pos) {
- continue;
- }
-
- if (it.value()->level() > level) {
- result = it.value();
- level = it.value()->level();
- }
- }
-
- return result;
-}
-
-bool KoSectionModel::isValidNewName(const QString &name) const
-{
- return (m_sectionNames.constFind(name) == m_sectionNames.constEnd());
-}
-
-QString KoSectionModel::possibleNewName()
-{
- QString newName;
- int i = m_registeredSections.count();
- do {
- i++;
- newName = i18nc("new numbered section name", "New section %1", i);
- } while (!isValidNewName(newName));
-
- return newName;
-}
-
-bool KoSectionModel::setName(KoSection *section, const QString &name)
-{
- if (section->name() == name || isValidNewName(name)) {
- section->setName(name);
- //TODO: we don't have name in columns, but need something to notify views about change
- emit dataChanged(m_modelIndex[section], m_modelIndex[section]);
- return true;
- }
- return false;
-}
-
-void KoSectionModel::allowMovingEndBound()
-{
- QSet<KoSection *>::iterator it = m_registeredSections.begin();
- for (; it != m_registeredSections.end(); it++) {
- (*it)->setKeepEndBound(false);
- }
-}
-
-int KoSectionModel::findRowOfChild(KoSection *section) const
-{
- QVector<KoSection *> lookOn;
- if (!section->parent()) {
- lookOn = m_rootSections;
- } else {
- lookOn = section->parent()->children();
- }
-
- int result = lookOn.indexOf(section);
- Q_ASSERT(result != -1);
- return result;
-}
-
-QModelIndex KoSectionModel::index(int row, int column, const QModelIndex &parentIdx) const
-{
- if (!hasIndex(row, column, parentIdx)) {
- return QModelIndex();
- }
-
- if (!parentIdx.isValid()) {
- return createIndex(row, column, m_rootSections[row]);
- }
-
- KoSection *parent = static_cast<KoSection *>(parentIdx.internalPointer());
- return createIndex(row, column, parent->children()[row]);
-}
-
-QModelIndex KoSectionModel::parent(const QModelIndex &child) const
-{
- if (!child.isValid()) {
- return QModelIndex();
- }
-
- KoSection *section = static_cast<KoSection *>(child.internalPointer());
- KoSection *parent = section->parent();
- if (parent) {
- return createIndex(findRowOfChild(parent), 0, parent);
- }
- return QModelIndex();
-}
-
-int KoSectionModel::rowCount(const QModelIndex &parent) const
-{
- if (!parent.isValid()) {
- return m_rootSections.size();
- }
- return static_cast<KoSection *>(parent.internalPointer())->children().size();
-}
-
-int KoSectionModel::columnCount(const QModelIndex &/*parent*/) const
-{
- return 1;
-}
-
-QVariant KoSectionModel::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid()) {
- return QVariant();
- }
-
- if (index.column() == 0 && role == PointerRole) {
- QVariant v;
- v.setValue(static_cast<KoSection *>(index.internalPointer()));
- return v;
- }
- return QVariant();
-}
-
-void KoSectionModel::insertToModel(KoSection *section, int childIdx)
-{
- Q_ASSERT(isValidNewName(section->name()));
-
- KoSection *parent = section->parent();
- if (parent) { // Inserting to some section
- beginInsertRows(m_modelIndex[parent], childIdx, childIdx);
- parent->insertChild(childIdx, section);
- endInsertRows();
- m_modelIndex[section] = QPersistentModelIndex(index(childIdx, 0, m_modelIndex[parent]));
- } else { // It will be root section
- beginInsertRows(QModelIndex(), childIdx, childIdx);
- m_rootSections.insert(childIdx, section);
- endInsertRows();
- m_modelIndex[section] = QPersistentModelIndex(index(childIdx, 0, QModelIndex()));
- }
-
- m_registeredSections.insert(section);
- m_sectionNames[section->name()] = section;
-}
-
-void KoSectionModel::deleteFromModel(KoSection *section)
-{
- KoSection *parent = section->parent();
- int childIdx = findRowOfChild(section);
- if (parent) { // Deleting non root section
- beginRemoveRows(m_modelIndex[parent], childIdx, childIdx);
- parent->removeChild(childIdx);
- endRemoveRows();
- } else { // Deleting root section
- beginRemoveRows(QModelIndex(), childIdx, childIdx);
- m_rootSections.remove(childIdx);
- endRemoveRows();
- }
- m_modelIndex.remove(section);
- m_sectionNames.remove(section->name());
-}
diff --git a/plugins/flake/textshape/kotext/KoSectionModel.h b/plugins/flake/textshape/kotext/KoSectionModel.h
deleted file mode 100644
index 438622472b..0000000000
--- a/plugins/flake/textshape/kotext/KoSectionModel.h
+++ /dev/null
@@ -1,144 +0,0 @@
-#ifndef KOSECTIONMODEL_H
-#define KOSECTIONMODEL_H
-
-#include <QTextDocument>
-#include <QAbstractItemModel>
-#include <QVector>
-#include <QSet>
-
-#include <KoSection.h>
-#include <KoSectionEnd.h>
-
-/**
- * Used to handle all the sections in the document
- *
- * Now there actually two levels of section handling:
- * 1) Formatting Level: on this level we should be sure, that
- * pointers to KoSection and KoSectionEnd in the KoParagraphStyles
- * properties SectionEndings and SectionStartings are consistent.
- * Handling on this level is provided on the level of text editing
- * commands: DeleteCommand, NewSectionCommand
- * We can't move it to another place, because we should know the
- * semantics of operation to handle it right way.
- * 2) Model(Tree) Level: on this level we should update KoSectionModel
- * right way, so it in any moment represents the actual tree
- * of sections. Tree is built easily:
- * One section is son of another, if it is directly nested in it.
- * As text editing commands have access to change Formatting Level,
- * they are declared as friend classes of KoSectionModel to be able
- * affect Model structure without changing something on Formatting
- * Level. Also affected by RenameSectionCommand.
- *
- * Also we need to look at the consistency of some section properties:
- *
- * 1) Bounds. Those now are handled with QTextCursors that are placed
- * on start and end of the section. In default state start cursor
- * isn't moving if text inserted in its position, and end cursor
- * moves. But in the case of initial document loading, it is necessary
- * to make some end cursors stop moving, so we have:
- * KoTextLoader -> calling -> KoSection::setKeepEndBound()
- * KoTextLoader -> calling -> KoSectionModel::allowMovingEndBound()
- * ^-- this needed to restore default behaviour after load
- *
- * 2) Level. Level means the depth of the section in tree. Root
- * sections has 0 (zero) level. Now if you look at the possible
- * text editing command affecting sections you may notice that
- * level of section doesn't change in any case. Initial level
- * is set in KoSection constructor as parent's level plus one.
- * TODO: write about drag-n-drop here, when its implemented
- *
- * 3) Name. Each KoSection has a name that must be unique. We have
- * two groups of KoSections in each moment of time: the first group
- * consists of the sections that are present in document now,
- * the second group consists of the sections that were deleted, but
- * we still need them as they may be restored with "undo".
- * This groups are stored in m_registeredSections and m_sectionNames.
- *
- * Sections are created through this newSection() and newSectionEnd()
- * functions.
- *
- * This object is created for QTextDocument on the first query of it.
- */
-class KRITATEXT_EXPORT KoSectionModel : public QAbstractItemModel
-{
- Q_OBJECT
-public:
- static const int PointerRole = Qt::UserRole;
-
- explicit KoSectionModel(QTextDocument *doc);
- ~KoSectionModel() override;
-
- QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
- QModelIndex parent(const QModelIndex &child) const override;
-
- int rowCount(const QModelIndex &parent = QModelIndex()) const override;
- int columnCount(const QModelIndex &parent = QModelIndex()) const override;
-
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
-
- /// Creates KoSection in position of @p cursor with some allowed name
- KoSection *createSection(const QTextCursor &cursor, KoSection *parent);
-
- /// Creates KoSection in position of @p cursor with specified @p name
- KoSection *createSection(const QTextCursor &cursor, KoSection *parent, const QString &name);
-
- /// Creates KoSectionEnd in pair for a @p section
- KoSectionEnd *createSectionEnd(KoSection *section);
-
- /** Tries to set @p section name to @p name
- * @return @c false if there is a section with such name
- * and new name isn't accepted and @c true otherwise.
- */
- bool setName(KoSection *section, const QString &name);
-
- /**
- * Returns pointer to the deepest KoSection that covers @p pos
- * or 0 if there is no such section
- */
- KoSection *sectionAtPosition(int pos);
-
- /// Returns name for the new section.
- QString possibleNewName();
-
- /// Returns if this name is possible.
- bool isValidNewName(const QString &name) const;
-
- /// Setting all sections end bound cursor to move with text inserting.
- void allowMovingEndBound();
-
- /// Finds index of @p child inside his parent.
- int findRowOfChild(KoSection *child) const;
-
-private:
- Q_DISABLE_COPY(KoSectionModel)
-
- friend class DeleteCommand;
- friend class NewSectionCommand;
-
- /**
- * Inserts @p section to it's parent (should be
- * stored in @p section already) in position childIdx.
- * Affects only Model Level
- * @see KoSectionModel
- */
- void insertToModel(KoSection* section, int childIdx);
- /**
- * Deletes @p section from it's parent (should be
- * stored in @p section already).
- * Affects only Model Level
- * @see KoSectionModel
- */
- void deleteFromModel(KoSection *section);
-
- QTextDocument *m_doc;
- QSet<KoSection *> m_registeredSections; ///< stores pointer to sections that sometime was registered
- QHash<QString, KoSection *> m_sectionNames; ///< stores name -> pointer reference, for sections that are visible in document now
- QHash<KoSection *, QPersistentModelIndex> m_modelIndex;
-
- QVector<KoSection *> m_rootSections;
-
-};
-
-Q_DECLARE_METATYPE(KoSectionModel *)
-
-#endif //KOSECTIONMODEL_H
diff --git a/plugins/flake/textshape/kotext/KoSectionUtils.cpp b/plugins/flake/textshape/kotext/KoSectionUtils.cpp
deleted file mode 100644
index cfbc402ed3..0000000000
--- a/plugins/flake/textshape/kotext/KoSectionUtils.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2014 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 <KoSectionUtils.h>
-#include <KoParagraphStyle.h>
-
-bool KoSectionUtils::getNextBlock(QTextCursor &cur)
-{
- QTextCursor next = cur;
- bool ok = next.movePosition(QTextCursor::NextBlock);
-
- while (ok && next.currentFrame() != cur.currentFrame()) {
- ok = next.movePosition(QTextCursor::NextBlock);
- }
-
- if (!ok || next.currentFrame() != cur.currentFrame()) {
- // There is no previous block.
- return false;
- }
- cur = next;
- return true;
-}
-
-void KoSectionUtils::setSectionStartings(QTextBlockFormat &fmt, const QList<KoSection *> &list)
-{
- if (list.empty()) {
- fmt.clearProperty(KoParagraphStyle::SectionStartings);
- } else {
- fmt.setProperty(KoParagraphStyle::SectionStartings,
- QVariant::fromValue< QList<KoSection *> >(list));
- }
-}
-
-void KoSectionUtils::setSectionEndings(QTextBlockFormat &fmt, const QList<KoSectionEnd *> &list)
-{
- if (list.empty()) {
- fmt.clearProperty(KoParagraphStyle::SectionEndings);
- } else {
- fmt.setProperty(KoParagraphStyle::SectionEndings,
- QVariant::fromValue< QList<KoSectionEnd *> >(list));
- }
-}
-
-QList<KoSection *> KoSectionUtils::sectionStartings(const QTextBlockFormat &fmt)
-{
- if (!fmt.hasProperty(KoParagraphStyle::SectionStartings)) {
- return QList<KoSection *>();
- } else {
- return fmt.property(KoParagraphStyle::SectionStartings).value< QList<KoSection *> >();
- }
-}
-
-QList<KoSectionEnd *> KoSectionUtils::sectionEndings(const QTextBlockFormat &fmt)
-{
- if (!fmt.hasProperty(KoParagraphStyle::SectionEndings)) {
- return QList<KoSectionEnd *>();
- } else {
- return fmt.property(KoParagraphStyle::SectionEndings).value< QList<KoSectionEnd *> >();
- }
-}
diff --git a/plugins/flake/textshape/kotext/KoSectionUtils.h b/plugins/flake/textshape/kotext/KoSectionUtils.h
deleted file mode 100644
index 7b089b2ba7..0000000000
--- a/plugins/flake/textshape/kotext/KoSectionUtils.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2014 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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.
- */
-#ifndef KOSECTIONUTILS_H
-#define KOSECTIONUTILS_H
-
-#include <KoSection.h>
-#include <KoSectionEnd.h>
-
-#include <QTextCursor>
-#include <QVariant>
-#include <QString>
-
-namespace KoSectionUtils {
- /**
- * Moves the cursors to the next block within the same QTextFrame.
- * @param cur cursor to move, modified during call
- * @return @c false if there is no next block, @c true otherwise
- */
- bool getNextBlock(QTextCursor &cur);
-
- /**
- * Convenient function to set a list of startings to QTextBlockFormat.
- * This checks that list is empty.
- *
- * @param fmt QTextBlockFormat reference to set startings.
- * @param list QList<KoSection *> is a list to set.
- */
- KRITATEXT_EXPORT void setSectionStartings(QTextBlockFormat &fmt, const QList<KoSection *> &list);
-
- /**
- * Convenient function to set a list of endings to QTextBlockFormat.
- * This checks that list is empty.
- *
- * @param fmt QTextBlockFormat reference to set endings.
- * @param list QList<KoSectionEnd *> is a list to set.
- */
- KRITATEXT_EXPORT void setSectionEndings(QTextBlockFormat& fmt, const QList<KoSectionEnd *> &list);
-
- /**
- * Convenient function to get section startings from QTextBlockFormat.
- * @param fmt QTextBlockFormat format to retrieve section startings from.
- * @return QList<KoSection *> that contains pointers to sections that start
- * according to QTextBlockFormat.
- */
- KRITATEXT_EXPORT QList<KoSection *> sectionStartings(const QTextBlockFormat &fmt);
-
- /**
- * Convenient function to get section endings from QTextBlockFormat.
- * @param fmt QTextBlockFormat format to retrieve section startings from.
- * @return QList<KoSectionEnd *> that contains pointers to sections that end
- * according to QTextBlockFormat.
- */
- KRITATEXT_EXPORT QList<KoSectionEnd *> sectionEndings(const QTextBlockFormat& fmt);
-
-}
-
-#endif //KOSECTIONUTILS_H
diff --git a/plugins/flake/textshape/kotext/KoTableColumnAndRowStyleManager.cpp b/plugins/flake/textshape/kotext/KoTableColumnAndRowStyleManager.cpp
deleted file mode 100644
index 363a74f0d3..0000000000
--- a/plugins/flake/textshape/kotext/KoTableColumnAndRowStyleManager.cpp
+++ /dev/null
@@ -1,242 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- *
- * 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 "KoTableColumnAndRowStyleManager.h"
-
-#include "styles/KoTableColumnStyle.h"
-#include "styles/KoTableRowStyle.h"
-#include "styles/KoTableCellStyle.h"
-#include "styles/KoTableStyle.h"
-
-#include <QVector>
-#include <QVariant>
-#include <QTextTable>
-
-#include "TextDebug.h"
-
-class Q_DECL_HIDDEN KoTableColumnAndRowStyleManager::Private : public QSharedData
-{
-public:
- Private() : QSharedData() { }
- ~Private() {
- }
- QVector<KoTableColumnStyle> tableColumnStyles;
- QVector<KoTableRowStyle> tableRowStyles;
-
- QVector<KoTableCellStyle*> defaultRowCellStyles;
- QVector<KoTableCellStyle*> defaultColumnCellStyles;
-};
-
-KoTableColumnAndRowStyleManager::KoTableColumnAndRowStyleManager()
- : d(new Private())
-{
-}
-
-KoTableColumnAndRowStyleManager::KoTableColumnAndRowStyleManager(const KoTableColumnAndRowStyleManager &rhs)
- : d(rhs.d)
-{
-}
-
-KoTableColumnAndRowStyleManager &KoTableColumnAndRowStyleManager::operator=(const KoTableColumnAndRowStyleManager &rhs)
-{
- d = rhs.d;
-
- return *this;
-}
-
-KoTableColumnAndRowStyleManager::~KoTableColumnAndRowStyleManager()
-{
-}
-
-KoTableColumnAndRowStyleManager KoTableColumnAndRowStyleManager::getManager(QTextTable *table)
-{
- QTextTableFormat tableFormat = table->format();
-
- if (tableFormat.hasProperty(KoTableStyle::ColumnAndRowStyleManager)) {
- return tableFormat.property(KoTableStyle::ColumnAndRowStyleManager).value<KoTableColumnAndRowStyleManager>();
- } else {
- KoTableColumnAndRowStyleManager carsManager;
-
- QVariant var;
- var.setValue(carsManager);
- tableFormat.setProperty(KoTableStyle::ColumnAndRowStyleManager, var);
- table->setFormat(tableFormat);
- return carsManager;
- }
-}
-
-void KoTableColumnAndRowStyleManager::setColumnStyle(int column, const KoTableColumnStyle &columnStyle)
-{
- Q_ASSERT(column >= 0);
-
- if (column < 0) {
- return;
- }
-
- if (column < d->tableColumnStyles.size() && d->tableColumnStyles.value(column) == columnStyle) {
- return;
- }
-
- while (column >= d->tableColumnStyles.size())
- d->tableColumnStyles.append(KoTableColumnStyle());
-
- d->tableColumnStyles.replace(column, columnStyle);
-}
-
-void KoTableColumnAndRowStyleManager::insertColumns(int column, int numberColumns, const KoTableColumnStyle &columnStyle)
-{
- Q_ASSERT(column >= 0);
- Q_ASSERT(numberColumns >= 0);
-
- if (column < 0 || numberColumns < 0) {
- return;
- }
-
- while (column > d->tableColumnStyles.size())
- d->tableColumnStyles.append(KoTableColumnStyle());
-
- d->tableColumnStyles.insert(column, numberColumns, columnStyle);
-}
-
-void KoTableColumnAndRowStyleManager::removeColumns(int column, int numberColumns)
-{
- Q_ASSERT(column >= 0);
- Q_ASSERT(numberColumns >= 0);
-
- if (column >= d->tableColumnStyles.size() || column < 0 || numberColumns < 0) {
- return;
- }
-
- while (column > d->tableColumnStyles.size())
- d->tableColumnStyles.append(KoTableColumnStyle());
-
- d->tableColumnStyles.remove(column, numberColumns);
-}
-
-KoTableColumnStyle KoTableColumnAndRowStyleManager::columnStyle(int column) const
-{
- Q_ASSERT(column >= 0);
-
- if (column < 0) {
- return KoTableColumnStyle();
- }
-
- return d->tableColumnStyles.value(column);
-}
-
-void KoTableColumnAndRowStyleManager::setRowStyle(int row, const KoTableRowStyle &rowStyle)
-{
- Q_ASSERT(row >= 0);
-
- if (row < 0) {
- return;
- }
-
- if (row < d->tableRowStyles.size() && d->tableRowStyles.value(row) == rowStyle) {
- return;
- }
-
- while (row >= d->tableRowStyles.size())
- d->tableRowStyles.append(KoTableRowStyle());
-
- d->tableRowStyles.replace(row, rowStyle);
-}
-
-void KoTableColumnAndRowStyleManager::insertRows(int row, int numberRows, const KoTableRowStyle &rowStyle)
-{
- Q_ASSERT(row >= 0);
- Q_ASSERT(numberRows >= 0);
-
- if (row < 0 || numberRows < 0) {
- return;
- }
-
- while (row > d->tableRowStyles.size())
- d->tableRowStyles.append(KoTableRowStyle());
-
- d->tableRowStyles.insert(row, numberRows, rowStyle);
-}
-
-void KoTableColumnAndRowStyleManager::removeRows(int row, int numberRows)
-{
- Q_ASSERT(row >= 0);
- Q_ASSERT(numberRows >= 0);
-
- if (row >= d->tableRowStyles.size() || row < 0 || numberRows < 0) {
- return;
- }
-
- while (row > d->tableRowStyles.size())
- d->tableRowStyles.append(KoTableRowStyle());
-
- d->tableRowStyles.remove(row, numberRows);
-}
-
-KoTableRowStyle KoTableColumnAndRowStyleManager::rowStyle(int row) const
-{
- Q_ASSERT(row >= 0);
-
- if (row < 0) {
- return KoTableRowStyle();
- }
-
- return d->tableRowStyles.value(row);
-}
-
-KoTableCellStyle* KoTableColumnAndRowStyleManager::defaultColumnCellStyle(int column) const
-{
- Q_ASSERT(column >= 0);
-
- return d->defaultColumnCellStyles.value(column);
-}
-
-void KoTableColumnAndRowStyleManager::setDefaultColumnCellStyle(int column, KoTableCellStyle* cellStyle)
-{
- Q_ASSERT(column >= 0);
-
- if (column < d->defaultColumnCellStyles.size() && d->defaultColumnCellStyles.value(column) == cellStyle) {
- return;
- }
-
- while (column > d->defaultColumnCellStyles.size())
- d->defaultColumnCellStyles.append(0);
-
- d->defaultColumnCellStyles.append(cellStyle);
-}
-
-KoTableCellStyle* KoTableColumnAndRowStyleManager::defaultRowCellStyle(int row) const
-{
- Q_ASSERT(row >= 0);
-
- return d->defaultRowCellStyles.value(row);
-}
-
-void KoTableColumnAndRowStyleManager::setDefaultRowCellStyle(int row, KoTableCellStyle* cellStyle)
-{
- Q_ASSERT(row >= 0);
-
- if (row < d->defaultRowCellStyles.size() && d->defaultRowCellStyles.value(row) == cellStyle) {
- return;
- }
-
- while (row > d->defaultRowCellStyles.size())
- d->defaultRowCellStyles.append(0);
-
- d->defaultRowCellStyles.append(cellStyle);
-}
diff --git a/plugins/flake/textshape/kotext/KoTableColumnAndRowStyleManager.h b/plugins/flake/textshape/kotext/KoTableColumnAndRowStyleManager.h
deleted file mode 100644
index 9bf9f66c5b..0000000000
--- a/plugins/flake/textshape/kotext/KoTableColumnAndRowStyleManager.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2009 Elvis Stansvik <elvstone@gmail.com>
- *
- * 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 KOTABLECOLUMNANDROWSTYLEMANAGER_H
-#define KOTABLECOLUMNANDROWSTYLEMANAGER_H
-
-#include "kritatext_export.h"
-
-#include <QMetaType>
-#include <QExplicitlySharedDataPointer>
-
-class KoTableColumnStyle;
-class KoTableRowStyle;
-class KoTableCellStyle;
-class QTextTable;
-
-/**
- * Manages all column and row styles for a single table.
- *
- * It's not managing the lifetime of named styles, which is the job of the KoStyleManager,
- * so you should still register such styles in the styleManager too.
- *
- * The main purpose of this manager is simply to keep track of which styles are in
- * which column (and in which row).
- *
- * It's explicitly shared (for the same table)
- * TODO:
- * - Eliminate duplicates.
- */
-class KRITATEXT_EXPORT KoTableColumnAndRowStyleManager
-{
-public:
- /// constructor @see getManager for how to create a class the correct way
- explicit KoTableColumnAndRowStyleManager();
-
- virtual ~KoTableColumnAndRowStyleManager();
-
- /// Convenience function to get the KoTableColumnAndRowStyleManager for a table (or create one)
- static KoTableColumnAndRowStyleManager getManager(QTextTable *table);
-
- /// Constructor
- KoTableColumnAndRowStyleManager(const KoTableColumnAndRowStyleManager &rhs);
- /// assign operator
- KoTableColumnAndRowStyleManager &operator=(const KoTableColumnAndRowStyleManager &rhs);
-
- /**
- * Set the column style for the column \a column to \a columnStyle.
- *
- * @param column the column to set the style for.
- * @param columnStyle a column style.
- */
- void setColumnStyle(int column, const KoTableColumnStyle &columnStyle);
-
- /**
- * Insert a number of columns before the column \a column to \a columnStyle.
- *
- * @param column the columns are inserted before this column.
- * @param numberColumns how many columns to insert.
- * @param columnStyle the column style of the new columns.
- * @see QTextTable::insertColumns for the analog method for the table data.
- */
- void insertColumns(int column, int numberColumns, const KoTableColumnStyle &columnStyle);
-
- /**
- * Remove a number of columns \a column to \a columnStyle.
- *
- * @param column this and possibly following columns are removed.
- * @param numberColumns how many columns to remove.
- * @see QTextTable::removeColumns for the analog method for the table data.
- */
- void removeColumns(int column, int numberColumns);
-
- /**
- * Get the column style for the column \a column.
- *
- * If you modify it don't forget to set it back here to actually have an effect
- *
- * @param column the column to get the style for.
- * @return the column style.
- */
- KoTableColumnStyle columnStyle(int column) const;
-
- /**
- * Set the row style for the row \a row to \a rowStyle.
- *
- * @param row the row to set the style for.
- * @param rowStyle a row style.
- */
- void setRowStyle(int row, const KoTableRowStyle &rowStyle);
-
- /**
- * Insert a number of rows above the row \a row to \a rowStyle.
- *
- * @param row the rows are inserted above this row.
- * @param numberRows how many rows to insert.
- * @param rowStyle the row style of the new rows.
- * @see QTextTable::insertRows for the analog method for the table data.
- */
- void insertRows(int row, int numberRows, const KoTableRowStyle &rowStyle);
-
- /**
- * Remove a number of rows \a row to \a rowStyle.
- *
- * @param row this and possibly following rows are removed.
- * @param numberRows how many rows to remove.
- * @see QTextTable::removeRows for the analog method for the table data.
- */
- void removeRows(int row, int numberRows);
-
- /**
- * Get the row style for the row \a column.
- *
- * If you modify it don't forget to set it back here to actually have an effect
- *
- * @param row the row to get the style for.
- * @return the row style.
- */
- KoTableRowStyle rowStyle(int row) const;
-
- /**
- * Get the default cell style for the row \a row.
- *
- * @param row the row to get the style for.
- * @return the default cell style for \a row.
- */
- KoTableCellStyle* defaultRowCellStyle(int row) const;
-
- /**
- * Set the default cell style for the row \a row.
- *
- * @param row the row to set the style to.
- * @return the default cell style for \a row.
- */
- void setDefaultRowCellStyle(int row, KoTableCellStyle* cellStyle);
-
- /**
- * Get the default cell style for the column \a column.
- *
- * @param column the column to get the style for.
- * @return the default cell style for \a column.
- */
- KoTableCellStyle* defaultColumnCellStyle(int column) const;
-
- /**
- * Set the default cell style for the column \a column.
- *
- * @param column the column to set the style to.
- * @return the default cell style for \a column.
- */
- void setDefaultColumnCellStyle(int column, KoTableCellStyle* cellStyle);
-
-private:
- class Private;
- QExplicitlySharedDataPointer<Private> d;
-};
-
-Q_DECLARE_METATYPE(KoTableColumnAndRowStyleManager)
-
-#endif // KOTABLECOLUMNANDROWSTYLEMANAGER_H
-
diff --git a/plugins/flake/textshape/kotext/KoTableOfContentsGeneratorInfo.cpp b/plugins/flake/textshape/kotext/KoTableOfContentsGeneratorInfo.cpp
deleted file mode 100644
index 8ae3c77db3..0000000000
--- a/plugins/flake/textshape/kotext/KoTableOfContentsGeneratorInfo.cpp
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (C) 2011 Lukáš Tvrdý <lukas.tvrdy@ixonos.com>
- * Copyright (C) 2011 Ko GmbH <cbo@kogmbh.com>
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 "KoTableOfContentsGeneratorInfo.h"
-
-#include <KoXmlNS.h>
-#include <KoTextSharedLoadingData.h>
-#include <KoParagraphStyle.h>
-#include <KoXmlWriter.h>
-#include <KoXmlReader.h>
-
-int KoTableOfContentsGeneratorInfo::styleNameToStyleId(KoTextSharedLoadingData *sharedLoadingData, const QString &styleName)
-{
- //find styleId of a style based on its style:name property
- KoParagraphStyle * style = sharedLoadingData->paragraphStyle(styleName, true);
- if (style) {
- return style->styleId();
- }
-
- //if the previous way of finding styles fails fall back on using style:display-name property of a style
- QList<KoParagraphStyle *> paragraphStyles = sharedLoadingData->paragraphStyles(true);
- QList<KoParagraphStyle *>::const_iterator iter = paragraphStyles.constBegin();
-
- for (; iter != paragraphStyles.constEnd(); ++iter) {
- if ((*iter)->name() == styleName) {
- return (*iter)->styleId();
- }
- }
-
- return 0;
-}
-
-
-KoTableOfContentsGeneratorInfo::KoTableOfContentsGeneratorInfo(bool generateEntryTemplate)
- :
- m_indexScope("document")
- , m_outlineLevel(10)
- , m_relativeTabStopPosition(true)
- , m_useIndexMarks(true)
- , m_useIndexSourceStyles(false)
- , m_useOutlineLevel(true)
-{
- // index-title-template
- // m_indexTitleTemplate.text = "title";
- if (generateEntryTemplate) {
- // table-of-content-entry-template
- for (int level = 1; level <= m_outlineLevel; level++) {
- TocEntryTemplate tocEntryTemplate;
- tocEntryTemplate.outlineLevel = level;
-
- // index-entry-link-start
- IndexEntryLinkStart *link = new IndexEntryLinkStart(QString());
- tocEntryTemplate.indexEntries.append(static_cast<IndexEntry*>(link));
-
- // index-entry-chapter
- // use null String if the style name is not present, it means that we inherit it from the parent
- IndexEntryChapter *entryChapter = new IndexEntryChapter(QString());
- entryChapter->display = "number";
- entryChapter->outlineLevel = level;
- tocEntryTemplate.indexEntries.append(static_cast<IndexEntry*>(entryChapter));
-
- // index-entry-text
- IndexEntryText *entryText = new IndexEntryText(QString());
- tocEntryTemplate.indexEntries.append(static_cast<IndexEntry*>(entryText));
-
- // index-entry-tab-stop
- IndexEntryTabStop *entryTabStop = new IndexEntryTabStop(QString());
- entryTabStop->tab.type = QTextOption::RightTab;
- entryTabStop->setPosition(QString());
- entryTabStop->tab.leaderText = '.';
- tocEntryTemplate.indexEntries.append(static_cast<IndexEntry*>(entryTabStop));
-
- // index-entry-page-number
- IndexEntryPageNumber *entryPageNumber = new IndexEntryPageNumber(QString());
- tocEntryTemplate.indexEntries.append(static_cast<IndexEntry*>(entryPageNumber) );
-
- // index-entry-link-end
- IndexEntryLinkEnd *linkend = new IndexEntryLinkEnd(QString());
- tocEntryTemplate.indexEntries.append(static_cast<IndexEntry*>(linkend));
-
- m_entryTemplate.append(tocEntryTemplate);
- }
- }
-}
-
-KoTableOfContentsGeneratorInfo::~KoTableOfContentsGeneratorInfo()
-{
- foreach (const TocEntryTemplate &entryTemplate, m_entryTemplate) {
- qDeleteAll(entryTemplate.indexEntries);
- }
-}
-
-
-void KoTableOfContentsGeneratorInfo::loadOdf(KoTextSharedLoadingData *sharedLoadingData, const KoXmlElement& element)
-{
- Q_ASSERT(element.localName() == "table-of-content-source" && element.namespaceURI() == KoXmlNS::text);
-
- foreach (const TocEntryTemplate &entryTemplate, m_entryTemplate) {
- qDeleteAll(entryTemplate.indexEntries);
- }
- m_entryTemplate.clear();
-
- m_indexScope = element.attribute("index-scope", "document"); // enum {document, chapter}
- m_outlineLevel = element.attribute("outline-level","1").toInt();
- m_relativeTabStopPosition = element.attribute("relative-tab-stop-position","true") == "true";
- m_useIndexMarks = element.attribute("use-index-marks","f") == "true";
- m_useIndexSourceStyles = element.attribute("use-index-source-styles","false") == "true";
- m_useOutlineLevel = element.attribute("use-outline-level","true") == "true";
-
- // three other children to visit
- KoXmlElement p;
- forEachElement(p, element) {
- if (p.namespaceURI() != KoXmlNS::text) {
- continue;
- }
-
- // first child
- if (p.localName() == "index-title-template") {
- m_indexTitleTemplate.styleName = p.attribute("style-name");
- m_indexTitleTemplate.styleId = styleNameToStyleId(sharedLoadingData, m_indexTitleTemplate.styleName);
- m_indexTitleTemplate.text = p.text();
- // second child
- } else if (p.localName() == "table-of-content-entry-template") {
- TocEntryTemplate tocEntryTemplate;
- tocEntryTemplate.outlineLevel = p.attribute("outline-level").toInt();
- tocEntryTemplate.styleName = p.attribute("style-name");
- tocEntryTemplate.styleId = styleNameToStyleId(sharedLoadingData, tocEntryTemplate.styleName );
-
- KoXmlElement indexEntry;
- forEachElement(indexEntry, p) {
- if (indexEntry.namespaceURI() != KoXmlNS::text) {
- continue;
- }
-
- if (indexEntry.localName() == "index-entry-chapter") {
- // use null String if the style name is not present, it means that we inherit it from the parent
- IndexEntryChapter *entryChapter = new IndexEntryChapter(
- indexEntry.attribute("style-name", QString())
- );
-
- // display can be "name", "number", "number-and-name", "plain-number" or "plain-number-and-name"
- // "number" is default according the specs ODF v1.2
- entryChapter->display = indexEntry.attribute("display", "number");
- entryChapter->outlineLevel = indexEntry.attribute("outline-level", QString::number(tocEntryTemplate.outlineLevel)).toInt();
- tocEntryTemplate.indexEntries.append(static_cast<IndexEntry*>(entryChapter));
-
- } else if (indexEntry.localName() == "index-entry-text") {
- IndexEntryText *entryText = new IndexEntryText(indexEntry.attribute("style-name", QString()));
- tocEntryTemplate.indexEntries.append(static_cast<IndexEntry*>(entryText));
-
- } else if (indexEntry.localName() == "index-entry-page-number") {
- IndexEntryPageNumber *entryPageNumber = new IndexEntryPageNumber(indexEntry.attribute("style-name", QString()));
- tocEntryTemplate.indexEntries.append(static_cast<IndexEntry*>(entryPageNumber) );
-
- } else if (indexEntry.localName() == "index-entry-span") {
- IndexEntrySpan *entrySpan = new IndexEntrySpan(indexEntry.attribute("style-name", QString()) );
- entrySpan->text = indexEntry.text();
- tocEntryTemplate.indexEntries.append(static_cast<IndexEntry*>(entrySpan));
-
- } else if (indexEntry.localName() == "index-entry-tab-stop") {
- IndexEntryTabStop *entryTabStop = new IndexEntryTabStop(indexEntry.attribute("style-name", QString()));
-
- QString type = indexEntry.attribute("type","right"); // left or right
- if (type == "left") {
- entryTabStop->tab.type = QTextOption::LeftTab;
- } else {
- entryTabStop->tab.type = QTextOption::RightTab;
- }
- entryTabStop->setPosition(indexEntry.attribute("position", QString()));
- entryTabStop->tab.leaderText = indexEntry.attribute("leader-char",".");
- tocEntryTemplate.indexEntries.append(static_cast<IndexEntry*>(entryTabStop));
-
- } else if (indexEntry.localName() == "index-entry-link-start") {
- IndexEntryLinkStart *link = new IndexEntryLinkStart(indexEntry.attribute("style-name", QString()));
- tocEntryTemplate.indexEntries.append(static_cast<IndexEntry*>(link));
- } else if (indexEntry.localName() == "index-entry-link-end") {
- IndexEntryLinkEnd *link = new IndexEntryLinkEnd(indexEntry.attribute("style-name", QString()));
- tocEntryTemplate.indexEntries.append(static_cast<IndexEntry*>(link));
- }
- }
- m_entryTemplate.append(tocEntryTemplate);
-
- // third child
- } else if (p.localName() == "index-source-styles" && p.namespaceURI() == KoXmlNS::text) {
- IndexSourceStyles indexStyles;
- indexStyles.outlineLevel = p.attribute("outline-level").toInt();
-
- IndexSourceStyle indexStyle;
- KoXmlElement sourceElement;
- forEachElement(sourceElement, p) {
- if (sourceElement.localName() == "index-source-style") {
- indexStyle.styleName = sourceElement.attribute("style-name");
- indexStyle.styleId = styleNameToStyleId(sharedLoadingData, indexStyle.styleName);
- indexStyles.styles.append(indexStyle);
- }
- }
- m_indexSourceStyles.append(indexStyles);
- }
- }// forEachElement
-}
-
-
-void KoTableOfContentsGeneratorInfo::saveOdf(KoXmlWriter * writer) const
-{
- writer->startElement("text:table-of-content-source");
- writer->addAttribute("text:index-scope", m_indexScope);
- writer->addAttribute("text:outline-level", m_outlineLevel);
- writer->addAttribute("text:relative-tab-stop-position", m_relativeTabStopPosition);
- writer->addAttribute("text:use-index-marks", m_useIndexMarks);
- writer->addAttribute("text:use-index-source-styles", m_useIndexSourceStyles);
- writer->addAttribute("text:use-outline-level", m_useOutlineLevel);
-
- m_indexTitleTemplate.saveOdf(writer);
-
- foreach (const TocEntryTemplate &entry, m_entryTemplate) {
- entry.saveOdf(writer);
- }
-
- foreach (const IndexSourceStyles &sourceStyle, m_indexSourceStyles) {
- sourceStyle.saveOdf(writer);
- }
-
- writer->endElement(); // text:table-of-content-source
-}
-
-KoTableOfContentsGeneratorInfo *KoTableOfContentsGeneratorInfo::clone()
-{
- KoTableOfContentsGeneratorInfo *newToCInfo=new KoTableOfContentsGeneratorInfo(false);
- newToCInfo->m_entryTemplate.clear();
- newToCInfo->m_name = QString(m_name);
- newToCInfo->m_styleName = QString(m_styleName);
- newToCInfo->m_indexScope = QString(m_indexScope);
- newToCInfo->m_outlineLevel = m_outlineLevel;
- newToCInfo->m_relativeTabStopPosition = m_relativeTabStopPosition;
- newToCInfo->m_useIndexMarks = m_useIndexMarks;
- newToCInfo->m_useIndexSourceStyles = m_useIndexSourceStyles;
- newToCInfo->m_useOutlineLevel = m_useOutlineLevel;
- newToCInfo->m_indexTitleTemplate = m_indexTitleTemplate;
-
- foreach (const TocEntryTemplate &tocTemplate, m_entryTemplate) {
- newToCInfo->m_entryTemplate.append(tocTemplate);
- }
-
- foreach (const IndexSourceStyles &indexSourceStyles, m_indexSourceStyles) {
- newToCInfo->m_indexSourceStyles.append(indexSourceStyles);
- }
-
- return newToCInfo;
-}
-
diff --git a/plugins/flake/textshape/kotext/KoTableOfContentsGeneratorInfo.h b/plugins/flake/textshape/kotext/KoTableOfContentsGeneratorInfo.h
deleted file mode 100644
index 53ca045a6e..0000000000
--- a/plugins/flake/textshape/kotext/KoTableOfContentsGeneratorInfo.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2011 Lukáš Tvrdý <lukas.tvrdy@ixonos.com>
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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_TABLE_OF_CONTENTS_GENERATOR_INFO
-#define KO_TABLE_OF_CONTENTS_GENERATOR_INFO
-
-#define ppVar( var ) #var << "=" << var
-//#define DEBUG_TOC_STRUCTURE
-
-#include <QList>
-#include <QString>
-
-#include "ToCBibGeneratorInfo.h"
-
-class KoTextSharedLoadingData;
-class KoXmlWriter;
-
-class KRITATEXT_EXPORT KoTableOfContentsGeneratorInfo
-{
-public:
- explicit KoTableOfContentsGeneratorInfo(bool generateEntryTemplate = true);
- ~KoTableOfContentsGeneratorInfo();
- void loadOdf(KoTextSharedLoadingData *sharedLoadingData, const KoXmlElement &element);
- void saveOdf(KoXmlWriter *writer) const;
- KoTableOfContentsGeneratorInfo *clone();
-
- QString m_name;
- QString m_styleName;
- // TODO: add support for those according ODF v1.2
- // text: protected
- // text: protection-key
- // text:protection-key-digest-algorithm
- // xml:id
- QString m_indexScope; // enum {document, chapter}
- int m_outlineLevel;
- bool m_relativeTabStopPosition;
- bool m_useIndexMarks;
- bool m_useIndexSourceStyles;
- bool m_useOutlineLevel;
-
- IndexTitleTemplate m_indexTitleTemplate;
- QList<TocEntryTemplate> m_entryTemplate; // N-entries
- QList<IndexSourceStyles> m_indexSourceStyles;
-
-private:
- int styleNameToStyleId(KoTextSharedLoadingData *sharedLoadingData, const QString &styleName);
-};
-
-Q_DECLARE_METATYPE(KoTableOfContentsGeneratorInfo *)
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoText.cpp b/plugins/flake/textshape/kotext/KoText.cpp
deleted file mode 100644
index 6faf8fdf28..0000000000
--- a/plugins/flake/textshape/kotext/KoText.cpp
+++ /dev/null
@@ -1,204 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
- *
- * 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 "KoText.h"
-
-#include <KoUnit.h>
-
-#include <klocalizedstring.h>
-
-using namespace KoText;
-
-QStringList KoText::underlineTypeList()
-{
- QStringList lst;
- lst << i18nc("Underline Style", "None");
- lst << i18nc("Underline Style", "Single");
- lst << i18nc("Underline Style", "Double");
- return lst;
-}
-
-QStringList KoText::underlineStyleList()
-{
- QStringList lst;
- lst << "_________"; // solid
- lst << "___ ___ __"; // dash
- lst << "_ _ _ _ _ _"; // dot
- lst << "___ _ ___ _"; // dash_dot
- lst << "___ _ _ ___"; // dash_dot_dot
- lst << "~~~~~~~"; // wavy lines
- return lst;
-}
-
-KoText::Tab::Tab()
- : position(0.),
- type(QTextOption::LeftTab),
- leaderType(KoCharacterStyle::NoLineType),
- leaderStyle(KoCharacterStyle::NoLineStyle),
- leaderWeight(KoCharacterStyle::AutoLineWeight),
- leaderWidth(0)
-{
-}
-
-bool KoText::Tab::operator==(const Tab &other) const
-{
- return other.position == position &&
- other.type == type &&
- other.delimiter == delimiter &&
- other.leaderStyle == leaderStyle &&
- other.leaderColor == leaderColor &&
- other.leaderText == leaderText ;
-}
-
-Qt::Alignment KoText::alignmentFromString(const QString &align)
-{
- Qt::Alignment alignment = Qt::AlignLeft;
- if (align == "left")
- alignment = Qt::AlignLeft | Qt::AlignAbsolute;
- else if (align == "right")
- alignment = Qt::AlignRight | Qt::AlignAbsolute;
- else if (align == "start")
- alignment = Qt::AlignLeading;
- else if (align == "end")
- alignment = Qt::AlignTrailing;
- else if (align == "center")
- alignment = Qt::AlignHCenter;
- else if (align == "justify")
- alignment = Qt::AlignJustify;
- else if (align == "margins") // in tables this is effectively the same as justify
- alignment = Qt::AlignJustify;
- return alignment;
-}
-
-QString KoText::alignmentToString(Qt::Alignment alignment)
-{
- QString align;
-
- alignment &= Qt::AlignHorizontal_Mask;
- if (alignment == (Qt::AlignLeft | Qt::AlignAbsolute))
- align = "left";
- else if (alignment == (Qt::AlignRight | Qt::AlignAbsolute))
- align = "right";
- else if (alignment == Qt::AlignLeading)
- align = "start";
- else if (alignment == Qt::AlignTrailing)
- align = "end";
- else if (alignment == Qt::AlignHCenter)
- align = "center";
- else if (alignment == Qt::AlignJustify)
- align = "justify";
- return align;
-}
-
-Qt::Alignment KoText::valignmentFromString(const QString &align)
-{
- Qt::Alignment alignment = Qt::AlignTop;
- if (align == "top")
- alignment = Qt::AlignTop;
- else if (align == "middle")
- alignment = Qt::AlignVCenter;
- else if (align == "bottom")
- alignment = Qt::AlignBottom;
- return alignment;
-}
-
-QString KoText::valignmentToString(Qt::Alignment alignment)
-{
- QString align;
- alignment &= Qt::AlignVertical_Mask;
- if (alignment == (Qt::AlignTop))
- align = "top";
- else if (alignment == Qt::AlignVCenter)
- align = "middle";
- else if (alignment == Qt::AlignBottom)
- align = "bottom";
- else
- align = "automatic";
- return align;
-}
-
-KoText::Direction KoText::directionFromString(const QString &writingMode)
-{
- // LTR is lr-tb. RTL is rl-tb
- if (writingMode == "lr" || writingMode == "lr-tb")
- return KoText::LeftRightTopBottom;
- if (writingMode == "rl" || writingMode == "rl-tb")
- return KoText::RightLeftTopBottom;
- if (writingMode == "tb" || writingMode == "tb-rl")
- return KoText::TopBottomRightLeft;
- if (writingMode == "tb-lr")
- return KoText::TopBottomLeftRight;
- if (writingMode == "page")
- return KoText::InheritDirection;
- return KoText::AutoDirection;
-}
-
-QString KoText::directionToString(KoText::Direction direction)
-{
- if (direction == KoText::LeftRightTopBottom)
- return "lr";
- if (direction == KoText::RightLeftTopBottom)
- return "rl";
- if (direction == KoText::TopBottomRightLeft)
- return "tb-rl";
- if (direction == KoText::TopBottomLeftRight)
- return "tb-lr";
- if (direction == KoText::InheritDirection)
- return "page";
-
- return "auto";
-}
-
-KoText::KoTextBreakProperty KoText::textBreakFromString(const QString& textBreak)
-{
- if (textBreak == "page")
- return KoText::PageBreak;
- if (textBreak == "column")
- return KoText::ColumnBreak;
- return KoText::NoBreak;
-}
-
-QString KoText::textBreakToString(KoText::KoTextBreakProperty textBreak)
-{
- if (textBreak == KoText::PageBreak)
- return "page";
- if (textBreak == KoText::ColumnBreak)
- return "column";
- return "auto";
-}
-
-QTextLength KoText::parseLength(const QString &length)
-{
- if (length.contains('%'))
- {
- QString lengthValue = length.left(length.indexOf('%'));
- bool ok = false;
- qreal realLength = lengthValue.toDouble(&ok);
- if (ok)
- return QTextLength(QTextLength::PercentageLength, realLength);
- else
- return QTextLength(QTextLength::PercentageLength, 0);
- }
- else
- {
- return QTextLength(QTextLength::FixedLength, KoUnit::parseValue(length));
- }
-}
-
diff --git a/plugins/flake/textshape/kotext/KoText.h b/plugins/flake/textshape/kotext/KoText.h
deleted file mode 100644
index f549b58f93..0000000000
--- a/plugins/flake/textshape/kotext/KoText.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006, 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
- *
- * 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 KOTEXT_H
-#define KOTEXT_H
-
-#include "kritatext_export.h"
-
-#include <KoDocumentResourceManager.h>
-#include <styles/KoCharacterStyle.h>
-
-#include <QChar>
-#include <QMetaType>
-#include <QTextOption>
-
-class QStringList;
-
-/**
- * Generic namespace of the Calligra Text library for helper methods and data.
- */
-namespace KoText
-{
-KRITATEXT_EXPORT QStringList underlineTypeList();
-KRITATEXT_EXPORT QStringList underlineStyleList();
-KRITATEXT_EXPORT Qt::Alignment alignmentFromString(const QString &align);
-KRITATEXT_EXPORT QString alignmentToString(Qt::Alignment align);
-KRITATEXT_EXPORT Qt::Alignment valignmentFromString(const QString &align);
-KRITATEXT_EXPORT QString valignmentToString(Qt::Alignment align);
-
-/// This enum contains values to be used as keys in KoCanvasResourceProvider
-enum CanvasResource {
- CurrentTextDocument = 382490375, ///< set by the text plugin whenever the document is changed
- CurrentTextPosition = 183523, ///< used by the text plugin whenever the position is changed
- CurrentTextAnchor = 341899485, ///< used by the text plugin whenever the anchor-position is changed
- SelectedTextPosition = 21314576, ///< used by the text plugin whenever the alternative selection is changed
- /// used by the text plugin whenever the alternative selection anchor-position is changed
- SelectedTextAnchor = 3344189
-};
-
-/// For paragraphs each tab definition is represented by this struct.
-struct KRITATEXT_EXPORT Tab {
- Tab();
- qreal position; ///< distance in ps-points from the edge of the text-shape
- QTextOption::TabType type; ///< Determine which type is used.
- QChar delimiter; ///< If type is DelimitorTab; tab until this char was found in the text.
- KoCharacterStyle::LineType leaderType; // none/single/double
- KoCharacterStyle::LineStyle leaderStyle; // solid/dotted/dash/...
- KoCharacterStyle::LineWeight leaderWeight; // auto/bold/thin/length/percentage/...
- qreal leaderWidth; // the width value if length/percentage
- QColor leaderColor; ///< if color is valid, then use this instead of the (current) text color
- QString leaderText; ///< character to print as the leader (filler of the tabbed space)
-
- bool operator==(const Tab &tab) const;
-};
-
-/**
- * Text resources per calligra-document.
- * \sa KoDocumentResourceManager KoShapeController::resourceManager()
- */
-enum DocumentResource {
- ChangeTracker = KoDocumentResourceManager::KoTextStart + 1, ///< KoChangeTracker
- InlineTextObjectManager, ///< The KoText inline-text-object manager. KoInlineTextObjectManager
- TextRangeManager, ///< The KoText inline-text-object manager. KoInlineTextObjectManager
- StyleManager, ///< The KoStyleManager
- PageProvider, ///< The KoPageProvider
- /** The KoDocumentRdf for the document,
- this will be a KoDocumentRdfBase when Soprano support is not compiled in. */
- DocumentRdf
-
-};
-
-enum KoTextFrameProperty {
- SubFrameType = QTextFormat::UserProperty + 1
-};
-
-enum KoSubFrameType {
- AuxillaryFrameType = 1,
- NoteFrameType
-};
-
-/// Text in the objects will be positioned according to the direction.
-enum Direction {
- AutoDirection, ///< Take the direction from the text.
- LeftRightTopBottom, ///< Text layout for most western languages
- RightLeftTopBottom, ///< Text layout for languages like Hebrew
- TopBottomRightLeft, ///< Vertical text layout.
- TopBottomLeftRight, ///< Vertical text layout. ?
- InheritDirection ///< Direction is unspecified and should come from the container
-};
-
-/// convert the string version of directions (as specified in XSL and ODF) to the Direction enum
-KRITATEXT_EXPORT Direction directionFromString(const QString &direction);
-/// convert the Direction enum to the string version of directions (as specified in XSL and ODF)
-KRITATEXT_EXPORT QString directionToString(Direction direction);
-
-/// There are several possible text breaks
-enum KoTextBreakProperty {
- NoBreak = 0, ///< No text break
- ColumnBreak, ///< Column break
- PageBreak ///< Page break
-};
-
-/// convert the string version of text break (as specified in ODF) to the KoTextBreakProperty enum
-KRITATEXT_EXPORT KoTextBreakProperty textBreakFromString(const QString &textBreak);
-/// convert the KoTextBreakProperty enum to the string version of text break (as specified in ODF)
-KRITATEXT_EXPORT QString textBreakToString (KoTextBreakProperty textBreak);
-
-///TODO: move to KoUnit ?
-KRITATEXT_EXPORT QTextLength parseLength (const QString &length);
-}
-
-Q_DECLARE_METATYPE(KoText::Tab)
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoTextBlockBorderData.cpp b/plugins/flake/textshape/kotext/KoTextBlockBorderData.cpp
deleted file mode 100644
index 9a8c59c004..0000000000
--- a/plugins/flake/textshape/kotext/KoTextBlockBorderData.cpp
+++ /dev/null
@@ -1,207 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006 Thomas Zander <zander@kde.org>
- * Copyright (C) 2011 Stuart Dickson <stuart@furkinfantastic.net>
- *
- * 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 "KoTextBlockBorderData.h"
-
-#include <QPainter>
-
-#include "TextDebug.h"
-
-struct Edge {
- Edge() : distance(0.0) { innerPen.setWidthF(0.); outerPen.setWidthF(0.); }
- QPen innerPen;
- QPen outerPen;
- qreal distance;
-};
-
-class Q_DECL_HIDDEN KoTextBlockBorderData::Private
-{
-public:
- Private() : refCount(0), mergeWithNext(true) {}
- Edge edges[4];
-
- QAtomicInt refCount;
- bool mergeWithNext;
-};
-
-KoTextBlockBorderData::KoTextBlockBorderData(const QRectF &paragRect)
- : d(new Private())
-{
- ///TODO Remove parameter paragRect and update references to this constructor.
- Q_UNUSED(paragRect);
-}
-
-KoTextBlockBorderData::~KoTextBlockBorderData()
-{
- delete d;
-}
-
-KoTextBlockBorderData::KoTextBlockBorderData(const KoTextBlockBorderData &other)
- : d(new Private())
-{
- d->mergeWithNext = other.d->mergeWithNext;
-
- for (int i = Top; i <= Right; i++)
- d->edges[i] = other.d->edges[i];
-}
-
-void KoTextBlockBorderData::setMergeWithNext(bool merge)
-{
- d->mergeWithNext = merge;
-}
-
-bool KoTextBlockBorderData::hasBorders() const
-{
- for (int i = Top; i <= Right; i++)
- if (d->edges[i].outerPen.widthF() > 0.0)
- return true;
- return false;
-}
-
-bool KoTextBlockBorderData::operator==(const KoTextBlockBorderData &border) const
-{
- return equals(border);
-}
-bool KoTextBlockBorderData::equals(const KoTextBlockBorderData &border) const
-{
- if (!d->mergeWithNext) {
- return false;
- }
- for (int i = Top; i <= Right; i++) {
- if (d->edges[i].outerPen != border.d->edges[i].outerPen)
- return false;
- if (d->edges[i].innerPen != border.d->edges[i].innerPen)
- return false;
- if (qAbs(d->edges[i].distance - border.d->edges[i].distance) > 1E-10)
- return false;
- }
- return true;
-}
-
-void KoTextBlockBorderData::paint(QPainter &painter, const QRectF &bounds) const
-{
- QRectF innerBounds = bounds;
- if (d->edges[Top].outerPen.widthF() > 0) {
- QPen pen = d->edges[Top].outerPen;
- painter.setPen(pen);
- const qreal t = bounds.top() + pen.widthF() / 2.0;
- painter.drawLine(QLineF(bounds.left(), t, bounds.right(), t));
- innerBounds.setTop(bounds.top() + d->edges[Top].distance + pen.widthF());
- }
- if (d->edges[Bottom].outerPen.widthF() > 0) {
- QPen pen = d->edges[Bottom].outerPen;
- painter.setPen(pen);
- const qreal b = bounds.bottom() - pen.widthF() / 2.0;
- innerBounds.setBottom(bounds.bottom() - d->edges[Bottom].distance - pen.widthF());
- painter.drawLine(QLineF(bounds.left(), b, bounds.right(), b));
- }
- if (d->edges[Left].outerPen.widthF() > 0) {
- QPen pen = d->edges[Left].outerPen;
- painter.setPen(pen);
- const qreal l = bounds.left() + pen.widthF() / 2.0;
- innerBounds.setLeft(bounds.left() + d->edges[Left].distance + pen.widthF());
- painter.drawLine(QLineF(l, bounds.top(), l, bounds.bottom()));
- }
- if (d->edges[Right].outerPen.widthF() > 0) {
- QPen pen = d->edges[Right].outerPen;
- painter.setPen(pen);
- const qreal r = bounds.right() - pen.widthF() / 2.0;
- innerBounds.setRight(bounds.right() - d->edges[Right].distance - pen.widthF());
- painter.drawLine(QLineF(r, bounds.top(), r, bounds.bottom()));
- }
- // inner lines
- if (d->edges[Top].innerPen.widthF() > 0) {
- QPen pen = d->edges[Top].innerPen;
- painter.setPen(pen);
- const qreal t = innerBounds.top() + pen.widthF() / 2.0;
- painter.drawLine(QLineF(innerBounds.left(), t, innerBounds.right(), t));
- }
- if (d->edges[Bottom].innerPen.widthF() > 0) {
- QPen pen = d->edges[Bottom].innerPen;
- painter.setPen(pen);
- const qreal b = innerBounds.bottom() - pen.widthF() / 2.0;
- painter.drawLine(QLineF(innerBounds.left(), b, innerBounds.right(), b));
- }
- if (d->edges[Left].innerPen.widthF() > 0) {
- QPen pen = d->edges[Left].innerPen;
- painter.setPen(pen);
- const qreal l = innerBounds.left() + pen.widthF() / 2.0;
- painter.drawLine(QLineF(l, innerBounds.top(), l, innerBounds.bottom()));
- }
- if (d->edges[Right].innerPen.widthF() > 0) {
- QPen pen = d->edges[Right].innerPen;
- painter.setPen(pen);
- const qreal r = innerBounds.right() - pen.widthF() / 2.0;
- painter.drawLine(QLineF(r, innerBounds.top(), r, innerBounds.bottom()));
- }
-}
-
-qreal KoTextBlockBorderData::inset(Side side) const
-{
- return d->edges[side].outerPen.widthF() + d->edges[side].distance + d->edges[side].innerPen.widthF();
-}
-
-void KoTextBlockBorderData::setEdge(Side side, const QTextBlockFormat &bf,
- KoParagraphStyle::Property style, KoParagraphStyle::Property width,
- KoParagraphStyle::Property color, KoParagraphStyle::Property space,
- KoParagraphStyle::Property innerWidth)
-{
-
- Edge edge;
- KoBorder::BorderStyle borderStyle;
- borderStyle = static_cast<KoBorder::BorderStyle>(bf.intProperty(style));
- switch (borderStyle) {
- case KoBorder::BorderDotted: edge.innerPen.setStyle(Qt::DotLine); break;
- case KoBorder::BorderDashed: edge.innerPen.setStyle(Qt::DashLine); break;
- case KoBorder::BorderDashDot: edge.innerPen.setStyle(Qt::DashDotLine); break;
- case KoBorder::BorderDashDotDot: edge.innerPen.setStyle(Qt::DashDotDotLine); break;
- case KoBorder::BorderGroove: /* TODO */ break;
- case KoBorder::BorderRidge: /* TODO */ break;
- case KoBorder::BorderInset: /* TODO */ break;
- case KoBorder::BorderOutset: /* TODO */ break;
- default:
- edge.innerPen.setStyle(Qt::SolidLine);
- }
- edge.innerPen.setColor(bf.colorProperty(color));
- edge.innerPen.setJoinStyle(Qt::MiterJoin);
- edge.innerPen.setCapStyle(Qt::FlatCap);
- edge.outerPen = edge.innerPen;
- edge.outerPen.setWidthF(bf.doubleProperty(width)); // TODO check if this does not need any conversion
-
- edge.distance = bf.doubleProperty(space);
- edge.innerPen.setWidthF(bf.doubleProperty(innerWidth));
-
- d->edges[side] = edge;
-}
-
-bool KoTextBlockBorderData::ref()
-{
- return d->refCount.ref();
-}
-
-bool KoTextBlockBorderData::deref()
-{
- return d->refCount.deref();
-}
-
-int KoTextBlockBorderData::useCount() const
-{
- return d->refCount;
-}
diff --git a/plugins/flake/textshape/kotext/KoTextBlockBorderData.h b/plugins/flake/textshape/kotext/KoTextBlockBorderData.h
deleted file mode 100644
index fc8ab2d950..0000000000
--- a/plugins/flake/textshape/kotext/KoTextBlockBorderData.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006 Thomas Zander <zander@kde.org>
- *
- * 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 KOTEXTBLOCKBORDERDATA_H
-#define KOTEXTBLOCKBORDERDATA_H
-
-#include "styles/KoParagraphStyle.h"
-
-#include "kritatext_export.h"
-
-class QRectF;
-class QPainter;
-
-/**
- * This class holds data for paragraph-borders.
- * All the information needed to paint the borders, but also to calculate the insets that the borders
- * cause on text-layout is stored in here.
- * An instance of this class is owned by the KoTextBlockData and this class is being refcounted
- * to allow multiple paragraphs to share one border.
- *
- */
-class KRITATEXT_EXPORT KoTextBlockBorderData
-{
-public:
- /// Enum used to differentiate between the 4 types of borders this class maintains
- enum Side {
- Top = 0, ///< References the border at the top of the paragraph
- Left, ///< References the border at the left side of the paragraph
- Bottom, ///< References the border at the bottom of the paragraph
- Right ///< References the border at the right side of the paragraph
- };
- /**
- * Constructor for the border data.
- * Will create a border-set with the param rectangle but all the borders will
- * be turned off.
- * @param paragRect the rectangle that will be used to paint the border inside of.
- * @see setEdge() to set the actual border properties.
- */
- explicit KoTextBlockBorderData(const QRectF &paragRect);
-
- /**
- * Copy constructor for the border data.
- * @param other the original object which will be duplicated.
- */
- explicit KoTextBlockBorderData(const KoTextBlockBorderData &other);
-
- ~KoTextBlockBorderData();
-
- /**
- * Increments the use-value.
- * Returns true if the new value is non-zero, false otherwise.
- */
- bool ref();
- /**
- * Decrements the use-value.
- * Returns true if the new value is non-zero, false otherwise.
- */
- bool deref();
- /// return the usage count
- int useCount() const;
-
- /**
- * Set the properties of an edge based on a paragraph-format.
- * @param side defines which edge this is for.
- * @param bf the format of the paragraph See QTextBlock.blockFormat()
- * @param style the border style for this side.
- * @param width the thickness of the border-line.
- * @param color the property for the color of the border-line(s).
- * @param space the amount of spacing between the outer border and the inner border in case of style being double
- * @param innerWidth the thickness of the inner border-line in case of style being double
- */
- void setEdge(Side side, const QTextBlockFormat &bf, KoParagraphStyle::Property style,
- KoParagraphStyle::Property width, KoParagraphStyle::Property color,
- KoParagraphStyle::Property space, KoParagraphStyle::Property innerWidth);
-
- /**
- * Set if this border should possibly be merged with the next.
- */
- void setMergeWithNext(bool merge);
-
- /**
- * @return true if there has been at least one border set.
- */
- bool hasBorders() const;
-
- /**
- * Find the inset that a border causes for a specific side.
- * @see applyInsets()
- */
- qreal inset(Side side) const;
-
- /// returns true if the borders of param border are the same as this one.
- bool operator==(const KoTextBlockBorderData &border) const;
- bool equals(const KoTextBlockBorderData &border) const;
-
- /**
- * Paint the borders.
- */
- void paint(QPainter &painter, const QRectF &clip) const;
-
-private:
- class Private;
- Private * const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoTextBlockData.cpp b/plugins/flake/textshape/kotext/KoTextBlockData.cpp
deleted file mode 100644
index 1fbdbf8a81..0000000000
--- a/plugins/flake/textshape/kotext/KoTextBlockData.cpp
+++ /dev/null
@@ -1,302 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006 Thomas Zander <zander@kde.org>
- * Copyright (C) 2010 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2011 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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 "KoTextBlockData.h"
-
-#include "KoTextBlockBorderData.h"
-#include "KoTextBlockPaintStrategyBase.h"
-
-class Q_DECL_HIDDEN KoTextBlockData::Private : public QTextBlockUserData
-{
-public:
- Private()
- : counterWidth(-1.0)
- , counterSpacing(0)
- , counterIsImage(false)
- , counterIndex(1)
- , border(0)
- , paintStrategy(0)
- {
- layoutedMarkupRanges[KoTextBlockData::Misspell] = false;
- layoutedMarkupRanges[KoTextBlockData::Grammar] = false;
- }
-
- ~Private() override {
- if (border && !border->deref())
- delete border;
- delete paintStrategy;
- }
- qreal counterWidth;
- qreal counterSpacing;
- QString counterPrefix;
- QString counterPlainText;
- QString counterSuffix;
- QString partialCounterText;
- bool counterIsImage;
- int counterIndex;
- QPointF counterPos;
- QTextCharFormat labelFormat;
- KoTextBlockBorderData *border;
- KoTextBlockPaintStrategyBase *paintStrategy;
- QMap<KoTextBlockData::MarkupType, QList<MarkupRange> > markupRangesMap;
- QMap<KoTextBlockData::MarkupType, bool> layoutedMarkupRanges;
-};
-
-KoTextBlockData::KoTextBlockData(QTextBlock &block)
- : d(block.userData() ? dynamic_cast<KoTextBlockData::Private *>(block.userData())
- : new Private())
-{
- block.setUserData(d);
-}
-
-KoTextBlockData::KoTextBlockData(QTextBlockUserData *userData)
- : d(dynamic_cast<KoTextBlockData::Private *>(userData))
-{
- Q_ASSERT(d);
-}
-
-KoTextBlockData::~KoTextBlockData()
-{
- // explicitly do not delete the d-pointer here
-}
-
-
-void KoTextBlockData::appendMarkup(MarkupType type, int firstChar, int lastChar)
-{
- Q_ASSERT(d->markupRangesMap[type].isEmpty() || d->markupRangesMap[type].last().lastChar < firstChar);
-
- MarkupRange range;
- range.firstChar = firstChar;
- range.lastChar = lastChar;
- d->layoutedMarkupRanges[type] = false;
-
- d->markupRangesMap[type].append(range);
-}
-
-void KoTextBlockData::clearMarkups(MarkupType type)
-{
- d->markupRangesMap[type].clear();
- d->layoutedMarkupRanges[type] = false;
-}
-
-KoTextBlockData::MarkupRange KoTextBlockData::findMarkup(MarkupType type, int positionWithin) const
-{
- foreach (const MarkupRange &range, d->markupRangesMap[type]) {
- if (positionWithin <= range.lastChar) {
- // possible hit
- if (positionWithin >= range.firstChar) {
- return range;
- } else {
- return MarkupRange(); // we have passed it without finding
- }
- }
- }
- return MarkupRange(); // either no ranges or not in last either
-}
-
-void KoTextBlockData::rebaseMarkups(MarkupType type, int fromPosition, int delta)
-{
- QList<MarkupRange>::Iterator markIt = markupsBegin(type);
- QList<MarkupRange>::Iterator markEnd = markupsEnd(type);
- while (markIt != markEnd) {
- if (fromPosition <= markIt->lastChar) {
- // we need to modify the end of this
- markIt->lastChar += delta;
- }
- if (fromPosition < markIt->firstChar) {
- // we need to modify the end of this
- markIt->firstChar += delta;
- }
- ++markIt;
- }
-}
-
-void KoTextBlockData::setMarkupsLayoutValidity(MarkupType type, bool valid)
-{
- d->layoutedMarkupRanges[type] = valid;
-}
-
-bool KoTextBlockData::isMarkupsLayoutValid(MarkupType type) const
-{
- return d->layoutedMarkupRanges[type];
-}
-
-QList<KoTextBlockData::MarkupRange>::Iterator KoTextBlockData::markupsBegin(MarkupType type)
-{
- return d->markupRangesMap[type].begin();
-}
-
-QList<KoTextBlockData::MarkupRange>::Iterator KoTextBlockData::markupsEnd(MarkupType type)
-{
- return d->markupRangesMap[type].end();
-}
-
-bool KoTextBlockData::hasCounterData() const
-{
- return d->counterWidth >= 0 && (!d->counterPlainText.isNull() || d->counterIsImage);
-}
-
-qreal KoTextBlockData::counterWidth() const
-{
- return qMax(qreal(0), d->counterWidth);
-}
-
-void KoTextBlockData::setBorder(KoTextBlockBorderData *border)
-{
- if (d->border && !d->border->deref())
- delete d->border;
- d->border = border;
- if (d->border)
- d->border->ref();
-}
-
-void KoTextBlockData::setCounterWidth(qreal width)
-{
- d->counterWidth = width;
-}
-
-qreal KoTextBlockData::counterSpacing() const
-{
- return d->counterSpacing;
-}
-
-void KoTextBlockData::setCounterSpacing(qreal spacing)
-{
- d->counterSpacing = spacing;
-}
-
-QString KoTextBlockData::counterText() const
-{
- return d->counterPrefix + d->counterPlainText + d->counterSuffix;
-}
-
-void KoTextBlockData::clearCounter()
-{
- d->partialCounterText.clear();
- d->counterPlainText.clear();
- d->counterPrefix.clear();
- d->counterSuffix.clear();
- d->counterSpacing = 0.0;
- d->counterWidth = 0.0;
- d->counterIsImage = false;
-}
-
-void KoTextBlockData::setPartialCounterText(const QString &text)
-{
- d->partialCounterText = text;
-}
-
-QString KoTextBlockData::partialCounterText() const
-{
- return d->partialCounterText;
-}
-
-void KoTextBlockData::setCounterPlainText(const QString &text)
-{
- d->counterPlainText = text;
-}
-
-QString KoTextBlockData::counterPlainText() const
-{
- return d->counterPlainText;
-}
-
-void KoTextBlockData::setCounterPrefix(const QString &text)
-{
- d->counterPrefix = text;
-}
-
-QString KoTextBlockData::counterPrefix() const
-{
- return d->counterPrefix;
-}
-
-void KoTextBlockData::setCounterSuffix(const QString &text)
-{
- d->counterSuffix = text;
-}
-
-QString KoTextBlockData::counterSuffix() const
-{
- return d->counterSuffix;
-}
-
-void KoTextBlockData::setCounterIsImage(bool isImage)
-{
- d->counterIsImage = isImage;
-}
-
-bool KoTextBlockData::counterIsImage() const
-{
- return d->counterIsImage;
-}
-
-void KoTextBlockData::setCounterIndex(int index)
-{
- d->counterIndex = index;
-}
-
-int KoTextBlockData::counterIndex() const
-{
- return d->counterIndex;
-}
-
-void KoTextBlockData::setCounterPosition(const QPointF &position)
-{
- d->counterPos = position;
-}
-
-QPointF KoTextBlockData::counterPosition() const
-{
- return d->counterPos;
-}
-
-void KoTextBlockData::setLabelFormat(const QTextCharFormat &format)
-{
- d->labelFormat = format;
-}
-
-QTextCharFormat KoTextBlockData::labelFormat() const
-{
- return d->labelFormat;
-}
-
-KoTextBlockBorderData *KoTextBlockData::border() const
-{
- return d->border;
-}
-
-void KoTextBlockData::setPaintStrategy(KoTextBlockPaintStrategyBase *paintStrategy)
-{
- delete d->paintStrategy;
- d->paintStrategy = paintStrategy;
-}
-
-KoTextBlockPaintStrategyBase *KoTextBlockData::paintStrategy() const
-{
- return d->paintStrategy;
-}
-
-bool KoTextBlockData::saveXmlID() const
-{
- // as suggested by boemann, https://marc.info/?l=calligra-devel&m=132396354701553&w=2
- return d->paintStrategy != 0;
-}
diff --git a/plugins/flake/textshape/kotext/KoTextBlockData.h b/plugins/flake/textshape/kotext/KoTextBlockData.h
deleted file mode 100644
index 6096e3f103..0000000000
--- a/plugins/flake/textshape/kotext/KoTextBlockData.h
+++ /dev/null
@@ -1,224 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006 Thomas Zander <zander@kde.org>
- * Copyright (C) 2011 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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 KOTEXTBLOCKDATA_H
-#define KOTEXTBLOCKDATA_H
-
-#include <QTextBlockUserData>
-
-#include "kritatext_export.h"
-
-class KoTextBlockBorderData;
-class KoTextBlockPaintStrategyBase;
-
-/**
- * This class is used to store properties for KoText layouting inside Qt QTextBlock
- * instances.
- */
-class KRITATEXT_EXPORT KoTextBlockData
-{
-public:
- /**
- * Supplemental data to allow advanced tabs to be used for layout and painting.
- * Qt-Scribe knows only left-tabs and it also only knows tab-positions per paragraph
- * which is not enough for our needs.
- * Using the tabs list we calculated in the layout step, we can emulate
- * all tabs by setting these as left-tabs on scribe prior to the re-layout of the text in the
- * line which is redone at painting time.
- * The tabLength list holds a length for each tab in the line and thus corresponds to the tab
- * positions in the tabs list. We can then calculate the tab to have started the position
- * minus the length and use that to paint special tab attributes.
- */
- struct TabLineData {
- /// the tab positions as set on the QTextOption.setTabArray()
- QList<qreal> tabs;
- /// the length of each tab so we know which area to paint when we want to decorate it.
- QList<qreal> tabLength;
- };
-
- /**
- * Datastructure to define a range of characters assigned a temporary meaning.
- * Common use cases are spellchecking and grammar.
- */
- struct MarkupRange {
- int firstChar;
- int lastChar;
- qreal startX;
- qreal endX;
- };
-
- /**
- * The different types of markups.
- */
- enum MarkupType {
- Misspell,
- Grammar
- };
-
- explicit KoTextBlockData(QTextBlock &block);
- explicit KoTextBlockData(QTextBlockUserData *userData);
- virtual ~KoTextBlockData();
-
- /**
- * Add a range to the _end_ of the list of markups. It's important that firstChar is after
- * lastChar of the previous range for that type of markup.
- */
- void appendMarkup(MarkupType type, int firstChar, int lastChar);
-
- /**
- * Clear all ranges for a specific type of markup.
- */
- void clearMarkups(MarkupType type);
-
- /**
- * Move all ranges following fromPosition delta number of characters to the right.
- * Applies to a specific type of markup.
- */
- void rebaseMarkups(MarkupType type, int fromPosition, int delta);
-
- /**
- * Find a range that contains positionWithin.
- * If none is found a default Markuprange firstChar = lastChar = 0 is returned
- */
- MarkupRange findMarkup(MarkupType type, int positionWithin) const;
-
- void setMarkupsLayoutValidity(MarkupType type, bool valid);
- bool isMarkupsLayoutValid(MarkupType type) const;
-
- QList<MarkupRange>::Iterator markupsBegin(MarkupType type);
- QList<MarkupRange>::Iterator markupsEnd(MarkupType type);
-
- /**
- * Clear the counter and set everything to default values.
- */
- void clearCounter();
-
- /// return if this block has up-to-date counter data
- bool hasCounterData() const;
- /// return the width (in pt) of the counter.
- qreal counterWidth() const;
- /// set the width of the counter in pt.
- void setCounterWidth(qreal width);
- /// return the spacing (in pt) between the counter and the text
- qreal counterSpacing() const;
- /// set the spacing (in pt) between the counter and the text
- void setCounterSpacing(qreal spacing);
-
- /** sets the index that is used at this level.
- * If this represents a paragraph with counter 3.1, then the text is the 1.
- * If this represents a paragraph with counter IV.V, then the index is 5.
- */
- void setCounterIndex(int index);
- /// returns the index for the counter at this level
- int counterIndex() const;
-
- /// return the exact text that will be painted as the counter
- QString counterText() const;
-
- /**
- * set the text that is used for the counter at this level. the text is formatted
- * depending on the language/style.
- * If this represents a parag with counter 3.1 then the text is the '1'..
- * If this represents a paragraph with counter IV.V, then the text is V.
- * since the rest is not dependent on this parag, but only its location in the text
- *
- */
- void setPartialCounterText(const QString &text);
- /// return the partial text for this paragraphs counter
- QString partialCounterText() const;
-
- /// set the plain counter text which equals the counterText minus prefix and sufix
- void setCounterPlainText(const QString &text);
- /// return the plain counter text which equals the counterText minus prefix and sufix
- QString counterPlainText() const;
-
- void setCounterPrefix(const QString &text);
- QString counterPrefix() const;
-
- void setCounterSuffix(const QString &text);
- QString counterSuffix() const;
-
- /// Set if the counter is a image or not
- void setCounterIsImage(bool isImage);
-
- /// return if the counter is a image or not
- bool counterIsImage() const;
-
- /**
- * The actual position of the counter can be set, in actual (text) document coordinates.
- * @param position the location of the top/left of the counter text line.
- */
- void setCounterPosition(const QPointF &position);
- /**
- * Return the counter position.
- * @see setCounterPosition
- */
- QPointF counterPosition() const;
-
- /**
- * Sets a textformat to be used for the counter/bullet
- * @param font the format
- */
- void setLabelFormat(const QTextCharFormat &format);
-
- /**
- * Return the format to be used for the counter/bullet
- */
- QTextCharFormat labelFormat() const;
-
- /**
- * When a paragraph has a border, it will have a KoTextBlockBorderData instance.
- * Adding the border will increase the refcount.
- * @param border the border used for this paragraph, or 0 if no border is needed (anymore).
- */
- void setBorder(KoTextBlockBorderData *border);
-
- /**
- * Return the border associated with this paragraph, or 0 if there is no border set.
- */
- KoTextBlockBorderData *border() const;
-
- /**
- * sets a paintStrategy of this paragraph
- * @param paintStrategy the paintStrategy to be used for this paragraph
- */
- void setPaintStrategy(KoTextBlockPaintStrategyBase *paintStrategy);
-
- /**
- * Return the paintStrategy of this paragraph
- */
- KoTextBlockPaintStrategyBase *paintStrategy() const;
-
- /**
- * @brief saveXmlID can be used to determine whether we need to save the xml:id
- * for this text block data object. This is true if the text block data describes
- * animations.
- * @return true of we need to save the xml id, false if not.
- */
- bool saveXmlID() const;
-
-private:
- class Private;
- Private * const d;
-};
-
-Q_DECLARE_METATYPE(QTextBlockUserData*)
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoTextBlockPaintStrategyBase.cpp b/plugins/flake/textshape/kotext/KoTextBlockPaintStrategyBase.cpp
deleted file mode 100644
index 902688a5c1..0000000000
--- a/plugins/flake/textshape/kotext/KoTextBlockPaintStrategyBase.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2010 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2010 Thomas Zander <zander@kde.org>
- *
- * 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 "KoTextBlockPaintStrategyBase.h"
-
-#include <QBrush>
-
-KoTextBlockPaintStrategyBase::KoTextBlockPaintStrategyBase()
-{
-}
-
-KoTextBlockPaintStrategyBase::~KoTextBlockPaintStrategyBase()
-{
-}
-
-QBrush KoTextBlockPaintStrategyBase::background(const QBrush &defaultBackground) const
-{
- return defaultBackground;
-}
-
-void KoTextBlockPaintStrategyBase::applyStrategy(QPainter *)
-{
-}
-
-bool KoTextBlockPaintStrategyBase::isVisible() const
-{
- return true;
-}
diff --git a/plugins/flake/textshape/kotext/KoTextBlockPaintStrategyBase.h b/plugins/flake/textshape/kotext/KoTextBlockPaintStrategyBase.h
deleted file mode 100644
index cc725789c7..0000000000
--- a/plugins/flake/textshape/kotext/KoTextBlockPaintStrategyBase.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2010 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2010 Thomas Zander <zander@kde.org>
- *
- * 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 KOTEXTBLOCKPAINTSTRATEGYBASE_H
-#define KOTEXTBLOCKPAINTSTRATEGYBASE_H
-
-#include "kritatext_export.h"
-
-class QPainter;
-class QBrush;
-
-/**
- * This class is used to control aspects of textblock painting
- * Which is used when KPresenter animates text.
- */
-class KRITATEXT_EXPORT KoTextBlockPaintStrategyBase
-{
-public:
- KoTextBlockPaintStrategyBase();
- virtual ~KoTextBlockPaintStrategyBase();
- /// returns a background for the block, the default implementation returns the defaultBackground
- virtual QBrush background(const QBrush &defaultBackground) const;
- /// A strategy implementing this class can apply its settings by modifying the \a painter
- virtual void applyStrategy(QPainter *painter);
- /// Returns true if the block should be painted at all or false when it should be skipped
- virtual bool isVisible() const;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoTextCommandBase.cpp b/plugins/flake/textshape/kotext/KoTextCommandBase.cpp
deleted file mode 100644
index cdaa205e22..0000000000
--- a/plugins/flake/textshape/kotext/KoTextCommandBase.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2011 Boudewijn Rempt <boud@kde.org>
- *
- * 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 "KoTextCommandBase.h"
-
-
-KoTextCommandBase::KoTextCommandBase(KUndo2Command *parent)
- : KUndo2Command(parent)
- , m_tool(0)
-{
-}
-
-KoTextCommandBase::~KoTextCommandBase()
-{
-}
-
-
-void KoTextCommandBase::redo()
-{
- KUndo2Command::redo();
- if (m_tool) {
- m_tool->setAddUndoCommandAllowed(false);
- }
-}
-
-void KoTextCommandBase::setTool(KoUndoableTool *tool) {
- m_tool = tool;
-}
-
-
-void KoTextCommandBase::undo()
-{
- KUndo2Command::undo();
- if (m_tool) {
- m_tool->setAddUndoCommandAllowed(false);
- }
-}
-
-void KoTextCommandBase::setAllow(bool set)
-{
- if (m_tool) {
- m_tool->setAddUndoCommandAllowed(set);
- }
-}
-
-KoTextCommandBase::UndoRedoFinalizer::~UndoRedoFinalizer()
-{
- if (m_parent) {
- m_parent->setAllow(true);
- }
-}
diff --git a/plugins/flake/textshape/kotext/KoTextCommandBase.h b/plugins/flake/textshape/kotext/KoTextCommandBase.h
deleted file mode 100644
index 3c060f8cfe..0000000000
--- a/plugins/flake/textshape/kotext/KoTextCommandBase.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2011 Boudewijn Rempt <boud@kde.org>
- *
- * 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_TEXT_COMMAND_BASE_H
-#define KO_TEXT_COMMAND_BASE_H
-
-#include <kundo2command.h>
-
-#include "kritatext_export.h"
-
-class KRITATEXT_EXPORT KoUndoableTool {
-public:
- virtual ~KoUndoableTool(){}
- virtual void setAddUndoCommandAllowed(bool allowed) = 0;
-};
-
-/**
- * Base class for all commands that work together with a tool that needs to handle undo/redo
- * in a tricky way.
- * Due to the fact that QTextDocument has its own undo queue we need to do some trickery
- * to integrate that into the apps.
- * If your command in some way changes the document, it will create unwanted undo commands in the undoStack
- * unless you inherit from this class and simply implement your undo and redo like this:
-@code
-void MyCommand::redo() {
- TextCommandBase::redo();
- UndoRedoFinalizer finalizer(m_tool);
- // rest code
-}
-
-void MyCommand::undo() {
- TextCommandBase::undo();
- UndoRedoFinalizer finalizer(m_tool);
- // rest code
-}
-@endcode
- * @see TextTool::addCommand()
- */
-class KRITATEXT_EXPORT KoTextCommandBase : public KUndo2Command
-{
-public:
-
- /// constructor
- explicit KoTextCommandBase(KUndo2Command *parent);
- ~KoTextCommandBase() override;
-
- /// method called by the tool.
- void setTool(KoUndoableTool *tool);
-
- // reimplemented from KUndo2Command
- void redo() override;
- // reimplemented from KUndo2Command
- void undo() override;
-
- /// Sets the m_allowAddUndoCommand of the associated tool
- void setAllow(bool set);
-
-protected:
-
- class KRITATEXT_EXPORT UndoRedoFinalizer
- {
- public:
- explicit UndoRedoFinalizer(KoTextCommandBase* parent) : m_parent(parent) {}
- ~UndoRedoFinalizer();
- private:
- KoTextCommandBase* m_parent;
- };
-
- KoUndoableTool *m_tool;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoTextDebug.cpp b/plugins/flake/textshape/kotext/KoTextDebug.cpp
deleted file mode 100644
index 78a37cb4a0..0000000000
--- a/plugins/flake/textshape/kotext/KoTextDebug.cpp
+++ /dev/null
@@ -1,999 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 Elvis Stansvik <elvstone@gmail.com>
- *
- * 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 "KoTextDebug.h"
-
-#include <QTextDocument>
-#include <QTextDocumentFragment>
-#include <QTextFrame>
-#include <QTextBlock>
-#include <QTextTable>
-#include <QTextFragment>
-#include <QTextList>
-#include <QTextStream>
-#include <QTextCursor>
-
-#include "styles/KoParagraphStyle.h"
-#include "styles/KoCharacterStyle.h"
-#include "styles/KoListStyle.h"
-#include "styles/KoTableStyle.h"
-#include "styles/KoTableCellStyle.h"
-#include "styles/KoStyleManager.h"
-#include "KoTextDocument.h"
-#include "KoTextBlockData.h"
-#include <KoInlineTextObjectManager.h>
-#include <KoInlineNote.h>
-#include <KoImageData.h>
-
-#define PARAGRAPH_BORDER_DEBUG
-
-int KoTextDebug::depth = 0;
-const int KoTextDebug::INDENT = 2;
-const QTextDocument *KoTextDebug::document = 0;
-
-#define dumpIndent(T) { for (int i=0; i<T; ++i) out << ' '; }
-#define dumpList(T) { foreach (const QString &x, T) out << x << ' '; }
-
-Q_DECLARE_METATYPE(QList<KoText::Tab>)
-
-static QString fontProperties(const QTextCharFormat &textFormat)
-{
- QMap<int, QVariant> properties = textFormat.properties();
- QStringList fontProps;
- // add only font properties here
- Q_FOREACH (int id, properties.keys()) {
- QString key, value;
- switch (id) {
- case QTextFormat::FontFamily:
- fontProps.append(properties[id].toString());
- break;
- case QTextFormat::FontPointSize:
- fontProps.append(QString("%1pt").arg(properties[id].toDouble()));
- break;
- case QTextFormat::FontSizeAdjustment:
- fontProps.append(QString("%1adj").arg(properties[id].toDouble()));
- break;
- case QTextFormat::FontWeight:
- fontProps.append(QString("weight %1").arg(properties[id].toInt()));
- break;
- case QTextFormat::FontItalic:
- fontProps.append(properties[id].toBool() ? "italic" : "non-italic");
- break;
- case QTextFormat::FontPixelSize:
- fontProps.append(QString("%1px").arg(properties[id].toDouble()));
- break;
- case QTextFormat::FontFixedPitch:
- fontProps.append(properties[id].toBool() ? "fixedpitch" : "varpitch");
- break;
- case QTextFormat::FontCapitalization:
- fontProps.append(QString("caps %1").arg(properties[id].toInt()));
- break;
- case KoCharacterStyle::FontCharset:
- fontProps.append(properties[id].toString());
- break;
- case QTextFormat::FontStyleHint:
- fontProps.append(QString::number(properties[id].toInt()));
- break;
- case QTextFormat::FontKerning:
- fontProps.append(QString("kerning %1").arg(properties[id].toInt()));
- break;
- default:
- break;
- }
- }
- return fontProps.join(",");
-}
-
-void KoTextDebug::dumpDocument(const QTextDocument *doc, QTextStream &out)
-{
- Q_ASSERT(doc);
- document = doc;
- out << QString("<document defaultfont=\"%1\">").arg(doc->defaultFont().toString());
- dumpFrame(document->rootFrame(), out);
- out << "</document>";
- document = 0;
-}
-
-QString KoTextDebug::textAttributes(const KoCharacterStyle &style)
-{
- QTextCharFormat format;
- style.applyStyle(format);
- return textAttributes(format);
-}
-
-QString KoTextDebug::inlineObjectAttributes(const QTextCharFormat &textFormat)
-{
- QString attrs;
-
- if (textFormat.objectType() == QTextFormat::UserObject + 1) {
- KoInlineTextObjectManager *inlineObjectManager = KoTextDocument(document).inlineTextObjectManager();
- KoInlineObject *inlineObject = inlineObjectManager->inlineTextObject(textFormat);
- if (KoInlineNote *note = dynamic_cast<KoInlineNote *>(inlineObject)) {
- attrs.append(QString(" id=\"%1\"").arg(note->id()));
- if (note->type() == KoInlineNote::Footnote) {
- attrs.append(" type=\"footnote\"");
- } else if (note->type() == KoInlineNote::Endnote) {
- attrs.append(" type=\"endnote\"");
- }
- attrs.append(QString(" label=\"%1\"").arg(note->label()));
- } else {
- attrs.append(" type=\"inlineobject\">");
- }
- }
-
- return attrs;
-}
-
-QString KoTextDebug::textAttributes(const QTextCharFormat &textFormat)
-{
- QString attrs;
-
- QTextImageFormat imageFormat = textFormat.toImageFormat();
-
- if (imageFormat.isValid()) {
- attrs.append(" type=\"image\">");
- return attrs;
- }
-
- KoStyleManager *styleManager = document ? KoTextDocument(document).styleManager() : 0;
- if (styleManager && textFormat.hasProperty(KoCharacterStyle::StyleId)) {
- int id = textFormat.intProperty(KoCharacterStyle::StyleId);
- KoCharacterStyle *characterStyle = styleManager->characterStyle(id);
- attrs.append(" characterStyle=\"id:").append(QString::number(id));
- if (characterStyle)
- attrs.append(" name:").append(characterStyle->name());
- attrs.append("\"");
- }
-
- QMap<int, QVariant> properties = textFormat.properties();
- attrs.append(" type=\"char\"");
- QString fontProps = fontProperties(textFormat);
- if (!fontProps.isEmpty())
- attrs.append(QString(" font=\"%1\"").arg(fontProps));
-
- if (textFormat.isAnchor()) {
- attrs.append(QString(" achorHref=\"%1\"").arg(textFormat.anchorHref()));
- attrs.append(QString(" achorName=\"%1\"").arg(textFormat.anchorName()));
- }
-
- Q_FOREACH (int id, properties.keys()) {
- QString key, value;
- switch (id) {
- case QTextFormat::TextOutline: {
- key = "outline";
- QPen pen = qvariant_cast<QPen>(properties[id]);
- if (pen.style() == Qt::NoPen)
- value = "false";
- else
- value = pen.color().name();
- break;
- }
- case KoCharacterStyle::UnderlineStyle:
- key = "underlinestyle";
- value = QString::number(properties[id].toInt());
- break;
- case QTextFormat::TextUnderlineColor:
- key = "underlinecolor";
- value = qvariant_cast<QColor>(properties[id]).name();
- break;
- case KoCharacterStyle::UnderlineType:
- key = "underlinetype";
- value = QString::number(properties[id].toInt());
- break;
- case KoCharacterStyle::UnderlineMode:
- key = "underlinemode";
- value = QString::number(properties[id].toInt());
- break;
- case KoCharacterStyle::UnderlineWeight:
- key = "underlineweight";
- value = QString::number(properties[id].toInt());
- break;
- case KoCharacterStyle::UnderlineWidth:
- key = "underlinewidth";
- value = QString::number(properties[id].toDouble());
- break;
- case KoCharacterStyle::StrikeOutStyle:
- key = "strikeoutstyle";
- value = QString::number(properties[id].toInt());
- break;
- case KoCharacterStyle::StrikeOutColor:
- key = "strikeoutcolor";
- value = qvariant_cast<QColor>(properties[id]).name();
- break;
- case KoCharacterStyle::StrikeOutType:
- key = "strikeouttype";
- value = QString::number(properties[id].toInt());
- break;
- case KoCharacterStyle::StrikeOutMode:
- key = "strikeoutmode";
- value = QString::number(properties[id].toInt());
- break;
- case KoCharacterStyle::StrikeOutWeight:
- key = "strikeoutweight";
- value = QString::number(properties[id].toInt());
- break;
- case KoCharacterStyle::StrikeOutWidth:
- key = "strikeoutwidth";
- value = QString::number(properties[id].toDouble());
- break;
- case QTextFormat::ForegroundBrush:
- key = "foreground";
- value = qvariant_cast<QBrush>(properties[id]).color().name(); // beware!
- break;
- case QTextFormat::BackgroundBrush:
- key = "background";
- value = qvariant_cast<QBrush>(properties[id]).color().name(); // beware!
- break;
- case QTextFormat::BlockAlignment:
- key = "align";
- value = QString::number(properties[id].toInt());
- break;
- case QTextFormat::TextIndent:
- key = "textindent";
- value = QString::number(properties[id].toInt());
- break;
- case QTextFormat::BlockIndent:
- key = "indent";
- value = QString::number(properties[id].toInt());
- break;
- case KoCharacterStyle::Country:
- key = "country";
- value = properties[id].toString();
- break;
- case KoCharacterStyle::Language:
- key = "language";
- value = properties[id].toString();
- break;
- case KoCharacterStyle::HasHyphenation:
- key = "hyphenation";
- value = QString::number(properties[id].toBool());
- break;
- case KoCharacterStyle::StrikeOutText:
- key = "strikeout-text";
- value = properties[id].toString();
- break;
- case KoCharacterStyle::FontCharset:
- key = "font-charset";
- value = properties[id].toString();
- break;
- case KoCharacterStyle::TextRotationAngle:
- key = "rotation-angle";
- value = QString::number(properties[id].toInt());
- break;
- case KoCharacterStyle::TextRotationScale:
- key = "text-rotation-scale";
- value = properties[id].toInt() == KoCharacterStyle::Fixed ? "Fixed" : "LineHeight";
- break;
- case KoCharacterStyle::TextScale:
- key = "text-scale";
- value = QString::number(properties[id].toInt());
- break;
- case KoCharacterStyle::InlineRdf:
- key = "inline-rdf";
- value = QString::number(properties[id].toInt());
- break;
- default:
- key = "unknown"+QString::number(id);
- value = QString::number(properties[id].toInt());
- break;
- }
- if (!key.isEmpty())
- attrs.append(" ").append(key).append("=\"").append(value).append("\"");
- }
- return attrs;
-}
-
-QString KoTextDebug::paraAttributes(const KoParagraphStyle &style)
-{
- QTextBlockFormat format;
- style.applyStyle(format);
- return paraAttributes(format);
-}
-
-QString KoTextDebug::paraAttributes(const QTextBlockFormat &blockFormat)
-{
- QString attrs;
- KoStyleManager *styleManager = document ? KoTextDocument(document).styleManager() : 0;
- if (styleManager && blockFormat.hasProperty(KoParagraphStyle::StyleId)) {
- int id = blockFormat.intProperty(KoParagraphStyle::StyleId);
- KoParagraphStyle *paragraphStyle = styleManager->paragraphStyle(id);
- attrs.append(" paragraphStyle=\"id:").append(QString::number(id));
- if (paragraphStyle)
- attrs.append(" name:").append(paragraphStyle->name());
- attrs.append("\"");
- }
-
- QMap<int, QVariant> properties = blockFormat.properties();
- Q_FOREACH (int id, properties.keys()) {
- QString key, value;
- switch (id) {
- // the following are 'todo'
- case KoParagraphStyle::PercentLineHeight:
- case KoParagraphStyle::FixedLineHeight:
- case KoParagraphStyle::MinimumLineHeight:
- case KoParagraphStyle::LineSpacing:
- case KoParagraphStyle::LineSpacingFromFont:
- case KoParagraphStyle::AlignLastLine:
- case KoParagraphStyle::WidowThreshold:
- case KoParagraphStyle::OrphanThreshold:
- case KoParagraphStyle::DropCapsTextStyle:
- case KoParagraphStyle::FollowDocBaseline:
- case KoParagraphStyle::HasLeftBorder:
- case KoParagraphStyle::HasTopBorder:
- case KoParagraphStyle::HasRightBorder:
- case KoParagraphStyle::HasBottomBorder:
- case KoParagraphStyle::BorderLineWidth:
- case KoParagraphStyle::SecondBorderLineWidth:
- case KoParagraphStyle::DistanceToSecondBorder:
- case KoParagraphStyle::LeftPadding:
- case KoParagraphStyle::TopPadding:
- case KoParagraphStyle::RightPadding:
- case KoParagraphStyle::BottomPadding:
- case KoParagraphStyle::LeftBorderColor:
- case KoParagraphStyle::TopInnerBorderWidth:
- case KoParagraphStyle::TopBorderSpacing:
- case KoParagraphStyle::TopBorderStyle:
- case KoParagraphStyle::TopBorderColor:
- case KoParagraphStyle::RightInnerBorderWidth:
- case KoParagraphStyle::RightBorderSpacing:
- case KoParagraphStyle::RightBorderStyle:
- case KoParagraphStyle::RightBorderColor:
- case KoParagraphStyle::BottomInnerBorderWidth:
- case KoParagraphStyle::BottomBorderSpacing:
- case KoParagraphStyle::BottomBorderStyle:
- case KoParagraphStyle::BottomBorderColor:
- case KoParagraphStyle::ListStyleId:
- case KoParagraphStyle::ListStartValue:
- case KoParagraphStyle::RestartListNumbering:
- case KoParagraphStyle::TextProgressionDirection:
- case KoParagraphStyle::MasterPageName:
- case KoParagraphStyle::OutlineLevel:
- break;
- case KoParagraphStyle::AutoTextIndent:
- key = "autotextindent";
- value = properties[id].toBool() ? "true" : "false" ;
- break;
-#ifdef PARAGRAPH_BORDER_DEBUG // because it tends to get annoyingly long :)
- case KoParagraphStyle::LeftBorderWidth:
- key = "border-width-left";
- value = QString::number(properties[id].toDouble()) ;
- break;
- case KoParagraphStyle::TopBorderWidth:
- key = "border-width-top";
- value = QString::number(properties[id].toDouble()) ;
- break;
- case KoParagraphStyle::RightBorderWidth:
- key = "border-width-right";
- value = QString::number(properties[id].toDouble()) ;
- break;
- case KoParagraphStyle::BottomBorderWidth:
- key = "border-width-bottom";
- value = QString::number(properties[id].toDouble()) ;
- break;
- case KoParagraphStyle::LeftBorderStyle:
- key = "border-style-left";
- value = QString::number(properties[id].toDouble()) ;
- break;
- case KoParagraphStyle::LeftBorderSpacing:
- key = "inner-border-spacing-left";
- value = QString::number(properties[id].toDouble()) ;
- break;
- case KoParagraphStyle::LeftInnerBorderWidth:
- key = "inner-border-width-left";
- value = QString::number(properties[id].toDouble()) ;
- break;
-#endif
- case KoParagraphStyle::TabStopDistance:
- key = "tab-stop-distance";
- value = QString::number(properties[id].toDouble());
- break;
- case KoParagraphStyle::TabPositions:
- key = "tab-stops";
- value.clear();
- Q_FOREACH (const QVariant & qvtab, qvariant_cast<QList<QVariant> >(properties[id])) {
- KoText::Tab tab = qvtab.value<KoText::Tab>();
- value.append("{");
- value.append(" pos:").append(QString::number(tab.position));
- value.append(" type:").append(QString::number(tab.type));
- if (! tab.delimiter.isNull())
- value.append(" delim:").append(QString(tab.delimiter));
- value.append(" leadertype:").append(QString::number(tab.leaderType));
- value.append(" leaderstyle:").append(QString::number(tab.leaderStyle));
- value.append(" leaderweight:").append(QString::number(tab.leaderWeight));
- value.append(" leaderwidth:").append(QString().setNum(tab.leaderWidth));
- value.append(" leadercolor:").append(tab.leaderColor.name());
- if (! tab.leaderText.isEmpty())
- value.append(" leadertext:").append(QString(tab.leaderText));
- value.append("}, ");
- }
- break;
- case KoParagraphStyle::DropCaps:
- key = "drop-caps";
- value = QString::number(properties[id].toBool());
- break;
- case KoParagraphStyle::DropCapsLines:
- key = "drop-caps-lines";
- value = QString::number(properties[id].toInt());
- break;
- case KoParagraphStyle::DropCapsLength:
- key = "drop-caps-length";
- value = QString::number(properties[id].toInt());
- break;
- case KoParagraphStyle::DropCapsDistance:
- key = "drop-caps-distance";
- value = QString::number(properties[id].toDouble());
- break;
- case QTextFormat::BlockBottomMargin:
- value = QString::number(properties[id].toDouble());
- if (value != "0")
- key = "block-bottom-margin";
- break;
- case QTextFormat::BlockTopMargin:
- value = QString::number(properties[id].toDouble());
- if (value != "0")
- key = "block-top-margin";
- break;
- case QTextFormat::BlockLeftMargin:
- value = QString::number(properties[id].toDouble());
- if (value != "0")
- key = "block-left-margin";
- break;
- case QTextFormat::BlockRightMargin:
- value = QString::number(properties[id].toDouble());
- if (value != "0")
- key = "block-right-margin";
- break;
- case KoParagraphStyle::UnnumberedListItem:
- key = "unnumbered-list-item";
- value = QString::number(properties[id].toBool());
- break;
- case KoParagraphStyle::IsListHeader:
- key = "list-header";
- value = '1';
- break;
- case KoParagraphStyle::ListLevel:
- key = "list-level";
- value = QString::number(properties[id].toInt());
- break;
- default:
- break;
- }
- if (!key.isEmpty())
- attrs.append(" ").append(key).append("=\"").append(value).append("\"");
- }
- return attrs;
-}
-
-QString KoTextDebug::listAttributes(const QTextListFormat &listFormat)
-{
- QString attrs;
- KoStyleManager *styleManager = document ? KoTextDocument(document).styleManager() : 0;
- if (styleManager && listFormat.hasProperty(KoListStyle::StyleId)) {
- int id = listFormat.intProperty(KoListStyle::StyleId);
- KoListStyle *listStyle = styleManager->listStyle(id);
- attrs.append(" listStyle=\"id:").append(QString::number(id));
- if (listStyle)
- attrs.append(" name:").append(listStyle->name());
- attrs.append("\"");
- }
-
- QMap<int, QVariant> properties = listFormat.properties();
- Q_FOREACH (int id, properties.keys()) {
- QString key, value;
- switch (id) {
- case QTextListFormat::ListStyle:
- key = "type";
- value = QString::number(properties[id].toInt());
- break;
- case QTextListFormat::ListIndent:
- key = "indent";
- value = QString::number(properties[id].toDouble());
- break;
- case KoListStyle::ListItemPrefix:
- key = "prefix";
- value = properties[id].toString();
- break;
- case KoListStyle::ListItemSuffix:
- key = "suffix";
- value = properties[id].toString();
- break;
- case KoListStyle::StartValue:
- key = "start-value";
- value = QString::number(properties[id].toInt());
- break;
- case KoListStyle::Level:
- key = "level";
- value = QString::number(properties[id].toInt());
- break;
- case KoListStyle::DisplayLevel:
- key = "display-level";
- value = QString::number(properties[id].toInt());
- break;
- case KoListStyle::Alignment:
- key = "alignment";
- value = QString::number(properties[id].toInt());
- break;
- case KoListStyle::RelativeBulletSize:
- key = "bullet-size";
- value = QString::number(properties[id].toInt());
- break;
- case KoListStyle::BulletCharacter:
- key = "bullet-char";
- value = properties[id].toString();
- break;
- case KoListStyle::LetterSynchronization:
- key = "letter-sync";
- value = QString::number(properties[id].toInt());
- break;
- case KoListStyle::StyleId:
- key = "styleid";
- value = QString::number(properties[id].toInt());
- break;
- case KoListStyle::MinimumWidth:
- key = "minimum-width";
- value = QString::number(properties[id].toDouble());
- break;
- case KoListStyle::ListId:
- key = "list-id";
- value = QString::number(properties[id].toInt());
- break;
- case KoListStyle::IsOutline:
- key = "is-outline";
- value = QString::number(properties[id].toBool());
- break;
- case KoListStyle::Indent:
- key = "indent";
- value = QString::number(properties[id].toInt());
- break;
- case KoListStyle::MinimumDistance:
- key = "minimum-distance";
- value = QString::number(properties[id].toDouble());
- break;
- case KoListStyle::Width:
- key = "width";
- value = QString::number(properties[id].toDouble());
- break;
- case KoListStyle::Height:
- key = "height";
- value = QString::number(properties[id].toDouble());
- break;
- case KoListStyle::BulletImage:
- key = "bullet-image";
- value = QString::number((quintptr)(properties[id].value<KoImageData*>()));
- break;
- case KoListStyle::Margin:
- key="margin-left";
- value =QString::number(properties[id].toInt());
- break;
- case KoListStyle::TextIndent:
- key="text-indent";
- value =QString::number(properties[id].toInt());
- break;
- case KoListStyle::AlignmentMode:
- key="label-alignment";
- value=QString(properties[id].toBool()? "true":"false");
- break;
- case KoListStyle::LabelFollowedBy:
- key="label-followed-by";
- value =QString::number(properties[id].toInt());
- break;
- case KoListStyle::TabStopPosition:
- key="tab-stop-position";
- value =QString::number(properties[id].toInt());
- break;
- default:
- break;
- }
- if (!key.isEmpty())
- attrs.append(" ").append(key).append("=\"").append(value).append("\"");
- }
- return attrs;
-}
-
-QString KoTextDebug::tableAttributes(const KoTableStyle &tableStyle)
-{
- QTextTableFormat format;
- tableStyle.applyStyle(format);
- return tableAttributes(format);
-}
-
-QString KoTextDebug::tableAttributes(const QTextTableFormat &tableFormat)
-{
- QString attrs;
- KoStyleManager *styleManager = document ? KoTextDocument(document).styleManager() : 0;
- if (styleManager) {
- int id = tableFormat.intProperty(KoTableStyle::StyleId);
- KoTableStyle *tableStyle = styleManager->tableStyle(id);
- attrs.append(" tableStyle=\"id:").append(QString::number(id));
- if (tableStyle)
- attrs.append(" name:").append(tableStyle->name());
- attrs.append("\"");
- }
-
- QMap<int, QVariant> properties = tableFormat.properties();
- Q_FOREACH (int id, properties.keys()) {
- QString key, value;
- switch (id) {
- case QTextTableFormat::TableColumnWidthConstraints:
- case QTextFormat::BackgroundBrush:
- key = "background";
- value = qvariant_cast<QBrush>(properties[id]).color().name(); // beware!
- break;
- case QTextFormat::BlockAlignment:
- key = "alignment";
- switch (properties[id].toInt()) {
- case Qt::AlignLeft:
- value = "left";
- break;
- case Qt::AlignRight:
- value = "right";
- break;
- case Qt::AlignHCenter:
- value = "center";
- break;
- case Qt::AlignJustify:
- value = "justify";
- break;
- default:
- value.clear();
- break;
- }
- break;
- case KoTableStyle::KeepWithNext:
- key = "keep-with-next";
- value = properties[id].toBool() ? "true" : "false";
- break;
- case KoTableStyle::BreakBefore:
- key = "break-before";
- value = properties[id].toBool() ? "true" : "false";
- break;
- case KoTableStyle::BreakAfter:
- key = "break-after";
- value = properties[id].toBool() ? "true" : "false";
- break;
- case KoTableStyle::MayBreakBetweenRows:
- key = "may-break-between-rows";
- value = properties[id].toBool() ? "true" : "false";
- break;
- case KoTableStyle::MasterPageName:
- key = "master-page-name";
- value = properties[id].toString();
- break;
- case QTextTableFormat::TableColumns:
- key = "columns";
- value = QString::number(properties[id].toInt());
- break;
- case QTextTableFormat::TableCellSpacing:
- key = "cell-spacing";
- value = QString::number(properties[id].toDouble());
- break;
- case QTextTableFormat::TableHeaderRowCount:
- key = "header-row-count";
- value = QString::number(properties[id].toInt());
- break;
- default:
- break;
- }
- if (!key.isEmpty())
- attrs.append(" ").append(key).append("=\"").append(value).append("\"");
- }
- return attrs;
-}
-
-QString KoTextDebug::frameAttributes(const QTextFrameFormat &frameFormat)
-{
- QString attrs;
-
- QMap<int, QVariant> properties = frameFormat.properties();
- Q_FOREACH (int id, properties.keys()) {
- QString key, value;
- switch (id) {
- case QTextFrameFormat::FrameBorderBrush:
- break;
- case QTextFrameFormat::FrameBorderStyle:
- key = "border-style";
- // determine border style.
- switch (properties[id].toInt()) {
- case QTextFrameFormat::BorderStyle_None:
- value = "None";
- break;
- case QTextFrameFormat::BorderStyle_Dotted:
- value = "Dotted";
- break;
- case QTextFrameFormat::BorderStyle_Dashed:
- value = "Dashed";
- break;
- case QTextFrameFormat::BorderStyle_Solid:
- value = "Solid";
- break;
- case QTextFrameFormat::BorderStyle_Double:
- value = "Double";
- break;
- case QTextFrameFormat::BorderStyle_DotDash:
- value = "DotDash";
- break;
- case QTextFrameFormat::BorderStyle_DotDotDash:
- value = "DotDotDash";
- break;
- case QTextFrameFormat::BorderStyle_Groove:
- value = "Groove";
- break;
- case QTextFrameFormat::BorderStyle_Ridge:
- value = "Ridge";
- break;
- case QTextFrameFormat::BorderStyle_Inset:
- value = "Inset";
- break;
- case QTextFrameFormat::BorderStyle_Outset:
- value = "Outset";
- break;
- default:
- value = "Unknown";
- break;
- }
- break;
- case QTextFrameFormat::FrameBorder:
- key = "border";
- value = QString::number(properties[id].toDouble());
- break;
- case QTextFrameFormat::FrameMargin:
- key = "margin";
- value = QString::number(properties[id].toDouble());
- break;
- case QTextFrameFormat::FramePadding:
- key = "padding";
- value = QString::number(properties[id].toDouble());
- break;
- case QTextFrameFormat::FrameWidth:
- key = "width";
- value = QString::number(properties[id].toDouble());
- break;
- case QTextFrameFormat::FrameHeight:
- key = "height";
- value = QString::number(properties[id].toDouble());
- break;
- case QTextFrameFormat::FrameTopMargin:
- key = "top-margin";
- value = QString::number(properties[id].toDouble());
- break;
- case QTextFrameFormat::FrameBottomMargin:
- key = "bottom-margin";
- value = QString::number(properties[id].toDouble());
- break;
- case QTextFrameFormat::FrameLeftMargin:
- key = "left-margin";
- value = QString::number(properties[id].toDouble());
- break;
- case QTextFrameFormat::FrameRightMargin:
- key = "right-margin";
- value = QString::number(properties[id].toDouble());
- break;
- default:
- break;
- }
- if (!key.isEmpty())
- attrs.append(" ").append(key).append("=\"").append(value).append("\"");
- }
- return attrs;
-}
-
-QString KoTextDebug::tableCellAttributes(const KoTableCellStyle &tableCellStyle)
-{
- QTextTableCellFormat format;
- tableCellStyle.applyStyle(format);
- return tableCellAttributes(format);
-}
-
-QString KoTextDebug::tableCellAttributes(const QTextTableCellFormat &tableCellFormat)
-{
- QString attrs;
- KoStyleManager *styleManager = document ? KoTextDocument(document).styleManager() : 0;
- if (styleManager) {
- int id = tableCellFormat.intProperty(KoTableCellStyle::StyleId);
- KoTableCellStyle *tableCellStyle = styleManager->tableCellStyle(id);
- attrs.append(" tableCellStyle=\"id:").append(QString::number(id));
- if (tableCellStyle)
- attrs.append(" name:").append(tableCellStyle->name());
- attrs.append("\"");
- }
-
- QMap<int, QVariant> properties = tableCellFormat.properties();
- Q_FOREACH (int id, properties.keys()) {
- QString key, value;
- switch (id) {
- case QTextTableCellFormat::TableCellRowSpan:
- key = "row-span";
- value = QString::number(properties[id].toInt());
- break;
- case QTextTableCellFormat::TableCellColumnSpan:
- key = "column-span";
- value = QString::number(properties[id].toInt());
- break;
- case QTextFormat::TableCellTopPadding:
- key = "top-padding";
- value = QString::number(properties[id].toDouble());
- break;
- case QTextFormat::TableCellBottomPadding:
- key = "bottom-padding";
- value = QString::number(properties[id].toDouble());
- break;
- case QTextFormat::TableCellLeftPadding:
- key = "left-padding";
- value = QString::number(properties[id].toDouble());
- break;
- case QTextFormat::TableCellRightPadding:
- key = "right-padding";
- value = QString::number(properties[id].toDouble());
- break;
- case KoTableCellStyle::MasterPageName:
- key = "master-page-name";
- value = properties[id].toString();
- break;
- default:
- break;
- }
- if (!key.isEmpty())
- attrs.append(" ").append(key).append("=\"").append(value).append("\"");
- }
- return attrs;
-}
-
-void KoTextDebug::dumpFrame(const QTextFrame *frame, QTextStream &out)
-{
- depth += INDENT;
-
- dumpIndent(depth);
- out << "<frame" << frameAttributes(frame->frameFormat()) << '>' << endl;
-
- QTextFrame::iterator iterator = frame->begin();
-
- for (; !iterator.atEnd(); ++iterator) {
- QTextFrame *childFrame = iterator.currentFrame();
- QTextBlock textBlock = iterator.currentBlock();
-
- if (childFrame) {
- QTextTable *table = qobject_cast<QTextTable *>(childFrame);
- if (table) {
- dumpTable(table, out);
- } else {
- dumpFrame(frame, out);
- }
- } else if (textBlock.isValid()) {
- dumpBlock(textBlock, out);
- }
- }
-
- dumpIndent(depth);
- out << "</frame>" << endl;
- depth -= INDENT;
-}
-
-void KoTextDebug::dumpBlock(const QTextBlock &block, QTextStream &out)
-{
- depth += INDENT;
-
- QString attrs;
- attrs.append(paraAttributes(block.blockFormat()));
- //attrs.append(" blockcharformat=\"").append(textAttributes(QTextCursor(block).blockCharFormat())).append('\"');
- attrs.append(textAttributes(QTextCursor(block).blockCharFormat()));
-
- QTextList *list = block.textList();
- if (list) {
- attrs.append(" list=\"item:").append(QString::number(list->itemNumber(block) + 1)).append('/')
- .append(QString::number(list->count()));
- attrs.append('"');
- attrs.append(listAttributes(list->format()));
- }
-
- dumpIndent(depth);
- out << "<block" << attrs << '>' << endl;
-
- QTextBlock::Iterator iterator = block.begin();
- for (; !iterator.atEnd(); ++iterator) {
- QTextFragment fragment = iterator.fragment();
- if (fragment.isValid()) {
- dumpFragment(fragment, out);
- }
- }
- dumpIndent(depth);
- out << "</block>" << endl;
- depth -= INDENT;
- if (block.next().isValid())
- out << ' ';
-}
-
-void KoTextDebug::dumpTable(const QTextTable *table, QTextStream &out)
-{
- depth += INDENT;
-
- QString attrs;
- attrs.append(tableAttributes(table->format()));
- attrs.append(frameAttributes(table->frameFormat())); // include frame attributes too.
-
- dumpIndent(depth);
- out << "<table" << attrs << '>' << endl;
-
- // loop through all the cells in the table and dump the cells.
- for (int row = 0; row < table->rows(); ++row) {
- for (int column = 0; column < table->columns(); ++column) {
- dumpTableCell(table->cellAt(row, column), out);
- }
- }
-
- dumpIndent(depth);
- out << "</table>" << endl;
- depth -= INDENT;
-}
-
-void KoTextDebug::dumpTableCell(const QTextTableCell &cell, QTextStream &out)
-{
- depth += INDENT;
-
- QString attrs;
- attrs.append(textAttributes(cell.format()));
- attrs.append(tableCellAttributes(cell.format().toTableCellFormat()));
-
- dumpIndent(depth);
- out << "<cell" << attrs << '>' << endl;
-
- // iterate through the cell content.
- QTextFrame::iterator cellIter = cell.begin();
- while (!cellIter.atEnd()) {
- if (cellIter.currentFrame() != 0) {
- // content is a frame or table.
- dumpFrame(cellIter.currentFrame(), out);
- } else {
- // content is a block.
- dumpBlock(cellIter.currentBlock(), out);
- }
- ++cellIter;
- }
-
- dumpIndent(depth);
- out << "</cell>\n";
-
- depth -= INDENT;
-}
-
-void KoTextDebug::dumpFragment(const QTextFragment &fragment, QTextStream &out)
-{
- depth += INDENT;
-
- QTextCharFormat charFormat = fragment.charFormat();
- KoInlineObject *inlineObject = KoTextDocument(document).inlineTextObjectManager()->inlineTextObject(charFormat);
- if (inlineObject) {
- QString cf = inlineObjectAttributes(charFormat);
-
- dumpIndent(depth);
- out << "<fragment" << cf << ">\n";
- } else {
- QString cf = textAttributes(charFormat);
-
- dumpIndent(depth);
- out << "<fragment" << cf << ">\n";
- dumpIndent(depth + INDENT);
- out << '|' << fragment.text() << "|\n";
- dumpIndent(depth);
- out << "</fragment>\n";
- }
-
- depth -= INDENT;
-}
-
diff --git a/plugins/flake/textshape/kotext/KoTextDebug.h b/plugins/flake/textshape/kotext/KoTextDebug.h
deleted file mode 100644
index 5be3e0f03a..0000000000
--- a/plugins/flake/textshape/kotext/KoTextDebug.h
+++ /dev/null
@@ -1,293 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 Elvis Stansvik <elvstone@gmail.com>
- *
- * 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 KOTEXTDEBUG_H
-#define KOTEXTDEBUG_H
-
-#include "kritatext_export.h"
-
-class QTextDocument;
-class QTextFrame;
-class QTextBlock;
-class QTextTable;
-class QTextTableCell;
-class QTextFragment;
-class QTextCharFormat;
-class QTextListFormat;
-class QTextTableFormat;
-class QTextTableCellFormat;
-class QTextFrameFormat;
-class QTextBlockFormat;
-class QTextStream;
-class KoParagraphStyle;
-class KoCharacterStyle;
-class KoTableStyle;
-class KoTableCellStyle;
-
-#include <QMap>
-#include <QVariant>
-
-/**
- * @brief KoText debugging class.
- *
- * This class provides a set of public static functions for debugging the structure of
- * QTextDocument text documents. The functions will dump the structure of the document
- * along with any formats in a human-friendly pseudo-XML format.
- *
- * To most top level function is dumpDocument(), which can be used to dump an entire
- * document. In addition to that, there's a set of functions for dumping certain
- * parts of a document , such as dumpFrame(), dumpBlock() et.c.
- *
- * For example, the following code
- *
- * @code
- * QTextDocument doc;
- * QTextCursor cursor(&doc);
- * cursor.insertText("Hello!\n");
- * cursor.insertHtml("<b>World!</b>");
- *
- * QTextStream out(stdout);
- * KoTextDebug::dumpDocument(&doc, out);
- * @endcode
- *
- * will result in this output:
- *
- * @verbatim
- * <document defaultfont="Sans Serif,9,-1,5,50,0,0,0,0,0">
- * <frame margin="4" top-margin="4" bottom-margin="4" left-margin="4" right-margin="4" border-style="Outset">
- * <block type="char">
- * <fragment type="char">
- * |Hello!|
- * </fragment>
- * </block>
- *
- * <block type="char">
- * <fragment type="char" font="weight 75">
- * |World!|
- * </fragment>
- * </block>
- * </frame>
- * </document>
- * @endverbatim
- *
- * @sa dumpDocument(), dumpFrame(), dumpBlock()
- */
-class KRITATEXT_EXPORT KoTextDebug
-{
-public:
- /**
- * Dump the structure of the specified document.
- *
- * @param document a pointer to the document that should be dumped.
- * @param out output stream to dump to.
- */
- static void dumpDocument(const QTextDocument *document, QTextStream &out);
-
- /**
- * Dump the structure of the specified frame.
- *
- * @sa frameAttributes()
- *
- * @param frame a pointer to the frame that should be dumped.
- * @param out output stream to dump to.
- */
- static void dumpFrame(const QTextFrame *frame, QTextStream &out);
-
- /**
- * Dump the structure of the specified block.
- *
- * @param block the block that should be dumped.
- * @param out output stream to dump to.
- */
- static void dumpBlock(const QTextBlock &block, QTextStream &out);
-
- /**
- * Dump the structure of the specified table.
- *
- * @sa tableAttributes()
- *
- * @param table pointer to the table that should be dumped.
- * @param out output stream to dump to.
- */
- static void dumpTable(const QTextTable *table, QTextStream &out);
-
- /**
- * Dump the structure of the specified table cell.
- *
- * @sa tableCellAttributes()
- *
- * @param cell the cell that should be dumped.
- * @param out output stream to dump to.
- */
- static void dumpTableCell(const QTextTableCell &cell, QTextStream &out);
-
- /**
- * Dump the contents of the specified text fragment.
- *
- * @note { The fragment content will be enclosed in '|' characters. }
- *
- * @param fragment the fragment which content should be dumped.
- * @param out output stream to dump to.
- */
- static void dumpFragment(const QTextFragment &fragment, QTextStream &out);
-
- /**
- * Get the properties of the given text character format.
- *
- * The returned string will be formatted in XML-like attribute list format:
- *
- * <pre>"key=value key2=value2 ..."</pre>
- *
- * @param format the text character format from which properties should be fetched.
- * @return the formatted attribute string.
- */
- static QString textAttributes(const QTextCharFormat &format);
-
- /**
- * Get the properties of the given character style.
- *
- * The returned string will be formatted in XML-like attribute list format:
- *
- * <pre>"key=value key2=value2 ..."</pre>
- *
- * @param style the character style from which properties should be fetched.
- * @return the formatted attribute string.
- */
- static QString textAttributes(const KoCharacterStyle &style);
-
- /**
- * Get the properties of the given text block format.
- *
- * The returned string will be formatted in XML-like attribute list format:
- *
- * <pre>"key=value key2=value2 ..."</pre>
- *
- * @param format the text block format from which properties should be fetched.
- * @return the formatted attribute string.
- */
- static QString paraAttributes(const QTextBlockFormat &format);
-
- /**
- * Get the properties of the given paragraph style.
- *
- * The returned string will be formatted in XML-like attribute list format:
- *
- * <pre>"key=value key2=value2 ..."</pre>
- *
- * @param style the paragraph style from which properties should be fetched.
- * @return the formatted attribute string.
- */
- static QString paraAttributes(const KoParagraphStyle &style);
-
- /**
- * Get the properties of the given list format.
- *
- * The returned string will be formatted in XML-like attribute list format:
- *
- * <pre>"key=value key2=value2 ..."</pre>
- *
- * @param format the list format from which properties should be fetched.
- * @return the formatted attribute string.
- */
- static QString listAttributes(const QTextListFormat &format);
-
- /**
- * Get the properties of the given table style.
- *
- * The returned string will be formatted in XML-like attribute list format:
- *
- * <pre>"key=value key2=value2 ..."</pre>
- *
- * @param tableStyle the table style from which properties should be fetched.
- * @return the formatted attribute string.
- */
- static QString tableAttributes(const KoTableStyle &tableStyle);
-
- /**
- * Get the properties of the given table format.
- *
- * The returned string will be formatted in XML-like attribute list format:
- *
- * <pre>"key=value key2=value2 ..."</pre>
- *
- * @param tableFormat the table format from which properties should be fetched.
- * @return the formatted attribute string.
- */
- static QString tableAttributes(const QTextTableFormat &tableFormat);
-
- /**
- * Get the properties of the given table cell style.
- *
- * The returned string will be formatted in XML-like attribute list format:
- *
- * <pre>"key=value key2=value2 ..."</pre>
- *
- * @param tableCellStyle the table cell style from which properties should be fetched.
- * @return the formatted attribute string.
- */
- static QString tableCellAttributes(const KoTableCellStyle &tableCellStyle);
-
- /**
- * Get the properties of the given table cell format.
- *
- * The returned string will be formatted in XML-like attribute list format:
- *
- * <pre>"key=value key2=value2 ..."</pre>
- *
- * @param tableCellFormat the table cell format from which properties should be fetched.
- * @return the formatted attribute string.
- */
- static QString tableCellAttributes(const QTextTableCellFormat &tableCellFormat);
-
- /**
- * Get the properties of the given text frame format.
- *
- * The returned string will be formatted in XML-like attribute list format:
- *
- * <pre>"key=value key2=value2 ..."</pre>
- *
- * @param frameFormat the text frame format from which properties should be fetched.
- * @return the formatted attribute string.
- */
- static QString frameAttributes(const QTextFrameFormat &frameFormat);
-
- /**
- * Get the inline object properties of the object with the given text character format.
- *
- * The returned string will be formatted in XML-like attribute list format:
- *
- * <pre>"key=value key2=value2 ..."</pre>
- *
- * @param textFormat the character format of the object from which properties should be fetched.
- * @return the formatted attribute string.
- */
- static QString inlineObjectAttributes(const QTextCharFormat &textFormat);
-
-private:
- KoTextDebug();
- KoTextDebug(const KoTextDebug&);
- KoTextDebug operator=(const KoTextDebug&);
-
- static const QTextDocument *document; /**< Pointer to the debugged document. */
- static int depth; /**< Current indentation depth. */
- static const int INDENT; /**< Indentation value. */
-};
-
-#endif /* KOTEXTDEBUG_H */
diff --git a/plugins/flake/textshape/kotext/KoTextDocument.cpp b/plugins/flake/textshape/kotext/KoTextDocument.cpp
deleted file mode 100644
index 4514a31769..0000000000
--- a/plugins/flake/textshape/kotext/KoTextDocument.cpp
+++ /dev/null
@@ -1,416 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Pierre Stirnweiss \pierre.stirnweiss_calligra@gadz.org>
- * Copyright (C) 2011-2012 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2014-2015 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 Licen give you se
- * 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 "KoTextDocument.h"
-
-#include <QTextCursor>
-#include <QVariant>
-#include <QVariantList>
-
-#include "TextDebug.h"
-#include <KoTextDebug.h>
-
-#include <kundo2stack.h>
-
-#include "KoText.h"
-#include "KoTextEditor.h"
-#include "styles/KoStyleManager.h"
-#include "OdfTextTrackStyles.h"
-#include "KoTextRangeManager.h"
-#include "KoInlineTextObjectManager.h"
-#include "KoList.h"
-#include "KoOdfLineNumberingConfiguration.h"
-#include "changetracker/KoChangeTracker.h"
-#include <KoShapeController.h>
-#include <KoSectionModel.h>
-
-Q_DECLARE_METATYPE(QAbstractTextDocumentLayout::Selection)
-Q_DECLARE_METATYPE(QTextFrame*)
-Q_DECLARE_METATYPE(QTextCharFormat)
-Q_DECLARE_METATYPE(QTextBlockFormat)
-
-const QUrl KoTextDocument::StyleManagerURL = QUrl("kotext://stylemanager");
-const QUrl KoTextDocument::ListsURL = QUrl("kotext://lists");
-const QUrl KoTextDocument::InlineObjectTextManagerURL = QUrl("kotext://inlineObjectTextManager");
-const QUrl KoTextDocument::TextRangeManagerURL = QUrl("kotext://textRangeManager");
-const QUrl KoTextDocument::UndoStackURL = QUrl("kotext://undoStack");
-const QUrl KoTextDocument::ChangeTrackerURL = QUrl("kotext://changetracker");
-const QUrl KoTextDocument::TextEditorURL = QUrl("kotext://textEditor");
-const QUrl KoTextDocument::LineNumberingConfigurationURL = QUrl("kotext://linenumberingconfiguration");
-const QUrl KoTextDocument::RelativeTabsURL = QUrl("kotext://relativetabs");
-const QUrl KoTextDocument::HeadingListURL = QUrl("kotext://headingList");
-const QUrl KoTextDocument::SelectionsURL = QUrl("kotext://selections");
-const QUrl KoTextDocument::LayoutTextPageUrl = QUrl("kotext://layoutTextPage");
-const QUrl KoTextDocument::ParaTableSpacingAtStartUrl = QUrl("kotext://spacingAtStart");
-const QUrl KoTextDocument::IndexGeneratorManagerUrl = QUrl("kotext://indexGeneratorManager");
-const QUrl KoTextDocument::FrameCharFormatUrl = QUrl("kotext://frameCharFormat");
-const QUrl KoTextDocument::FrameBlockFormatUrl = QUrl("kotext://frameBlockFormat");
-const QUrl KoTextDocument::ShapeControllerUrl = QUrl("kotext://shapeController");
-const QUrl KoTextDocument::SectionModelUrl = QUrl("ktext://sectionModel");
-
-KoTextDocument::KoTextDocument(QTextDocument *document)
- : m_document(document)
-{
- Q_ASSERT(m_document);
-}
-
-KoTextDocument::KoTextDocument(const QTextDocument *document)
- : m_document(const_cast<QTextDocument *>(document))
-{
- Q_ASSERT(m_document);
-}
-
-KoTextDocument::KoTextDocument(QWeakPointer<QTextDocument> document)
- : m_document(document.data())
-{
- Q_ASSERT(m_document);
-}
-
-KoTextDocument::~KoTextDocument()
-{
-}
-
-QTextDocument *KoTextDocument::document() const
-{
- return m_document;
-}
-
-void KoTextDocument::setTextEditor (KoTextEditor* textEditor)
-{
- Q_ASSERT(textEditor->document() == m_document);
-
- QVariant v;
- v.setValue(textEditor);
- m_document->addResource(KoTextDocument::TextEditor, TextEditorURL, v);
-}
-
-KoTextEditor* KoTextDocument::textEditor() const
-{
- QVariant resource = m_document->resource(KoTextDocument::TextEditor, TextEditorURL);
- return resource.value<KoTextEditor *>();
-}
-
-void KoTextDocument::setStyleManager(KoStyleManager *sm)
-{
- QVariant v;
- v.setValue(sm);
- m_document->addResource(KoTextDocument::StyleManager, StyleManagerURL, v);
- if (sm) {
- OdfTextTrackStyles *cf = OdfTextTrackStyles::instance(sm);
- cf->registerDocument(m_document);
- }
-}
-
-void KoTextDocument::setInlineTextObjectManager(KoInlineTextObjectManager *manager)
-{
- QVariant v;
- v.setValue(manager);
- m_document->addResource(KoTextDocument::InlineTextManager, InlineObjectTextManagerURL, v);
-}
-
-void KoTextDocument::setTextRangeManager(KoTextRangeManager *manager)
-{
- QVariant v;
- v.setValue(manager);
- m_document->addResource(KoTextDocument::TextRangeManager, TextRangeManagerURL, v);
-}
-
-KoStyleManager *KoTextDocument::styleManager() const
-{
- QVariant resource = m_document->resource(KoTextDocument::StyleManager, StyleManagerURL);
- return resource.value<KoStyleManager *>();
-}
-
-void KoTextDocument::setChangeTracker(KoChangeTracker *changeTracker)
-{
- QVariant v;
- v.setValue(changeTracker);
- m_document->addResource(KoTextDocument::ChangeTrackerResource, ChangeTrackerURL, v);
-}
-
-KoChangeTracker *KoTextDocument::changeTracker() const
-{
- QVariant resource = m_document->resource(KoTextDocument::ChangeTrackerResource, ChangeTrackerURL);
- if (resource.isValid()) {
- return resource.value<KoChangeTracker *>();
- }
- else {
- return 0;
- }
-}
-
-void KoTextDocument::setShapeController(KoShapeController *controller)
-{
- QVariant v;
- v.setValue(controller);
- m_document->addResource(KoTextDocument::ShapeController, ShapeControllerUrl, v);
-}
-
-KoShapeController *KoTextDocument::shapeController() const
-{
- QVariant resource = m_document->resource(KoTextDocument::ShapeController, ShapeControllerUrl);
- if (resource.isValid()) {
- return resource.value<KoShapeController *>();
- }
- else {
- return 0;
- }
-}
-
-void KoTextDocument::setLineNumberingConfiguration(KoOdfLineNumberingConfiguration *lineNumberingConfiguration)
-{
- lineNumberingConfiguration->setParent(m_document);
- QVariant v;
- v.setValue(lineNumberingConfiguration);
- m_document->addResource(KoTextDocument::LineNumberingConfiguration, LineNumberingConfigurationURL, v);
-}
-
-KoOdfLineNumberingConfiguration *KoTextDocument::lineNumberingConfiguration() const
-{
- return m_document->resource(KoTextDocument::LineNumberingConfiguration, LineNumberingConfigurationURL)
- .value<KoOdfLineNumberingConfiguration*>();
-}
-
-void KoTextDocument::setHeadingList(KoList *headingList)
-{
- QVariant v;
- v.setValue(headingList);
- m_document->addResource(KoTextDocument::HeadingList, HeadingListURL, v);
-}
-
-KoList *KoTextDocument::headingList() const
-{
- QVariant resource = m_document->resource(KoTextDocument::HeadingList, HeadingListURL);
- return resource.value<KoList *>();
-}
-
-void KoTextDocument::setUndoStack(KUndo2Stack *undoStack)
-{
- QVariant v;
- v.setValue<void*>(undoStack);
- m_document->addResource(KoTextDocument::UndoStack, UndoStackURL, v);
-}
-
-KUndo2Stack *KoTextDocument::undoStack() const
-{
- QVariant resource = m_document->resource(KoTextDocument::UndoStack, UndoStackURL);
- return static_cast<KUndo2Stack*>(resource.value<void*>());
-}
-
-void KoTextDocument::setLists(const QList<KoList *> &lists)
-{
- QVariant v;
- v.setValue(lists);
- m_document->addResource(KoTextDocument::Lists, ListsURL, v);
-}
-
-QList<KoList *> KoTextDocument::lists() const
-{
- QVariant resource = m_document->resource(KoTextDocument::Lists, ListsURL);
- return resource.value<QList<KoList *> >();
-}
-
-void KoTextDocument::addList(KoList *list)
-{
- Q_ASSERT(list);
- list->setParent(m_document);
- QList<KoList *> l = lists();
- if (l.contains(list))
- return;
- l.append(list);
- setLists(l);
-}
-
-void KoTextDocument::removeList(KoList *list)
-{
- QList<KoList *> l = lists();
- if (l.contains(list)) {
- l.removeAll(list);
- setLists(l);
- }
-}
-
-KoList *KoTextDocument::list(const QTextBlock &block) const
-{
- QTextList *textList = block.textList();
- if (!textList)
- return 0;
- return list(textList);
-}
-
-KoList *KoTextDocument::list(QTextList *textList) const
-{
- if (!textList) {
- return 0;
- }
- // FIXME: this is horrible.
- Q_FOREACH (KoList *l, lists()) {
- if (l->textLists().contains(textList))
- return l;
- }
- return 0;
-}
-
-KoList *KoTextDocument::list(KoListStyle::ListIdType listId) const
-{
- Q_FOREACH (KoList *l, lists()) {
- if (l->textListIds().contains(listId))
- return l;
- }
- return 0;
-}
-
-void KoTextDocument::clearText()
-{
- QTextCursor cursor(m_document);
- cursor.select(QTextCursor::Document);
- cursor.removeSelectedText();
-}
-
-QVector< QAbstractTextDocumentLayout::Selection > KoTextDocument::selections() const
-{
- QVariant resource = m_document->resource(KoTextDocument::Selections, SelectionsURL);
- QVariantList variants = resource.toList();
-
- QVector<QAbstractTextDocumentLayout::Selection> selections;
- Q_FOREACH (const QVariant &variant, variants) {
- selections.append(variant.value<QAbstractTextDocumentLayout::Selection>());
- }
-
- return selections;
-}
-
-void KoTextDocument::setSelections(const QVector< QAbstractTextDocumentLayout::Selection >& selections)
-{
- QVariantList variants;
- Q_FOREACH (const QAbstractTextDocumentLayout::Selection &selection, selections) {
- variants.append(QVariant::fromValue<QAbstractTextDocumentLayout::Selection>(selection));
- }
-
- m_document->addResource(KoTextDocument::Selections, SelectionsURL, variants);
-}
-
-KoInlineTextObjectManager *KoTextDocument::inlineTextObjectManager() const
-{
- QVariant resource = m_document->resource(KoTextDocument::InlineTextManager,
- InlineObjectTextManagerURL);
- return resource.value<KoInlineTextObjectManager *>();
-}
-
-KoTextRangeManager *KoTextDocument::textRangeManager() const
-{
- QVariant resource = m_document->resource(KoTextDocument::TextRangeManager,
- TextRangeManagerURL);
- return resource.value<KoTextRangeManager *>();
-}
-
-QTextFrame *KoTextDocument::auxillaryFrame()
-{
- QTextCursor cursor(m_document->rootFrame()->lastCursorPosition());
- cursor.movePosition(QTextCursor::PreviousCharacter);
- QTextFrame *frame = cursor.currentFrame();
-
- if (frame->format().intProperty(KoText::SubFrameType) != KoText::AuxillaryFrameType) {
- cursor = m_document->rootFrame()->lastCursorPosition();
-
- QTextFrameFormat format;
- format.setProperty(KoText::SubFrameType, KoText::AuxillaryFrameType);
-
- frame = cursor.insertFrame(format);
- }
- return frame;
-}
-
-void KoTextDocument::setRelativeTabs(bool relative)
-{
- QVariant v(relative);
- m_document->addResource(KoTextDocument::RelativeTabs, RelativeTabsURL, v);
-}
-
-bool KoTextDocument::relativeTabs() const
-{
- QVariant resource = m_document->resource(KoTextDocument::RelativeTabs, RelativeTabsURL);
- if (resource.isValid())
- return resource.toBool();
- else
- return true;
-}
-
-void KoTextDocument::setParaTableSpacingAtStart(bool spacingAtStart)
-{
- QVariant v(spacingAtStart);
- m_document->addResource(KoTextDocument::ParaTableSpacingAtStart, ParaTableSpacingAtStartUrl, v);
-}
-
-bool KoTextDocument::paraTableSpacingAtStart() const
-{
- QVariant resource = m_document->resource(KoTextDocument::ParaTableSpacingAtStart, ParaTableSpacingAtStartUrl);
- if (resource.isValid())
- return resource.toBool();
- else
- return false;
-}
-
-QTextCharFormat KoTextDocument::frameCharFormat() const
-{
- QVariant resource = m_document->resource(KoTextDocument::FrameCharFormat, FrameCharFormatUrl);
- if (resource.isValid())
- return resource.value<QTextCharFormat>();
- else
- return QTextCharFormat();
-}
-
-void KoTextDocument::setFrameCharFormat(const QTextCharFormat &format)
-{
- m_document->addResource(KoTextDocument::FrameCharFormat, FrameCharFormatUrl, QVariant::fromValue(format));
-}
-
-QTextBlockFormat KoTextDocument::frameBlockFormat() const
-{
- QVariant resource = m_document->resource(KoTextDocument::FrameBlockFormat, FrameBlockFormatUrl);
- if (resource.isValid())
- return resource.value<QTextBlockFormat>();
- else
- return QTextBlockFormat();
-}
-
-void KoTextDocument::setFrameBlockFormat(const QTextBlockFormat &format)
-{
- m_document->addResource(KoTextDocument::FrameBlockFormat, FrameBlockFormatUrl, QVariant::fromValue(format));
-}
-
-KoSectionModel* KoTextDocument::sectionModel()
-{
- QVariant resource = m_document->resource(KoTextDocument::SectionModel, SectionModelUrl);
- if (!resource.isValid()) {
- setSectionModel(new KoSectionModel(document())); // Using create on demand strategy
- }
- return m_document->resource(KoTextDocument::SectionModel, SectionModelUrl).value<KoSectionModel *>();
-}
-
-void KoTextDocument::setSectionModel(KoSectionModel *model)
-{
- QVariant v;
- v.setValue(model);
- m_document->addResource(KoTextDocument::SectionModel, SectionModelUrl, v);
-}
diff --git a/plugins/flake/textshape/kotext/KoTextDocument.h b/plugins/flake/textshape/kotext/KoTextDocument.h
deleted file mode 100644
index 1147f0d4ae..0000000000
--- a/plugins/flake/textshape/kotext/KoTextDocument.h
+++ /dev/null
@@ -1,267 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Pierre Stirnweiss <pierre.stirnweiss_calligra@gadz.org>
- * Copyright (C) 2014-2015 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 KOTEXTDOCUMENT_H
-#define KOTEXTDOCUMENT_H
-
-#include <QTextDocument>
-#include <QWeakPointer>
-#include <QAbstractTextDocumentLayout>
-#include <QUrl>
-
-#include <styles/KoListStyle.h>
-
-class KoList;
-class KoStyleManager;
-class KoInlineTextObjectManager;
-class KoTextRangeManager;
-class KUndo2Stack;
-class KoTextEditor;
-class KoOdfLineNumberingConfiguration;
-class KoChangeTracker;
-class KoShapeController;
-class KoSectionModel;
-
-class QTextCharFormat;
-
-/**
- * KoTextDocument provides an easy mechanism to set and access the
- * editing members of a QTextDocument. The meta data are stored as resources
- * in the QTextDocument using QTextDocument::addResource() and fetched
- * using QTextDocument::resource().
- *
- */
-class KRITATEXT_EXPORT KoTextDocument
-{
-public:
- /// Constructor
- KoTextDocument(QTextDocument *document); // krazy:exclude=explicit
- /// Constructor
- KoTextDocument(const QTextDocument *document); // krazy:exclude=explicit
- /// Constructor
- KoTextDocument(QWeakPointer<QTextDocument> document); // krazy:exclude=explicit
-
- /// Destructor
- ~KoTextDocument();
-
- /// Returns the document that was passed in the constructor
- QTextDocument *document() const;
-
- ///Returns the text editor for that document
- KoTextEditor *textEditor() const;
-
- ///Sets the text editor for the document
- void setTextEditor(KoTextEditor *textEditor);
-
- /// Sets the style manager that defines the named styles in the document
- void setStyleManager(KoStyleManager *styleManager);
-
- /// Returns the style manager
- KoStyleManager *styleManager() const;
-
- /// Sets the change tracker of the document
- void setChangeTracker(KoChangeTracker *changeTracker);
-
- ///Returns the change tracker of the document
- KoChangeTracker *changeTracker() const;
-
- void setLineNumberingConfiguration(KoOdfLineNumberingConfiguration *lineNumberingConfiguration);
-
- /// @return the notes configuration
- KoOdfLineNumberingConfiguration *lineNumberingConfiguration() const;
-
- ///Sets the global undo stack
- void setUndoStack(KUndo2Stack *undoStack);
-
- ///Returns the global undo stack
- KUndo2Stack *undoStack() const;
-
- ///Sets the global heading list
- void setHeadingList(KoList *list);
-
- ///Returns the global heading list
- KoList *headingList() const;
-
- /// Sets the lists of the document
- void setLists(const QList<KoList *> &lists);
-
- /// Returns the lists in the document
- QList<KoList *> lists() const;
-
- /// Adds a list to the document
- void addList(KoList *list);
-
- /// Removes a list from the document
- void removeList(KoList *list);
-
- /// Returns the KoList that holds \a block; 0 if block is not part of any list
- KoList *list(const QTextBlock &block) const;
-
- /// Returns the KoList that holds \a list
- KoList *list(QTextList *textList) const;
-
- /// Return the KoList that holds \a listId
- KoList *list(KoListStyle::ListIdType listId) const;
-
- /// Return the selections used during painting.
- QVector<QAbstractTextDocumentLayout::Selection> selections() const;
-
- /**
- * Set the selections to use for painting.
- *
- * The selections are used to apply temporary styling to
- * parts of a document.
- *
- * \param selections The new selections to use.
- */
- void setSelections(const QVector<QAbstractTextDocumentLayout::Selection> &selections);
-
- /// Returns the KoInlineTextObjectManager
- KoInlineTextObjectManager *inlineTextObjectManager() const;
-
- /// Set the KoInlineTextObjectManager
- void setInlineTextObjectManager(KoInlineTextObjectManager *manager);
-
- /// @return section model for the document
- KoSectionModel *sectionModel();
-
- /// Sets the section model for the document
- void setSectionModel(KoSectionModel *model);
-
- /// Returns the KoTextRangeManager
- KoTextRangeManager *textRangeManager() const;
-
- /// Set the KoTextRangeManager
- void setTextRangeManager(KoTextRangeManager *manager);
-
- /// Set the KoDocument's shapeController. This controller exists as long as KoDocument exists. It should only be used for deleting shapes.
- void setShapeController(KoShapeController *controller);
-
- /// Returns the shapeController
- KoShapeController *shapeController() const;
-
- QTextFrame* auxillaryFrame();
-
- /**
- * Specifies if tabs are relative to paragraph indent.
- *
- * By default it's false.
- */
- void setRelativeTabs(bool relative);
-
- /**
- * Returns if tabs are placed relative to paragraph indent.
- *
- * By default, this is false.
- *
- * @see setRelativeTabs
- */
- bool relativeTabs() const;
-
- void setParaTableSpacingAtStart(bool spacingAtStart);
- bool paraTableSpacingAtStart() const;
-
- /**
- * Returns the character format for the frame of this document.
- *
- * @return the character format for the frame of this document.
- * @see setFrameCharFormat
- */
- QTextCharFormat frameCharFormat() const;
-
- /**
- * Sets the character format for the frame of this document.
- *
- * @param format the character format for the frame of this document.
- * @see frameCharFormat
- */
- void setFrameCharFormat(const QTextCharFormat &format);
-
- /**
- * Returns the block format for the frame of this document.
- *
- * @return the block format for the frame of this document.
- * @see setFrameBlockFormat
- */
- QTextBlockFormat frameBlockFormat() const;
-
- /**
- * Sets the block format for the frame of this document.
- *
- * @param format the block format for the frame of this document.
- * @see frameBlockFormat
- */
- void setFrameBlockFormat(const QTextBlockFormat &format);
-
- /**
- * Clears the text in the document. Unlike QTextDocument::clear(), this
- * function does not clear the resources of the QTextDocument.
- */
- void clearText();
-
- /// Enum (type) used to add resources using QTextDocument::addResource()
- enum ResourceType {
- StyleManager = QTextDocument::UserResource,
- Lists,
- TextRangeManager,
- InlineTextManager,
- ChangeTrackerResource,
- UndoStack,
- TextEditor,
- LineNumberingConfiguration,
- RelativeTabs,
- HeadingList,
- Selections,
- LayoutTextPage, /// this is used for setting the correct page variable on the first resize and should not be used for other purposes
- ParaTableSpacingAtStart, /// this is used during layouting to specify if at the first paragraph margin-top should be applied.
- IndexGeneratorManager,
- FrameCharFormat,
- FrameBlockFormat,
- ShapeController,
- SectionModel
- };
-
- static const QUrl StyleManagerURL;
- static const QUrl ListsURL;
- static const QUrl TextRangeManagerURL;
- static const QUrl InlineObjectTextManagerURL;
- static const QUrl ChangeTrackerURL;
- static const QUrl UndoStackURL;
- static const QUrl TextEditorURL;
- static const QUrl LineNumberingConfigurationURL;
- static const QUrl BibliographyConfigurationURL;
- static const QUrl RelativeTabsURL;
- static const QUrl HeadingListURL;
- static const QUrl SelectionsURL;
- static const QUrl LayoutTextPageUrl;
- static const QUrl ParaTableSpacingAtStartUrl;
- static const QUrl IndexGeneratorManagerUrl;
- static const QUrl FrameCharFormatUrl;
- static const QUrl FrameBlockFormatUrl;
- static const QUrl ShapeControllerUrl;
- static const QUrl SectionModelUrl;
-
-private:
- QTextDocument *m_document;
-};
-
-#endif // KOTEXTDOCUMENT_H
diff --git a/plugins/flake/textshape/kotext/KoTextDrag.cpp b/plugins/flake/textshape/kotext/KoTextDrag.cpp
deleted file mode 100644
index b21f259d37..0000000000
--- a/plugins/flake/textshape/kotext/KoTextDrag.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007-2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Pierre Stirnweiss \pierre.stirnweiss_calligra@gadz.org>
- *
- * 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 "KoTextDrag.h"
-
-#include <QBuffer>
-#include <QByteArray>
-#include <QMimeData>
-#include <QString>
-
-#include <KoStore.h>
-#include <KoGenStyles.h>
-#include <KoGenChanges.h>
-#include <KoOdfWriteStore.h>
-#include <KoXmlWriter.h>
-#include <KoDocumentBase.h>
-#include <KoEmbeddedDocumentSaver.h>
-#include "KoShapeSavingContext.h"
-#include "KoStyleManager.h"
-#include <opendocument/KoTextSharedSavingData.h>
-
-#include "KoTextOdfSaveHelper.h"
-
-#ifdef SHOULD_BUILD_RDF
-#include "KoTextRdfCore.h"
-#endif
-
-#include "TextDebug.h"
-
-KoTextDrag::KoTextDrag()
- : m_mimeData(0)
-{
-}
-
-KoTextDrag::~KoTextDrag()
-{
- if (m_mimeData == 0) {
- delete m_mimeData;
- }
-}
-
-bool KoTextDrag::setOdf(const char * mimeType, KoTextOdfSaveHelper &helper)
-{
- QBuffer buffer;
- QScopedPointer<KoStore> store(KoStore::createStore(&buffer, KoStore::Write, mimeType));
- Q_ASSERT(store);
- Q_ASSERT(!store->bad());
-
- KoOdfWriteStore odfStore(store.data());
- KoEmbeddedDocumentSaver embeddedSaver;
-
- KoXmlWriter* manifestWriter = odfStore.manifestWriter(mimeType);
- KoXmlWriter* contentWriter = odfStore.contentWriter();
-
- if (!contentWriter) {
- return false;
- }
-
- KoGenStyles mainStyles;
- KoXmlWriter *bodyWriter = odfStore.bodyWriter();
- KoShapeSavingContext * context = helper.context(bodyWriter, mainStyles, embeddedSaver);
- KoGenChanges changes;
-
- KoSharedSavingData *sharedData = context->sharedData(KOTEXT_SHARED_SAVING_ID);
- KoTextSharedSavingData *textSharedData = 0;
- if (sharedData) {
- textSharedData = dynamic_cast<KoTextSharedSavingData *>(sharedData);
- }
-
- if (!textSharedData) {
- textSharedData = new KoTextSharedSavingData();
- textSharedData->setGenChanges(changes);
- if (!sharedData) {
- context->addSharedData(KOTEXT_SHARED_SAVING_ID, textSharedData);
- } else {
- warnText << "A different type of sharedData was found under the" << KOTEXT_SHARED_SAVING_ID;
- Q_ASSERT(false);
- }
- }
-#ifdef SHOULD_BUILD_RDF
- debugText << "helper.model:" << helper.rdfModel();
- textSharedData->setRdfModel(helper.rdfModel());
-#endif
- if (!helper.writeBody()) {
- return false;
- }
- // Save the named styles that was referred to by the copied text
- if (KoStyleManager *styleManager = helper.styleManager()) {
- styleManager->saveReferredStylesToOdf(*context);
- }
-
- mainStyles.saveOdfStyles(KoGenStyles::DocumentAutomaticStyles, contentWriter);
- changes.saveOdfChanges(contentWriter, false);
-
- odfStore.closeContentWriter();
-
- //add manifest line for content.xml
- manifestWriter->addManifestEntry("content.xml", "text/xml");
-
- debugText << "testing to see if we should add rdf to odf file?";
-
-#ifdef SHOULD_BUILD_RDF
- debugText << "helper has model" << ( helper.rdfModel() != 0 );
- // RDF: Copy relevant RDF to output ODF
- if (QSharedPointer<Soprano::Model> m = helper.rdfModel()) {
- debugText << "rdf model size:" << m->statementCount();
- KoTextRdfCore::createAndSaveManifest(m, textSharedData->getRdfIdMapping(),
- store.data(), manifestWriter);
- }
-#endif
-
- if (!mainStyles.saveOdfStylesDotXml(store.data(), manifestWriter)) {
- return false;
- }
-
- if (!context->saveDataCenter(store.data(), manifestWriter)) {
- debugText << "save data centers failed";
- return false;
- }
-
- // Save embedded objects
- KoDocumentBase::SavingContext documentContext(odfStore, embeddedSaver);
- if (!embeddedSaver.saveEmbeddedDocuments(documentContext)) {
- debugText << "save embedded documents failed";
- return false;
- }
-
- // Write out manifest file
- if (!odfStore.closeManifestWriter()) {
- return false;
- }
-
- store.reset();
- setData(mimeType, buffer.buffer());
-
- return true;
-}
-
-void KoTextDrag::setData(const QString & mimeType, const QByteArray & data)
-{
- if (m_mimeData == 0) {
- m_mimeData = new QMimeData();
- }
- m_mimeData->setData(mimeType, data);
-}
-
-QMimeData * KoTextDrag::takeMimeData()
-{
- QMimeData * mimeData = m_mimeData;
- m_mimeData = 0;
- return mimeData;
-}
diff --git a/plugins/flake/textshape/kotext/KoTextDrag.h b/plugins/flake/textshape/kotext/KoTextDrag.h
deleted file mode 100644
index 303a552f84..0000000000
--- a/plugins/flake/textshape/kotext/KoTextDrag.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* This file is part of the KDE project
- * Copyright ( C ) 2007 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 KOTEXTDRAG_H
-#define KOTEXTDRAG_H
-
-#include "kritatext_export.h"
-
-class QMimeData;
-class QString;
-class QByteArray;
-class KoTextOdfSaveHelper;
-
-/**
- * Class for simplifying adding a odf text with tracked changes to the clip board
- *
- * For saving the odf a KoDragOdfSaveHelper class is used.
- * It implements the writing of the body of the document. The
- * setOdf takes care of saving styles and tracked changes and all the other
- * common stuff.
- */
-class KRITATEXT_EXPORT KoTextDrag
-{
-public:
- KoTextDrag();
- ~KoTextDrag();
-
- /**
- * Set odf mime type
- *
- * This calls helper.writeBody();
- *
- * @param mimeType used for creating the odf document
- * @param helper helper for saving the body of the odf document
- */
- bool setOdf(const char * mimeType, KoTextOdfSaveHelper &helper);
-
- /**
- * Add additional mimeTypes
- */
- void setData(const QString & mimeType, const QByteArray & data);
-
- /**
- * Get the mime data
- *
- * This transfers the ownership of the mimeData to the caller
- */
- QMimeData *takeMimeData();
-
-private:
- QMimeData *m_mimeData;
-};
-
-#endif /* KOTEXTDRAG_H */
diff --git a/plugins/flake/textshape/kotext/KoTextEditingFactory.cpp b/plugins/flake/textshape/kotext/KoTextEditingFactory.cpp
deleted file mode 100644
index aed3f414cc..0000000000
--- a/plugins/flake/textshape/kotext/KoTextEditingFactory.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 "KoTextEditingFactory.h"
-
-#include <QString>
-
-class Q_DECL_HIDDEN KoTextEditingFactory::Private
-{
-public:
- Private(const QString &identifier)
- : id(identifier),
- showInMenu(false) {
- }
-
- const QString id;
- bool showInMenu;
- QString title;
-};
-
-KoTextEditingFactory::KoTextEditingFactory(const QString &id)
- : d(new Private(id))
-{
-}
-
-KoTextEditingFactory::~KoTextEditingFactory()
-{
- delete d;
-}
-
-QString KoTextEditingFactory::id() const
-{
- return d->id;
-}
-
-bool KoTextEditingFactory::showInMenu() const
-{
- return d->showInMenu;
-}
-
-void KoTextEditingFactory::setShowInMenu(bool show)
-{
- d->showInMenu = show;
-}
-
-QString KoTextEditingFactory::title() const
-{
- return d->title;
-}
-
-void KoTextEditingFactory::setTitle(const QString &title)
-{
- d->title = title;
-}
-
diff --git a/plugins/flake/textshape/kotext/KoTextEditingFactory.h b/plugins/flake/textshape/kotext/KoTextEditingFactory.h
deleted file mode 100644
index 29cf43d8bb..0000000000
--- a/plugins/flake/textshape/kotext/KoTextEditingFactory.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 KOTEXTEDITINGFACTORY_H
-#define KOTEXTEDITINGFACTORY_H
-
-#include "kritatext_export.h"
-
-class KoTextEditingPlugin;
-class QString;
-
-/**
- * A factory for text editing plugins. There should be one for each plugin type to
- * allow the creation of the text-editing-class from that plugin.
- * @see KoTextEditingRegistry
- */
-class KRITATEXT_EXPORT KoTextEditingFactory
-{
-public:
- /**
- * Create the new factory
- * @param id a string that will be used internally for referencing the variable-type.
- */
- explicit KoTextEditingFactory(const QString &id);
- virtual ~KoTextEditingFactory();
-
- /**
- * Create a new instance of an inline object.
- */
- virtual KoTextEditingPlugin *create() const = 0;
-
- /**
- * return the id for the plugin this factory creates.
- * @return the id for the plugin this factory creates.
- */
- QString id() const;
-
- /**
- * return if the plugin this factory creates has to be shown in the context menu.
- * @see KoTextEditingPlugin::checkSection()
- */
- bool showInMenu() const;
-
- /// If showInMenu() returns true; the returned text is used in the context menu.
- QString title() const;
-
-protected:
- /**
- * Set if the plugin this factory creates has to be shown in the context menu.
- * @see KoTextEditingPlugin::checkSection()
- */
- void setShowInMenu(bool show);
- /// set the title used in the context menu
- void setTitle(const QString &title);
-
-private:
- class Private;
- Private * const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoTextEditingPlugin.cpp b/plugins/flake/textshape/kotext/KoTextEditingPlugin.cpp
deleted file mode 100644
index 63147e3b56..0000000000
--- a/plugins/flake/textshape/kotext/KoTextEditingPlugin.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 "KoTextEditingPlugin.h"
-
-#include <QTextDocument>
-#include <QTextBlock>
-#include <QTextCursor>
-
-#include "TextDebug.h"
-
-class Q_DECL_HIDDEN KoTextEditingPlugin::Private
-{
-public:
- QHash<QString, QAction*> actionCollection;
-};
-
-KoTextEditingPlugin::KoTextEditingPlugin()
- : d(new Private())
-{
-}
-
-KoTextEditingPlugin::~KoTextEditingPlugin()
-{
- delete d;
-}
-
-void KoTextEditingPlugin::selectWord(QTextCursor &cursor, int cursorPosition) const
-{
- cursor.setPosition(cursorPosition);
- QTextBlock block = cursor.block();
- cursor.setPosition(block.position());
- cursorPosition -= block.position();
- QString string = block.text();
- int pos = 0;
- bool space = false;
- QString::Iterator iter = string.begin();
- while (iter != string.end()) {
- if (iter->isSpace()) {
- if (space) ;// double spaces belong to the previous word
- else if (pos < cursorPosition)
- cursor.setPosition(pos + block.position() + 1); // +1 because we don't want to set it on the space itself
- else
- space = true;
- } else if (space)
- break;
- pos++;
- iter++;
- }
- cursor.setPosition(pos + block.position(), QTextCursor::KeepAnchor);
-}
-
-QString KoTextEditingPlugin::paragraph(QTextDocument *document, int cursorPosition) const
-{
- QTextBlock block = document->findBlock(cursorPosition);
- return block.text();
-}
-
-void KoTextEditingPlugin::addAction(const QString &name, QAction *action)
-{
- d->actionCollection.insert(name, action);
-}
-
-void KoTextEditingPlugin::checkSection(QTextDocument *document, int startPosition, int endPosition)
-{
- QTextBlock block = document->findBlock(startPosition);
- int pos = block.position();
- while (true) {
- if (!block.contains(startPosition - 1) && !block.contains(endPosition + 1)) // only parags that are completely in
- finishedParagraph(document, block.position());
-
- QString text = block.text();
- bool space = true;
- QString::Iterator iter = text.begin();
- while (pos < endPosition && iter != text.end()) {
- bool isSpace = iter->isSpace();
- if (pos >= startPosition && space && !isSpace) // for each word, call finishedWord
- finishedWord(document, pos);
- else if (!isSpace && pos == startPosition)
- finishedWord(document, startPosition);
- space = isSpace;
- pos++;
- iter++;
- }
-
- if (!(block.isValid() && block.position() + block.length() < endPosition))
- break;
- block = block.next();
- }
-}
-
-QHash<QString, QAction*> KoTextEditingPlugin::actions() const
-{
- return d->actionCollection;
-}
-
-void KoTextEditingPlugin::setCurrentCursorPosition(QTextDocument *document, int cursorPosition)
-{
- Q_UNUSED(cursorPosition);
- Q_UNUSED(document);
-}
diff --git a/plugins/flake/textshape/kotext/KoTextEditingPlugin.h b/plugins/flake/textshape/kotext/KoTextEditingPlugin.h
deleted file mode 100644
index 608107aad3..0000000000
--- a/plugins/flake/textshape/kotext/KoTextEditingPlugin.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 KOTEXTEDITINGPLUGIN_H
-#define KOTEXTEDITINGPLUGIN_H
-
-#include <QObject>
-#include <QHash>
-#include "kritatext_export.h"
-
-class QAction;
-class QTextDocument;
-class QTextCursor;
-class QString;
-
-/**
- * This is a base class for a text editing plugin as used by the text tool.
- * When the user types text into the text shape text editing plugins will be notified of
- * changes in the text document. The plugin is meant to be for altering or checking text as the user
- * types it,
- * To ensure a good user experience this plugin will only be called when it makes sense from
- * a users perspective.
- * The finishedWord() method will be called when the user makes at least one change to
- * a word and then moves the cursor out of the word, a similar approach happens with the
- * finishedParagraph(), it will only be called after the cursor has been moved out of the paragraph.
- */
-class KRITATEXT_EXPORT KoTextEditingPlugin : public QObject
-{
- Q_OBJECT
-public:
- /// constructor
- KoTextEditingPlugin();
- ~KoTextEditingPlugin() override;
-
- /**
- * This method will be called when the user makes at least one change to
- * a word and then moves the cursor out of the word.
- * You are free to alter the word via the textDocument. Be aware that operations should be done
- * via a QTextCursor and should retain any formatting already present on the text.
- * @param document the text document that was altered.
- * @param cursorPosition the last altered position in the word.
- */
- virtual void finishedWord(QTextDocument *document, int cursorPosition) = 0;
-
- /**
- * This method will be called when the user makes at least one change to
- * a paragraph and then moves the cursor out of the paragraph.
- * You are free to alter the paragraph via the textDocument. Be aware that operations should be done
- * via a QTextCursor and should retain any formatting already present on the text.
- * Note that finishedWord() is always called just prior to the call to this method.
- * @param document the text document that was altered.
- * @param cursorPosition the last altered position in the paragraph.
- */
- virtual void finishedParagraph(QTextDocument *document, int cursorPosition) = 0;
-
- /**
- * This method will be called just before the user makes at simple manual change to
- * the text. Such as inserting a single character.
- * This is for information only. You should not make any corrections to the text at this point
- * @param document the text document that was altered.
- * @param cursorPosition the last altered position in the paragraph.
- */
- virtual void startingSimpleEdit(QTextDocument *document, int cursorPosition) = 0;
-
- /**
- * This method will be called when the user selects a portion of text and selects this plugin
- * to handle it.
- * You are free to alter the text via the textDocument. Be aware that operations should be done
- * via a QTextCursor and should retain any formatting already present on the text.
- * @param document the text document that was altered.
- * @param startPosition the position at the start of the selection
- * @param endPosition the position at the end of the selection
- */
- virtual void checkSection(QTextDocument *document, int startPosition, int endPosition);
-
- /// can be called when this plugin needs the current position of the textcursor
- virtual void setCurrentCursorPosition(QTextDocument *document, int cursorPosition);
-
- /**
- * Retrieves the entire collection of actions for the plugin
- */
- QHash<QString, QAction*> actions() const;
-
-Q_SIGNALS:
- /// emitted when a series of commands is started that together need to become 1 undo action.
- void startMacro(const QString &name);
- /// emitted when a series of commands has ended that together should be 1 undo action.
- void stopMacro();
-
-protected:
- /**
- * Helper method that allows you to easily get the word out of the document.
- * This method will create a selection on the parameter cursor where the altered word
- * is selected.
- * Example usage:
- * @code
- QTextCursor cursor(document);
- selectWord(cursor, cursorPosition);
- QString word = cursor.selectedText();
- * @endcode
- * @param cursor the cursor to alter.
- * @param cursorPosition the position of the cursor somewhere in the word.
- */
- void selectWord(QTextCursor &cursor, int cursorPosition) const;
- /**
- * Helper method that allows you to easily get the text of the paragraph which
- * holds the cursor position.
- * Please realize that altering of the paragraph text should be done on a
- * QTextCursor and not by altering the returned string. Doing so would loose
- * all text formatting of the paragraph.
- * @param document the document.
- * @param cursorPosition the position of the cursor somewhere in the word.
- */
- QString paragraph(QTextDocument *document, int cursorPosition) const;
-
- /**
- * Add an action under the given name to the action collection.
- *
- * @param name The name by which the action be retrieved again from the collection.
- * @param action The action to add.
- */
- void addAction(const QString &name, QAction *action);
-
-private:
- class Private;
- Private * const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoTextEditingRegistry.cpp b/plugins/flake/textshape/kotext/KoTextEditingRegistry.cpp
deleted file mode 100644
index ab29cd9299..0000000000
--- a/plugins/flake/textshape/kotext/KoTextEditingRegistry.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
- *
- * 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 "KoTextEditingRegistry.h"
-
-#include <KoPluginLoader.h>
-#include <QGlobalStatic>
-
-Q_GLOBAL_STATIC(KoTextEditingRegistry, s_instance)
-
-void KoTextEditingRegistry::init()
-{
- KoPluginLoader::PluginsConfig config;
- config.whiteList = "TextEditingPlugins";
- config.blacklist = "TextEditingPluginsDisabled";
- config.group = "krita";
- KoPluginLoader::instance()->load(QString::fromLatin1("Krita/Text-EditingPlugin"),
- QString::fromLatin1("[X-KoText-PluginVersion] == 28"), config);
-}
-
-KoTextEditingRegistry* KoTextEditingRegistry::instance()
-{
- if (!s_instance.exists()) {
- s_instance->init();
- }
- return s_instance;
-}
-
-KoTextEditingRegistry::~KoTextEditingRegistry()
-{
- qDeleteAll(doubleEntries());
- qDeleteAll(values());
-}
diff --git a/plugins/flake/textshape/kotext/KoTextEditingRegistry.h b/plugins/flake/textshape/kotext/KoTextEditingRegistry.h
deleted file mode 100644
index 1d8efa487f..0000000000
--- a/plugins/flake/textshape/kotext/KoTextEditingRegistry.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
- *
- * 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 KOTEXTEDITINGREGISTRY_H
-#define KOTEXTEDITINGREGISTRY_H
-
-#include <KoGenericRegistry.h>
-#include <KoTextEditingFactory.h>
-
-/**
- * This singleton class keeps a register of all available text editing plugins.
- * The text editing plugins are all about handling user input while (s)he
- * is editing the text. A plugin can do near everything with the typed text,
- * including altering it and adding markup. The plugin gives events when a
- * word and when a paragraph has been finished. Which is ideal for autocorrection
- * and autoreplacement of text.
- * @see KoTextEditingFactory
- * @see KoTextEditingPlugin
- */
-class KRITATEXT_EXPORT KoTextEditingRegistry : public KoGenericRegistry<KoTextEditingFactory*>
-{
-public:
- /**
- * Return an instance of the KoTextEditingRegistry
- * Creates an instance if that has never happened before and returns the singleton instance.
- */
- KoTextEditingRegistry() {}
- ~KoTextEditingRegistry() override;
- static KoTextEditingRegistry *instance();
-
-private:
-
- void init();
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoTextEditor.cpp b/plugins/flake/textshape/kotext/KoTextEditor.cpp
deleted file mode 100644
index cf2ac88238..0000000000
--- a/plugins/flake/textshape/kotext/KoTextEditor.cpp
+++ /dev/null
@@ -1,1585 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2009-2012 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
- * Copyright (c) 2011 Boudewijn Rempt <boud@valdyas.org>
- * Copyright (C) 2011-2015 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2014-2015 Denis Kuplyakov <dener.kup@gmail.com>
- * Copyright (C) 2015 Soma Schliszka <soma.schliszka@gmail.com>
- *
- * 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 "KoTextEditor.h"
-#include "KoTextEditor_p.h"
-
-#include "KoList.h"
-#include "KoBookmark.h"
-#include "KoAnnotation.h"
-#include "KoTextRangeManager.h"
-#include "KoInlineTextObjectManager.h"
-#include "KoInlineNote.h"
-#include "KoInlineCite.h"
-#include <KoTextShapeDataBase.h>
-#include <KoSelection.h>
-#include <KoShapeController.h>
-#include <KoShapeManager.h>
-#include <KoCanvasBase.h>
-#include "KoShapeAnchor.h"
-#include "KoTextDocument.h"
-#include "KoTextLocator.h"
-#include "KoTableOfContentsGeneratorInfo.h"
-#include "KoBibliographyInfo.h"
-#include "changetracker/KoChangeTracker.h"
-#include "changetracker/KoChangeTrackerElement.h"
-#include "styles/KoCharacterStyle.h"
-#include "styles/KoParagraphStyle.h"
-#include "styles/KoStyleManager.h"
-#include "styles/KoTableCellStyle.h"
-#include "styles/KoTableStyle.h"
-#include "KoTableColumnAndRowStyleManager.h"
-#include "commands/DeleteTableRowCommand.h"
-#include "commands/DeleteTableColumnCommand.h"
-#include "commands/InsertTableRowCommand.h"
-#include "commands/InsertTableColumnCommand.h"
-#include "commands/ResizeTableCommand.h"
-#include "commands/TextPasteCommand.h"
-#include "commands/ListItemNumberingCommand.h"
-#include "commands/ChangeListCommand.h"
-#include "commands/InsertInlineObjectCommand.h"
-#include "commands/DeleteCommand.h"
-#include "commands/DeleteAnchorsCommand.h"
-#include "commands/DeleteAnnotationsCommand.h"
-#include "commands/InsertNoteCommand.h"
-#include "commands/AddTextRangeCommand.h"
-#include "commands/AddAnnotationCommand.h"
-#include "commands/RenameSectionCommand.h"
-#include "commands/NewSectionCommand.h"
-#include "commands/SplitSectionsCommand.h"
-
-#include <klocalizedstring.h>
-
-#include <QTextList>
-#include <QTextBlock>
-#include <QTextBlockFormat>
-#include <QTextCharFormat>
-#include <QTextDocument>
-#include <QTextDocumentFragment>
-#include <QTextFormat>
-#include <QTextTable>
-#include <QTextTableCell>
-#include <kundo2command.h>
-
-#include "TextDebug.h"
-#include "KoTextDebug.h"
-
-Q_DECLARE_METATYPE(QTextFrame*)
-
-/*Private*/
-
-KoTextEditor::Private::Private(KoTextEditor *qq, QTextDocument *document)
- : q(qq)
- , document (document)
- , addNewCommand(true)
- , dummyMacroAdded(false)
- , customCommandCount(0)
- , editProtectionCached(false)
-{
- caret = QTextCursor(document);
- editorState = NoOp;
-}
-
-void KoTextEditor::Private::emitTextFormatChanged()
-{
- emit q->textFormatChanged();
-}
-
-void KoTextEditor::Private::newLine(KUndo2Command *parent)
-{
- // Handle if this is the special block before a table
- bool hiddenTableHandling = caret.blockFormat().hasProperty(KoParagraphStyle::HiddenByTable);
- if (hiddenTableHandling) {
- // Easy solution is to go back to the end of previous block and do the insertion from there.
- // However if there is no block before we have a problem. This may be the case if there is
- // a table before or we are at the beginning of a cell or a document.
- // So here is a better approach
- // 1) create block
- // 2) select the previous block so it gets deleted and replaced
- // 3) remove HiddenByTable from both new and previous block
- // 4) actually make new line replacing the block we just inserted
- // 5) set HiddenByTable on the block just before the table again
- caret.insertText("oops you should never see this");
- caret.insertBlock();
- caret.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
- caret.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
- QTextBlockFormat bf = caret.blockFormat();
- bf.clearProperty(KoParagraphStyle::HiddenByTable);
- caret.setBlockFormat(bf);
- }
-
-
- if (caret.hasSelection()) {
- q->deleteChar(false, parent);
- }
- KoTextDocument textDocument(document);
- KoStyleManager *styleManager = textDocument.styleManager();
- KoParagraphStyle *nextStyle = 0;
- KoParagraphStyle *currentStyle = 0;
- if (styleManager) {
- int id = caret.blockFormat().intProperty(KoParagraphStyle::StyleId);
- currentStyle = styleManager->paragraphStyle(id);
- if (currentStyle == 0) // not a style based parag. Lets make the next one correct.
- nextStyle = styleManager->defaultParagraphStyle();
- else
- nextStyle = styleManager->paragraphStyle(currentStyle->nextStyle());
- Q_ASSERT(nextStyle);
- if (currentStyle == nextStyle)
- nextStyle = 0;
- }
-
- QTextCharFormat format = caret.charFormat();
- if (format.hasProperty(KoCharacterStyle::ChangeTrackerId)) {
- format.clearProperty(KoCharacterStyle::ChangeTrackerId);
- }
-
- // Build the block format and subtract the properties that are not inherited
- QTextBlockFormat bf = caret.blockFormat();
-
- bf.clearProperty(KoParagraphStyle::BreakBefore);
- bf.clearProperty(KoParagraphStyle::ListStartValue);
- bf.clearProperty(KoParagraphStyle::UnnumberedListItem);
- bf.clearProperty(KoParagraphStyle::IsListHeader);
- bf.clearProperty(KoParagraphStyle::MasterPageName);
- bf.clearProperty(KoParagraphStyle::OutlineLevel);
- bf.clearProperty(KoParagraphStyle::HiddenByTable);
-
- // We should stay in the same section so we can't start new one.
- bf.clearProperty(KoParagraphStyle::SectionStartings);
- // But we move all the current endings to the next paragraph.
- QTextBlockFormat origin = caret.blockFormat();
- origin.clearProperty(KoParagraphStyle::SectionEndings);
- caret.setBlockFormat(origin);
-
- // Build the block char format which is just a copy
- QTextCharFormat bcf = caret.blockCharFormat();
-
- // Actually insert the new paragraph char
- int startPosition = caret.position();
-
- caret.insertBlock(bf, bcf);
-
- int endPosition = caret.position();
-
- // Mark the CR as a tracked change
- QTextCursor changeCursor(document);
- changeCursor.beginEditBlock();
- changeCursor.setPosition(startPosition);
- changeCursor.setPosition(endPosition, QTextCursor::KeepAnchor);
- changeCursor.endEditBlock();
-
- q->registerTrackedChange(changeCursor, KoGenChange::InsertChange, kundo2_i18n("New Paragraph"), format, format, false);
-
- // possibly change the style if requested
- if (nextStyle) {
- QTextBlock block = caret.block();
- if (currentStyle)
- currentStyle->unapplyStyle(block);
- nextStyle->applyStyle(block);
- format = block.charFormat();
- }
-
- caret.setCharFormat(format);
-
- if (hiddenTableHandling) {
- // see code and comment above
- QTextBlockFormat bf = caret.blockFormat();
- bf.setProperty(KoParagraphStyle::HiddenByTable, true);
- caret.setBlockFormat(bf);
- caret.movePosition(QTextCursor::PreviousCharacter);
- }
-}
-
-/*KoTextEditor*/
-
-//TODO factor out the changeTracking charFormat setting from all individual slots to a public slot, which will be available for external commands (TextShape)
-
-//The BlockFormatVisitor and CharFormatVisitor are used when a property needs to be modified relative to its current value (which could be different over the selection). For example: increase indentation by 10pt.
-//The BlockFormatVisitor is also used for the change tracking of a blockFormat. The changeTracker stores the information about the changeId in the charFormat. The BlockFormatVisitor ensures that thd changeId is set on the whole block (even if only a part of the block is actually selected).
-//Should such mechanisms be later provided directly by Qt, we could dispose of these classes.
-
-
-KoTextEditor::KoTextEditor(QTextDocument *document)
- : QObject(document),
- d (new Private(this, document))
-{
- connect (d->document, SIGNAL (undoCommandAdded()), this, SLOT (documentCommandAdded()));
-}
-
-KoTextEditor::~KoTextEditor()
-{
- delete d;
-}
-
-KoTextEditor *KoTextEditor::getTextEditorFromCanvas(KoCanvasBase *canvas)
-{
- KoSelection *selection = canvas->shapeManager()->selection();
- if (selection) {
- Q_FOREACH (KoShape *shape, selection->selectedShapes()) {
- if (KoTextShapeDataBase *textData = qobject_cast<KoTextShapeDataBase*>(shape->userData())) {
- KoTextDocument doc(textData->document());
- return doc.textEditor();
- }
- }
- }
- return 0;
-}
-
-QTextCursor* KoTextEditor::cursor()
-{
- return &(d->caret);
-}
-
-const QTextCursor KoTextEditor::constCursor() const
-{
- return QTextCursor(d->caret);
-}
-
-void KoTextEditor::registerTrackedChange(QTextCursor &/*selection*/, KoGenChange::Type /*changeType*/, const KUndo2MagicString &/*title*/, QTextFormat& /*format*/, QTextFormat& /*prevFormat*/, bool /*applyToWholeBlock*/)
-{
-}
-
-// To figure out if a the blocks of the selection are write protected we need to
-// traverse the entire document as sections build up the protectiveness recursively.
-void KoTextEditor::recursivelyVisitSelection(QTextFrame::iterator it, KoTextVisitor &visitor) const
-{
- do {
- if (visitor.abortVisiting())
- return;
-
- QTextBlock block = it.currentBlock();
- QTextTable *table = qobject_cast<QTextTable*>(it.currentFrame());
- QTextFrame *subFrame = it.currentFrame();
- if (table) {
- // There are 4 ways this table can be selected:
- // - "before to mid"
- // - "mid to after"
- // - "complex mid to mid"
- // - "simple mid to mid"
- // The 3 first are entire cells, the fourth is within a cell
-
- if (d->caret.selectionStart() <= table->lastPosition()
- && d->caret.selectionEnd() >= table->firstPosition()) {
- // We have a selection somewhere
- QTextTableCell cell1 = table->cellAt(d->caret.selectionStart());
- QTextTableCell cell2 = table->cellAt(d->caret.selectionEnd());
- if (cell1 != cell2 || !cell1.isValid() || !cell2.isValid()) {
- // And the selection is complex or entire table
- int selectionRow;
- int selectionColumn;
- int selectionRowSpan;
- int selectionColumnSpan;
- if (!cell1.isValid() || !cell2.isValid()) {
- // entire table
- visitor.visitTable(table, KoTextVisitor::Entirely);
- selectionRow = selectionColumn = 0;
- selectionRowSpan = table->rows();
- selectionColumnSpan = table->columns();
- } else {
- visitor.visitTable(table, KoTextVisitor::Partly);
- d->caret.selectedTableCells(&selectionRow, &selectionRowSpan, &selectionColumn, &selectionColumnSpan);
- }
-
- for (int r = selectionRow; r < selectionRow + selectionRowSpan; r++) {
- for (int c = selectionColumn; c < selectionColumn +
- selectionColumnSpan; c++) {
- QTextTableCell cell = table->cellAt(r,c);
- if (!cell.format().boolProperty(KoTableCellStyle::CellIsProtected)) {
- visitor.visitTableCell(&cell, KoTextVisitor::Partly);
- recursivelyVisitSelection(cell.begin(), visitor);
- } else {
- visitor.nonVisit();
- }
-
- if (visitor.abortVisiting())
- return;
- }
- }
- } else {
- visitor.visitTable(table, KoTextVisitor::Partly);
- // And the selection is simple
- if (!cell1.format().boolProperty(KoTableCellStyle::CellIsProtected)) {
- visitor.visitTableCell(&cell1, KoTextVisitor::Entirely);
- recursivelyVisitSelection(cell1.begin(), visitor);
- } else {
- visitor.nonVisit();
- }
- return;
- }
- }
- if (d->caret.selectionEnd() <= table->lastPosition()) {
- return;
- }
- } else if (subFrame) {
- recursivelyVisitSelection(subFrame->begin(), visitor);
- } else {
- // TODO build up the section stack
-
- if (d->caret.selectionStart() < block.position() + block.length()
- && d->caret.selectionEnd() >= block.position()) {
- // We have a selection somewhere
- if (true) { // TODO don't change if block is protected by section
- visitor.visitBlock(block, d->caret);
- } else {
- visitor.nonVisit();
- }
- }
-
- // TODO tear down the section stack
-
- if (d->caret.selectionEnd() < block.position() + block.length()) {
- return;
- }
- }
- if (!it.atEnd()) {
- ++it;
- }
- } while (!it.atEnd());
-}
-
-KoBookmark *KoTextEditor::addBookmark(const QString &name)
-{//TODO changeTracking
- KUndo2Command *topCommand = beginEditBlock(kundo2_i18n("Add Bookmark"));
-
- KoBookmark *bookmark = new KoBookmark(d->caret);
- bookmark->setName(name);
- bookmark->setManager(KoTextDocument(d->document).textRangeManager());
-
- addCommand(new AddTextRangeCommand(bookmark, topCommand));
-
- endEditBlock();
-
- return bookmark;
-}
-KoTextRangeManager *KoTextEditor::textRangeManager() const
-{
- return KoTextDocument(d->document).textRangeManager();
-}
-
-KoAnnotation *KoTextEditor::addAnnotation(KoShape *annotationShape)
-{
- KUndo2Command *topCommand = beginEditBlock(kundo2_i18n("Add Annotation"));
-
- KoAnnotation *annotation = new KoAnnotation(d->caret);
- KoTextRangeManager *textRangeManager = KoTextDocument(d->document).textRangeManager();
- annotation->setManager(textRangeManager);
- //FIXME: I need the name, a unique name, we can set selected text as annotation name or use createUniqueAnnotationName function
- // to do it for us.
- QString name = annotation->createUniqueAnnotationName(textRangeManager->annotationManager(), "", false);
- annotation->setName(name);
- annotation->setAnnotationShape(annotationShape);
-
- addCommand(new AddAnnotationCommand(annotation, topCommand));
-
- endEditBlock();
-
- return annotation;
-}
-
-KoInlineObject *KoTextEditor::insertIndexMarker()
-{//TODO changeTracking
- if (isEditProtected()) {
- return 0;
- }
-
- d->updateState(KoTextEditor::Private::Custom, kundo2_i18n("Insert Index"));
-
- if (d->caret.blockFormat().hasProperty(KoParagraphStyle::HiddenByTable)) {
- d->newLine(0);
- }
-
- QTextBlock block = d->caret.block();
- if (d->caret.position() >= block.position() + block.length() - 1)
- return 0; // can't insert one at end of text
- if (block.text()[ d->caret.position() - block.position()].isSpace())
- return 0; // can't insert one on a whitespace as that does not indicate a word.
-
- KoTextLocator *tl = new KoTextLocator();
- KoTextDocument(d->document).inlineTextObjectManager()->insertInlineObject(d->caret, tl);
- d->updateState(KoTextEditor::Private::NoOp);
- return tl;
-}
-
-void KoTextEditor::insertInlineObject(KoInlineObject *inliner, KUndo2Command *cmd)
-{
- if (isEditProtected()) {
- return;
- }
-
- KUndo2Command *topCommand = cmd;
- if (!cmd) {
- topCommand = beginEditBlock(kundo2_i18n("Insert Variable"));
- }
-
- if (d->caret.hasSelection()) {
- deleteChar(false, topCommand);
- }
- d->caret.beginEditBlock();
-
-
- if (d->caret.blockFormat().hasProperty(KoParagraphStyle::HiddenByTable)) {
- d->newLine(0);
- }
-
- QTextCharFormat format = d->caret.charFormat();
- if (format.hasProperty(KoCharacterStyle::ChangeTrackerId)) {
- format.clearProperty(KoCharacterStyle::ChangeTrackerId);
- }
-
- InsertInlineObjectCommand *insertInlineObjectCommand = new InsertInlineObjectCommand(inliner, d->document, topCommand);
- Q_UNUSED(insertInlineObjectCommand);
- d->caret.endEditBlock();
-
- if (!cmd) {
- addCommand(topCommand);
- endEditBlock();
- }
-
- emit cursorPositionChanged();
-}
-
-void KoTextEditor::updateInlineObjectPosition(int start, int end)
-{
- KoInlineTextObjectManager *inlineObjectManager = KoTextDocument(d->document).inlineTextObjectManager();
- // and, of course, every inline object after the current position has the wrong position
- QTextCursor cursor = d->document->find(QString(QChar::ObjectReplacementCharacter), start);
- while (!cursor.isNull() && (end > -1 && cursor.position() < end )) {
- QTextCharFormat fmt = cursor.charFormat();
- KoInlineObject *obj = inlineObjectManager->inlineTextObject(fmt);
- obj->updatePosition(d->document, cursor.position(), fmt);
- cursor = d->document->find(QString(QChar::ObjectReplacementCharacter), cursor.position());
- }
-
-}
-
-void KoTextEditor::removeAnchors(const QList<KoShapeAnchor*> &anchors, KUndo2Command *parent)
-{
- Q_ASSERT(parent);
- addCommand(new DeleteAnchorsCommand(anchors, d->document, parent));
-}
-
-void KoTextEditor::removeAnnotations(const QList<KoAnnotation *> &annotations, KUndo2Command *parent)
-{
- Q_ASSERT(parent);
- addCommand(new DeleteAnnotationsCommand(annotations, d->document, parent));
-}
-
-void KoTextEditor::insertFrameBreak()
-{
- if (isEditProtected()) {
- return;
- }
-
- QTextCursor curr(d->caret.block());
- if (dynamic_cast<QTextTable *> (curr.currentFrame())) {
- return;
- }
-
- d->updateState(KoTextEditor::Private::KeyPress, kundo2_i18n("Insert Break"));
- QTextBlock block = d->caret.block();
- if (d->caret.position() == block.position() && block.length() > 0) { // start of parag
- QTextBlockFormat bf = d->caret.blockFormat();
- bf.setProperty(KoParagraphStyle::BreakBefore, KoText::PageBreak);
- d->caret.insertBlock(bf);
- if (block.textList())
- block.textList()->remove(block);
- } else {
- QTextBlockFormat bf = d->caret.blockFormat();
- if (!d->caret.blockFormat().hasProperty(KoParagraphStyle::HiddenByTable)) {
- newLine();
- }
- bf = d->caret.blockFormat();
- bf.setProperty(KoParagraphStyle::BreakBefore, KoText::PageBreak);
- d->caret.setBlockFormat(bf);
- }
- d->updateState(KoTextEditor::Private::NoOp);
- emit cursorPositionChanged();
-}
-
-void KoTextEditor::paste(KoCanvasBase *canvas, const QMimeData *mimeData, bool pasteAsText)
-{
- if (isEditProtected()) {
- return;
- }
-
- KoShapeController *shapeController = KoTextDocument(d->document).shapeController();
-
- addCommand(new TextPasteCommand(mimeData,
- d->document,
- shapeController,
- canvas, 0,
- pasteAsText));
-}
-
-void KoTextEditor::deleteChar(bool previous, KUndo2Command *parent)
-{
- if (isEditProtected()) {
- return;
- }
-
- KoShapeController *shapeController = KoTextDocument(d->document).shapeController();
-
- // Find out if we should track changes or not
-// KoChangeTracker *changeTracker = KoTextDocument(d->document).changeTracker();
-// bool trackChanges = false;
-// if (changeTracker && changeTracker->recordChanges()) {
-// trackChanges = true;
-// }
-
- if (previous) {
- if (!d->caret.hasSelection() && d->caret.block().blockFormat().hasProperty(KoParagraphStyle::HiddenByTable)) {
- movePosition(QTextCursor::PreviousCharacter);
- if (d->caret.block().length() <= 1) {
- movePosition(QTextCursor::NextCharacter);
- } else
- return; // it becomes just a cursor movement;
- }
- } else {
- if (!d->caret.hasSelection() && d->caret.block().length() > 1) {
- QTextCursor tmpCursor = d->caret;
- tmpCursor.movePosition(QTextCursor::NextCharacter);
- if (tmpCursor.block().blockFormat().hasProperty(KoParagraphStyle::HiddenByTable)) {
- movePosition(QTextCursor::NextCharacter);
- return; // it becomes just a cursor movement;
- }
- }
- }
-
- if (previous) {
- addCommand(new DeleteCommand(DeleteCommand::PreviousChar,
- d->document,
- shapeController, parent));
- } else {
- addCommand(new DeleteCommand(DeleteCommand::NextChar,
- d->document,
- shapeController, parent));
- }
-}
-
-void KoTextEditor::toggleListNumbering(bool numberingEnabled)
-{
- if (isEditProtected()) {
- return;
- }
-
- addCommand(new ListItemNumberingCommand(block(), numberingEnabled));
- emit textFormatChanged();
-}
-
-void KoTextEditor::setListProperties(const KoListLevelProperties &llp,
- ChangeListFlags flags, KUndo2Command *parent)
-{
- if (isEditProtected()) {
- return;
- }
-
- if (flags & AutoListStyle && d->caret.block().textList() == 0) {
- flags = MergeWithAdjacentList;
- }
-
- if (KoList *list = KoTextDocument(d->document).list(d->caret.block().textList())) {
- KoListStyle *listStyle = list->style();
- if (KoStyleManager *styleManager = KoTextDocument(d->document).styleManager()) {
- QList<KoParagraphStyle *> paragraphStyles = styleManager->paragraphStyles();
- foreach (KoParagraphStyle *paragraphStyle, paragraphStyles) {
- if (paragraphStyle->listStyle() == listStyle ||
- (paragraphStyle->list() && paragraphStyle->list()->style() == listStyle)) {
- flags = NoFlags;
- break;
- }
- }
- }
- }
-
- addCommand(new ChangeListCommand(d->caret, llp, flags, parent));
- emit textFormatChanged();
-}
-
-
-int KoTextEditor::anchor() const
-{
- return d->caret.anchor();
-}
-
-bool KoTextEditor::atBlockEnd() const
-{
- return d->caret.atBlockEnd();
-}
-
-bool KoTextEditor::atBlockStart() const
-{
- return d->caret.atBlockStart();
-}
-
-bool KoTextEditor::atEnd() const
-{
- QTextCursor cursor(d->caret.document()->rootFrame()->lastCursorPosition());
- cursor.movePosition(QTextCursor::PreviousCharacter);
- QTextFrame *auxFrame = cursor.currentFrame();
-
- if (auxFrame->format().intProperty(KoText::SubFrameType) == KoText::AuxillaryFrameType) {
- //auxFrame really is the auxiliary frame
- if (d->caret.position() == auxFrame->firstPosition() - 1) {
- return true;
- }
- return false;
- }
- return d->caret.atEnd();
-}
-
-bool KoTextEditor::atStart() const
-{
- return d->caret.atStart();
-}
-
-QTextBlock KoTextEditor::block() const
-{
- return d->caret.block();
-}
-
-int KoTextEditor::blockNumber() const
-{
- return d->caret.blockNumber();
-}
-
-void KoTextEditor::clearSelection()
-{
- d->caret.clearSelection();
-}
-
-int KoTextEditor::columnNumber() const
-{
- return d->caret.columnNumber();
-}
-
-void KoTextEditor::deleteChar()
-{
- if (isEditProtected()) {
- return;
- }
-
- if (!d->caret.hasSelection()) {
- if (d->caret.atEnd())
- return;
-
- // We alson need to refuse delete if we are at final pos in table cell
- if (QTextTable *table = d->caret.currentTable()) {
- QTextTableCell cell = table->cellAt(d->caret.position());
- if (d->caret.position() == cell.lastCursorPosition().position()) {
- return;
- }
- }
-
- // We also need to refuse delete if it will delete a note frame
- QTextCursor after(d->caret);
- after.movePosition(QTextCursor::NextCharacter);
-
- QTextFrame *beforeFrame = d->caret.currentFrame();
- while (qobject_cast<QTextTable *>(beforeFrame)) {
- beforeFrame = beforeFrame->parentFrame();
- }
-
- QTextFrame *afterFrame = after.currentFrame();
- while (qobject_cast<QTextTable *>(afterFrame)) {
- afterFrame = afterFrame->parentFrame();
- }
- if (beforeFrame != afterFrame) {
- return;
- }
- }
-
-
- deleteChar(false);
-
- emit cursorPositionChanged();
-}
-
-void KoTextEditor::deletePreviousChar()
-{
- if (isEditProtected()) {
- return;
- }
-
- if (!d->caret.hasSelection()) {
- if (d->caret.atStart())
- return;
-
- // We also need to refuse delete if we are at first pos in table cell
- if (QTextTable *table = d->caret.currentTable()) {
- QTextTableCell cell = table->cellAt(d->caret.position());
- if (d->caret.position() == cell.firstCursorPosition().position()) {
- return;
- }
- }
-
- // We also need to refuse delete if it will delete a note frame
- QTextCursor after(d->caret);
- after.movePosition(QTextCursor::PreviousCharacter);
-
- QTextFrame *beforeFrame = d->caret.currentFrame();
- while (qobject_cast<QTextTable *>(beforeFrame)) {
- beforeFrame = beforeFrame->parentFrame();
- }
-
- QTextFrame *afterFrame = after.currentFrame();
- while (qobject_cast<QTextTable *>(afterFrame)) {
- afterFrame = afterFrame->parentFrame();
- }
-
- if (beforeFrame != afterFrame) {
- return;
- }
- }
-
- deleteChar(true);
-
- emit cursorPositionChanged();
-}
-
-QTextDocument *KoTextEditor::document() const
-{
- return d->caret.document();
-}
-
-bool KoTextEditor::hasComplexSelection() const
-{
- return d->caret.hasComplexSelection();
-}
-
-bool KoTextEditor::hasSelection() const
-{
- return d->caret.hasSelection();
-}
-
-
-class ProtectionCheckVisitor : public KoTextVisitor
-{
-public:
- ProtectionCheckVisitor(const KoTextEditor *editor)
- : KoTextVisitor(const_cast<KoTextEditor *>(editor))
- {
- }
-
- // override super's implementation to not waste cpu cycles
- void visitBlock(QTextBlock&, const QTextCursor &) override
- {
- }
-
- void nonVisit() override
- {
- setAbortVisiting(true);
- }
-};
-
-bool KoTextEditor::isEditProtected(bool useCached) const
-{
- ProtectionCheckVisitor visitor(this);
-
- if (useCached) {
- if (! d->editProtectionCached) {
- recursivelyVisitSelection(d->document->rootFrame()->begin(), visitor);
- d->editProtected = visitor.abortVisiting();
- d->editProtectionCached = true;
- }
- return d->editProtected;
- }
- d->editProtectionCached = false;
- recursivelyVisitSelection(d->document->rootFrame()->begin(), visitor);
- return visitor.abortVisiting();
-}
-
-void KoTextEditor::insertTable(int rows, int columns)
-{
- if (isEditProtected() || rows <= 0 || columns <= 0) {
- return;
- }
-
- bool hasSelection = d->caret.hasSelection();
- if (!hasSelection) {
- d->updateState(KoTextEditor::Private::Custom, kundo2_i18n("Insert Table"));
- } else {
- KUndo2Command *topCommand = beginEditBlock(kundo2_i18n("Insert Table"));
- deleteChar(false, topCommand);
- d->caret.beginEditBlock();
- }
-
- QTextTableFormat tableFormat;
-
- tableFormat.setWidth(QTextLength(QTextLength::PercentageLength, 100));
- tableFormat.setProperty(KoTableStyle::CollapsingBorders, true);
- tableFormat.setMargin(5);
-
- KoChangeTracker *changeTracker = KoTextDocument(d->document).changeTracker();
- if (changeTracker && changeTracker->recordChanges()) {
- QTextCharFormat charFormat = d->caret.charFormat();
- QTextBlockFormat blockFormat = d->caret.blockFormat();
- KUndo2MagicString title = kundo2_i18n("Insert Table");
-
- int changeId;
- if (!d->caret.atBlockStart()) {
- changeId = changeTracker->mergeableId(KoGenChange::InsertChange, title, charFormat.intProperty(KoCharacterStyle::ChangeTrackerId));
- } else {
- changeId = changeTracker->mergeableId(KoGenChange::InsertChange, title, blockFormat.intProperty(KoCharacterStyle::ChangeTrackerId));
- }
-
- if (!changeId) {
- changeId = changeTracker->getInsertChangeId(title, 0);
- }
-
- tableFormat.setProperty(KoCharacterStyle::ChangeTrackerId, changeId);
- }
-
- QTextBlock currentBlock = d->caret.block();
- if (d->caret.position() != currentBlock.position()) {
- d->caret.insertBlock();
- currentBlock = d->caret.block();
- }
-
- QTextTable *table = d->caret.insertTable(rows, columns, tableFormat);
-
- // Get (and thus create) columnandrowstyle manager so it becomes part of undo
- // and not something that happens uncontrollably during layout
- KoTableColumnAndRowStyleManager::getManager(table);
-
- // 'Hide' the block before the table
- QTextBlockFormat blockFormat = currentBlock.blockFormat();
- QTextCursor cursor(currentBlock);
- blockFormat.setProperty(KoParagraphStyle::HiddenByTable, true);
- cursor.setBlockFormat(blockFormat);
-
- // Define the initial cell format
- QTextTableCellFormat format;
- KoTableCellStyle cellStyle;
- cellStyle.setEdge(KoBorder::TopBorder, KoBorder::BorderSolid, 2, QColor(Qt::black));
- cellStyle.setEdge(KoBorder::LeftBorder, KoBorder::BorderSolid, 2, QColor(Qt::black));
- cellStyle.setEdge(KoBorder::BottomBorder, KoBorder::BorderSolid, 2, QColor(Qt::black));
- cellStyle.setEdge(KoBorder::RightBorder, KoBorder::BorderSolid, 2, QColor(Qt::black));
- cellStyle.setPadding(5);
- cellStyle.applyStyle(format);
-
- // Apply formatting to all cells
- for (int row = 0; row < table->rows(); ++row) {
- for (int col = 0; col < table->columns(); ++col) {
- QTextTableCell cell = table->cellAt(row, col);
- cell.setFormat(format);
- }
- }
-
- if (hasSelection) {
- d->caret.endEditBlock();
- endEditBlock();
- } else {
- d->updateState(KoTextEditor::Private::NoOp);
- }
-
- emit cursorPositionChanged();
-}
-
-void KoTextEditor::insertTableRowAbove()
-{
- if (isEditProtected()) {
- return;
- }
-
- QTextTable *table = d->caret.currentTable();
- if (table) {
- addCommand(new InsertTableRowCommand(this, table, false));
- }
-}
-
-void KoTextEditor::insertTableRowBelow()
-{
- if (isEditProtected()) {
- return;
- }
-
- QTextTable *table = d->caret.currentTable();
- if (table) {
- addCommand(new InsertTableRowCommand(this, table, true));
- }
-}
-
-void KoTextEditor::insertTableColumnLeft()
-{
- if (isEditProtected()) {
- return;
- }
-
- QTextTable *table = d->caret.currentTable();
- if (table) {
- addCommand(new InsertTableColumnCommand(this, table, false));
- }
-}
-
-void KoTextEditor::insertTableColumnRight()
-{
- if (isEditProtected()) {
- return;
- }
-
- QTextTable *table = d->caret.currentTable();
- if (table) {
- addCommand(new InsertTableColumnCommand(this, table, true));
- }
-}
-
-void KoTextEditor::deleteTableColumn()
-{
- if (isEditProtected()) {
- return;
- }
-
- QTextTable *table = d->caret.currentTable();
- if (table) {
- addCommand(new DeleteTableColumnCommand(this, table));
- }
-}
-
-void KoTextEditor::deleteTableRow()
-{
- if (isEditProtected()) {
- return;
- }
-
- QTextTable *table = d->caret.currentTable();
- if (table) {
- addCommand(new DeleteTableRowCommand(this, table));
- }
-}
-
-void KoTextEditor::mergeTableCells()
-{
- if (isEditProtected()) {
- return;
- }
-
- d->updateState(KoTextEditor::Private::Custom, kundo2_i18n("Merge Cells"));
-
- QTextTable *table = d->caret.currentTable();
-
- if (table) {
- table->mergeCells(d->caret);
- }
-
- d->updateState(KoTextEditor::Private::NoOp);
-}
-
-void KoTextEditor::splitTableCells()
-{
- if (isEditProtected()) {
- return;
- }
-
- d->updateState(KoTextEditor::Private::Custom, kundo2_i18n("Split Cells"));
-
- QTextTable *table = d->caret.currentTable();
-
- if (table) {
- QTextTableCell cell = table->cellAt(d->caret);
- table->splitCell(cell.row(), cell.column(), 1, 1);
- }
-
- d->updateState(KoTextEditor::Private::NoOp);
-}
-
-void KoTextEditor::adjustTableColumnWidth(QTextTable *table, int column, qreal width, KUndo2Command *parentCommand)
-{
- ResizeTableCommand *cmd = new ResizeTableCommand(table, true, column, width, parentCommand);
-
- addCommand(cmd);
-}
-
-
-void KoTextEditor::adjustTableRowHeight(QTextTable *table, int column, qreal height, KUndo2Command *parentCommand)
-{
- ResizeTableCommand *cmd = new ResizeTableCommand(table, false, column, height, parentCommand);
-
- addCommand(cmd);
-}
-
-void KoTextEditor::adjustTableWidth(QTextTable *table, qreal dLeft, qreal dRight)
-{
- d->updateState(KoTextEditor::Private::Custom, kundo2_i18n("Adjust Table Width"));
- d->caret.beginEditBlock();
- QTextTableFormat fmt = table->format();
- if (dLeft) {
- fmt.setLeftMargin(fmt.leftMargin() + dLeft);
- }
- if (dRight) {
- fmt.setRightMargin(fmt.rightMargin() + dRight);
- }
- table->setFormat(fmt);
- d->caret.endEditBlock();
- d->updateState(KoTextEditor::Private::NoOp);
-}
-
-void KoTextEditor::setTableBorderData(QTextTable *table, int row, int column,
- KoBorder::BorderSide cellSide, const KoBorder::BorderData &data)
-{
- d->updateState(KoTextEditor::Private::Custom, kundo2_i18n("Change Border Formatting"));
- d->caret.beginEditBlock();
- QTextTableCell cell = table->cellAt(row, column);
- QTextCharFormat fmt = cell.format();
- KoBorder border = fmt.property(KoTableCellStyle::Borders).value<KoBorder>();
-
- border.setBorderData(cellSide, data);
- fmt.setProperty(KoTableCellStyle::Borders, QVariant::fromValue<KoBorder>(border));
- cell.setFormat(fmt);
- d->caret.endEditBlock();
- d->updateState(KoTextEditor::Private::NoOp);
-}
-
-KoInlineNote *KoTextEditor::insertFootNote()
-{
- if (isEditProtected()) {
- return 0;
- }
-
- InsertNoteCommand *cmd = new InsertNoteCommand(KoInlineNote::Footnote, d->document);
- addCommand(cmd);
-
- emit cursorPositionChanged();
- return cmd->m_inlineNote;
-}
-
-KoInlineNote *KoTextEditor::insertEndNote()
-{
- if (isEditProtected()) {
- return 0;
- }
-
- InsertNoteCommand *cmd = new InsertNoteCommand(KoInlineNote::Endnote, d->document);
- addCommand(cmd);
-
- emit cursorPositionChanged();
- return cmd->m_inlineNote;
-}
-
-void KoTextEditor::insertTableOfContents(KoTableOfContentsGeneratorInfo *info)
-{
- if (isEditProtected()) {
- return;
- }
-
- bool hasSelection = d->caret.hasSelection();
- if (!hasSelection) {
- d->updateState(KoTextEditor::Private::Custom, kundo2_i18n("Insert Table Of Contents"));
- } else {
- KUndo2Command *topCommand = beginEditBlock(kundo2_i18n("Insert Table Of Contents"));
- deleteChar(false, topCommand);
- d->caret.beginEditBlock();
- }
-
- QTextBlockFormat tocFormat;
- KoTableOfContentsGeneratorInfo *newToCInfo = info->clone();
- QTextDocument *tocDocument = new QTextDocument();
- tocFormat.setProperty(KoParagraphStyle::TableOfContentsData, QVariant::fromValue<KoTableOfContentsGeneratorInfo *>(newToCInfo) );
- tocFormat.setProperty(KoParagraphStyle::GeneratedDocument, QVariant::fromValue<QTextDocument*>(tocDocument));
-
- //make sure we set up the textrangemanager on the subdocument as well
- KoTextDocument(tocDocument).setTextRangeManager(new KoTextRangeManager);
-
- KoChangeTracker *changeTracker = KoTextDocument(d->document).changeTracker();
- if (changeTracker && changeTracker->recordChanges()) {
- QTextCharFormat charFormat = d->caret.charFormat();
- QTextBlockFormat blockFormat = d->caret.blockFormat();
- KUndo2MagicString title = kundo2_i18n("Insert Table Of Contents");
-
- int changeId;
- if (!d->caret.atBlockStart()) {
- changeId = changeTracker->mergeableId(KoGenChange::InsertChange, title, charFormat.intProperty(KoCharacterStyle::ChangeTrackerId));
- } else {
- changeId = changeTracker->mergeableId(KoGenChange::InsertChange, title, blockFormat.intProperty(KoCharacterStyle::ChangeTrackerId));
- }
-
- if (!changeId) {
- changeId = changeTracker->getInsertChangeId(title, 0);
- }
-
- tocFormat.setProperty(KoCharacterStyle::ChangeTrackerId, changeId);
- }
-
- d->caret.insertBlock();
- d->caret.movePosition(QTextCursor::Left);
- d->caret.insertBlock(tocFormat);
- d->caret.movePosition(QTextCursor::Right);
-
- if (hasSelection) {
- d->caret.endEditBlock();
- endEditBlock();
- } else {
- d->updateState(KoTextEditor::Private::NoOp);
- }
-
- emit cursorPositionChanged();
-}
-
-void KoTextEditor::setTableOfContentsConfig(KoTableOfContentsGeneratorInfo *info, const QTextBlock &block)
-{
- if (isEditProtected()) {
- return;
- }
-
- KoTableOfContentsGeneratorInfo *newToCInfo=info->clone();
-
- d->updateState(KoTextEditor::Private::Custom, kundo2_i18n("Modify Table Of Contents"));
-
- QTextCursor cursor(block);
- QTextBlockFormat tocBlockFormat=block.blockFormat();
-
- tocBlockFormat.setProperty(KoParagraphStyle::TableOfContentsData, QVariant::fromValue<KoTableOfContentsGeneratorInfo*>(newToCInfo) );
- cursor.setBlockFormat(tocBlockFormat);
-
- d->updateState(KoTextEditor::Private::NoOp);
- emit cursorPositionChanged();
- const_cast<QTextDocument *>(document())->markContentsDirty(document()->firstBlock().position(), 0);
-}
-
-void KoTextEditor::insertBibliography(KoBibliographyInfo *info)
-{
- bool hasSelection = d->caret.hasSelection();
- if (!hasSelection) {
- d->updateState(KoTextEditor::Private::Custom, kundo2_i18n("Insert Bibliography"));
- } else {
- KUndo2Command *topCommand = beginEditBlock(kundo2_i18n("Insert Bibliography"));
- deleteChar(false, topCommand);
- d->caret.beginEditBlock();
- }
-
- QTextBlockFormat bibFormat;
- KoBibliographyInfo *newBibInfo = info->clone();
- QTextDocument *bibDocument = new QTextDocument();
-
- bibFormat.setProperty( KoParagraphStyle::BibliographyData, QVariant::fromValue<KoBibliographyInfo*>(newBibInfo));
- bibFormat.setProperty( KoParagraphStyle::GeneratedDocument, QVariant::fromValue<QTextDocument*>(bibDocument));
-
- //make sure we set up the textrangemanager on the subdocument as well
- KoTextDocument(bibDocument).setTextRangeManager(new KoTextRangeManager);
-
- KoChangeTracker *changeTracker = KoTextDocument(d->document).changeTracker();
- if (changeTracker && changeTracker->recordChanges()) {
- QTextCharFormat charFormat = d->caret.charFormat();
- QTextBlockFormat blockFormat = d->caret.blockFormat();
- KUndo2MagicString title = kundo2_i18n("Insert Bibliography");
-
- int changeId;
- if (!d->caret.atBlockStart()) {
- changeId = changeTracker->mergeableId(KoGenChange::InsertChange, title, charFormat.intProperty(KoCharacterStyle::ChangeTrackerId));
- } else {
- changeId = changeTracker->mergeableId(KoGenChange::InsertChange, title, blockFormat.intProperty(KoCharacterStyle::ChangeTrackerId));
- }
-
- if (!changeId) {
- changeId = changeTracker->getInsertChangeId(title, 0);
- }
-
- bibFormat.setProperty(KoCharacterStyle::ChangeTrackerId, changeId);
- }
-
- d->caret.insertBlock();
- d->caret.movePosition(QTextCursor::Left);
- d->caret.insertBlock(bibFormat);
- d->caret.movePosition(QTextCursor::Right);
-
- if (hasSelection) {
- d->caret.endEditBlock();
- endEditBlock();
- } else {
- d->updateState(KoTextEditor::Private::NoOp);
- }
-
- emit cursorPositionChanged();
-}
-
-KoInlineCite *KoTextEditor::insertCitation()
-{
- bool hasSelection = d->caret.hasSelection();
- if (!hasSelection) {
- d->updateState(KoTextEditor::Private::KeyPress, kundo2_i18n("Add Citation"));
- } else {
- KUndo2Command *topCommand = beginEditBlock(kundo2_i18n("Add Citation"));
- deleteChar(false, topCommand);
- d->caret.beginEditBlock();
- }
-
- KoInlineCite *cite = new KoInlineCite(KoInlineCite::Citation);
- KoInlineTextObjectManager *manager = KoTextDocument(d->document).inlineTextObjectManager();
- manager->insertInlineObject(d->caret,cite);
-
- if (hasSelection) {
- d->caret.endEditBlock();
- endEditBlock();
- } else {
- d->updateState(KoTextEditor::Private::NoOp);
- }
-
- return cite;
-}
-
-void KoTextEditor::insertText(const QString &text, const QString &hRef)
-{
- if (isEditProtected()) {
- return;
- }
-
- bool hasSelection = d->caret.hasSelection();
- if (!hasSelection) {
- d->updateState(KoTextEditor::Private::KeyPress, kundo2_i18n("Typing"));
- } else {
- KUndo2Command *topCommand = beginEditBlock(kundo2_i18n("Typing"));
- deleteChar(false, topCommand);
- d->caret.beginEditBlock();
- }
-
- //first we make sure that we clear the inlineObject charProperty, if we have no selection
- if (!hasSelection && d->caret.charFormat().hasProperty(KoCharacterStyle::InlineInstanceId))
- d->clearCharFormatProperty(KoCharacterStyle::InlineInstanceId);
-
- int startPosition = d->caret.position();
-
- if (d->caret.blockFormat().hasProperty(KoParagraphStyle::HiddenByTable)) {
- d->newLine(0);
- startPosition = d->caret.position();
- }
-
- QTextCharFormat format = d->caret.charFormat();
- if (format.hasProperty(KoCharacterStyle::ChangeTrackerId)) {
- format.clearProperty(KoCharacterStyle::ChangeTrackerId);
- }
- static QRegExp urlScanner("\\S+://\\S+");
- if (!hRef.isEmpty()) {
- format.setAnchor(true);
- format.setProperty(KoCharacterStyle::AnchorType, KoCharacterStyle::Anchor);
- if ((urlScanner.indexIn(hRef)) == 0) {//web url
- format.setAnchorHref(hRef);
- } else {
- format.setAnchorHref("#"+hRef);
- }
- }
- d->caret.insertText(text, format);
-
- int endPosition = d->caret.position();
-
- //Mark the inserted text
- d->caret.setPosition(startPosition);
- d->caret.setPosition(endPosition, QTextCursor::KeepAnchor);
-
- registerTrackedChange(d->caret, KoGenChange::InsertChange, kundo2_i18n("Typing"), format, format, false);
-
- d->caret.clearSelection();
-
- if (hasSelection) {
- d->caret.endEditBlock();
- endEditBlock();
- }
- if (!hRef.isEmpty()) {
- format.setAnchor(false);
- format.clearProperty(KoCharacterStyle::Anchor);
- format.clearProperty(KoCharacterStyle::AnchorType);
- d->caret.setCharFormat(format);
- }
- emit cursorPositionChanged();
-}
-
-void KoTextEditor::insertHtml(const QString &html)
-{
- if (isEditProtected()) {
- return;
- }
-
- // XXX: do the changetracking and everything!
- QTextBlock currentBlock = d->caret.block();
- d->caret.insertHtml(html);
-
- QList<QTextList *> pastedLists;
- KoList *currentPastedList = 0;
- while (currentBlock != d->caret.block()) {
- currentBlock = currentBlock.next();
- QTextList *currentTextList = currentBlock.textList();
- if(currentTextList && !pastedLists.contains(currentBlock.textList())) {
- KoListStyle *listStyle = KoTextDocument(d->document).styleManager()->defaultListStyle()->clone();
- listStyle->setName(QString());
- listStyle->setStyleId(0);
- currentPastedList = new KoList(d->document, listStyle);
- QTextListFormat currentTextListFormat = currentTextList->format();
-
- KoListLevelProperties levelProperty = listStyle->levelProperties(currentTextListFormat.indent());
- levelProperty.setStyle(static_cast<KoListStyle::Style>(currentTextListFormat.style()));
- levelProperty.setLevel(currentTextListFormat.indent());
- levelProperty.setListItemPrefix(QString());
- levelProperty.setListItemSuffix(QString());
- levelProperty.setListId((KoListStyle::ListIdType)currentTextList);
- listStyle->setLevelProperties(levelProperty);
-
- currentTextListFormat.setProperty(KoListStyle::Level, currentTextListFormat.indent());
- currentBlock.textList()->setFormat(currentTextListFormat);
-
- currentPastedList->updateStoredList(currentBlock);
- currentPastedList->setStyle(listStyle);
-
- pastedLists.append(currentBlock.textList());
- }
- }
-}
-
-bool KoTextEditor::movePosition(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode, int n)
-{
- d->editProtectionCached = false;
-
- // We need protection against moving in and out of note areas
- QTextCursor after(d->caret);
- bool b = after.movePosition (operation, mode, n);
-
- QTextFrame *beforeFrame = d->caret.currentFrame();
- while (qobject_cast<QTextTable *>(beforeFrame)) {
- beforeFrame = beforeFrame->parentFrame();
- }
-
- QTextFrame *afterFrame = after.currentFrame();
- while (qobject_cast<QTextTable *>(afterFrame)) {
- afterFrame = afterFrame->parentFrame();
- }
-
- if (beforeFrame == afterFrame) {
- if (after.selectionEnd() == after.document()->characterCount() -1) {
- QTextCursor cursor(d->caret.document()->rootFrame()->lastCursorPosition());
- cursor.movePosition(QTextCursor::PreviousCharacter);
- QTextFrame *auxFrame = cursor.currentFrame();
-
- if (auxFrame->format().intProperty(KoText::SubFrameType) == KoText::AuxillaryFrameType) {
- if (operation == QTextCursor::End) {
- d->caret.setPosition(auxFrame->firstPosition() - 1, mode);
- emit cursorPositionChanged();
- return true;
- }
- return false;
- }
- }
- d->caret = after;
- emit cursorPositionChanged();
- return b;
- }
- return false;
-}
-
-void KoTextEditor::newSection()
-{
- if (isEditProtected()) {
- return;
- }
-
- NewSectionCommand *cmd = new NewSectionCommand(d->document);
- addCommand(cmd);
- emit cursorPositionChanged();
-}
-
-void KoTextEditor::splitSectionsStartings(int sectionIdToInsertBefore)
-{
- if (isEditProtected()) {
- return;
- }
- addCommand(new SplitSectionsCommand(
- d->document,
- SplitSectionsCommand::Startings,
- sectionIdToInsertBefore));
- emit cursorPositionChanged();
-}
-
-void KoTextEditor::splitSectionsEndings(int sectionIdToInsertAfter)
-{
- if (isEditProtected()) {
- return;
- }
- addCommand(new SplitSectionsCommand(
- d->document,
- SplitSectionsCommand::Endings,
- sectionIdToInsertAfter));
- emit cursorPositionChanged();
-}
-
-void KoTextEditor::renameSection(KoSection* section, const QString &newName)
-{
- if (isEditProtected()) {
- return;
- }
- addCommand(new RenameSectionCommand(section, newName, document()));
-}
-
-void KoTextEditor::newLine()
-{
- if (isEditProtected()) {
- return;
- }
-
- bool hasSelection = d->caret.hasSelection();
- if (!hasSelection) {
- d->updateState(KoTextEditor::Private::Custom, kundo2_i18n("New Paragraph"));
- } else {
- KUndo2Command *topCommand = beginEditBlock(kundo2_i18n("New Paragraph"));
- deleteChar(false, topCommand);
- }
- d->caret.beginEditBlock();
-
- d->newLine(0);
-
- d->caret.endEditBlock();
-
- if (hasSelection) {
- endEditBlock();
- } else {
- d->updateState(KoTextEditor::Private::NoOp);
- }
-
- emit cursorPositionChanged();
-}
-
-class WithinSelectionVisitor : public KoTextVisitor
-{
-public:
- WithinSelectionVisitor(KoTextEditor *editor, int position)
- : KoTextVisitor(editor)
- , m_position(position)
- , m_returnValue(false)
- {
- }
-
- void visitBlock(QTextBlock &block, const QTextCursor &caret) override
- {
- if (m_position >= qMax(block.position(), caret.selectionStart())
- && m_position <= qMin(block.position() + block.length(), caret.selectionEnd())) {
- m_returnValue = true;
- setAbortVisiting(true);
- }
- }
- int m_position; //the position we are searching for
- bool m_returnValue; //if position is within the selection
-};
-
-bool KoTextEditor::isWithinSelection(int position) const
-{
- // we know the visitor doesn't do anything with the texteditor so let's const cast
- // to have a more beautiful outer api
- WithinSelectionVisitor visitor(const_cast<KoTextEditor *>(this), position);
-
- recursivelyVisitSelection(d->document->rootFrame()->begin(), visitor);
- return visitor.m_returnValue;
-}
-
-int KoTextEditor::position() const
-{
- return d->caret.position();
-}
-
-void KoTextEditor::select(QTextCursor::SelectionType selection)
-{
- //TODO add selection of previous/next char, and option about hasSelection
- d->caret.select(selection);
-}
-
-QString KoTextEditor::selectedText() const
-{
- return d->caret.selectedText();
-}
-
-QTextDocumentFragment KoTextEditor::selection() const
-{
- return d->caret.selection();
-}
-
-int KoTextEditor::selectionEnd() const
-{
- return d->caret.selectionEnd();
-}
-
-int KoTextEditor::selectionStart() const
-{
- return d->caret.selectionStart();
-}
-
-void KoTextEditor::setPosition(int pos, QTextCursor::MoveMode mode)
-{
- d->editProtectionCached = false;
-
- if (pos == d->caret.document()->characterCount() -1) {
- QTextCursor cursor(d->caret.document()->rootFrame()->lastCursorPosition());
- cursor.movePosition(QTextCursor::PreviousCharacter);
- QTextFrame *auxFrame = cursor.currentFrame();
-
- if (auxFrame->format().intProperty(KoText::SubFrameType) == KoText::AuxillaryFrameType) {
- return;
- }
- }
-
- if (mode == QTextCursor::MoveAnchor) {
- d->caret.setPosition (pos, mode);
- emit cursorPositionChanged();
- }
-
- // We need protection against moving in and out of note areas
- QTextCursor after(d->caret);
- after.setPosition (pos, mode);
-
- QTextFrame *beforeFrame = d->caret.currentFrame();
- while (qobject_cast<QTextTable *>(beforeFrame)) {
- beforeFrame = beforeFrame->parentFrame();
- }
-
- QTextFrame *afterFrame = after.currentFrame();
- while (qobject_cast<QTextTable *>(afterFrame)) {
- afterFrame = afterFrame->parentFrame();
- }
-
- if (beforeFrame == afterFrame) {
- d->caret = after;
- emit cursorPositionChanged();
- }
-}
-
-void KoTextEditor::setVisualNavigation(bool b)
-{
- d->caret.setVisualNavigation (b);
-}
-
-bool KoTextEditor::visualNavigation() const
-{
- return d->caret.visualNavigation();
-}
-
-const QTextFrame *KoTextEditor::currentFrame () const
-{
- return d->caret.currentFrame();
-}
-
-const QTextList *KoTextEditor::currentList () const
-{
- return d->caret.currentList();
-}
-
-const QTextTable *KoTextEditor::currentTable () const
-{
- return d->caret.currentTable();
-}
-
-//have to include this because of Q_PRIVATE_SLOT
-#include "moc_KoTextEditor.cpp"
diff --git a/plugins/flake/textshape/kotext/KoTextEditor.h b/plugins/flake/textshape/kotext/KoTextEditor.h
deleted file mode 100644
index 4708c735a6..0000000000
--- a/plugins/flake/textshape/kotext/KoTextEditor.h
+++ /dev/null
@@ -1,568 +0,0 @@
-/* This file is part of the KDE project
-* Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
-* Copyright (C) 2009 Thomas Zander <zander@kde.org>
-* Copyright (C) 2011 Boudewijn Rempt <boud@valdyas.org>
-* Copyright (C) 2011-2012 C. Boemann <cbo@boemann.dk>
-* Copyright (C) 2014 Denis Kuplyakov <dener.kup@gmail.com>
-*
-* 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 KOTEXTEDITOR_H
-#define KOTEXTEDITOR_H
-
-#include "kritatext_export.h"
-
-#include <kundo2magicstring.h>
-#include <KoGenChange.h>
-#include <KoBorder.h>
-#include <KoSection.h>
-
-#include <QMetaType>
-#include <QTextCursor>
-#include <QTextFrame>
-
-class KoListLevelProperties;
-class KoCharacterStyle;
-class KoInlineObject;
-class KoParagraphStyle;
-class KoInlineNote;
-class KoInlineCite;
-class KoBibliographyInfo;
-class KoCanvasBase;
-class KoTableOfContentsGeneratorInfo;
-class KoShapeAnchor;
-class KoShape;
-class KoBookmark;
-class KoAnnotation;
-class KoTextRangeManager;
-class KoTextVisitor;
-
-class KUndo2Command;
-
-class QTextBlock;
-class QTextCharFormat;
-class QTextBlockFormat;
-class QTextDocument;
-class QTextDocumentFragment;
-class QString;
-class QMimeData;
-
-
-/**
- * KoTextEditor is a wrapper around QTextCursor. It handles undo/redo and change
- * tracking for all editing commands.
- */
-class KRITATEXT_EXPORT KoTextEditor: public QObject
-{
- Q_OBJECT
-public:
- enum ChangeListFlag {
- NoFlags = 0,
- ModifyExistingList = 1,
- MergeWithAdjacentList = 2,
- MergeExactly = 4,
- CreateNumberedParagraph = 8,
- AutoListStyle = 16,
- DontUnsetIfSame = 32 /// do not unset the current list style if it is already been set the same
- };
- Q_DECLARE_FLAGS(ChangeListFlags, ChangeListFlag)
-
- explicit KoTextEditor(QTextDocument *document);
-
- ~KoTextEditor() override;
-
- /**
- * Retrieves the texteditor for the document of the first text shape in the current
- * set of selected shapes on the given canvas.
- *
- * @param canvas the canvas we will check for a suitable selected shape.
- * @returns a texteditor, or 0 if there is no shape active that has a QTextDocument as
- * userdata
- */
- static KoTextEditor *getTextEditorFromCanvas(KoCanvasBase *canvas);
-
-
-public: // KoToolSelection overloads
-
- /// returns true if the wrapped QTextCursor has a selection.
- bool hasSelection() const;
-
- /** returns true if the current cursor position is protected from editing
- * @param useCached use cached value if available.
- */
- bool isEditProtected(bool useCached = false) const;
-
-public:
-
- bool operator!=(const QTextCursor &other) const;
-
- bool operator<(const QTextCursor &other) const;
-
- bool operator<=(const QTextCursor &other) const;
-
- bool operator==(const QTextCursor &other) const;
-
- bool operator>(const QTextCursor &other) const;
-
- bool operator>=(const QTextCursor &other) const;
-
- const QTextCursor constCursor() const;
-
-private:
-
- // for the call to KoTextLoader::loadBody, which has a QTextCursor
- friend class KoTextPaste;
-
- // from KoTextEditor_p.h
- friend class CharFormatVisitor;
-
- // our commands can have access to us
- friend class DeleteTableRowCommand;
- friend class DeleteTableColumnCommand;
- friend class InsertTableRowCommand;
- friend class InsertTableColumnCommand;
- friend class ChangeTrackedDeleteCommand;
- friend class DeleteCommand;
- friend class InsertInlineObjectCommand;
- friend class InsertNoteCommand;
- friend class ParagraphFormattingCommand;
- friend class RenameSectionCommand;
- friend class NewSectionCommand;
- friend class SplitSectionsCommand;
-
- // for unittests
- friend class TestKoInlineTextObjectManager;
-
- // temporary...
- friend class TextShape;
- friend class TextTool;
-
- /**
- * This should be used only as read-only cursor or within a KUndo2Command sub-class which
- * will be added to the textEditor with addCommand. For examples of proper implementation of
- * such undoCommands, see the TextShape commands.
- */
- QTextCursor* cursor();
-
-public Q_SLOTS:
-
- /// This adds the \p command to the calligra undo stack.
- ///
- /// From this point forward all text manipulation is placed in the qt text systems internal
- /// undostack while also adding representative subcommands to \p command.
- ///
- /// The \p command is not redone as part of this process.
- ///
- /// \note Be aware that many KoTextEditor methods start their own commands thus terminating
- /// the recording of this \p command. Only use QTextCursor manipulation (with all the issues
- /// that brings) or only use KoTextEditor methods that don't start their own command.
- ///
- /// The recording is automatically terminated when another command is added, which as mentioned
- /// can happen by executing some of the KoTextEditor methods.
- void addCommand(KUndo2Command *command);
-
- /// This instantly "redo" the command thus placing all the text manipulation the "redo" does
- /// (should be implemented with a "first redo" pattern) in the qt text systems internal
- /// undostack while also adding representative subcommands to \p command.
- ///
- /// When \p command is done "redoing" no further text manipulation is added as subcommands.
- ///
- /// \p command is not put on the calligra undo stack. That is the responsibility of the
- /// caller, or the caller can choose to quickly undo and then delete the \p command.
- void instantlyExecuteCommand(KUndo2Command *command);
-
- void registerTrackedChange(QTextCursor &selection, KoGenChange::Type changeType, const KUndo2MagicString &title, QTextFormat &format, QTextFormat &prevFormat, bool applyToWholeBlock = false);
-
- void bold(bool bold);
-
- void italic(bool italic);
-
- void underline(bool underline);
-
- void strikeOut(bool strikeOut);
-
- void setHorizontalTextAlignment(Qt::Alignment align);
-
- void setVerticalTextAlignment(Qt::Alignment align);
-
- void increaseIndent();
-
- void decreaseIndent();
-
- void increaseFontSize();
-
- void decreaseFontSize();
-
- void setFontFamily(const QString &font);
-
- void setFontSize(qreal size);
-
- void setTextColor(const QColor &color);
-
- void setTextBackgroundColor(const QColor &color);
-
- void setStyle(KoParagraphStyle *style);
-
- void setStyle(KoCharacterStyle *style);
-
- void mergeAutoStyle(const QTextCharFormat &deltaCharFormat);
-
- void applyDirectFormatting(const QTextCharFormat &deltaCharFormat, const QTextBlockFormat &deltaBlockFormat, const KoListLevelProperties &llp);
-
- /**
- * Insert an inlineObject (such as a variable) at the current cursor position. Possibly replacing the selection.
- * @param inliner the object to insert.
- * @param parent a parent command for the commands created by this methods. If present, the commands
- * will not be added to the document's undo stack automatically.
- */
- void insertInlineObject(KoInlineObject *inliner, KUndo2Command *parent = 0);
-
- /**
- * update the position of all inline objects from the given start point to the given end point.
- * @param start start position for updating. If 0, we update from the start of the document
- * @param end end position for updating. If -1, we update to the end of the document
- */
- void updateInlineObjectPosition(int start = 0, int end = -1);
-
- /**
- * Remove the KoShapeAnchor objects from the document.
- *
- * NOTE: Call this method only when the shapes belonging to the anchors have been deleted.
- */
- void removeAnchors(const QList<KoShapeAnchor *> &anchors, KUndo2Command *parent);
-
- /**
- * Remove the KoAnnotation objects from the document.
- *
- * NOTE: Call this method only when the shapes belonging to the annotations have been deleted.
- * This is not the way to delete annotations directly - instead delete the shape or
- * delete the text containing the annotation
- */
- void removeAnnotations(const QList<KoAnnotation *> &annotations, KUndo2Command *parent);
-
- /**
- * At the current cursor position, insert a marker that marks the next word as being part of the index.
- * @returns returns the index marker when successful, or 0 if failed. Failure can be because there is no word
- * at the cursor position or there already is an index marker available.
- */
- KoInlineObject *insertIndexMarker();
-
- /// add a bookmark on current cursor location or current selection
- KoBookmark *addBookmark(const QString &name);
-
- /// Add an annotation at the current cursor location or the current selection.
- KoAnnotation *addAnnotation(KoShape *annotationShape);
-
- KoTextRangeManager *textRangeManager() const;
-
- /**
- * Insert a frame break at the cursor position, moving the rest of the text to the next frame.
- */
- void insertFrameBreak();
-
- /**
- * paste the given mimedata object at the current position
- * @param canvas the canvas we used when placing the shape.
- * @param mimeData: the mimedata containing text, html or odf
- * @param pasteAsText: if true, paste without formatting
- */
- void paste(KoCanvasBase *canvas, const QMimeData *mimeData, bool pasteAsText=false);
-
- /**
- * @param numberingEnabled when true, we will enable numbering for the current paragraph (block).
- */
- void toggleListNumbering(bool numberingEnabled);
-
- /**
- * change the current block's list properties
- */
- void setListProperties(const KoListLevelProperties &llp,
- ChangeListFlags flags = ChangeListFlags(ModifyExistingList | MergeWithAdjacentList), KUndo2Command *parent = 0);
-
- // -------------------------------------------------------------
- // Wrapped QTextCursor methods
- // -------------------------------------------------------------
-
- int anchor() const;
-
- bool atBlockEnd() const;
-
- bool atBlockStart() const;
-
- bool atEnd() const;
-
- bool atStart() const;
-
- QTextBlock block() const;
-
- QTextCharFormat blockCharFormat() const;
-
- QTextBlockFormat blockFormat() const;
-
- int blockNumber() const;
-
- QTextCharFormat charFormat() const;
-
- void clearSelection();
-
- int columnNumber() const;
-
- void deleteChar();
-
- void deletePreviousChar();
-
- QTextDocument *document() const;
-
- /// Same as Qt, only to be used inside KUndo2Commands
- KUndo2Command *beginEditBlock(const KUndo2MagicString &title = KUndo2MagicString());
- void endEditBlock();
-
- /**
- * Delete one character in the specified direction or a selection.
- * Warning: From the outside this method should only be used with a parent command
- * and only if there is a selection
- * @param previous should be true if act like backspace
- * @param parent the parent command used for stacking
- */
- void deleteChar(bool previous, KUndo2Command *parent = 0);
-
-
- bool hasComplexSelection() const;
-
- /**
- * Insert a table at the current cursor position.
- * @param rows the number of rows in the created table.
- * @param columns the number of columns in the created table.
- */
- void insertTable(int rows, int columns);
-
- /**
- * Insert a table row above the current cursor position (if in a table).
- */
- void insertTableRowAbove();
-
- /**
- * Insert a table row below the current cursor position (if in a table).
- */
- void insertTableRowBelow();
-
- /**
- * Insert a table column to the left of the current cursor position (if in a table).
- */
- void insertTableColumnLeft();
-
- /**
- * Insert a table column to the right of the current cursor position (if in a table).
- */
- void insertTableColumnRight();
-
- /**
- * Delete a table column where the cursor is (if in a table).
- */
- void deleteTableColumn();
-
- /**
- * Delete a table row where the cursor is (if in a table).
- */
- void deleteTableRow();
-
- /**
- * Merge table cells (selected by the cursor).
- */
- void mergeTableCells();
-
- /**
- * Split table cells (selected by the cursor) that were previously merged.
- */
- void splitTableCells();
-
- /**
- * Sets the width of a table column.
- * @param table is the table to be adjusted.
- * @param column the column that is to be adjusted.
- * @param width the new width of the column.
- * @param parentCommand the parent command used for stacking.
- */
- void adjustTableColumnWidth(QTextTable *table, int column, qreal width, KUndo2Command *parentCommand = 0);
-
- /**
- * Sets the height of a table row.
- * @param table is the table to be adjusted.
- * @param row the row that is to be adjusted.
- * @param height the row height.
- * @param parentCommand the parent command used for stacking.
- */
- void adjustTableRowHeight(QTextTable *table, int row, qreal height, KUndo2Command *parentCommand = 0);
-
- /**
- * Changes the width of a table by adjusting the margins.
- * @param table is the table to be adjusted.
- * @param dLeft delta value for the left margin.
- * @param dRight delta value for the right margin.
- */
- void adjustTableWidth(QTextTable *table, qreal dLeft, qreal dRight);
-
- /**
- * Sets the border formatting of a side in a table cell.
- * @param table is the table to be adjusted.
- * @param row the row coordinate of the cell that is to be adjusted.
- * @param column the column coordinate of the cell that is to be adjusted.
- * @param cellSide the side border of the cell.
- * @param data the border data.
- */
- void setTableBorderData(QTextTable *table, int row, int column, KoBorder::BorderSide cellSide,
- const KoBorder::BorderData &data);
-
- /**
- * Insert a footnote at the current cursor position
- * @return a pointer to the inserted footnote
- */
- KoInlineNote *insertFootNote();
-
- /**
- * Insert an endnote at the current cursor position
- * @return a pointer to the inserted endnote
- */
- KoInlineNote *insertEndNote();
-
- /**
- * Insert a table of Contents at the current cursor position.
- */
- void insertTableOfContents(KoTableOfContentsGeneratorInfo *info);
-
- /**
- * Configures various values of a ToC to the one passed in info
- */
- void setTableOfContentsConfig(KoTableOfContentsGeneratorInfo *info, const QTextBlock &block);
-
- void insertBibliography(KoBibliographyInfo *info);
-
- KoInlineCite *insertCitation();
-
- /**
- * Inserts the supplied text at the current cursor position. If the second argument is
- * supplied, a link is inserted at the current cursor position with the hRef as given
- * by the user. To test whether the supplied link destination is a web url or a bookmark,
- * a regular expression ( \\S+://\\S+ ) is used.
- * @param text is the text to be inserted
- * @param hRef if supplied is the Hypertext reference
- */
- void insertText(const QString &text, const QString &hRef = QString());
-
- void insertHtml(const QString &html);
-
- void mergeBlockFormat( const QTextBlockFormat &modifier);
-
- bool movePosition(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor, int n = 1);
-
- /**
- * Inserts a new paragraph and warps it to new section
- * Source:
- * some|textP
- * Result:
- * someP
- * [|textP]
- *
- * [] -- section bounds
- * | -- cursor зщышешщт
- * P -- paragraph sign
- */
- void newSection();
-
- /**
- * Splits sections startings and inserts paragraph between them.
- * Source: {sectionIdToInsertBefore == 1}
- * [[[sometext...
- * ^
- * 012
- * Result:
- * [P
- * [[sometext...
- *
- * [] -- section bounds
- * P -- paragraph sign
- */
- void splitSectionsStartings(int sectionIdToInsertBefore);
-
- /**
- * Splits section endings and insert paragraph between them.
- * Source: {sectionIdToInsertAfter == 1}
- * sometext]]]
- * ^
- * 012
- * Result:
- * sometext]]P
- * P]
- *
- * [] -- section bounds
- * P -- paragraph sign
- */
- void splitSectionsEndings(int sectionIdToInsertAfter);
-
- void renameSection(KoSection *section, const QString &newName);
-
- void newLine();
-
- bool isWithinSelection(int position) const;
-
- int position() const;
-
- void select(QTextCursor::SelectionType selection);
-
- QString selectedText() const;
-
- QTextDocumentFragment selection() const;
-
- int selectionEnd() const;
-
- int selectionStart() const;
-
- void setBlockFormat(const QTextBlockFormat &format);
-
- void setCharFormat(const QTextCharFormat &format);
-
- void setPosition(int pos, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor);
-
- void setVisualNavigation(bool on);
-
- bool visualNavigation() const;
-
- const QTextFrame *currentFrame () const;
- const QTextList *currentList () const;
- const QTextTable *currentTable () const;
-
-Q_SIGNALS:
- void cursorPositionChanged();
- void textFormatChanged();
- void characterStyleApplied(KoCharacterStyle *style);
- void paragraphStyleApplied(KoParagraphStyle *style);
-
-protected:
- void recursivelyVisitSelection(QTextFrame::iterator it, KoTextVisitor &visitor) const;
-
-private:
- Q_PRIVATE_SLOT(d, void documentCommandAdded())
-
- class Private;
- friend class Private;
- Private* const d;
-};
-
-Q_DECLARE_METATYPE(KoTextEditor*)
-Q_DECLARE_METATYPE(bool *)
-Q_DECLARE_OPERATORS_FOR_FLAGS(KoTextEditor::ChangeListFlags)
-
-#endif // KOTEXTEDITOR_H
diff --git a/plugins/flake/textshape/kotext/KoTextEditor_format.cpp b/plugins/flake/textshape/kotext/KoTextEditor_format.cpp
deleted file mode 100644
index 9091fa4093..0000000000
--- a/plugins/flake/textshape/kotext/KoTextEditor_format.cpp
+++ /dev/null
@@ -1,605 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2009-2012 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
- * Copyright (c) 2011 Boudewijn Rempt <boud@valdyas.org>
- * Copyright (C) 2011-2012 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2014 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 "KoTextEditor.h"
-#include "KoTextEditor_p.h"
-
-#include "styles/KoCharacterStyle.h"
-#include "styles/KoParagraphStyle.h"
-#include "styles/KoStyleManager.h"
-#include "commands/ParagraphFormattingCommand.h"
-
-#include <klocalizedstring.h>
-
-#include <QFontDatabase>
-#include <QTextBlock>
-#include <QTextBlockFormat>
-#include <QTextCharFormat>
-#include <QTextFormat>
-#include <QTextList>
-
-#include "TextDebug.h"
-#include "KoTextDebug.h"
-
-
-void KoTextEditor::Private::clearCharFormatProperty(int property)
-{
- class PropertyWiper : public CharFormatVisitor
- {
- public:
- PropertyWiper(int propertyId) : propertyId(propertyId) {}
- void visit(QTextCharFormat &format) const override {
- format.clearProperty(propertyId);
- }
-
- int propertyId;
- };
- PropertyWiper wiper(property);
- CharFormatVisitor::visitSelection(q, wiper, KUndo2MagicString(), false);
-}
-
-void KoTextEditor::bold(bool bold)
-{
- if (isEditProtected()) {
- return;
- }
-
- d->updateState(KoTextEditor::Private::Format, kundo2_i18n("Bold"));
- QTextCharFormat format;
- format.setFontWeight(bold ? QFont::Bold : QFont::Normal);
- mergeAutoStyle(format);
- d->updateState(KoTextEditor::Private::NoOp);
-}
-
-void KoTextEditor::italic(bool italic)
-{
- if (isEditProtected()) {
- return;
- }
-
- d->updateState(KoTextEditor::Private::Format, kundo2_i18n("Italic"));
- QTextCharFormat format;
- format.setFontItalic(italic);
- mergeAutoStyle(format);
- d->updateState(KoTextEditor::Private::NoOp);
-}
-
-void KoTextEditor::underline(bool underline)
-{
- if (isEditProtected()) {
- return;
- }
-
- d->updateState(KoTextEditor::Private::Format, kundo2_i18n("Underline"));
- QTextCharFormat format;
- if (underline) {
- format.setProperty(KoCharacterStyle::UnderlineType, KoCharacterStyle::SingleLine);
- format.setProperty(KoCharacterStyle::UnderlineStyle, KoCharacterStyle::SolidLine);
- } else {
- format.setProperty(KoCharacterStyle::UnderlineType, KoCharacterStyle::NoLineType);
- format.setProperty(KoCharacterStyle::UnderlineStyle, KoCharacterStyle::NoLineStyle);
- }
- mergeAutoStyle(format);
- d->updateState(KoTextEditor::Private::NoOp);
-}
-
-void KoTextEditor::strikeOut(bool strikeout)
-{
- if (isEditProtected()) {
- return;
- }
-
- d->updateState(KoTextEditor::Private::Format, kundo2_i18n("Strike Out"));
- QTextCharFormat format;
- if (strikeout) {
- format.setProperty(KoCharacterStyle::StrikeOutType, KoCharacterStyle::SingleLine);
- format.setProperty(KoCharacterStyle::StrikeOutStyle, KoCharacterStyle::SolidLine);
- } else {
- format.setProperty(KoCharacterStyle::StrikeOutType, KoCharacterStyle::NoLineType);
- format.setProperty(KoCharacterStyle::StrikeOutStyle, KoCharacterStyle::NoLineStyle);
- }
- mergeAutoStyle(format);
- d->updateState(KoTextEditor::Private::NoOp);
-}
-
-void KoTextEditor::setHorizontalTextAlignment(Qt::Alignment align)
-{
- if (isEditProtected()) {
- return;
- }
-
- class Aligner : public BlockFormatVisitor
- {
- public:
- Aligner(Qt::Alignment align) : alignment(align) {}
- void visit(QTextBlock &block) const override {
- QTextBlockFormat format = block.blockFormat();
- format.setAlignment(alignment);
- QTextCursor cursor(block);
- cursor.setBlockFormat(format);
- }
- Qt::Alignment alignment;
- };
-
- Aligner aligner(align);
- d->updateState(KoTextEditor::Private::Format, kundo2_i18n("Change Alignment"));
- BlockFormatVisitor::visitSelection(this, aligner, kundo2_i18n("Change Alignment"));
- d->updateState(KoTextEditor::Private::NoOp);
- emit textFormatChanged();
-}
-
-void KoTextEditor::setVerticalTextAlignment(Qt::Alignment align)
-{
- if (isEditProtected()) {
- return;
- }
-
- QTextCharFormat::VerticalAlignment charAlign = QTextCharFormat::AlignNormal;
- if (align == Qt::AlignTop)
- charAlign = QTextCharFormat::AlignSuperScript;
- else if (align == Qt::AlignBottom)
- charAlign = QTextCharFormat::AlignSubScript;
-
- d->updateState(KoTextEditor::Private::Format, kundo2_i18n("Set Vertical Alignment"));
- QTextCharFormat format;
- format.setVerticalAlignment(charAlign);
- mergeAutoStyle(format);
- d->updateState(KoTextEditor::Private::NoOp);
-}
-
-void KoTextEditor::decreaseIndent()
-{
- if (isEditProtected()) {
- return;
- }
-
- class Indenter : public BlockFormatVisitor
- {
- public:
- void visit(QTextBlock &block) const override {
- QTextBlockFormat format = block.blockFormat();
- // TODO make the 10 configurable.
- format.setLeftMargin(qMax(qreal(0.0), format.leftMargin() - 10));
-
- if (block.textList()) {
- const QTextListFormat listFormat = block.textList()->format();
- if (format.leftMargin() < listFormat.doubleProperty(KoListStyle::Margin)) {
- format.setLeftMargin(listFormat.doubleProperty(KoListStyle::Margin));
- }
- }
- QTextCursor cursor(block);
- cursor.setBlockFormat(format);
- }
- Qt::Alignment alignment;
- };
-
- Indenter indenter;
- d->updateState(KoTextEditor::Private::Format, kundo2_i18n("Decrease Indent"));
- BlockFormatVisitor::visitSelection(this, indenter, kundo2_i18n("Decrease Indent"));
- d->updateState(KoTextEditor::Private::NoOp);
- emit textFormatChanged();
-}
-
-void KoTextEditor::increaseIndent()
-{
- if (isEditProtected()) {
- return;
- }
-
- class Indenter : public BlockFormatVisitor
- {
- public:
- void visit(QTextBlock &block) const override {
- QTextBlockFormat format = block.blockFormat();
- // TODO make the 10 configurable.
-
- if (!block.textList()) {
- format.setLeftMargin(format.leftMargin() + 10);
- } else {
- const QTextListFormat listFormat = block.textList()->format();
- if (format.leftMargin() == 0) {
- format.setLeftMargin(listFormat.doubleProperty(KoListStyle::Margin) + 10);
- } else {
- format.setLeftMargin(format.leftMargin() + 10);
- }
- }
- QTextCursor cursor(block);
- cursor.setBlockFormat(format);
- }
- Qt::Alignment alignment;
- };
-
- Indenter indenter;
- d->updateState(KoTextEditor::Private::Format, kundo2_i18n("Increase Indent"));
- BlockFormatVisitor::visitSelection(this, indenter, kundo2_i18n("Increase Indent"));
- d->updateState(KoTextEditor::Private::NoOp);
- emit textFormatChanged();
-}
-
-class FontResizer : public CharFormatVisitor
-{
-public:
- enum Type { Grow, Shrink };
- FontResizer(Type type_) : type(type_) {
- QFontDatabase fontDB;
- defaultSizes = fontDB.standardSizes();
- }
- void visit(QTextCharFormat &format) const override {
- const qreal current = format.fontPointSize();
- int prev = 1;
- Q_FOREACH (int pt, defaultSizes) {
- if ((type == Grow && pt > current) || (type == Shrink && pt >= current)) {
- format.setFontPointSize(type == Grow ? pt : prev);
- return;
- }
- prev = pt;
- }
- }
-
- QList<int> defaultSizes;
- const Type type;
-};
-
-void KoTextEditor::decreaseFontSize()
-{
- if (isEditProtected()) {
- return;
- }
-
- d->updateState(KoTextEditor::Private::Format, kundo2_i18n("Decrease font size"));
- FontResizer sizer(FontResizer::Shrink);
- CharFormatVisitor::visitSelection(this, sizer, kundo2_i18n("Decrease font size"));
- d->updateState(KoTextEditor::Private::NoOp);
- emit textFormatChanged();
-}
-
-void KoTextEditor::increaseFontSize()
-{
- if (isEditProtected()) {
- return;
- }
-
- d->updateState(KoTextEditor::Private::Format, kundo2_i18n("Increase font size"));
- FontResizer sizer(FontResizer::Grow);
- CharFormatVisitor::visitSelection(this, sizer, kundo2_i18n("Increase font size"));
- d->updateState(KoTextEditor::Private::NoOp);
- emit textFormatChanged();
-}
-
-void KoTextEditor::setFontFamily(const QString &font)
-{
- if (isEditProtected()) {
- return;
- }
-
- d->updateState(KoTextEditor::Private::Format, kundo2_i18n("Set Font"));
- QTextCharFormat format;
- format.setFontFamily(font);
- mergeAutoStyle(format);
- d->updateState(KoTextEditor::Private::NoOp);
-}
-
-void KoTextEditor::setFontSize(qreal size)
-{
- if (isEditProtected()) {
- return;
- }
-
- d->updateState(KoTextEditor::Private::Format, kundo2_i18n("Set Font Size"));
- QTextCharFormat format;
- format.setFontPointSize(size);
- mergeAutoStyle(format);
- d->updateState(KoTextEditor::Private::NoOp);
-}
-
-void KoTextEditor::setTextBackgroundColor(const QColor &color)
-{
- if (isEditProtected()) {
- return;
- }
-
- d->updateState(KoTextEditor::Private::Format, kundo2_i18n("Set Background Color"));
- QTextCharFormat format;
- format.setBackground(QBrush(color));
- mergeAutoStyle(format);
- d->updateState(KoTextEditor::Private::NoOp);
-}
-
-void KoTextEditor::setTextColor(const QColor &color)
-{
- if (isEditProtected()) {
- return;
- }
-
- d->updateState(KoTextEditor::Private::Format, kundo2_i18n("Set Text Color"));
- QTextCharFormat format;
- format.setForeground(QBrush(color));
- mergeAutoStyle(format);
- d->updateState(KoTextEditor::Private::NoOp);
-}
-
-class SetCharacterStyleVisitor : public KoTextVisitor
-{
-public:
- SetCharacterStyleVisitor(KoTextEditor *editor, KoCharacterStyle *style)
- : KoTextVisitor(editor)
- , m_style(style)
- {
- }
-
- void visitBlock(QTextBlock &block, const QTextCursor &caret) override
- {
- m_newFormat = block.charFormat();
- m_style->applyStyle(m_newFormat);
- m_style->ensureMinimalProperties(m_newFormat);
-
- KoTextVisitor::visitBlock(block, caret);
-
- QList<QTextCharFormat>::Iterator it = m_formats.begin();
- Q_FOREACH (QTextCursor cursor, m_cursors) {
- QTextFormat prevFormat(cursor.charFormat());
- cursor.setCharFormat(*it);
- editor()->registerTrackedChange(cursor, KoGenChange::FormatChange, kundo2_i18n("Set Character Style"), *it, prevFormat, false);
- ++it;
- }
- }
-
- void visitFragmentSelection(QTextCursor &fragmentSelection) override
- {
- QTextCharFormat format = m_newFormat;
-
- QVariant v;
- v = fragmentSelection.charFormat().property(KoCharacterStyle::InlineInstanceId);
- if (!v.isNull()) {
- format.setProperty(KoCharacterStyle::InlineInstanceId, v);
- }
-
- v = fragmentSelection.charFormat().property(KoCharacterStyle::ChangeTrackerId);
- if (!v.isNull()) {
- format.setProperty(KoCharacterStyle::ChangeTrackerId, v);
- }
-
- if (fragmentSelection.charFormat().isAnchor()) {
- format.setAnchor(true);
- format.setProperty(KoCharacterStyle::AnchorType, fragmentSelection.charFormat().intProperty(KoCharacterStyle::AnchorType));
- format.setAnchorHref(fragmentSelection.charFormat().anchorHref());
- }
-
- m_formats.append(format);
- m_cursors.append(fragmentSelection);
- }
-
- KoCharacterStyle *m_style;
- QTextCharFormat m_newFormat;
- QList<QTextCharFormat> m_formats;
- QList<QTextCursor> m_cursors;
-};
-
-void KoTextEditor::setStyle(KoCharacterStyle *style)
-{
- Q_ASSERT(style);
- d->updateState(KoTextEditor::Private::Custom, kundo2_i18n("Set Character Style"));
-
- int caretAnchor = d->caret.anchor();
- int caretPosition = d->caret.position();
-
- SetCharacterStyleVisitor visitor(this, style);
-
- recursivelyVisitSelection(d->document->rootFrame()->begin(), visitor);
-
- if (!isEditProtected() && caretAnchor == caretPosition) { //if there is no selection, it can happen that the caret does not get the proper style applied (beginning of a block). We need to force it.
- //applying a style is absolute, so first initialise the caret with the frame's style, then apply the paragraph's. Finally apply the character style
- QTextCharFormat charFormat = KoTextDocument(d->document).frameCharFormat();
- KoStyleManager *styleManager = KoTextDocument(d->document).styleManager();
- KoParagraphStyle *paragraphStyle = styleManager->paragraphStyle(d->caret.charFormat().intProperty(KoParagraphStyle::StyleId));
- if (paragraphStyle) {
- paragraphStyle->KoCharacterStyle::applyStyle(charFormat);
- }
- d->caret.setCharFormat(charFormat);
- style->applyStyle(&(d->caret));
- }
- else { //if the caret has a selection, the visitor has already applied the style, reset the caret's position so it picks the proper style.
- d->caret.setPosition(caretAnchor);
- d->caret.setPosition(caretPosition, QTextCursor::KeepAnchor);
- }
-
- d->updateState(KoTextEditor::Private::NoOp);
- emit textFormatChanged();
- emit characterStyleApplied(style);
-}
-
-
-class SetParagraphStyleVisitor : public KoTextVisitor
-{
-public:
- SetParagraphStyleVisitor(KoTextEditor *editor, KoStyleManager *styleManager, KoParagraphStyle *style)
- : KoTextVisitor(editor)
- , m_styleManager(styleManager)
- , m_style(style)
- {
- }
-
- void visitBlock(QTextBlock &block, const QTextCursor &) override
- {
- if (m_styleManager) {
- QTextBlockFormat bf = block.blockFormat();
- KoParagraphStyle *old = m_styleManager->paragraphStyle(bf.intProperty(KoParagraphStyle::StyleId));
- if (old)
- old->unapplyStyle(block);
- }
- // The above should unapply the style and it's lists part, but we want to clear everything
- // except section info.
- QTextCursor cursor(block);
- QVariant sectionStartings = cursor.blockFormat().property(KoParagraphStyle::SectionStartings);
- QVariant sectionEndings = cursor.blockFormat().property(KoParagraphStyle::SectionEndings);
- QTextBlockFormat fmt;
- fmt.setProperty(KoParagraphStyle::SectionStartings, sectionStartings);
- fmt.setProperty(KoParagraphStyle::SectionEndings, sectionEndings);
- cursor.setBlockFormat(fmt);
- m_style->applyStyle(block);
- }
-
- KoStyleManager *m_styleManager;
- KoParagraphStyle *m_style;
-};
-
-void KoTextEditor::setStyle(KoParagraphStyle *style)
-{
- d->updateState(KoTextEditor::Private::Custom, kundo2_i18n("Set Paragraph Style"));
-
- int caretAnchor = d->caret.anchor();
- int caretPosition = d->caret.position();
- KoStyleManager *styleManager = KoTextDocument(d->document).styleManager();
- SetParagraphStyleVisitor visitor(this, styleManager, style);
-
- recursivelyVisitSelection(d->document->rootFrame()->begin(), visitor);
-
- if (!isEditProtected() && caretAnchor == caretPosition) { //if there is no selection, it can happen that the caret does not get the proper style applied (beginning of a block). We need to force it.
- //applying a style is absolute, so first initialise the caret with the frame's style, then apply the paragraph style
- QTextCharFormat charFormat = KoTextDocument(d->document).frameCharFormat();
- d->caret.setCharFormat(charFormat);
- style->KoCharacterStyle::applyStyle(&(d->caret));
- }
- else {
- d->caret.setPosition(caretAnchor);
- d->caret.setPosition(caretPosition, QTextCursor::KeepAnchor);
- }
-
- d->updateState(KoTextEditor::Private::NoOp);
- emit paragraphStyleApplied(style);
- emit textFormatChanged();
-}
-
-class MergeAutoCharacterStyleVisitor : public KoTextVisitor
-{
-public:
- MergeAutoCharacterStyleVisitor(KoTextEditor *editor, QTextCharFormat deltaCharFormat)
- : KoTextVisitor(editor)
- , m_deltaCharFormat(deltaCharFormat)
- {
- }
-
- void visitBlock(QTextBlock &block, const QTextCursor &caret) override
- {
- KoTextVisitor::visitBlock(block, caret);
-
- QList<QTextCharFormat>::Iterator it = m_formats.begin();
- Q_FOREACH (QTextCursor cursor, m_cursors) {
- QTextFormat prevFormat(cursor.charFormat());
- cursor.setCharFormat(*it);
- editor()->registerTrackedChange(cursor, KoGenChange::FormatChange, kundo2_i18n("Formatting"), *it, prevFormat, false);
- ++it;
- }
- }
-
- void visitFragmentSelection(QTextCursor &fragmentSelection) override
- {
- QTextCharFormat format = fragmentSelection.charFormat();
- format.merge(m_deltaCharFormat);
-
- m_formats.append(format);
- m_cursors.append(fragmentSelection);
- }
-
- QTextCharFormat m_deltaCharFormat;
- QList<QTextCharFormat> m_formats;
- QList<QTextCursor> m_cursors;
-};
-
-void KoTextEditor::mergeAutoStyle(const QTextCharFormat &deltaCharFormat)
-{
- d->updateState(KoTextEditor::Private::Custom, kundo2_i18n("Formatting"));
-
- int caretAnchor = d->caret.anchor();
- int caretPosition = d->caret.position();
- MergeAutoCharacterStyleVisitor visitor(this, deltaCharFormat);
-
- recursivelyVisitSelection(d->document->rootFrame()->begin(), visitor);
-
- if (!isEditProtected() && caretAnchor == caretPosition) { //if there is no selection, it can happen that the caret does not get the proper style applied (beginning of a block). We need to force it.
- d->caret.mergeCharFormat(deltaCharFormat);
- }
- else {
- d->caret.setPosition(caretAnchor);
- d->caret.setPosition(caretPosition, QTextCursor::KeepAnchor);
- }
-
- d->updateState(KoTextEditor::Private::NoOp);
- emit textFormatChanged();
-}
-
-
-void KoTextEditor::applyDirectFormatting(const QTextCharFormat &deltaCharFormat,
- const QTextBlockFormat &deltaBlockFormat,
- const KoListLevelProperties &llp)
-{
- addCommand(new ParagraphFormattingCommand(this, deltaCharFormat, deltaBlockFormat, llp));
- emit textFormatChanged();
-}
-
-QTextCharFormat KoTextEditor::blockCharFormat() const
-{
- return d->caret.blockCharFormat();
-}
-
-QTextBlockFormat KoTextEditor::blockFormat() const
-{
- return d->caret.blockFormat();
-}
-
-QTextCharFormat KoTextEditor::charFormat() const
-{
- return d->caret.charFormat();
-}
-
-
-void KoTextEditor::mergeBlockFormat(const QTextBlockFormat &modifier)
-{
- if (isEditProtected()) {
- return;
- }
- d->caret.mergeBlockFormat(modifier);
- emit textFormatChanged();
-}
-
-
-void KoTextEditor::setBlockFormat(const QTextBlockFormat &format)
-{
- if (isEditProtected()) {
- return;
- }
-
- Q_UNUSED(format)
- d->caret.setBlockFormat(format);
- emit textFormatChanged();
-}
-
-void KoTextEditor::setCharFormat(const QTextCharFormat &format)
-{
- if (isEditProtected()) {
- return;
- }
-
- d->caret.setCharFormat(format);
- emit textFormatChanged();
-}
diff --git a/plugins/flake/textshape/kotext/KoTextEditor_p.h b/plugins/flake/textshape/kotext/KoTextEditor_p.h
deleted file mode 100644
index 18c3a53c1c..0000000000
--- a/plugins/flake/textshape/kotext/KoTextEditor_p.h
+++ /dev/null
@@ -1,264 +0,0 @@
-/* This file is part of the KDE project
-* Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
-* Copyright (C) 2009 Thomas Zander <zander@kde.org>
-* Copyright (C) 2015 Soma Schliszka <soma.schliszka@gmail.com>
-*
-* 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 KOTEXTEDITOR_P_H
-#define KOTEXTEDITOR_P_H
-
-#include "KoTextEditor.h"
-
-#include "KoTextDocument.h"
-#include "styles/KoParagraphStyle.h"
-#include "styles/KoStyleManager.h"
-#include "changetracker/KoChangeTracker.h"
-
-#include <klocalizedstring.h>
-#include <kundo2magicstring.h>
-
-#include <QStack>
-#include <QTextBlock>
-#include <QTextDocument>
-#include <QTextTableCell>
-#include <QTimer>
-
-class KUndo2Command;
-
-class Q_DECL_HIDDEN KoTextEditor::Private
-{
-public:
- enum State {
- NoOp,
- KeyPress,
- Delete,
- Format,
- Custom
- };
-
- explicit Private(KoTextEditor *qq, QTextDocument *document);
-
- ~Private() {}
-
- void documentCommandAdded();
- void updateState(State newState, const KUndo2MagicString &title = KUndo2MagicString());
-
- void newLine(KUndo2Command *parent);
- void clearCharFormatProperty(int propertyId);
-
- void emitTextFormatChanged();
-
- KoTextEditor *q;
- QTextCursor caret;
- QTextDocument *document;
- QStack<KUndo2Command*> commandStack;
- bool addNewCommand;
- bool dummyMacroAdded;
- int customCommandCount;
- KUndo2MagicString commandTitle;
-
- State editorState;
-
- bool editProtected;
- bool editProtectionCached;
-};
-
-class KoTextVisitor
-{
-public:
- /// The ObjectVisitingMode enum marks how was the visited object selected.
- enum ObjectVisitingMode {
- Partly, /// The visited object (table, cell, ...) is just @b partly selected. (Eg. just one cell is selected in the visited table)
- Entirely, /// The visited object (table, cell, ...) is @b entirely selected.
- };
-
- explicit KoTextVisitor(KoTextEditor *editor)
- : m_abortVisiting(false)
- , m_editor(editor)
- {
- }
-
- virtual ~KoTextVisitor() {}
- // called whenever a visit was prevented by editprotection
- virtual void nonVisit() {}
-
- virtual void visitFragmentSelection(QTextCursor &)
- {
- }
-
- /**
- * This method allows to perform custom operation when the visitor reaches a QTextTable
- * @param visitedTable pointer to the currently visited table object
- * @param visitingMode flag, marks if the table is just partly visited or entirely
- */
- virtual void visitTable(QTextTable *visitedTable, ObjectVisitingMode visitingMode)
- {
- Q_UNUSED(visitedTable);
- Q_UNUSED(visitingMode);
- }
-
- /**
- * This method allows to perform custom operation when the visitor reaches a QTextTableCell
- * @param visitedCell pointer to the currently visited cell object
- * @param visitingMode flag, marks if the cell is just partly visited or entirely
- */
- virtual void visitTableCell(QTextTableCell *visitedCell, ObjectVisitingMode visitingMode)
- {
- Q_UNUSED(visitedCell);
- Q_UNUSED(visitingMode);
- }
-
- // The default implementation calls visitFragmentSelection on each fragment.intersect.selection
- virtual void visitBlock(QTextBlock &block, const QTextCursor &caret)
- {
- for (QTextBlock::iterator it = block.begin(); it != block.end(); ++it) {
- QTextCursor fragmentSelection(caret);
- fragmentSelection.setPosition(qMax(caret.selectionStart(), it.fragment().position()));
- fragmentSelection.setPosition(qMin(caret.selectionEnd(), it.fragment().position() + it.fragment().length()), QTextCursor::KeepAnchor);
-
- if (fragmentSelection.anchor() >= fragmentSelection.position()) {
- continue;
- }
-
- visitFragmentSelection(fragmentSelection);
- }
- }
-
- bool abortVisiting() { return m_abortVisiting;}
- void setAbortVisiting(bool abort) {m_abortVisiting = abort;}
- KoTextEditor * editor() const {return m_editor;}
-private:
- bool m_abortVisiting;
- KoTextEditor *m_editor;
-};
-
-class BlockFormatVisitor
-{
-public:
- BlockFormatVisitor() {}
- virtual ~BlockFormatVisitor() {}
-
- virtual void visit(QTextBlock &block) const = 0;
-
- static void visitSelection(KoTextEditor *editor, const BlockFormatVisitor &visitor, const KUndo2MagicString &title = kundo2_i18n("Format"), bool resetProperties = false, bool registerChange = true) {
- int start = qMin(editor->position(), editor->anchor());
- int end = qMax(editor->position(), editor->anchor());
-
- QTextBlock block = editor->block();
- if (block.position() > start)
- block = block.document()->findBlock(start);
-
- // now loop over all blocks that the selection contains and alter the text fragments where applicable.
- while (block.isValid() && block.position() <= end) {
- QTextBlockFormat prevFormat = block.blockFormat();
- if (resetProperties) {
- if (KoTextDocument(editor->document()).styleManager()) {
- KoParagraphStyle *old = KoTextDocument(editor->document()).styleManager()->paragraphStyle(block.blockFormat().intProperty(KoParagraphStyle::StyleId));
- if (old)
- old->unapplyStyle(block);
- }
- }
- visitor.visit(block);
- QTextCursor cursor(block);
- QTextBlockFormat format = cursor.blockFormat();
- if (registerChange)
- editor->registerTrackedChange(cursor, KoGenChange::FormatChange, title, format, prevFormat, true);
- block = block.next();
- }
- }
-};
-
-class CharFormatVisitor
-{
-public:
- CharFormatVisitor() {}
- virtual ~CharFormatVisitor() {}
-
- virtual void visit(QTextCharFormat &format) const = 0;
-
- static void visitSelection(KoTextEditor *editor, const CharFormatVisitor &visitor, const KUndo2MagicString &title = kundo2_i18n("Format"), bool registerChange = true) {
- int start = qMin(editor->position(), editor->anchor());
- int end = qMax(editor->position(), editor->anchor());
- if (start == end) { // just set a new one.
- QTextCharFormat format = editor->charFormat();
- visitor.visit(format);
-
- if (registerChange && KoTextDocument(editor->document()).changeTracker() && KoTextDocument(editor->document()).changeTracker()->recordChanges()) {
- QTextCharFormat prevFormat(editor->charFormat());
-
- int changeId = KoTextDocument(editor->document()).changeTracker()->getFormatChangeId(title, format, prevFormat, editor->charFormat().property( KoCharacterStyle::ChangeTrackerId ).toInt());
- format.setProperty(KoCharacterStyle::ChangeTrackerId, changeId);
- }
-
- editor->cursor()->setCharFormat(format);
- return;
- }
-
- QTextBlock block = editor->block();
- if (block.position() > start)
- block = block.document()->findBlock(start);
-
- QList<QTextCursor> cursors;
- QList<QTextCharFormat> formats;
- // now loop over all blocks that the selection contains and alter the text fragments where applicable.
- while (block.isValid() && block.position() < end) {
- QTextBlock::iterator iter = block.begin();
- while (! iter.atEnd()) {
- QTextFragment fragment = iter.fragment();
- if (fragment.position() > end)
- break;
- if (fragment.position() + fragment.length() <= start) {
- ++iter;
- continue;
- }
-
- QTextCursor cursor(block);
- cursor.setPosition(fragment.position() + 1);
- QTextCharFormat format = cursor.charFormat(); // this gets the format one char after the position.
- visitor.visit(format);
-
- if (registerChange && KoTextDocument(editor->document()).changeTracker() && KoTextDocument(editor->document()).changeTracker()->recordChanges()) {
- QTextCharFormat prevFormat(cursor.charFormat());
-
- int changeId = KoTextDocument(editor->document()).changeTracker()->getFormatChangeId(title, format, prevFormat, cursor.charFormat().property( KoCharacterStyle::ChangeTrackerId ).toInt());
- format.setProperty(KoCharacterStyle::ChangeTrackerId, changeId);
- }
-
- cursor.setPosition(qMax(start, fragment.position()));
- int to = qMin(end, fragment.position() + fragment.length());
- cursor.setPosition(to, QTextCursor::KeepAnchor);
- cursors.append(cursor);
- formats.append(format);
-
- QTextCharFormat prevFormat(cursor.charFormat());
- if (registerChange)
- editor->registerTrackedChange(cursor,KoGenChange::FormatChange,title, format, prevFormat, false); //this will lead to every fragment having a different change until the change merging in registerTrackedChange checks also for formatChange or not?
-
- ++iter;
- }
- block = block.next();
- }
- QList<QTextCharFormat>::Iterator iter = formats.begin();
- Q_FOREACH (QTextCursor cursor, cursors) {
- cursor.setCharFormat(*iter);
- ++iter;
- }
- }
-};
-
-#endif //KOTEXTEDITOR_P_H
diff --git a/plugins/flake/textshape/kotext/KoTextEditor_undo.cpp b/plugins/flake/textshape/kotext/KoTextEditor_undo.cpp
deleted file mode 100644
index d131318109..0000000000
--- a/plugins/flake/textshape/kotext/KoTextEditor_undo.cpp
+++ /dev/null
@@ -1,329 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2009-2012 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
- * Copyright (c) 2011 Boudewijn Rempt <boud@valdyas.org>
- * Copyright (C) 2011-2012 C. Boemann <cbo@boemann.dk>
- *
- * 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 "KoTextEditor.h"
-#include "KoTextEditor_p.h"
-
-#include "KoTextDocument.h"
-
-#include <kundo2command.h>
-
-#include <klocalizedstring.h>
-
-#include <QTextDocument>
-#include <QWeakPointer>
-
-#include "TextDebug.h"
-
-/** Calligra's undo/redo framework.
- The @c KoTextEditor undo/redo framework sits between the @c QTextDocument and the application's undo/redo stack.
-
- When the @c QTextDocument is changed by an editing action, it internally creates an undo/redo command. When doing so a signal (undoCommandAdded()) is emitted by the @c QTextDocument in order for applications to update their undo/redo stack accordingly.
- Each @c QTextDocument used in Calligra is handled by a specific @c KoTextEditor. It is responsible for on the one hand edit the @c QTextDocument, and on the other hand to listen for the QTextDocument's signal.
-
- Calligra uses a @c KUndo2Stack as its application undo/redo stack. This stack is populated by @c KUndo2Command or sub-classes of it.
-
- In order to limit the number of command sub-classes, KoTextEditor provides a framework which uses a generic command.
-
- The framework is based on a sort of state machine. The KoTextEditor can be in several different states (see @ref KoTextEditor::Private::State ).
- These are:
- @c NoOp : this states indicates that the KoTextEditor is not editing the QTextDocument.
- @c KeyPress : this state indicates that the user is typing text. All text typed in succession should correspond to one undo command. To be used when entering text outside of an insertTextCommand.
- @c Delete : this state indicates that the user is deleting characters. All deletions done in succession should correspond to one undo command. To be used for deleting outside a deleteCommand. Currently not in use, our deletion is done through a command because of inline objects.
- @c Format : this state indicates that we are formatting text. To be used when formatting outside of a command.
- @c Custom : this state indicates that the QTextDocument is changed through a KUndo2Command.
-
- KoTextEditor reacts differently when receiving the QTextDocument's signal, depending on its state.
-
- In addition the framework allows to encapsulate modifications in a on-the-fly created custom command (\sa beginEditBlock() endEditBlock()).
- Furthermore the framework allows to push complete KUndo2Commands.
-
- See the documentation file for how to use this framework.
-*/
-
-/*
- Important members:
-
- commandStack: This stack holds the headCommands. These parent the generated UndoTextCommands. When undo or redo is called, they will in turn call UndoTextCommand::undo/redo.
-
- editorState: Holds the state of the KoTextEditor. see above
-
- commandTitle: Holds the title which is to be used when creating a headCommand.
-
- addNewCommand: bool used to tell the framework to create a new headCommand and push it on the commandStack, when receiving an undoCommandAdded signal from QTextDocument.
-
- customCommandCount: counter used to keep track of nested KUndo2Commands that are pushed on the KoTextEditor.
- */
-
-
-// This slot is called when the KoTextEditor receives the signal undoCommandAdded() from QTextDocument. A generic UndoTextCommand is used to match the QTextDocument's internal undo command. This command calls QTextDocument::undo() or QTextDocument::redo() respectively, which triggers the undo redo actions on the document.
-//In order to allow nesting commands, we maintain a stack of commands. The top command will be the parent of our auto generated UndoTextCommands.
-//Depending on the case, we might create a command which will serve as head command. This is pushed to our commandStack and eventually to the application's stack.
-void KoTextEditor::Private::documentCommandAdded()
-{
- class UndoTextCommand : public KUndo2Command
- {
- public:
- UndoTextCommand(QTextDocument *document, KoTextEditor::Private *p, KUndo2Command *parent = 0)
- : KUndo2Command(kundo2_i18n("Text"), parent),
- m_document(document)
- , m_p(p)
- {}
-
- void undo() override {
- QTextDocument *doc = m_document.data();
- if (doc == 0)
- return;
- doc->undo(KoTextDocument(doc).textEditor()->cursor());
- m_p->emitTextFormatChanged();
- }
-
- void redo() override {
- QTextDocument *doc = m_document.data();
- if (doc == 0)
- return;
- doc->redo(KoTextDocument(doc).textEditor()->cursor());
- m_p->emitTextFormatChanged();
- }
-
- QWeakPointer<QTextDocument> m_document;
- KoTextEditor::Private *m_p;
- };
-
- debugText << "received a QTextDocument undoCommand signal";
- debugText << "commandStack count: " << commandStack.count();
- debugText << "addCommand: " << addNewCommand;
- debugText << "editorState: " << editorState;
- if (commandStack.isEmpty()) {
- //We have an empty stack. We need a head command which is to be pushed onto our commandStack and on the application stack if there is one.
- //This command will serve as a parent for the auto-generated UndoTextCommands.
- debugText << "empty stack, will push a new headCommand on both commandStack and application's stack. title: " << commandTitle;
- commandStack.push(new KUndo2Command(commandTitle));
- if (KoTextDocument(document).undoStack()) {
- KoTextDocument(document).undoStack()->push(commandStack.top());
- }
- addNewCommand = false;
- debugText << "commandStack is now: " << commandStack.count();
- }
- else if (addNewCommand) {
- //We have already a headCommand on the commandStack. However we want a new child headCommand (nested commands) on the commandStack for parenting further UndoTextCommands. This shouldn't be pushed on the application's stack because it is a child of the current commandStack's top.
- debugText << "we have a headCommand on the commandStack but need a new child command. we will push it only on the commandStack: " << commandTitle;
- commandStack.push(new KUndo2Command(commandTitle, commandStack.top()));
- addNewCommand = false;
- debugText << "commandStack count is now: " << commandStack.count();
- }
- else if ((editorState == KeyPress || editorState == Delete) && !commandStack.isEmpty() && commandStack.top()->childCount()) {
- //QTextDocument emits a signal on the first key press (or delete) and "merges" the subsequent ones, until an incompatible one is done. In which case it re-emit a signal.
- //Here we are in KeyPress (or Delete) state. The fact that the commandStack isn't empty and its top command has children means that we just received such a signal. We therefore need to pop the previous headCommand (which were either key press or delete) and create a new one to parent the UndoTextCommands. This command also need to be pushed on the application's stack.
- debugText << "we are in subsequent keyPress/delete state and still received a signal. we need to create a new headCommand: " << commandTitle;
- debugText << "so we pop the current one and push the new one on both the commandStack and the application's stack";
- commandStack.pop();
- commandStack.push(new KUndo2Command(commandTitle, !commandStack.isEmpty()?commandStack.top():0));
- if (KoTextDocument(document).undoStack()) {
- KoTextDocument(document).undoStack()->push(commandStack.top());
- }
- debugText << "commandStack count: " << commandStack.count();
- }
-
- //Now we can create our UndoTextCommand which is parented to the commandStack't top headCommand.
- new UndoTextCommand(document, this, commandStack.top());
- debugText << "done creating the dummy UndoTextCommand";
-}
-
-//This method is used to update the KoTextEditor state, which will condition how the QTextDocument::undoCommandAdded signal will get handled.
-void KoTextEditor::Private::updateState(KoTextEditor::Private::State newState, const KUndo2MagicString &title)
-{
- debugText << "updateState from: " << editorState << " to: " << newState << " with: " << title;
- debugText << "commandStack count: " << commandStack.count();
- if (editorState == Custom && newState != NoOp) {
- //We already are in a custom state (meaning that either a KUndo2Command was pushed on us, an on-the-fly macro command was started or we are executing a complex editing from within the KoTextEditor.
- //In that state any update of the state different from NoOp is part of that "macro". However, updating the state means that we are now wanting to have a new command for parenting the UndoTextCommand generated after the signal
- //from QTextDocument. This is to ensure that undo/redo actions are done in the proper order. Setting addNewCommand will ensure that we create such a child headCommand on the commandStack. This command will not be pushed on the application's stack.
- debugText << "we are already in a custom state. a new state, which is not NoOp is part of the macro we are doing. we need however to create a new command on the commandStack to parent a signal induced UndoTextCommand";
- addNewCommand = true;
- if (!title.isEmpty())
- commandTitle = title;
- else
- commandTitle = kundo2_i18n("Text");
- debugText << "returning now. commandStack is not modified at this stage";
- return;
- }
- if (newState == NoOp && !commandStack.isEmpty()) {
- //Calling updateState to NoOp when the commandStack isn't empty means that the current headCommand on the commandStack is finished. Further UndoTextCommands do not belong to it. So we pop it.
- //If after popping the headCommand we still have some commands on the commandStack means we have not finished with the highest "macro". In that case we need to stay in the "Custom" state.
- //On the contrary, an empty commandStack means we have finished with the "macro". In that case, we set the editor to NoOp state. A signal from the QTextDocument should also generate a new headCommand.
- debugText << "we are in a macro and update the state to NoOp. this means that the command on top of the commandStack is finished. we should pop it";
- debugText << "commandStack count before: " << commandStack.count();
- commandStack.pop();
- debugText << "commandStack count after: " << commandStack.count();
- if (commandStack.isEmpty()) {
- debugText << "we have no more commands on the commandStack. the macro is complete. next signal induced command will need to be parented to a new headCommand. Also the editor should go to NoOp";
- addNewCommand = true;
- editorState = NoOp;
- }
- debugText << "returning now. commandStack count: " << commandStack.count();
- return;
- }
- if (editorState != newState || commandTitle != title) {
- //We are not in "Custom" state but either are moving to a new state (from editing to format,...) or the command type is the same, but not the command itself (like format:bold, format:italic). The later case is caracterised by a different command title.
- //When we change command, we need to pop the current commandStack's top and ask for a new headCommand to be created.
- debugText << "we are not in a custom state but change the command";
- debugText << "commandStack count: " << commandStack.count();
- if (!commandStack.isEmpty()) {
- debugText << "the commandStack is not empty. however the command on it is not a macro. so we pop it and ask to recreate a new one: " << title;
- commandStack.pop();
- addNewCommand = true;
- }
- }
- editorState = newState;
- if (!title.isEmpty())
- commandTitle = title;
- else
- commandTitle = kundo2_i18n("Text");
- debugText << "returning now. commandStack count: " << commandStack.count();
-}
-
-/// This method is used to push a complete KUndo2Command on the KoTextEditor. This command will be pushed on the application's stack if needed. The logic allows to push several commands which are then going to be nested, provided these children are pushed from within the redo method of their parent.
-void KoTextEditor::addCommand(KUndo2Command *command)
-{
- debugText << "we receive a command to add on the stack.";
- debugText << "commandStack count: " << d->commandStack.count();
- debugText << "customCommandCount counter: " << d->customCommandCount << " will increase";
-
- //We increase the customCommandCount counter to inform the framework that we are having a further KUndo2Command and update the KoTextEditor's state to Custom.
- //However, this update will request a new headCommand to be pushed on the commandStack. This is what we want for internal complex editions but not in this case. Indeed, it must be the KUndo2Command which will parent the UndoTextCommands. Therefore we set the addNewCommand back to false.
- //If the commandStack is empty, we are the highest "macro" command and we should therefore push the KUndo2Command on the application's stack.
- //On the contrary, if the commandStack is not empty, or the pushed command has a parent, it means that we are adding a nested KUndo2Command. In which case we just want to put it on the commandStack to parent UndoTextCommands. We need to call the redo method manually though.
- ++d->customCommandCount;
- debugText << "we will now go to custom state";
- d->updateState(KoTextEditor::Private::Custom, (!command->text().isEmpty())?command->text():kundo2_i18n("Text"));
- debugText << "but will set the addCommand to false. we don't want a new headCommand";
- d->addNewCommand = false;
- debugText << "commandStack count is: " << d->commandStack.count();
- if (d->commandStack.isEmpty()) {
- debugText << "the commandStack is empty. this means we are the top most command";
- d->commandStack.push(command);
- debugText << "command pushed on the commandStack. count: " << d->commandStack.count();
- KUndo2QStack *stack = KoTextDocument(d->document).undoStack();
- if (stack && !command->hasParent()) {
- debugText << "we have an application stack and the command is not a sub command of a non text command (which have been pushed outside kotext";
- stack->push(command);
- debugText << "so we pushed it on the application's' stack";
- } else {
- debugText << "we either have no application's stack, or our command is actually the child of a non kotext command";
- command->redo();
- debugText << "still called redo on it";
- }
- }
- else {
- debugText << "the commandStack is not empty, our command is actually nested in another kotext command. we don't push on the application stack but only on the commandStack";
- d->commandStack.push(command);
- debugText << "commandStack count after push: " << d->commandStack.count();
- command->redo();
- debugText << "called redo still";
- }
-
- //When we reach that point, the command has been executed. We first need to clean up all the automatically generated headCommand on our commandStack, which could potentially have been created during the editing. When we reach our pushed command, the commandStack is clean. We can then call a state update to NoOp and decrease the customCommandCount counter.
- debugText << "the command has been executed. we need to clean up the commandStack of the auto generated headCommands";
- debugText << "before cleaning. commandStack count: " << d->commandStack.count();
- while (d->commandStack.top() != command) {
- d->commandStack.pop();
- }
- debugText << "after cleaning. commandStack count: " << d->commandStack.count() << " will set NoOp";
- d->updateState(KoTextEditor::Private::NoOp);
- debugText << "after NoOp set. inCustomCounter: " << d->customCommandCount << " will decrease and return";
- --d->customCommandCount;
-}
-
-/// DO NOT USE THIS. It stays here for compiling reasons. But it will severely break everything. Again: DO NOT USE THIS.
-void KoTextEditor::instantlyExecuteCommand(KUndo2Command *command)
-{
- d->updateState(KoTextEditor::Private::Custom, (!command->text().isEmpty())?command->text():kundo2_i18n("Text"));
- command->redo();
- // instant replay done let's not keep it dangling
- if (!command->hasParent()) {
- d->updateState(KoTextEditor::Private::NoOp);
- }
-}
-
-/// This method is used to start an on-the-fly macro command. Use KoTextEditor::endEditBlock to stop it.
-/// ***
-/// Important note:
-/// ***
-/// The framework does not allow to push a complete KUndo2Command (through KoTextEditor::addCommand) from within an EditBlock. Doing so will lead in the best case to several undo/redo commands on the application's stack instead of one, in the worst case to an out of sync application's stack.
-/// ***
-KUndo2Command *KoTextEditor::beginEditBlock(const KUndo2MagicString &title)
-{
- debugText << "beginEditBlock";
- debugText << "commandStack count: " << d->commandStack.count();
- debugText << "customCommandCount counter: " << d->customCommandCount;
- if (!d->customCommandCount) {
- // We are not in a custom macro command. So we first need to update the KoTextEditor's state to Custom. Additionally, if the commandStack is empty, we need to create a master headCommand for our macro and push it on the stack.
- debugText << "we are not in a custom command. will update state to custom";
- d->updateState(KoTextEditor::Private::Custom, title);
- debugText << "commandStack count: " << d->commandStack.count();
- if (d->commandStack.isEmpty()) {
- debugText << "the commandStack is empty. we need a dummy headCommand both on the commandStack and on the application's stack";
- KUndo2Command *command = new KUndo2Command(title);
- d->commandStack.push(command);
- ++d->customCommandCount;
- d->dummyMacroAdded = true; //This bool is used to tell endEditBlock that we have created a master headCommand.
- KUndo2QStack *stack = KoTextDocument(d->document).undoStack();
- if (stack) {
- stack->push(command);
- } else {
- command->redo();
- }
- debugText << "done adding the headCommand. commandStack count: " << d->commandStack.count() << " inCommand counter: " << d->customCommandCount;
- }
- }
- //QTextDocument sends the undoCommandAdded signal at the end of the QTextCursor edit block. Since we want our master headCommand to parent the signal induced UndoTextCommands, we should not call QTextCursor::beginEditBlock for the headCommand.
- if (!(d->dummyMacroAdded && d->customCommandCount == 1)) {
- debugText << "we did not add a dummy command, or we are further down nesting. call beginEditBlock on the caret to nest the QTextDoc changes";
- //we don't call beginEditBlock for the first headCommand because we want the signals to be sent before we finished our command.
- d->caret.beginEditBlock();
- }
- debugText << "will return top od commandStack";
- return (d->commandStack.isEmpty())?0:d->commandStack.top();
-}
-
-void KoTextEditor::endEditBlock()
-{
- debugText << "endEditBlock";
- //Only the self created master headCommand (see beginEditBlock) is left on the commandStack, we need to decrease the customCommandCount counter that we increased on creation.
- //If we are not yet at this master headCommand, we can call QTextCursor::endEditBlock
- if (d->dummyMacroAdded && d->customCommandCount == 1) {
- debugText << "only the created dummy headCommand from beginEditBlock is left. we need to decrease further the nesting counter";
- //we don't call caret.endEditBlock because we did not begin a block for the first headCommand
- --d->customCommandCount;
- d->dummyMacroAdded = false;
- } else {
- debugText << "we are not at our top dummy headCommand. call caret.endEditBlock";
- d->caret.endEditBlock();
- }
- if (!d->customCommandCount) {
- //We have now finished completely the macro, set the editor state to NoOp then.
- debugText << "we have finished completely the macro, set the state to NoOp now. commandStack count: " << d->commandStack.count();
- d->updateState(KoTextEditor::Private::NoOp);
- debugText << "done setting the state. editorState: " << d->editorState << " commandStack count: " << d->commandStack.count();
- }
-}
diff --git a/plugins/flake/textshape/kotext/KoTextInlineRdf.cpp b/plugins/flake/textshape/kotext/KoTextInlineRdf.cpp
deleted file mode 100644
index 484e0a9a90..0000000000
--- a/plugins/flake/textshape/kotext/KoTextInlineRdf.cpp
+++ /dev/null
@@ -1,364 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2010 KO GmbH <ben.martin@kogmbh.com>
- Copyright (C) 2012 C. Boemann <cbo@boemann.dk>
-
- 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 "KoTextInlineRdf.h"
-// lib
-#include <opendocument/KoTextSharedSavingData.h>
-#include <styles/KoCharacterStyle.h>
-#include <KoBookmark.h>
-#include <KoAnnotation.h>
-#include <KoTextMeta.h>
-#include <KoTextEditor.h>
-#include <KoTextDocument.h>
-// komain
-#include <KoShapeSavingContext.h>
-#include <KoXmlWriter.h>
-#include <KoXmlNS.h>
-#include <KoElementReference.h>
-// KDE
-#include "TextDebug.h"
-// Qt
-#include <QTextCursor>
-#include <QTextDocument>
-#include <QTextTableCell>
-
-
-#ifdef SHOULD_BUILD_RDF
-#include <Soprano/Soprano>
-enum Type {
- EmptyNode = Soprano::Node::EmptyNode,
- ResourceNode = Soprano::Node::ResourceNode,
- LiteralNode = Soprano::Node::LiteralNode,
- BlankNode = Soprano::Node::BlankNode
-};
-#else
-enum Type {
- EmptyNode,
- ResourceNode,
- LiteralNode,
- BlankNode
-};
-#endif
-
-class Q_DECL_HIDDEN KoTextInlineRdf::Private
-{
-public:
- Private(const QTextDocument *doc, const QTextBlock &b)
- : block(b)
- , document(doc)
- {
- isObjectAttributeUsed = false;
- sopranoObjectType = LiteralNode;
- }
-
- Private(const QTextDocument *doc, KoBookmark *b)
- : document(doc)
- , bookmark(b)
- {
- isObjectAttributeUsed = false;
- sopranoObjectType = LiteralNode;
- }
-
- Private(const QTextDocument *doc, KoAnnotation *b)
- : document(doc)
- , annotation(b)
- {
- isObjectAttributeUsed = false;
- sopranoObjectType = LiteralNode;
- }
-
- Private(const QTextDocument *doc, KoTextMeta *b)
- : document(doc)
- , kotextmeta(b)
- {
- isObjectAttributeUsed = false;
- sopranoObjectType = LiteralNode;
- }
-
- Private(const QTextDocument *doc, const QTextTableCell &c)
- : document(doc)
- , cell(c)
- {
- isObjectAttributeUsed = false;
- sopranoObjectType = LiteralNode;
- }
-
- Private(const QTextDocument *doc, KoSection *s)
- : document(doc)
- , section(s)
- {
- isObjectAttributeUsed = false;
- sopranoObjectType = LiteralNode;
- }
-
-
- QString id; // original xml:id
-
- //FIXME: design like this seems inapropriate, maybe
- // making Interface from KoTextInlineRdf will be better.
- // Just my thoughts.
-
- // where we might get the object value from
- QTextBlock block;
-
- // or document and one of bookmark, annotation, kotextmeta, ...
- QWeakPointer<const QTextDocument> document;
- QWeakPointer<KoBookmark> bookmark;
- QWeakPointer<KoAnnotation> annotation;
- QWeakPointer<KoTextMeta> kotextmeta;
- KoSection *section;
- QTextTableCell cell;
-
- QString subject;
- QString predicate;
- int sopranoObjectType;
- QString dt;
-
- // if the content="" attribute was used,
- // then isObjectAttributeUsed=1 and object=content attribute value.
- QString object;
- bool isObjectAttributeUsed;
-};
-
-KoTextInlineRdf::KoTextInlineRdf(const QTextDocument *doc, const QTextBlock &b)
- : QObject(const_cast<QTextDocument*>(doc))
- , d(new Private(doc, b))
-{
-}
-
-KoTextInlineRdf::KoTextInlineRdf(const QTextDocument *doc, KoBookmark *b)
- : QObject(const_cast<QTextDocument*>(doc))
- , d(new Private(doc, b))
-{
-}
-
-KoTextInlineRdf::KoTextInlineRdf(const QTextDocument *doc, KoAnnotation *b)
- : QObject(const_cast<QTextDocument*>(doc))
- , d(new Private(doc, b))
-{
-}
-
-KoTextInlineRdf::KoTextInlineRdf(const QTextDocument *doc, KoTextMeta *b)
- : QObject(const_cast<QTextDocument*>(doc))
- , d(new Private(doc, b))
-{
-}
-
-KoTextInlineRdf::KoTextInlineRdf(const QTextDocument *doc, const QTextTableCell &b)
- : QObject(const_cast<QTextDocument*>(doc))
- , d(new Private(doc, b))
-{
-}
-
-KoTextInlineRdf::KoTextInlineRdf(const QTextDocument *doc, KoSection *s)
- : QObject(const_cast<QTextDocument*>(doc))
- , d(new Private(doc, s))
-{
-}
-
-KoTextInlineRdf::~KoTextInlineRdf()
-{
- debugText << " this:" << (void*)this;
- delete d;
-}
-
-bool KoTextInlineRdf::loadOdf(const KoXmlElement &e)
-{
- d->id = e.attribute("id", QString());
- d->subject = e.attributeNS(KoXmlNS::xhtml, "about");
- d->predicate = e.attributeNS(KoXmlNS::xhtml, "property");
- d->dt = e.attributeNS(KoXmlNS::xhtml, "datatype");
- QString content = e.attributeNS(KoXmlNS::xhtml, "content");
- //
- // Content / triple object explicitly set through an attribute
- //
- if (e.hasAttributeNS(KoXmlNS::xhtml, "content")) {
- d->isObjectAttributeUsed = true;
- d->object = content;
- }
- return true;
-}
-
-bool KoTextInlineRdf::saveOdf(KoShapeSavingContext &context, KoXmlWriter *writer, KoElementReference id) const
-{
- debugText << " this:" << (void*)this << " xmlid:" << d->id << "passed id" << id.toString();
- QString oldID = d->id;
-
- if (!id.isValid()) {
- id = KoElementReference();
- }
-
- QString newID = id.toString();
- if (KoTextSharedSavingData *sharedData =
- dynamic_cast<KoTextSharedSavingData *>(context.sharedData(KOTEXT_SHARED_SAVING_ID))) {
- sharedData->addRdfIdMapping(oldID, newID);
- }
- debugText << "oldID:" << oldID << " newID:" << newID;
- writer->addAttribute("xml:id", newID);
- if (!d->subject.isEmpty()) {
- writer->addAttribute("xhtml:about", d->subject);
- }
- if (!d->predicate.isEmpty()) {
- writer->addAttribute("xhtml:property", d->predicate);
- }
- if (!d->dt.isEmpty()) {
- writer->addAttribute("xhtml:datatype", d->dt);
- }
- if (d->isObjectAttributeUsed) {
- writer->addAttribute("xhtml:content", d->object);
- }
- debugText << "done..";
- return true;
-}
-
-QString KoTextInlineRdf::createXmlId()
-{
- KoElementReference ref;
- return ref.toString();
-}
-
-QString KoTextInlineRdf::subject() const
-{
- return d->subject;
-}
-
-QString KoTextInlineRdf::predicate() const
-{
- return d->predicate;
-}
-
-QPair<int, int> KoTextInlineRdf::findExtent() const
-{
- if (d->bookmark && d->document) {
- return QPair<int, int>(d->bookmark.data()->rangeStart(), d->bookmark.data()->rangeEnd());
- }
- if (d->annotation && d->document) {
- return QPair<int, int>(d->annotation.data()->rangeStart(), d->annotation.data()->rangeEnd());
- }
- // FIXME: We probably have to do something with endAnnotation()
- // too, but I don't know exactly what...
- if (d->kotextmeta && d->document) {
- KoTextMeta *e = d->kotextmeta.data()->endBookmark();
- if (!e) {
- return QPair<int, int>(0, 0);
- }
- // debugText << "(Semantic)meta... start:" << d->kotextmeta.data()->position() << " end:" << e->position();
- return QPair<int, int>(d->kotextmeta.data()->position(), e->position());
- }
- if (d->cell.isValid() && d->document) {
- QTextCursor b = d->cell.firstCursorPosition();
- QTextCursor e = d->cell.lastCursorPosition();
- return QPair<int, int>(b.position(), e.position());
- }
-
- if (d->section) {
- return d->section->bounds();
- }
-
- return QPair<int, int>(0, 0);
-}
-
-QString KoTextInlineRdf::object() const
-{
- if (d->isObjectAttributeUsed) {
- return d->object;
- }
-
- KoTextDocument textDocument(d->document.data());
-
- if (d->bookmark && d->document) {
- QString ret = d->bookmark.data()->text();
- return ret.remove(QChar::ObjectReplacementCharacter);
- }
- else if (d->kotextmeta && d->document) {
- // FIXME: Need to do something with endAnnotation?
- KoTextMeta *e = d->kotextmeta.data()->endBookmark();
- if (!e) {
- debugText << "Broken KoTextMeta, no end tag found!";
- return QString();
- } else {
- KoTextEditor *editor = textDocument.textEditor();
- editor->setPosition(d->kotextmeta.data()->position(), QTextCursor::MoveAnchor);
- editor->setPosition(e->position(), QTextCursor::KeepAnchor);
- QString ret = editor->selectedText();
- return ret.remove(QChar::ObjectReplacementCharacter);
- }
- }
- else if (d->cell.isValid() && d->document) {
- QTextCursor b = d->cell.firstCursorPosition();
- b.setPosition(d->cell.lastCursorPosition().position(), QTextCursor::KeepAnchor);
- QString ret = b.selectedText();
- return ret.remove(QChar::ObjectReplacementCharacter);
- }
-
- return d->block.text();
-}
-
-int KoTextInlineRdf::sopranoObjectType() const
-{
- return d->sopranoObjectType;
-}
-
-QString KoTextInlineRdf::xmlId() const
-{
- return d->id;
-}
-
-void KoTextInlineRdf::setXmlId(const QString &id)
-{
- d->id = id;
-}
-
-KoTextInlineRdf *KoTextInlineRdf::tryToGetInlineRdf(const QTextFormat &tf)
-{
- if (!tf.hasProperty(KoCharacterStyle::InlineRdf)) {
- return 0;
- }
- QVariant v = tf.property(KoCharacterStyle::InlineRdf);
- return v.value<KoTextInlineRdf *>();
-}
-
-KoTextInlineRdf *KoTextInlineRdf::tryToGetInlineRdf(QTextCursor &cursor)
-{
- QTextCharFormat cf = cursor.charFormat();
- if (!cf.hasProperty(KoCharacterStyle::InlineRdf)) {
- return 0;
- }
- QVariant v = cf.property(KoCharacterStyle::InlineRdf);
- return v.value<KoTextInlineRdf *>();
-}
-
-KoTextInlineRdf *KoTextInlineRdf::tryToGetInlineRdf(KoTextEditor *handler)
-{
- QTextCharFormat cf = handler->charFormat();
- if (!cf.hasProperty(KoCharacterStyle::InlineRdf)) {
- return 0;
- }
- QVariant v = cf.property(KoCharacterStyle::InlineRdf);
- return v.value<KoTextInlineRdf *>();
-}
-
-void KoTextInlineRdf::attach(KoTextInlineRdf *inlineRdf, QTextCursor &cursor)
-{
- QTextCharFormat format = cursor.charFormat();
- QVariant v = QVariant::fromValue(inlineRdf);
- format.setProperty(KoCharacterStyle::InlineRdf, v);
- cursor.mergeCharFormat(format);
-}
diff --git a/plugins/flake/textshape/kotext/KoTextInlineRdf.h b/plugins/flake/textshape/kotext/KoTextInlineRdf.h
deleted file mode 100644
index d9d748afdc..0000000000
--- a/plugins/flake/textshape/kotext/KoTextInlineRdf.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2010 KO GmbH <ben.martin@kogmbh.com>
-
- 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_TEXT_INLINE_RDF_H
-#define KO_TEXT_INLINE_RDF_H
-
-#include "kritatext_export.h"
-// komain
-#include <KoXmlReaderForward.h>
-#include <KoElementReference.h>
-// Qt
-#include <QPair>
-#include <QMetaType>
-#include <QObject>
-
-class KoXmlWriter;
-class KoShapeSavingContext;
-class KoBookmark;
-class KoAnnotation;
-class KoTextMeta;
-class KoTextEditor;
-class KoSection;
-
-class QTextDocument;
-class QTextCursor;
-class QTextFormat;
-class QTextBlock;
-class QTextTableCell;
-
-/**
- * @short Store information from xhtml:property etc which are for inline Rdf
- *
- * @author Ben Martin <ben.martin@kogmbh.com>
- * @see KoDocumentRdf
- *
- * The easiest way to handle inline Rdf from content.xml is to attach these
- * objects to the document's C++ objects. As you can see from the constructors
- * there are methods which can attach to bookmarks, textmeta, table cells etc.
- *
- * The main reason why the inlineRdf wants these document objects
- * passed in is so that object() can work out what the current value
- * is from the document. For example, when a KoTextInlineRdf is
- * attached to a bookmark-start, then when object() is called the
- * bookmark is inspected to find out the value currently between
- * bookmark-start and bookmark-end.
- *
- * The xmlId() method returns the xml:id that was associated with the
- * inline Rdf if there was one. For example,
- * <bookmark-start xml:id="foo" xhtml:property="uri:baba" ...>
- * the KoTextInlineRdf object will be attached to the KoBookmark
- * for the bookmark-start location and xmlId() will return foo.
- *
- * You can convert one of these to a Soprano::Statement using
- * KoDocumentRdf::toStatement().
- *
- * The attach() and tryToGetInlineRdf() are used by the ODF load and
- * save codepaths respectively. They associate an inlineRdf object
- * with the cursor and fetch back the inline Rdf if one is associated
- * with a text block.
- *
- * FIXME: createXmlId() should consult with the Calligra codebase when
- * generating new xml:id values during save.
- */
-class KRITATEXT_EXPORT KoTextInlineRdf : public QObject
-{
- Q_OBJECT
-
-public:
- KoTextInlineRdf(const QTextDocument *doc, const QTextBlock &b);
- KoTextInlineRdf(const QTextDocument *doc, KoBookmark *b);
- KoTextInlineRdf(const QTextDocument *doc, KoAnnotation *b);
- KoTextInlineRdf(const QTextDocument *doc, KoTextMeta *b);
- KoTextInlineRdf(const QTextDocument *doc, const QTextTableCell &b);
- KoTextInlineRdf(const QTextDocument *doc, KoSection *s);
-
- ~KoTextInlineRdf() override;
-
- /**
- * The attach() and tryToGetInlineRdf() are used by the ODF load and
- * save codepaths respectively. They associate an inlineRdf object
- * with the cursor and fetch back the inline Rdf if one is associated
- * with a text block.
- */
- static KoTextInlineRdf *tryToGetInlineRdf(QTextCursor &cursor);
- static KoTextInlineRdf *tryToGetInlineRdf(const QTextFormat &tf);
- static KoTextInlineRdf *tryToGetInlineRdf(KoTextEditor *handler);
- /**
- * The attach() and tryToGetInlineRdf() are used by the ODF load and
- * save codepaths respectively. They associate an inlineRdf object
- * with the cursor and fetch back the inline Rdf if one is associated
- * with a text block.
- */
- static void attach(KoTextInlineRdf *inlineRdf, QTextCursor &cursor);
-
- bool loadOdf(const KoXmlElement &element);
- bool saveOdf(KoShapeSavingContext &context, KoXmlWriter *writer, KoElementReference id = KoElementReference()) const;
-
- /**
- * Get the RDF subject for this inline RDF
- */
- QString subject() const;
- /**
- * Get the RDF predicate for this inline RDF
- */
- QString predicate() const;
- /**
- * Get the RDF object for this inline RDF
- */
- QString object() const;
- /**
- * Get the type of RDF node (bnode, literal, uri etc) for this inline RDF
- */
- int sopranoObjectType() const;
-
- /**
- * Because RDF is linked to the xml id attribute of elements in
- * content.xml the xml:id attribute that was read from the
- * content.xml file is available here
- */
- QString xmlId() const;
-
- /**
- * Find the start and end position of this inline RDF object in the
- * document.
- */
- QPair<int, int> findExtent() const;
-
-
- /**
- * Update the xml:id, using during cut and paste as well as document save.
- */
- void setXmlId(const QString &id);
-
- /**
- * Create a new and unique xml:id
- */
- static QString createXmlId();
-
-private:
-
- friend class KoRdfSemanticItem;
- friend class KoDocumentRdf;
-
- class Private;
- Private* const d;
-};
-
-Q_DECLARE_METATYPE(KoTextInlineRdf*)
-#endif
diff --git a/plugins/flake/textshape/kotext/KoTextLocator.cpp b/plugins/flake/textshape/kotext/KoTextLocator.cpp
deleted file mode 100644
index f6239edced..0000000000
--- a/plugins/flake/textshape/kotext/KoTextLocator.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 "KoTextLocator.h"
-
-#include "KoTextReference.h"
-#include "KoTextPage.h"
-#include "styles/KoListStyle.h"
-
-#include <KoShape.h>
-
-#include "TextDebug.h"
-#include <QTextDocument>
-#include <QTextList>
-#include <QTextInlineObject>
-#include <QTextBlock>
-#include <QTextCursor>
-
-// Include Q_UNSUSED classes, for building on Windows
-#include <KoShapeLoadingContext.h>
-#include <KoShapeSavingContext.h>
-
-class Q_DECL_HIDDEN KoTextLocator::Private
-{
-public:
- Private(KoTextLocator *q) : q(q), document(0), dirty(false), cursorPosition(0), chapterPosition(-1), pageNumber(0) { }
- void update() {
- if (dirty == false)
- return;
- dirty = false;
- chapterPosition = -1;
-
- int pageTmp = pageNumber, chapterTmp = chapterPosition;
- if (document == 0)
- return;
-
- QTextBlock block = document->findBlock(cursorPosition);
- while (block.isValid()) {
- QTextList *list = block.textList();
- if (list) {
- QTextListFormat lf = list->format();
- int level = lf.intProperty(KoListStyle::Level);
- if (level == 1) {
- chapterPosition = block.position();
- break;
- }
- }
- block = block.previous();
- }
-/*
- KoShape *shape = shapeForPosition(document, cursorPosition);
- if (shape == 0)
- pageNumber = -1;
- else {
- KoTextShapeData *data = static_cast<KoTextShapeData*>(shape->userData());
- KoTextPage* page = data->page();
- pageNumber = page->pageNumber();
- }
-*/ if (pageTmp != pageNumber || chapterTmp != chapterPosition) {
- Q_FOREACH (KoTextReference* reference, listeners)
- reference->variableMoved(0, 0);
- }
- }
-
- KoTextLocator *q;
- const QTextDocument *document;
- bool dirty;
- int cursorPosition;
- int chapterPosition;
- int pageNumber;
-
- QList<KoTextReference*> listeners;
-};
-
-
-KoTextLocator::KoTextLocator()
- : KoInlineObject(false),
- d(new Private(this))
-{
-}
-
-KoTextLocator::~KoTextLocator()
-{
- delete d;
-}
-
-void KoTextLocator::updatePosition(const QTextDocument *document, int posInDocument, const QTextCharFormat &format)
-{
- Q_UNUSED(format);
- if (d->document != document || d->cursorPosition != posInDocument) {
- d->dirty = true;
- d->document = document;
- d->cursorPosition = posInDocument;
-//debugText <<"KoTextLocator page:" << pageNumber() <<", chapter:" << chapter() <<", '" << word() <<"'";
- }
-}
-
-void KoTextLocator::resize(const QTextDocument *document, QTextInlineObject &object, int posInDocument, const QTextCharFormat &format, QPaintDevice *pd)
-{
- Q_UNUSED(document);
- Q_UNUSED(posInDocument);
- Q_UNUSED(format);
- Q_UNUSED(pd);
- object.setWidth(0);
- object.setAscent(0);
- object.setDescent(0);
-}
-
-void KoTextLocator::paint(QPainter &, QPaintDevice *, const QTextDocument *, const QRectF &, const QTextInlineObject &, int , const QTextCharFormat &)
-{
- // nothing to paint.
-}
-
-QString KoTextLocator::chapter() const
-{
- d->update();
- if (d->chapterPosition < 0)
- return QString();
- QTextBlock block = d->document->findBlock(d->chapterPosition);
- return block.text().remove(QChar::ObjectReplacementCharacter);
-}
-
-int KoTextLocator::pageNumber() const
-{
- d->update();
- return d->pageNumber;
-}
-
-int KoTextLocator::indexPosition() const
-{
- return d->cursorPosition;
-}
-
-QString KoTextLocator::word() const
-{
- if (d->document == 0) // layout never started
- return QString();
- QTextCursor cursor(const_cast<QTextDocument*>(d->document));
- cursor.setPosition(d->cursorPosition);
- cursor.movePosition(QTextCursor::NextWord);
- cursor.movePosition(QTextCursor::WordLeft, QTextCursor::KeepAnchor);
- return cursor.selectedText().trimmed().remove(QChar::ObjectReplacementCharacter);
-}
-
-void KoTextLocator::addListener(KoTextReference *reference)
-{
- d->listeners.append(reference);
-}
-
-void KoTextLocator::removeListener(KoTextReference *reference)
-{
- d->listeners.removeAll(reference);
-}
-
-bool KoTextLocator::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- Q_UNUSED(element);
- Q_UNUSED(context);
- // TODO
- return false;
-}
-
-void KoTextLocator::saveOdf(KoShapeSavingContext &context)
-{
- Q_UNUSED(context);
- // TODO
-}
diff --git a/plugins/flake/textshape/kotext/KoTextLocator.h b/plugins/flake/textshape/kotext/KoTextLocator.h
deleted file mode 100644
index 5013c60126..0000000000
--- a/plugins/flake/textshape/kotext/KoTextLocator.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 KOTEXTLOCATOR_H
-#define KOTEXTLOCATOR_H
-
-#include "KoInlineObject.h"
-#include "kritatext_export.h"
-
-class KoTextReference;
-
-/**
- * This inline object can be inserted in text to mark it and to later get location information from.
- * After inserting this locator you can request things like pageNumber() and chapter() for the
- * place where the locator has been positioned in the document.
- */
-class KRITATEXT_EXPORT KoTextLocator : public KoInlineObject
-{
- Q_OBJECT
-public:
- /// constructor
- KoTextLocator();
- ~KoTextLocator() override;
-
- /// reimplemented from super
- void updatePosition(const QTextDocument *document,
- int posInDocument, const QTextCharFormat &format) override;
- /// reimplemented from super
- void resize(const QTextDocument *document, QTextInlineObject &object,
- int posInDocument, const QTextCharFormat &format, QPaintDevice *pd) override;
- /// reimplemented from super
- void paint(QPainter &painter, QPaintDevice *pd, const QTextDocument *document,
- const QRectF &rect, const QTextInlineObject &object, int posInDocument, const QTextCharFormat &format) override;
-
- /// returns the text of the paragraph that is the first chapter before the index.
- QString chapter() const;
- /// return the page number on which the locator is placed.
- int pageNumber() const;
- /// return the position in the text document at which the locator is inserted.
- int indexPosition() const;
- /// return the word in which the locator is inserted.
- QString word() const;
-
- /// Add a text reference that is interested in knowing when this locator is laid-out in a different position.
- void addListener(KoTextReference *reference);
- /// Remove a reference from the listeners.
- void removeListener(KoTextReference *reference);
-
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
- void saveOdf(KoShapeSavingContext &context) override;
-
-private:
- class Private;
- Private * const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoTextMeta.cpp b/plugins/flake/textshape/kotext/KoTextMeta.cpp
deleted file mode 100644
index 284902674e..0000000000
--- a/plugins/flake/textshape/kotext/KoTextMeta.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2010 KO GmbH <ben.martin@kogmbh.com>
- *
- * 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 "KoTextMeta.h"
-
-#include <KoShapeSavingContext.h>
-#include <KoXmlReader.h>
-#include <KoXmlWriter.h>
-#include <KoTextInlineRdf.h>
-
-#include <QTextDocument>
-#include <QTextInlineObject>
-#include <QWeakPointer>
-
-#include "TextDebug.h"
-
-// Include Q_UNSUSED classes, for building on Windows
-#include <KoShapeLoadingContext.h>
-
-class Q_DECL_HIDDEN KoTextMeta::Private
-{
-public:
- Private(const QTextDocument *doc)
- : document(doc),
- posInDocument(0) { }
- const QTextDocument *document;
- int posInDocument;
- QWeakPointer<KoTextMeta> endBookmark;
- BookmarkType type;
-};
-
-KoTextMeta::KoTextMeta(const QTextDocument *document)
- : KoInlineObject(false),
- d(new Private(document))
-{
- d->endBookmark.clear();
-}
-
-KoTextMeta::~KoTextMeta()
-{
- delete d;
-}
-
-void KoTextMeta::saveOdf(KoShapeSavingContext &context)
-{
- KoXmlWriter &writer = context.xmlWriter();
-
- debugText << "kom.save() this:" << (void*)this << " d->type:" << d->type;
- if (inlineRdf()) {
- debugText << "kom.save() have inline Rdf";
- }
-
- if (d->type == StartBookmark) {
- writer.startElement("text:meta", false);
- writer.addAttribute("text:name", "foo");
-
- if (inlineRdf()) {
- inlineRdf()->saveOdf(context, &writer);
- }
- } else {
- debugText << "adding endelement.";
- writer.endElement();
- }
- debugText << "kom.save() done this:" << (void*)this << " d->type:" << d->type;
-}
-
-bool KoTextMeta::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- Q_UNUSED(element);
- Q_UNUSED(context);
- debugText << "kom.load()";
- return true;
-}
-
-void KoTextMeta::updatePosition(const QTextDocument *document, int posInDocument, const QTextCharFormat &format)
-{
- Q_UNUSED(format);
- d->document = document;
- d->posInDocument = posInDocument;
-}
-
-void KoTextMeta::resize(const QTextDocument *document, QTextInlineObject &object, int posInDocument, const QTextCharFormat &format, QPaintDevice *pd)
-{
- Q_UNUSED(document);
- Q_UNUSED(posInDocument);
- Q_UNUSED(format);
- Q_UNUSED(pd);
- object.setWidth(0);
- object.setAscent(0);
- object.setDescent(0);
-}
-
-void KoTextMeta::paint(QPainter &, QPaintDevice *, const QTextDocument *, const QRectF &, const QTextInlineObject &, int , const QTextCharFormat &)
-{
- // nothing to paint.
-}
-
-void KoTextMeta::setType(BookmarkType type)
-{
- d->type = type;
-}
-
-KoTextMeta::BookmarkType KoTextMeta::type() const
-{
- return d->type;
-}
-
-void KoTextMeta::setEndBookmark(KoTextMeta *bookmark)
-{
- d->type = StartBookmark;
- bookmark->d->type = EndBookmark;
- d->endBookmark = bookmark;
-}
-
-KoTextMeta *KoTextMeta::endBookmark() const
-{
- return d->endBookmark.data();
-}
-
-int KoTextMeta::position() const
-{
- return d->posInDocument;
-}
diff --git a/plugins/flake/textshape/kotext/KoTextMeta.h b/plugins/flake/textshape/kotext/KoTextMeta.h
deleted file mode 100644
index 7d224feac7..0000000000
--- a/plugins/flake/textshape/kotext/KoTextMeta.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2010 KO GmbH <ben.martin@kogmbh.com>
- *
- * 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 KOTEXTMETA_H
-#define KOTEXTMETA_H
-
-#include "KoInlineObject.h"
-#include "kritatext_export.h"
-
-/**
- * Used to indicate an ODF text:meta container. This is very similar to a KoBookmark
- * in that a specific start-end is marked.
- */
-class KRITATEXT_EXPORT KoTextMeta : public KoInlineObject
-{
- Q_OBJECT
-public:
- enum BookmarkType {
- StartBookmark, ///< start position
- EndBookmark ///< end position
- };
-
- /**
- * Constructor
- * @param name the name for this bookmark
- * @param document the text document where this bookmark is located
- */
- explicit KoTextMeta(const QTextDocument *document);
-
- ~KoTextMeta() override;
-
- /// reimplemented from super
- void saveOdf(KoShapeSavingContext &context) override;
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
-
- /// reimplemented from super
- void updatePosition(const QTextDocument *document,
- int posInDocument, const QTextCharFormat &format) override;
- /// reimplemented from super
- void resize(const QTextDocument *document, QTextInlineObject &object,
- int posInDocument, const QTextCharFormat &format, QPaintDevice *pd) override;
- /// reimplemented from super
- void paint(QPainter &painter, QPaintDevice *pd, const QTextDocument *document,
- const QRectF &rect, const QTextInlineObject &object, int posInDocument, const QTextCharFormat &format) override;
-
- void setType(BookmarkType type);
-
- /// @return the current type of this bookmark
- BookmarkType type() const;
-
- void setEndBookmark(KoTextMeta *bookmark);
-
- /// @return the end bookmark if the type is StartBookmark
- KoTextMeta* endBookmark() const;
-
- /// @return the exact cursor position of this bookmark in document
- int position() const;
-
-private:
- class Private; // TODO share the private with super
- Private *const d;
-};
-
-#endif
-
diff --git a/plugins/flake/textshape/kotext/KoTextOdfSaveHelper.cpp b/plugins/flake/textshape/kotext/KoTextOdfSaveHelper.cpp
deleted file mode 100644
index 30b7c7477e..0000000000
--- a/plugins/flake/textshape/kotext/KoTextOdfSaveHelper.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2011 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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 "KoTextOdfSaveHelper.h"
-
-#include <KoXmlWriter.h>
-#include <KoOdf.h>
-#include "KoTextWriter.h"
-#include <KoShapeSavingContext.h>
-#include <KoTextDocument.h>
-
-#include <QTextDocument>
-
-struct Q_DECL_HIDDEN KoTextOdfSaveHelper::Private {
- Private(const QTextDocument *document, int from, int to)
- : context(0)
- , document(document)
- , from(from)
- , to(to)
-#ifdef SHOULD_BUILD_RDF
- , rdfModel(0)
-#endif
- {
- }
-
- KoShapeSavingContext *context;
- const QTextDocument *document;
-
- int from;
- int to;
-
-#ifdef SHOULD_BUILD_RDF
- QSharedPointer<Soprano::Model> rdfModel; //< This is so cut/paste can serialize the relevant RDF to the clipboard
-#endif
-};
-
-
-KoTextOdfSaveHelper::KoTextOdfSaveHelper(const QTextDocument *document, int from, int to)
- : d(new Private(document, from, to))
-{
-}
-
-KoTextOdfSaveHelper::~KoTextOdfSaveHelper()
-{
- delete d;
-}
-
-bool KoTextOdfSaveHelper::writeBody()
-{
- if (d->to < d->from) {
- std::swap(d->to, d->from);
- }
- Q_ASSERT(d->context);
- KoXmlWriter & bodyWriter = d->context->xmlWriter();
- bodyWriter.startElement("office:body");
- bodyWriter.startElement(KoOdf::bodyContentElement(KoOdf::Text, true));
-
- KoTextWriter writer(*d->context, 0);
- writer.write(d->document, d->from, d->to);
-
- bodyWriter.endElement(); // office:element
- bodyWriter.endElement(); // office:body
- return true;
-}
-
-KoShapeSavingContext * KoTextOdfSaveHelper::context(KoXmlWriter * bodyWriter,
- KoGenStyles & mainStyles,
- KoEmbeddedDocumentSaver & embeddedSaver)
-{
- d->context = new KoShapeSavingContext(*bodyWriter, mainStyles, embeddedSaver);
- return d->context;
-}
-
-#ifdef SHOULD_BUILD_RDF
-void KoTextOdfSaveHelper::setRdfModel(QSharedPointer<Soprano::Model> m)
-{
- d->rdfModel = m;
-}
-
-QSharedPointer<Soprano::Model> KoTextOdfSaveHelper::rdfModel() const
-{
- return d->rdfModel;
-}
-#endif
-
-KoStyleManager *KoTextOdfSaveHelper::styleManager() const
-{
- return KoTextDocument(d->document).styleManager();
-}
diff --git a/plugins/flake/textshape/kotext/KoTextOdfSaveHelper.h b/plugins/flake/textshape/kotext/KoTextOdfSaveHelper.h
deleted file mode 100644
index 9d57ff50d3..0000000000
--- a/plugins/flake/textshape/kotext/KoTextOdfSaveHelper.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 KOTEXTODFSAVEHELPER_H
-#define KOTEXTODFSAVEHELPER_H
-
-#include <KoDragOdfSaveHelper.h>
-#ifdef SHOULD_BUILD_RDF
-#include <Soprano/Soprano>
-#include <QSharedPointer>
-#endif
-#include "kritatext_export.h"
-
-class QTextDocument;
-class KoStyleManager;
-
-class KRITATEXT_EXPORT KoTextOdfSaveHelper : public KoDragOdfSaveHelper
-{
-public:
- KoTextOdfSaveHelper(const QTextDocument *document, int from, int to);
- ~KoTextOdfSaveHelper() override;
-
- /// reimplemented
- bool writeBody() override;
-
- KoShapeSavingContext *context(KoXmlWriter *bodyWriter, KoGenStyles &mainStyles, KoEmbeddedDocumentSaver &embeddedSaver) override;
-
-#ifdef SHOULD_BUILD_RDF
- /**
- * The Rdf Model ownership is not taken, you must still delete it,
- * and you need to ensure that it lives longer than this object
- * unless you reset the model to 0.
- */
- void setRdfModel(QSharedPointer<Soprano::Model> m);
- QSharedPointer<Soprano::Model> rdfModel() const;
-#endif
-
- KoStyleManager *styleManager() const;
-private:
- struct Private;
- Private * const d;
-};
-
-#endif /* KOTEXTODFSAVEHELPER_H */
diff --git a/plugins/flake/textshape/kotext/KoTextPage.cpp b/plugins/flake/textshape/kotext/KoTextPage.cpp
deleted file mode 100644
index 3abd02acba..0000000000
--- a/plugins/flake/textshape/kotext/KoTextPage.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/* This file is part of the Calligra project
- * Copyright (C) 2008 Thomas Zander <zander@kde.org>
- *
- * 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 "KoTextPage.h"
-
-#include <QString>
-
-KoTextPage::KoTextPage()
-{
-}
-
-KoTextPage::~KoTextPage()
-{
-}
-
-QString KoTextPage::masterPageName() const
-{
- return QString();
-}
diff --git a/plugins/flake/textshape/kotext/KoTextPage.h b/plugins/flake/textshape/kotext/KoTextPage.h
deleted file mode 100644
index 931a783b07..0000000000
--- a/plugins/flake/textshape/kotext/KoTextPage.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/* This file is part of the Calligra project
- * Copyright (C) 2008 Sebastian Sauer <mail@dipe.org>
- *
- * 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 KOTEXTPAGE_H
-#define KOTEXTPAGE_H
-
-#include "kritatext_export.h"
-
-#include <QRectF>
-#include <QMetaType>
-
-class QString;
-
-/**
- * Interface for a single OpenDocumentText page.
- *
- * The Words KWPageTextInfo class does implement this interface to provide
- * application specific functionality for single pages.
- * @see KoTextShapeData::setPage();
- */
-class KRITATEXT_EXPORT KoTextPage
-{
-public:
- /// Constructor.
- explicit KoTextPage();
- /// Destructor.
- virtual ~KoTextPage();
-
- enum PageSelection {
- PreviousPage = -1,
- CurrentPage = 0,
- NextPage = 1
- };
-
- /**
- * Returns the unique number of this page for internal purposes. All pages
- * are numbered consecutively starting by 1.
- *
- * This is used for example to anchor images to pages. The image then refers
- * to the unique page-number.
- */
- virtual int pageNumber() const = 0;
-
- /**
- * Returns the number of this page for display purposes.
- *
- * Example how the parameters are used within ODF to display the
- * current page number on all pages except the first page;
- * \code
- * <text:page-number text:select-page="previous" text:page-adjust="1" />
- * \endcode
- *
- * \param select Defines the offset of the page to select for the
- * resulting page number. If such a page does not exist, then -1 will be
- * returned before the adjustment will be taken into account. This
- * implements the ODF text:select-page attribute.
- * \param adjustment The value of the page number will be adjusted by this
- * specified number and if there exist a page with the resulting value it's
- * page number gets returned, otherwise -1 will be returned. This implements the
- * ODF text:page-adjust attribute.
- * \return the user visible page number, or -1 if the page referenced does not
- * exist.
- */
- virtual int visiblePageNumber(PageSelection select = CurrentPage, int adjustment = 0) const = 0;
-
- /**
- * Returns the name of the master-page that should be used for this page or a null
- * QString if this page does not explicit define a master-page in which case the
- * default master-page will be used.
- *
- * Per default a null QString is returned.
- */
- virtual QString masterPageName() const;
-
- /**
- * Returns the rect of the page in document coords
- */
- virtual QRectF rect() const = 0;
-
- /**
- * Returns the (text) content rect of the page in document coords
- */
- virtual QRectF contentRect() const {return rect();}
-
-};
-
-Q_DECLARE_METATYPE(KoTextPage*)
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoTextRange.cpp b/plugins/flake/textshape/kotext/KoTextRange.cpp
deleted file mode 100644
index b15fee9c6b..0000000000
--- a/plugins/flake/textshape/kotext/KoTextRange.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- *
- * 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 "KoTextRange.h"
-
-#include "KoTextRangeManager.h"
-#include "KoTextInlineRdf.h"
-
-#include "TextDebug.h"
-#include <QTextCursor>
-
-class KoTextRangePrivate
-{
-public:
- KoTextRangePrivate()
- : manager(0)
- , id(-1)
- , rdf(0)
- , positionOnlyMode(true)
- {
- }
- virtual ~KoTextRangePrivate();
-
- KoTextRangeManager *manager;
- int id;
- QTextCursor cursor;
- KoTextInlineRdf *rdf; //< A textrange might have RDF, we own it.
- bool positionOnlyMode;
- int snapAnchor;
- int snapPos;
-};
-
-KoTextRange::KoTextRange(const QTextCursor &cursor)
- : d_ptr(new KoTextRangePrivate)
-{
- d_ptr->cursor = cursor;
- d_ptr->cursor.setPosition(cursor.selectionStart());
- d_ptr->cursor.setKeepPositionOnInsert(true);
- if (cursor.hasSelection()) {
- setRangeEnd(cursor.selectionEnd());
- }
-}
-
-KoTextRangePrivate::~KoTextRangePrivate()
-{
- delete rdf;
-}
-
-
-KoTextRange::~KoTextRange()
-{
- if (d_ptr->manager) {
- d_ptr->manager->remove(this);
- }
- delete d_ptr;
- d_ptr = 0;
-}
-
-void KoTextRange::setManager(KoTextRangeManager *manager)
-{
- Q_D(KoTextRange);
- d->manager = manager;
-}
-
-KoTextRangeManager *KoTextRange::manager() const
-{
- Q_D(const KoTextRange);
- return d->manager;
-}
-
-QTextDocument *KoTextRange::document() const
-{
- Q_D(const KoTextRange);
- return d->cursor.document();
-}
-
-bool KoTextRange::positionOnlyMode() const
-{
- Q_D(const KoTextRange);
- return d->positionOnlyMode;
-}
-
-void KoTextRange::setPositionOnlyMode(bool b)
-{
- Q_D(KoTextRange);
- d->positionOnlyMode = b;
-}
-
-bool KoTextRange::hasRange() const
-{
- Q_D(const KoTextRange);
- return (!d->positionOnlyMode) && d->cursor.hasSelection();
-}
-
-int KoTextRange::rangeStart() const
-{
- Q_D(const KoTextRange);
- return d->positionOnlyMode ? d->cursor.position() : d->cursor.selectionStart();
-}
-
-int KoTextRange::rangeEnd() const
-{
- Q_D(const KoTextRange);
- return d->positionOnlyMode ? d->cursor.position() : d->cursor.selectionEnd();
-}
-
-void KoTextRange::setRangeStart(int position)
-{
- Q_D(KoTextRange);
- d->positionOnlyMode = true;
- d->cursor.setPosition(position);
-}
-
-void KoTextRange::setRangeEnd(int position)
-{
- Q_D(KoTextRange);
- d->positionOnlyMode = false;
- d->cursor.setPosition(d->cursor.selectionStart());
- d->cursor.setPosition(position, QTextCursor::KeepAnchor);
-}
-
-QString KoTextRange::text() const
-{
- Q_D(const KoTextRange);
- return d->positionOnlyMode ? QString() : d->cursor.selectedText();
-}
-
-void KoTextRange::setInlineRdf(KoTextInlineRdf* rdf)
-{
- Q_D(KoTextRange);
- d->rdf = rdf;
-}
-
-KoTextInlineRdf* KoTextRange::inlineRdf() const
-{
- Q_D(const KoTextRange);
- return d->rdf;
-}
-
-void KoTextRange::snapshot()
-{
- Q_D(KoTextRange);
- d->snapAnchor = d->cursor.anchor();
- d->snapPos = d->cursor.position();
-}
-
-void KoTextRange::restore()
-{
- Q_D(KoTextRange);
- d->cursor.setPosition(d->snapAnchor);
- d->cursor.setPosition(d->snapPos, QTextCursor::KeepAnchor);
-}
diff --git a/plugins/flake/textshape/kotext/KoTextRange.h b/plugins/flake/textshape/kotext/KoTextRange.h
deleted file mode 100644
index 05668f12f5..0000000000
--- a/plugins/flake/textshape/kotext/KoTextRange.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- *
- * 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 KOTEXTRANGE_H
-#define KOTEXTRANGE_H
-
-#include "kritatext_export.h"
-
-#include <QObject>
-#include <KoXmlReaderForward.h>
-
-class QTextDocument;
-class QTextCursor;
-
-class KoTextRangeManager;
-class KoTextRangePrivate;
-class KoShapeSavingContext;
-class KoTextInlineRdf;
-class KoShapeLoadingContext;
-
-/**
- * Base class for all text ranges.
- *
- * They are essentially anchored to a specific position or range in the text
- *
- * @see KoTextRangeManager
- */
-class KRITATEXT_EXPORT KoTextRange : public QObject
-{
- Q_OBJECT
-public:
- enum TagType {StartTag = 0, EndTag = 1};
-
- /**
- * constructor
- */
- explicit KoTextRange(const QTextCursor &cursor);
- ~KoTextRange() override;
-
- /**
- * Will be called by the manager when this variable is added.
- * Remember that inheriting classes should not use the manager() in the constructor, since it will be 0
- * @param manager the object manager for this object.
- */
- void setManager(KoTextRangeManager *manager);
-
- /**
- * Return the object manager set on this inline object.
- */
- KoTextRangeManager *manager() const;
-
- /**
- * Return the textdocument the range points to.
- */
- QTextDocument *document() const;
-
- /**
- * Save the part of this text range corresponding to position as ODF
- * This may save a beginning tag, ending tag, or nothing at all
- * @param context the context for saving.
- * @param position a position in the qtextdocument we are currently saving for.
- * @param tagType the type of tag we are interested in
- */
- virtual void saveOdf(KoShapeSavingContext &context, int position, TagType tagType) const = 0;
-
- bool positionOnlyMode() const;
- void setPositionOnlyMode(bool m);
-
- bool hasRange() const;
- int rangeStart() const;
- int rangeEnd() const;
-
- void setRangeStart(int position);
- void setRangeEnd(int position);
-
- QString text() const;
-
- /**
- * A text range might have some Rdf metadata associated with it
- * in content.xml
- * Ownership of the rdf object is taken by the text range, and you should not
- * delete it.
- */
- void setInlineRdf(KoTextInlineRdf *rdf);
-
- /**
- * Get any Rdf which was stored in content.xml for this text range
- */
- KoTextInlineRdf *inlineRdf() const;
-
- /**
- * Load a variable from odf.
- *
- * @param element element which represents the shape in odf
- * @param context the KoShapeLoadingContext used for loading
- *
- * @return false if loading failed
- */
- virtual bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) = 0;
-
- void snapshot();
- void restore();
-
-protected:
- KoTextRangePrivate *d_ptr;
-
-private:
- Q_DECLARE_PRIVATE(KoTextRange)
-};
-
-KRITATEXT_EXPORT QDebug operator<<(QDebug dbg, const KoTextRange *o);
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoTextRangeManager.cpp b/plugins/flake/textshape/kotext/KoTextRangeManager.cpp
deleted file mode 100644
index 9897ba3701..0000000000
--- a/plugins/flake/textshape/kotext/KoTextRangeManager.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (c) 2012 Boudewijn Rempt <boud@valdyas.org>
- * Copyright (c) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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 "KoTextRangeManager.h"
-
-#include "KoAnnotation.h"
-#include "KoBookmark.h"
-
-#include "TextDebug.h"
-
-KoTextRangeManager::KoTextRangeManager(QObject *parent)
- : QObject(parent)
-{
-}
-
-KoTextRangeManager::~KoTextRangeManager()
-{
-}
-
-void KoTextRangeManager::insert(KoTextRange *textRange)
-{
- if (!textRange) {
- return;
- }
-
-
- if (m_textRanges.contains(textRange)) {
- return;
- }
-
- if (m_deletedTextRanges.contains(textRange)) {
- m_deletedTextRanges.remove(textRange);
- textRange->restore();
- } else {
- textRange->setManager(this);
- }
-
- KoBookmark *bookmark = dynamic_cast<KoBookmark *>(textRange);
- if (bookmark) {
- m_bookmarkManager.insert(bookmark->name(), bookmark);
- }
- else {
- KoAnnotation *annotation = dynamic_cast<KoAnnotation *>(textRange);
- if (annotation) {
- m_annotationManager.insert(annotation->name(), annotation);
- }
- }
- m_textRanges.insert(textRange);
-}
-
-void KoTextRangeManager::remove(KoTextRange *textRange)
-{
- if (!textRange) {
- return;
- }
-
- KoBookmark *bookmark = dynamic_cast<KoBookmark *>(textRange);
- if (bookmark) {
- m_bookmarkManager.remove(bookmark->name());
- }
- else {
- KoAnnotation *annotation = dynamic_cast<KoAnnotation *>(textRange);
- if (annotation) {
- m_annotationManager.remove(annotation->name());
- }
- }
-
- m_textRanges.remove(textRange);
- m_deletedTextRanges.insert(textRange);
- textRange->snapshot();
-}
-
-const KoBookmarkManager *KoTextRangeManager::bookmarkManager() const
-{
- return &m_bookmarkManager;
-}
-
-const KoAnnotationManager *KoTextRangeManager::annotationManager() const
-{
- return &m_annotationManager;
-}
-
-QList<KoTextRange *> KoTextRangeManager::textRanges() const
-{
- return m_textRanges.values();
-}
-
-
-QHash<int, KoTextRange *> KoTextRangeManager::textRangesChangingWithin(const QTextDocument *doc, int first, int last, int matchFirst, int matchLast) const
-{
- QHash<int, KoTextRange *> ranges;
- foreach (KoTextRange *range, m_textRanges) {
- if (range->document() != doc) {
- continue;
- }
- if (!range->hasRange()) {
- if (range->rangeStart() >= first && range->rangeStart() <= last) {
- ranges.insertMulti(range->rangeStart(), range);
- }
- } else {
- if (range->rangeStart() >= first && range->rangeStart() <= last) {
- if (matchLast == -1 || range->rangeEnd() <= matchLast) {
- if (range->rangeEnd() >= matchFirst) {
- ranges.insertMulti(range->rangeStart(), range);
- }
- }
- }
- if (range->rangeEnd() >= first && range->rangeEnd() <= last) {
- if (matchLast == -1 || range->rangeStart() <= matchLast) {
- if (range->rangeStart() >= matchFirst) {
- ranges.insertMulti(range->rangeEnd(), range);
- }
- }
- }
- if (range->rangeStart() >= first && range->rangeStart() <= last) {
- if (matchLast == -1 || range->rangeEnd() >= matchLast) {
- if (range->rangeEnd() >= matchFirst) {
- ranges.insert(range->rangeStart(), range);
- }
- }
- }
- }
- }
- return ranges;
-}
diff --git a/plugins/flake/textshape/kotext/KoTextRangeManager.h b/plugins/flake/textshape/kotext/KoTextRangeManager.h
deleted file mode 100644
index 188d66818c..0000000000
--- a/plugins/flake/textshape/kotext/KoTextRangeManager.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- * Copyright (c) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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 KOTEXTRANGEMANAGER_H
-#define KOTEXTRANGEMANAGER_H
-
-#include "KoBookmarkManager.h"
-#include "KoAnnotationManager.h"
-#include "KoTextRange.h"
-#include "kritatext_export.h"
-
-// Qt + kde
-#include <QMetaType>
-#include <QHash>
-#include <QSet>
-
-
-/**
- * A container to register all the text ranges with.
- */
-class KRITATEXT_EXPORT KoTextRangeManager : public QObject
-{
- Q_OBJECT
-public:
- /// Constructor
- explicit KoTextRangeManager(QObject *parent = 0);
- ~KoTextRangeManager() override;
-
- QList<KoTextRange *> textRanges() const;
-
- /**
- * Insert a new text range into the manager.
- * @param object the text range to be inserted.
- */
- void insert(KoTextRange *object);
-
- /**
- * Remove a text range from this manager.
- * @param range the text range to be removed
- */
- void remove(KoTextRange *range);
-
- /**
- * Return the bookmark manager.
- */
- const KoBookmarkManager *bookmarkManager() const;
-
- /**
- * Return the annotation manager.
- */
- const KoAnnotationManager *annotationManager() const;
-
- /**
- * Return a multi hash of KoTextRange that have start or end points between first and last
- * If the text range is a selection then the opposite end has to be within matchFirst and
- * matchLast.
- * Single position text ranges is only added once to the hash
- */
- QHash<int, KoTextRange *> textRangesChangingWithin(const QTextDocument *, int first, int last, int matchFirst, int matchLast) const;
-
-private:
- QSet<KoTextRange *> m_textRanges;
- QSet<KoTextRange *> m_deletedTextRanges; // kept around for undo purposes
-
- KoBookmarkManager m_bookmarkManager;
- KoAnnotationManager m_annotationManager;
-};
-
-Q_DECLARE_METATYPE(KoTextRangeManager *)
-#endif
diff --git a/plugins/flake/textshape/kotext/KoTextRdfCore.cpp b/plugins/flake/textshape/kotext/KoTextRdfCore.cpp
deleted file mode 100644
index 7f70d22b7a..0000000000
--- a/plugins/flake/textshape/kotext/KoTextRdfCore.cpp
+++ /dev/null
@@ -1,278 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2010 KO GmbH <ben.martin@kogmbh.com>
-
- 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 "KoTextRdfCore.h"
-
-#include "TextDebug.h"
-#include <KoStoreDevice.h>
-#include <KoXmlWriter.h>
-#include <QFile>
-
-using namespace Soprano;
-
-bool KoTextRdfCore::saveRdf( QSharedPointer<Soprano::Model> model, Soprano::StatementIterator triples, KoStore *store, KoXmlWriter *manifestWriter, const QString &fileName)
-{
- bool ok = false;
-
- if (! store->open(fileName)) {
- return false;
- }
-
- KoStoreDevice dev(store);
- QTextStream oss(&dev);
-
- QString serialization = "application/rdf+xml";
- const Soprano::Serializer* serializer
- = Soprano::PluginManager::instance()->discoverSerializerForSerialization(
- Soprano::SerializationRdfXml);
-
- if (serializer) {
- QString data;
- QTextStream tss(&data);
- if (serializer->serialize(triples, tss, Soprano::SerializationRdfXml)) {
- tss.flush();
- oss << data;
- debugText << "fileName:" << fileName << " data.sz:" << data.size();
- debugText << "model.sz:" << model->statementCount();
- ok = true;
- } else {
- debugText << "serialization of Rdf failed!";
- }
- }
- oss.flush();
- store->close();
- manifestWriter->addManifestEntry(fileName, "application/rdf+xml");
- return ok;
-}
-
-bool KoTextRdfCore::createAndSaveManifest(QSharedPointer<Soprano::Model> docmodel, const QMap<QString, QString> &idmap, KoStore *store, KoXmlWriter *manifestWriter)
-{
- QSharedPointer<Soprano::Model> tmpmodel(Soprano::createModel());
- QMap<QString, QString>::const_iterator iditer = idmap.constBegin();
- QMap<QString, QString>::const_iterator idend = idmap.constEnd();
- for (; iditer != idend; ++iditer) {
- QString oldID = iditer.key();
- QString newID = iditer.value();
- debugText << "oldID:" << oldID << " newID:" << newID;
- QString sparqlQuery;
- QTextStream queryss(&sparqlQuery);
- queryss << ""
- << "prefix pkg: <http://docs.oasis-open.org/ns/office/1.2/meta/pkg#> \n"
- << ""
- << "select ?s ?p ?o \n"
- << "where { \n"
- << " ?s pkg:idref ?xmlid . \n"
- << " ?s ?p ?o . \n"
- << " filter( str(?xmlid) = \"" << oldID << "\" ) \n"
- << "}\n";
-
- Soprano::QueryResultIterator it =
- docmodel->executeQuery(sparqlQuery,
- Soprano::Query::QueryLanguageSparql);
- while (it.next()) {
- Soprano::Node pred = it.binding("p");
- Soprano::Node obj = it.binding("o");
- if (pred.toString() == "http://docs.oasis-open.org/ns/office/1.2/meta/pkg#idref") {
- debugText << "changing idref, oldID:" << oldID << " newID:" << newID;
- obj = Node::createLiteralNode(newID);
- }
- Statement s(it.binding("s"), pred, obj);
- tmpmodel->addStatement(s);
- }
- }
- debugText << "exporting triples model.sz:" << tmpmodel->statementCount();
- // save tmpmodel as manifest.rdf in C+P ODF file.
- Soprano::StatementIterator triples = tmpmodel->listStatements();
- bool ret = saveRdf(tmpmodel, triples, store, manifestWriter, "manifest.rdf");
- return ret;
-}
-
-bool KoTextRdfCore::loadManifest(KoStore *store, QSharedPointer<Soprano::Model> model)
-{
- bool ok = true;
- QString fileName = "manifest.rdf";
- if (!store->open(fileName)) {
- debugText << "Entry " << fileName << " not found!";
- return false;
- }
- Soprano::Node context(QUrl("http://www.calligra.org/Rdf/path/" + fileName));
- QUrl BaseURI = QUrl("");
- debugText << "Loading external Rdf/XML from:" << fileName;
-
- QString rdfxmlData(store->device()->readAll());
- const Soprano::Parser *parser =
- Soprano::PluginManager::instance()->discoverParserForSerialization(
- Soprano::SerializationRdfXml);
- Soprano::StatementIterator it = parser->parseString(rdfxmlData,
- BaseURI,
- Soprano::SerializationRdfXml);
- QList<Statement> allStatements = it.allElements();
- debugText << "Found " << allStatements.size() << " triples...";
- foreach (const Soprano::Statement &s, allStatements) {
- Error::ErrorCode err = model->addStatement(s.subject(), s.predicate(),
- s.object(), context);
- if (err != Error::ErrorNone) {
- debugText << "Error adding triple! s:" << s.subject()
- << " p:" << s.predicate()
- << " o:" << s.object();
- ok = false;
- break;
- }
- }
- store->close();
- return ok;
-}
-
-void KoTextRdfCore::dumpModel(const QString &msg, QSharedPointer<Soprano::Model> m)
-{
-#ifndef NDEBUG
- QList<Soprano::Statement> allStatements = m->listStatements().allElements();
- debugText << "----- " << msg << " ----- model size:" << allStatements.size() << endl;
- foreach (const Soprano::Statement &s, allStatements) {
- debugText << s;
- }
-#else
- Q_UNUSED(msg);
- Q_UNUSED(m);
-#endif
-}
-
-QList<Soprano::Statement> KoTextRdfCore::loadList(QSharedPointer<Soprano::Model> model, Soprano::Node ListHeadSubject)
-{
- Node rdfNil = Node::createResourceNode(QUrl("http://www.w3.org/1999/02/22-rdf-syntax-ns#nil"));
- Node rdfFirst = Node::createResourceNode(QUrl("http://www.w3.org/1999/02/22-rdf-syntax-ns#first"));
- Node rdfRest = Node::createResourceNode(QUrl("http://www.w3.org/1999/02/22-rdf-syntax-ns#rest"));
-
- Soprano::Node listBNode = ListHeadSubject;
- QList<Statement> ret;
- debugText << "finding all nodes in the list...";
- while (true) {
- ret << model->listStatements(listBNode, rdfFirst, Node()).allElements();
- Soprano::Node obj = KoTextRdfCore::getObject(model, listBNode, rdfRest);
- debugText << "ret:" << ret;
- debugText << "rest:" << obj;
- if (!obj.isValid()) {
- break;
- }
- if (obj.toString() == rdfNil.toString()) {
- break;
- }
- listBNode = obj;
- }
- return ret;
-}
-
-static void removeList(QSharedPointer<Soprano::Model> model, Soprano::Node ListHeadSubject)
-{
- Node rdfNil = Node::createResourceNode(QUrl("http://www.w3.org/1999/02/22-rdf-syntax-ns#nil"));
- Node rdfFirst = Node::createResourceNode(QUrl("http://www.w3.org/1999/02/22-rdf-syntax-ns#first"));
- Node rdfRest = Node::createResourceNode(QUrl("http://www.w3.org/1999/02/22-rdf-syntax-ns#rest"));
- //
- // Chain down the list recursively so we delete from
- // the list tail back to the head.
- //
- Soprano::Node obj = KoTextRdfCore::getObject(model, ListHeadSubject, rdfRest);
- if (obj.isValid()) {
- if (obj.toString() != rdfNil.toString()) {
- removeList(model, obj);
- }
- }
- model->removeAllStatements(ListHeadSubject, rdfFirst, Node());
- model->removeAllStatements(ListHeadSubject, rdfRest, Node());
-}
-
-void KoTextRdfCore::saveList(QSharedPointer<Soprano::Model> model, Soprano::Node ListHeadSubject, QList<Soprano::Node> &dataBNodeList, Soprano::Node context)
-{
- Node rdfNil = Node::createResourceNode(QUrl("http://www.w3.org/1999/02/22-rdf-syntax-ns#nil"));
- Node rdfFirst = Node::createResourceNode(QUrl("http://www.w3.org/1999/02/22-rdf-syntax-ns#first"));
- Node rdfRest = Node::createResourceNode(QUrl("http://www.w3.org/1999/02/22-rdf-syntax-ns#rest"));
-
- debugText << "header:" << ListHeadSubject.toString();
- debugText << "list.sz:" << dataBNodeList.size();
- debugText << "context:" << context.toString();
-
- removeList(model, ListHeadSubject);
-
- Soprano::Node listBNode = ListHeadSubject;
- Soprano::Node prevListBNode;
-
- foreach (const Soprano::Node &dataBNode, dataBNodeList) {
- // Link the list in Rdf
- model->addStatement(listBNode, rdfFirst, dataBNode, context);
- if (prevListBNode.isValid()) {
- debugText << "prev:" << prevListBNode << " current:" << listBNode;
- model->addStatement(prevListBNode, rdfRest, listBNode, context);
- }
- prevListBNode = listBNode;
- listBNode = model->createBlankNode();
- }
-
- debugText << "at end, prev.isValid:" << prevListBNode.isValid();
- if (prevListBNode.isValid()) {
- model->addStatement(prevListBNode, rdfRest, listBNode, context);
- }
- model->addStatement(listBNode, rdfRest, rdfNil, context);
-}
-
-void KoTextRdfCore::removeStatementsIfTheyExist( QSharedPointer<Soprano::Model> m, const QList<Soprano::Statement> &removeList)
-{
- foreach (const Soprano::Statement &s, removeList) {
- StatementIterator it = m->listStatements(s.subject(), s.predicate(), s.object(), s.context());
- QList<Statement> allStatements = it.allElements();
- Q_FOREACH (const Soprano::Statement &z, allStatements) {
- debugText << "found:" << z;
- m->removeStatement(z);
- }
- }
-}
-
-Soprano::Node KoTextRdfCore::getObject(QSharedPointer<Soprano::Model> model, Soprano::Node s, Soprano::Node p)
-{
- QList<Statement> all;
- all = model->listStatements(s, p, Node()).allElements();
- if (all.isEmpty()) {
- return Soprano::Node();
- }
- return all.first().object();
-}
-
-QByteArray KoTextRdfCore::fileToByteArray(const QString &fileName)
-{
- QFile t(fileName);
- t.open(QIODevice::ReadOnly);
- return t.readAll();
-}
-
-QString KoTextRdfCore::getProperty(QSharedPointer<Soprano::Model> m, Soprano::Node subj, Soprano::Node pred, const QString &defval)
-{
- StatementIterator it = m->listStatements(subj, pred, Node());
- QList<Statement> allStatements = it.allElements();
- foreach (const Soprano::Statement &s, allStatements) {
- return s.object().toString();
- }
- return defval;
-}
-
-QString KoTextRdfCore::optionalBindingAsString(Soprano::QueryResultIterator &it, const QString &bindingName, const QString &def)
-{
- if (it.binding(bindingName).isValid()) {
- return it.binding(bindingName).toString();
- }
- return def;
-}
diff --git a/plugins/flake/textshape/kotext/KoTextRdfCore.h b/plugins/flake/textshape/kotext/KoTextRdfCore.h
deleted file mode 100644
index a0aecac055..0000000000
--- a/plugins/flake/textshape/kotext/KoTextRdfCore.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2010 KO GmbH <ben.martin@kogmbh.com>
-
- 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_TEXT_RDF_CORE_H
-#define KO_TEXT_RDF_CORE_H
-
-#include "kritatext_export.h"
-
-#include <QSharedPointer>
-
-// this file can only be used by code that is built
-// with soprano enabled.
-#include <Soprano/Soprano>
-
-class KoStore;
-class KoXmlWriter;
-
-/**
- * @short Basic low level methods that are available to KoText objects
- *
- * Low level functionality such as streaming a Soprano::Model to and
- * from an ODF container is provided here so that both KoDocumentRdf
- * and other code in libs/kotext can share it.
- *
- * @author Ben Martin
- * @see KoDocumentRdf
- */
-namespace KoTextRdfCore
-{
-/**
- * Save the RDF selected triples from model to the store with the
- * given RDF/XML filename
- */
-bool saveRdf( QSharedPointer<Soprano::Model> model, Soprano::StatementIterator triples,
- KoStore *store, KoXmlWriter *manifestWriter, const QString &fileName);
-
-/**
- * Save the given RDF model to the manifest.rdf file. The idmap is used
- * to maintain xml:id links from the model so they will be valid with
- * the content.xml that generated the idmap.
- */
-bool createAndSaveManifest(QSharedPointer<Soprano::Model> model,
- const QMap<QString, QString> &idmap, KoStore *store, KoXmlWriter *manifestWriter);
-
-/**
- * Load the manifest.rdf file from the ODF container store
- * into the model provided.
- */
-bool loadManifest(KoStore *store, QSharedPointer<Soprano::Model> model);
-
-/**
- * For debugging, dump the model to debugText along with the
- * given header message for identification
- */
-void dumpModel(const QString &message, QSharedPointer<Soprano::Model> model);
-
-/**
- * Load an Rdf linked list of statements. See saveList() for the
- * details. The return value of loadList() is the equivalent of
- * dataBNodeList in saveList().
- *
- * @see saveList()
- */
-QList<Soprano::Statement> KRITATEXT_EXPORT loadList(QSharedPointer<Soprano::Model> model, Soprano::Node ListHeadSubject);
-
-/**
- * Save an Rdf List of data nodes into the model. Rdf defines a
- * linked list format in the
- * http://www.w3.org/1999/02/22-rdf-syntax-ns URI namespace using
- * first/rest to link the current element with the "rest" of the
- * list. A scheme that will be familiar to many lisp programmers
- * car/cdr. Unfortunately dealing with such lists directly is
- * clumsy so this and loadList() let you store a list of data
- * nodes and these methods create all the boilerplate Rdf triples
- * to store/read a simple QList of nodes to Rdf properly. You
- * supply the list header node ListHeadSubject which is normally
- * the subject that you want the list associated with in Rdf. The
- * other nodes used in the internal structure of the Rdf list are
- * just random bnodes as shown below. If you have a previous,
- * existing list then this method will remove those nodes first so
- * that the Rdf model does not grow with disgarded list nodes over
- * time.
- *
- * The old list nodes are removed if they exist, and a new list is
- * created starting at ListHeadSubject, and linking all the nodes
- * in dataBNodeList using the supplied rdf context. Use the
- * loadList() method to get the list dataBNodeList back from the
- * model again.
- *
- * The result will be like:
- * @verbatim
- * ListHeadSubject 22-rdf-syntax-ns#first dataBNodeList[0]
- * ListHeadSubject 22-rdf-syntax-ns#rest bnodeA
- * bnodeA 22-rdf-syntax-ns#first dataBNodeList[1]
- * bnodeA 22-rdf-syntax-ns#rest bnodeB
- * ...
- * bnodeZ 22-rdf-syntax-ns#first dataBNodeList[N]
- * bnodeZ 22-rdf-syntax-ns#rest nil
- * @endverbatim
- *
- */
-void KRITATEXT_EXPORT saveList(QSharedPointer<Soprano::Model> model, Soprano::Node ListHeadSubject,
- QList<Soprano::Node> &dataBNodeList, Soprano::Node context);
-
-/**
- * Using model->removeStatements() will fail if the statement does not
- * exist in the model. This method is a bit sloppier in that it ignores
- * attempts to remove statements twice, or ones that no longer exist
- * in the model. This is handy for set based remove/add bulk updates
- * because you don't have to ensure that a statement is added only once
- * to the remove list.
- */
-void KRITATEXT_EXPORT removeStatementsIfTheyExist( QSharedPointer<Soprano::Model> model,
- const QList<Soprano::Statement> &removeList);
-
-/**
- * Given the Subj+Pred get the Object for the triple. If there are
- * more than one object, a random one from the possible candidates is
- * returned. This is mainly useful when you *know* there is only zero
- * or one object.
- */
-Soprano::Node KRITATEXT_EXPORT getObject(QSharedPointer<Soprano::Model> model, Soprano::Node s, Soprano::Node p);
-
-QString KRITATEXT_EXPORT getProperty(QSharedPointer<Soprano::Model> m,
- Soprano::Node subj,
- Soprano::Node pred,
- const QString &defval);
-QString KRITATEXT_EXPORT optionalBindingAsString(Soprano::QueryResultIterator& it,
- const QString &bindingName,
- const QString &def = QString());
-QByteArray KRITATEXT_EXPORT fileToByteArray(const QString &fileName);
-
-}
-#endif
-
diff --git a/plugins/flake/textshape/kotext/KoTextReference.cpp b/plugins/flake/textshape/kotext/KoTextReference.cpp
deleted file mode 100644
index 2206813a01..0000000000
--- a/plugins/flake/textshape/kotext/KoTextReference.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 "KoTextReference.h"
-
-#include "KoTextLocator.h"
-#include "KoInlineTextObjectManager.h"
-
-// Include Q_UNSUSED classes, for building on Windows
-#include <KoShapeLoadingContext.h>
-#include <KoShapeSavingContext.h>
-#include <KoXmlReader.h>
-
-KoTextReference::KoTextReference(int indexId)
- : KoVariable(),
- m_indexId(indexId)
-{
-}
-
-KoTextReference::~KoTextReference()
-{
- KoTextLocator *loc = locator();
- if (loc)
- loc->removeListener(this);
-}
-
-void KoTextReference::variableMoved(const QTextDocument *document, int posInDocument)
-{
- Q_UNUSED(document);
- Q_UNUSED(posInDocument);
- Q_ASSERT(manager());
- KoTextLocator *loc = locator();
- if (loc)
- setValue(QString::number(loc->pageNumber()));
- else
- setValue("NOREF"); // anything smarter to point to a broken reference?
-}
-
-void KoTextReference::setup()
-{
- locator()->addListener(this);
- variableMoved(0, 0);
-}
-
-KoTextLocator* KoTextReference::locator()
-{
- return dynamic_cast<KoTextLocator*>(manager()->inlineTextObject(m_indexId));
-}
-
-bool KoTextReference::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- Q_UNUSED(element);
- Q_UNUSED(context);
- // TODO
- return false;
-}
-
-void KoTextReference::saveOdf(KoShapeSavingContext &context)
-{
- Q_UNUSED(context);
- // TODO
-}
diff --git a/plugins/flake/textshape/kotext/KoTextReference.h b/plugins/flake/textshape/kotext/KoTextReference.h
deleted file mode 100644
index 5fb2ccd5c3..0000000000
--- a/plugins/flake/textshape/kotext/KoTextReference.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 KOTEXTREFERENCE_H
-#define KOTEXTREFERENCE_H
-
-#include "KoVariable.h"
-
-class KoTextLocator;
-
-/**
- * This variable displays information about a text reference.
- * A user can insert characters that are called locators. And are represented by a KoTextLocator
- * the user can then insert (several) KoTextReference variables that will update the textual description
- * of the locator whenever text is re-layouted.
- * This effectively means that the reference will print the page number (for example) of where the
- * locator is and keep it updated automatically.
- */
-class KoTextReference : public KoVariable
-{
-public:
- /**
- * Constructor; please don't use directly as the KoInlineTextObjectManager will supply an action
- * to create one.
- * @param indexId the index of the inline object that is the locator. See KoInlineObject::id()
- */
- explicit KoTextReference(int indexId);
- ~KoTextReference() override;
-
- void variableMoved(const QTextDocument *document, int posInDocument) override;
- void setup() override;
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
- void saveOdf(KoShapeSavingContext &context) override;
-
-private:
- KoTextLocator *locator();
- int m_indexId;
- // TODO store a config of what we actually want to show. The hardcoded pagenumber is not enough.
- // we want 'section' / chapter name/number and maybe word. All in a nice formatted text.
- // see also the ODF spec.
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoTextShapeSavingContext.cpp b/plugins/flake/textshape/kotext/KoTextShapeSavingContext.cpp
deleted file mode 100644
index 36087a496e..0000000000
--- a/plugins/flake/textshape/kotext/KoTextShapeSavingContext.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2008 Pierre Stirnweiss \pierre.stirnweiss_calligra@gadz.org>
-
- 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 "KoTextShapeSavingContext.h"
-
-#include <KoGenChanges.h>
-
-#include "TextDebug.h"
-
-KoTextShapeSavingContext::KoTextShapeSavingContext(KoXmlWriter &xmlWriter, KoGenStyles& mainStyles,
- KoEmbeddedDocumentSaver& embeddedSaver, KoGenChanges& changes)
- : KoShapeSavingContext(xmlWriter, mainStyles, embeddedSaver)
- , m_changes(changes)
-{
-}
-
-KoTextShapeSavingContext::~KoTextShapeSavingContext()
-{
-}
-
-KoGenChanges & KoTextShapeSavingContext::changes()
-{
- return m_changes;
-}
diff --git a/plugins/flake/textshape/kotext/KoTextShapeSavingContext.h b/plugins/flake/textshape/kotext/KoTextShapeSavingContext.h
deleted file mode 100644
index 4041fc90ad..0000000000
--- a/plugins/flake/textshape/kotext/KoTextShapeSavingContext.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2008 Pierre Stirnweiss \pierre.stirnweiss_calligra@gadz.org>
-
- 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 KOTEXTSHAPESAVINGCONTEXT_H
-#define KOTEXTSHAPESAVINGCONTEXT_H
-
-#include "kritatext_export.h"
-
-#include <KoShapeSavingContext.h>
-
-class KoGenChanges;
-
-/**
- * The set of data for the ODF file format used during saving of a shape.
- */
-class KRITATEXT_EXPORT KoTextShapeSavingContext : public KoShapeSavingContext
-{
-public:
-
- /**
- * @brief Constructor
- * @param xmlWriter used for writing the xml
- * @param mainStyles for saving the styles
- * @param embeddedSaver for saving embedded documents
- * @param changes for saving the tracked changes
- */
- KoTextShapeSavingContext(KoXmlWriter &xmlWriter, KoGenStyles& mainStyles,
- KoEmbeddedDocumentSaver& embeddedSaver, KoGenChanges& changes);
- ~KoTextShapeSavingContext() override;
-
- /**
- * @brief Get the changes (tracked)
- *
- * @return changes (tracked)
- */
- KoGenChanges & changes();
-
-
-private:
- KoGenChanges& m_changes;
-};
-
-#endif // KOTEXTSHAPESAVINGCONTEXT_H
diff --git a/plugins/flake/textshape/kotext/KoTextSoftPageBreak.cpp b/plugins/flake/textshape/kotext/KoTextSoftPageBreak.cpp
deleted file mode 100644
index fb2118ce30..0000000000
--- a/plugins/flake/textshape/kotext/KoTextSoftPageBreak.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 "KoTextSoftPageBreak.h"
-
-#include <KoShapeSavingContext.h>
-#include <KoXmlReader.h>
-#include <KoXmlWriter.h>
-
-#include <QTextInlineObject>
-#include <QPainter>
-
-// Include Q_UNSUSED classes, for building on Windows
-#include <KoShapeLoadingContext.h>
-
-KoTextSoftPageBreak::KoTextSoftPageBreak()
-{
-}
-
-KoTextSoftPageBreak::~KoTextSoftPageBreak()
-{
-}
-
-bool KoTextSoftPageBreak::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- Q_UNUSED(element)
- Q_UNUSED(context)
- return true;
-}
-
-void KoTextSoftPageBreak::saveOdf(KoShapeSavingContext &context)
-{
- KoXmlWriter &writer = context.xmlWriter();
- writer.startElement("text:soft-page-break");
- writer.endElement();
-}
-
-void KoTextSoftPageBreak::updatePosition(const QTextDocument *document,
- int posInDocument, const QTextCharFormat &format)
-{
- Q_UNUSED(document)
- Q_UNUSED(posInDocument)
- Q_UNUSED(format)
-}
-
-void KoTextSoftPageBreak::resize(const QTextDocument *document, QTextInlineObject &object,
- int posInDocument, const QTextCharFormat &format, QPaintDevice *pd)
-{
- Q_UNUSED(document)
- Q_UNUSED(object)
- Q_UNUSED(posInDocument)
- Q_UNUSED(format)
- Q_UNUSED(pd)
- object.setWidth(0); // set the width to 0 as otherwise it is negative which results in the text being moved to left
- object.setAscent(0);
- object.setDescent(0);
-}
-
-void KoTextSoftPageBreak::paint(QPainter &painter, QPaintDevice *pd, const QTextDocument *document,
- const QRectF &rect, const QTextInlineObject &object, int posInDocument, const QTextCharFormat &format)
-{
- Q_UNUSED(painter)
- Q_UNUSED(pd)
- Q_UNUSED(document)
- Q_UNUSED(rect)
- Q_UNUSED(object)
- Q_UNUSED(posInDocument)
- Q_UNUSED(format)
- // TODO have a way to display the soft page break
-}
diff --git a/plugins/flake/textshape/kotext/KoTextSoftPageBreak.h b/plugins/flake/textshape/kotext/KoTextSoftPageBreak.h
deleted file mode 100644
index 62c4fe9a74..0000000000
--- a/plugins/flake/textshape/kotext/KoTextSoftPageBreak.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 KOTEXTSOFTPAGEBREAK_H
-#define KOTEXTSOFTPAGEBREAK_H
-
-#include "KoInlineObject.h"
-
-#include "kritatext_export.h"
-
-/**
- * This class defines a soft page break as defined in odf
- * <text:soft-page-break>
- *
- * The class does not have members as it's presence is enough.
- */
-class KRITATEXT_EXPORT KoTextSoftPageBreak : public KoInlineObject
-{
- Q_OBJECT
-public:
- KoTextSoftPageBreak();
- ~KoTextSoftPageBreak() override;
-
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
-
- void saveOdf(KoShapeSavingContext &context) override;
-
- void updatePosition(const QTextDocument *document,
- int posInDocument, const QTextCharFormat &format) override;
-
- void resize(const QTextDocument *document, QTextInlineObject &object,
- int posInDocument, const QTextCharFormat &format, QPaintDevice *pd) override;
-
- void paint(QPainter &painter, QPaintDevice *pd, const QTextDocument *document,
- const QRectF &rect, const QTextInlineObject &object, int posInDocument, const QTextCharFormat &format) override;
-};
-
-#endif /* KOTEXTSOFTPAGEBREAK_H */
diff --git a/plugins/flake/textshape/kotext/KoTextTableTemplate.cpp b/plugins/flake/textshape/kotext/KoTextTableTemplate.cpp
deleted file mode 100644
index 4e832b20af..0000000000
--- a/plugins/flake/textshape/kotext/KoTextTableTemplate.cpp
+++ /dev/null
@@ -1,292 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 "KoTextTableTemplate.h"
-
-#include "KoTextSharedLoadingData.h"
-
-#include <KoShapeLoadingContext.h>
-#include <KoTextSharedSavingData.h>
-#include <KoOdfWorkaround.h>
-#include <KoXmlNS.h>
-#include <KoTableCellStyle.h>
-#include <KoXmlWriter.h>
-#include <KoXmlReader.h>
-
-#include <QUrl>
-
-
-#include "Styles_p.h"
-
-#include "TextDebug.h"
-
-static const struct {
- KoTextTableTemplate::Property m_property;
- const char *m_element;
-} templateStyles[] = {
- { KoTextTableTemplate::BackGround, "background" },
- { KoTextTableTemplate::Body, "body" },
- { KoTextTableTemplate::EvenColumns, "even-columns" },
- { KoTextTableTemplate::EvenRows, "even-rows" },
- { KoTextTableTemplate::FirstColumn, "first-column" },
- { KoTextTableTemplate::FirstRow, "first-row" },
- { KoTextTableTemplate::LastColumn, "last-column" },
- { KoTextTableTemplate::LastRow, "last-row" },
- { KoTextTableTemplate::OddColumns, "odd-columns" },
- { KoTextTableTemplate::OddRows, "odd-rows" }
-};
-
-static const unsigned int numTemplateStyles = sizeof(templateStyles) / sizeof(*templateStyles);
-
-class Q_DECL_HIDDEN KoTextTableTemplate::Private
-{
-public:
- Private() { }
-
- ~Private() { }
-
- void setProperty(int key, const QVariant &value) {
- stylesPrivate.add(key, value);
- }
- int propertyInt(int key) const {
- QVariant variant = stylesPrivate.value(key);
- if (variant.isNull())
- return 0;
- return variant.toInt();
- }
-
- StylePrivate stylesPrivate;
- QString name;
-};
-
-
-KoTextTableTemplate::KoTextTableTemplate(QObject *parent)
- : QObject(parent),
- d(new Private())
-{
-
-}
-
-KoTextTableTemplate::~KoTextTableTemplate()
-{
- delete d;
-}
-
-QString KoTextTableTemplate::name() const
-{
- return d->name;
-}
-
-void KoTextTableTemplate::setName(const QString &name)
-{
- if (name == d->name)
- return;
- d->name = name;
-}
-
-void KoTextTableTemplate::setStyleId(int id)
-{
- d->stylesPrivate.add(KoTextTableTemplate::StyleId, id);
-}
-
-int KoTextTableTemplate::styleId() const
-{
- return d->propertyInt(StyleId);
-}
-
-int KoTextTableTemplate::background() const
-{
- return d->propertyInt(BackGround);
-}
-
-void KoTextTableTemplate::setBackground(int styleId)
-{
- d->stylesPrivate.add(BackGround, styleId);
-}
-
-int KoTextTableTemplate::body() const
-{
- return d->propertyInt(Body);
-}
-
-void KoTextTableTemplate::setBody(int styleId)
-{
- d->stylesPrivate.add(Body, styleId);
-}
-
-int KoTextTableTemplate::evenColumns() const
-{
- return d->propertyInt(EvenColumns);
-}
-
-void KoTextTableTemplate::setEvenColumns(int styleId)
-{
- d->stylesPrivate.add(EvenColumns, styleId);
-}
-
-int KoTextTableTemplate::evenRows() const
-{
- return d->propertyInt(EvenRows);
-}
-
-void KoTextTableTemplate::setEvenRows(int styleId)
-{
- d->stylesPrivate.add(EvenRows, styleId);
-}
-
-int KoTextTableTemplate::firstColumn() const
-{
- return d->propertyInt(FirstColumn);
-}
-
-void KoTextTableTemplate::setFirstColumn(int styleId)
-{
- d->stylesPrivate.add(FirstColumn, styleId);
-}
-
-int KoTextTableTemplate::firstRow() const
-{
- return d->propertyInt(FirstRow);
-}
-
-void KoTextTableTemplate::setFirstRow(int styleId)
-{
- d->stylesPrivate.add(FirstRow, styleId);
-}
-
-int KoTextTableTemplate::lastColumn() const
-{
- return d->propertyInt(LastColumn);
-}
-
-void KoTextTableTemplate::setLastColumn(int styleId)
-{
- d->stylesPrivate.add(LastColumn, styleId);
-}
-
-int KoTextTableTemplate::lastRow() const
-{
- return d->propertyInt(LastRow);
-}
-
-void KoTextTableTemplate::setLastRow(int styleId)
-{
- d->stylesPrivate.add(LastRow, styleId);
-}
-
-int KoTextTableTemplate::oddColumns() const
-{
- return d->propertyInt(OddColumns);
-}
-
-void KoTextTableTemplate::setOddColumns(int styleId)
-{
- d->stylesPrivate.add(OddColumns, styleId);
-}
-
-int KoTextTableTemplate::oddRows() const
-{
- return d->propertyInt(OddRows);
-}
-
-void KoTextTableTemplate::setOddRows(int styleId)
-{
- d->stylesPrivate.add(OddRows, styleId);
-}
-
-void KoTextTableTemplate::loadOdf(const KoXmlElement *element, KoShapeLoadingContext &context)
-{
- QString templateName = element->attributeNS(KoXmlNS::table, "name", QString());
-#ifndef NWORKAROUND_ODF_BUGS
- if (templateName.isEmpty()) {
- templateName = KoOdfWorkaround::fixTableTemplateName(*element);
- }
-#endif
- d->name = templateName;
-
- KoSharedLoadingData *sharedData = context.sharedData(KOTEXT_SHARED_LOADING_ID);
- KoTextSharedLoadingData *textSharedData = 0;
- if (sharedData) {
- textSharedData = dynamic_cast<KoTextSharedLoadingData *>(sharedData);
- }
-
- if (textSharedData) {
- KoXmlElement styleElem;
- forEachElement(styleElem, (*element)) {
- if (styleElem.namespaceURI() == KoXmlNS::table) {
- for (uint index = 0; index < numTemplateStyles; ++index) {
- if (templateStyles[index].m_element == styleElem.localName()) {
- QString styleName = styleElem.attributeNS(KoXmlNS::table, "style-name", QString());
-#ifndef NWORKAROUND_ODF_BUGS
- if (styleName.isEmpty()) {
- styleName = KoOdfWorkaround::fixTableTemplateCellStyleName(styleElem);
- }
-#endif
- KoTableCellStyle *cs = 0;
- if (!styleName.isEmpty()) {
- cs = textSharedData->tableCellStyle(styleName, true);
- if (!cs) {
- warnText << "Missing KoTableCellStyle!";
- }
- else {
- // debugText << "==> cs.name:" << cs->name();
- // debugText << "==> cs.styleId:" << cs->styleId();
- d->stylesPrivate.add(templateStyles[index].m_property, cs->styleId());
- }
- }
- }
- }
- }
- }
- }
-}
-
-void KoTextTableTemplate::saveOdf(KoXmlWriter *writer, KoTextSharedSavingData *savingData) const
-{
- writer->startElement("table:table-template");
-
- QString styleName(QString(QUrl::toPercentEncoding(name(), "", " ")).replace('%', '_'));
- if (styleName.isEmpty())
- styleName = "TT";
-
- QString generatedName = styleName;
- int num = 1;
- while (savingData->styleNames().contains(generatedName)) {
- generatedName = styleName + QString::number(num++);
- }
-
- savingData->setStyleName(styleId(), generatedName);
- d->name = generatedName;
-
- writer->addAttribute("table:name", name());
-
- for (uint index = 0; index < numTemplateStyles; ++index) {
- if (d->stylesPrivate.contains(templateStyles[index].m_property)) {
- writer->startElement(QString("table:%1").arg(templateStyles[index].m_element).toLatin1());
- QString savedStyleName = savingData->styleName(d->stylesPrivate.value(templateStyles[index].m_property).toInt());
- if (! savedStyleName.isEmpty()) {
- writer->addAttribute("table:style-name", savedStyleName);
- }
-
- writer->endElement();
- }
- }
-
- writer->endElement(); //table:table-template
-}
diff --git a/plugins/flake/textshape/kotext/KoTextTableTemplate.h b/plugins/flake/textshape/kotext/KoTextTableTemplate.h
deleted file mode 100644
index ab0e0f8957..0000000000
--- a/plugins/flake/textshape/kotext/KoTextTableTemplate.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 KOTEXTTABLETEMPLATE_H
-#define KOTEXTTABLETEMPLATE_H
-
-#include "kritatext_export.h"
-
-#include <QObject>
-
-#include <KoXmlReaderForward.h>
-
-class KoXmlWriter;
-class KoShapeLoadingContext;
-class KoTextSharedSavingData;
-
-class KRITATEXT_EXPORT KoTextTableTemplate : public QObject
-{
-public:
- enum Property {
- StyleId = 0,
- BackGround,
- Body,
- EvenColumns,
- EvenRows,
- FirstColumn,
- FirstRow,
- LastColumn,
- LastRow,
- OddColumns,
- OddRows
- };
-
- int background() const;
- void setBackground(int styleId);
-
- int body() const;
- void setBody(int styleId);
-
- int evenColumns() const;
- void setEvenColumns(int styleId);
-
- int evenRows() const;
- void setEvenRows(int styleId);
-
- int firstColumn() const;
- void setFirstColumn(int styleId);
-
- int firstRow() const;
- void setFirstRow(int styleId);
-
- int lastColumn() const;
- void setLastColumn(int styleId);
-
- int lastRow() const;
- void setLastRow(int styleId);
-
- int oddColumns() const;
- void setOddColumns(int styleId);
-
- int oddRows() const;
- void setOddRows(int styleId);
-
- /// Constructor
- explicit KoTextTableTemplate(QObject *parent = 0);
-
- /// Destructor
- ~KoTextTableTemplate() override;
-
- /// return the name of the style.
- QString name() const;
-
- /// set a user-visible name on the style.
- void setName(const QString &name);
-
- /// each style has a unique ID (non persistent) given out by the styleManager
- int styleId() const;
-
- /// each style has a unique ID (non persistent) given out by the styleManager
- void setStyleId(int id);
-
- /**
- * Load the template style from the element
- *
- * @param context the odf loading context
- * @param element the element containing the
- */
- void loadOdf(const KoXmlElement *element, KoShapeLoadingContext &context);
-
- /**
- * save the table-template element
- */
- void saveOdf(KoXmlWriter *writer, KoTextSharedSavingData *savingData) const;
-
-
-private:
- class Private;
- Private * const d;
-
-};
-
-
-#endif //KOTEXTTABLETEMPLATE_H
diff --git a/plugins/flake/textshape/kotext/KoVariable.cpp b/plugins/flake/textshape/kotext/KoVariable.cpp
deleted file mode 100644
index c8889797ac..0000000000
--- a/plugins/flake/textshape/kotext/KoVariable.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- *
- * 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 "KoVariable.h"
-
-#include "KoInlineObject_p.h"
-
-#include <KoShape.h>
-
-#include <QPainter>
-#include <QFontMetricsF>
-#include <QTextDocument>
-#include <QTextInlineObject>
-#include "TextDebug.h"
-
-class KoVariablePrivate : public KoInlineObjectPrivate
-{
-public:
- KoVariablePrivate()
- : modified(true),
- document(0),
- lastPositionInDocument(-1)
- {
- }
-
- QDebug printDebug(QDebug dbg) const override
- {
- dbg.nospace() << "KoVariable value=" << value;
- return dbg.space();
- }
-
- QString value;
- bool modified;
- const QTextDocument *document;
- int lastPositionInDocument;
-};
-
-KoVariable::KoVariable(bool propertyChangeListener)
- : KoInlineObject(*(new KoVariablePrivate()), propertyChangeListener)
-{
-}
-
-KoVariable::~KoVariable()
-{
-}
-
-void KoVariable::setValue(const QString &value)
-{
- Q_D(KoVariable);
- if (d->value == value)
- return;
- d->value = value;
- d->modified = true;
- if (d->document) {
- const_cast<QTextDocument *>(d->document)->markContentsDirty(d->lastPositionInDocument, 0);
- }
-}
-
-void KoVariable::updatePosition(const QTextDocument *document, int posInDocument, const QTextCharFormat & format)
-{
- Q_D(KoVariable);
- if (d->document) {
- disconnect(d->document, SIGNAL(destroyed()), this, SLOT(documentDestroyed()));
- }
- d->document = document;
- connect(d->document, SIGNAL(destroyed()), this, SLOT(documentDestroyed()));
- d->lastPositionInDocument = posInDocument;
- Q_UNUSED(format);
- // Variables are always 'in place' so the position is 100% defined by the text layout.
- variableMoved(d->document, posInDocument);
-}
-
-void KoVariable::resize(const QTextDocument *document, QTextInlineObject &object, int posInDocument, const QTextCharFormat &format, QPaintDevice *pd)
-{
- Q_D(KoVariable);
- Q_UNUSED(document);
- Q_UNUSED(posInDocument);
- if (d->modified == false)
- return;
- if (object.isValid() == false)
- return;
- d->modified = true;
- Q_ASSERT(format.isCharFormat());
- QFontMetricsF fm(format.font(), pd);
-
- qreal width = qMax(qreal(0.0), fm.width(d->value));
- qreal ascent = fm.ascent();
- qreal descent = fm.descent();
- if (object.width() != width) {
- object.setWidth(width);
- }
- if (object.ascent() != ascent) {
- object.setAscent(ascent);
- }
- if (object.descent() != descent) {
- object.setDescent(descent);
- }
-}
-
-void KoVariable::paint(QPainter &painter, QPaintDevice *pd, const QTextDocument *document, const QRectF &rect, const QTextInlineObject &object, int posInDocument, const QTextCharFormat &format)
-{
- Q_D(KoVariable);
- Q_UNUSED(document);
- Q_UNUSED(posInDocument);
-
- // TODO set all the font properties from the format (color etc)
- QFont font(format.font(), pd);
- QTextLayout layout(d->value, font, pd);
- layout.setCacheEnabled(true);
- QVector<QTextLayout::FormatRange> layouts;
- QTextLayout::FormatRange range;
- range.start = 0;
- range.length = d->value.length();
- range.format = format;
- layouts.append(range);
- layout.setFormats(layouts);
-
- QTextOption option(Qt::AlignLeft | Qt::AlignAbsolute);
- if (object.isValid()) {
- option.setTextDirection(object.textDirection());
- }
- layout.setTextOption(option);
- layout.beginLayout();
- layout.createLine();
- layout.endLayout();
- layout.draw(&painter, rect.topLeft());
-}
-
-void KoVariable::variableMoved(const QTextDocument *document, int posInDocument)
-{
- Q_UNUSED(document);
- Q_UNUSED(posInDocument);
-}
-
-QString KoVariable::value() const
-{
- Q_D(const KoVariable);
- return d->value;
-}
-
-int KoVariable::positionInDocument() const
-{
- Q_D(const KoVariable);
- return d->lastPositionInDocument;
-}
-
-void KoVariable::documentDestroyed()
-{
- // deleteLater(); does not work when closing a document as the inline object manager is deleted before the control is given back to the event loop
- // therefore commit suicide.
- // See https://isocpp.org/wiki/faq/freestore-mgmt#delete-this
- delete(this);
-}
diff --git a/plugins/flake/textshape/kotext/KoVariable.h b/plugins/flake/textshape/kotext/KoVariable.h
deleted file mode 100644
index 9c04f71038..0000000000
--- a/plugins/flake/textshape/kotext/KoVariable.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 __KOVARIABLE_H__
-#define __KOVARIABLE_H__
-
-// Calligra libs
-#include "KoInlineObject.h"
-#include "kritatext_export.h"
-
-class KoProperties;
-class QWidget;
-class KoVariableManager;
-class KoVariablePrivate;
-
-/**
- * Base class for in-text variables.
- *
- * A variable is a field inserted into the text and the content is set to a specific value that
- * is used as text. This class is pretty boring in that it has just a setValue() to alter the
- * text shown; we depend on plugin writers to create more exciting ways to update variables.
- */
-class KRITATEXT_EXPORT KoVariable : public KoInlineObject
-{
- Q_OBJECT
-public:
- /**
- * Constructor.
- */
- explicit KoVariable(bool propertyChangeListener = false);
- ~KoVariable() override;
-
- /**
- * The new value this variable will show.
- * Will be used at the next repaint.
- * @param value the new value this variable shows.
- */
- void setValue(const QString &value);
-
- /// @return the current value of this variable.
- QString value() const;
-
- /**
- * Shortly after instantiating this variable the factory should set the
- * properties using this method.
- * Note that the loading mechanism will fill this properties object with the
- * attributes from the ODF file (if applicable), so it would be useful to synchronize
- * the property names based on that.
- */
- virtual void setProperties(const KoProperties *props) {
- Q_UNUSED(props);
- }
-
- /**
- * If this variable has user-editable options it should provide a widget that is capable
- * of manipulating these options so the text-tool can use it to show that to the user.
- * Note that all manipulations should have a direct effect on the variable itself.
- */
- virtual QWidget *createOptionsWidget() {
- return 0;
- }
-
-protected:
- /**
- * This hook is called whenever the variable gets a new position.
- * If this is a type of variable that needs to change its value based on that
- * you should implement this method and act on it.
- */
- virtual void variableMoved(const QTextDocument *document, int posInDocument);
-
- friend class KoVariableManager;
- /**
- * return the last known position in the document. Note that if the variable has not yet been layouted,
- * it does not know the position.
- */
- int positionInDocument() const;
-
- /// reimplemented
- void resize(const QTextDocument *document, QTextInlineObject &object,
- int posInDocument, const QTextCharFormat &format, QPaintDevice *pd) override;
-private:
- void updatePosition(const QTextDocument *document,
- int posInDocument, const QTextCharFormat &format) override;
- void paint(QPainter &painter, QPaintDevice *pd, const QTextDocument *document,
- const QRectF &rect, const QTextInlineObject &object, int posInDocument, const QTextCharFormat &format) override;
-
-private Q_SLOTS:
- void documentDestroyed();
-
-private:
- Q_DECLARE_PRIVATE(KoVariable)
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/KoVariableManager.cpp b/plugins/flake/textshape/kotext/KoVariableManager.cpp
deleted file mode 100644
index 51f456798a..0000000000
--- a/plugins/flake/textshape/kotext/KoVariableManager.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008, 2011 Sebastian Sauer <mail@dipe.org>
- * Copyright (C) 2011 Robert Mathias Marmorstein <robert@narnia.homeunix.com>
- *
- * 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 "KoVariableManager.h"
-
-#include "KoInlineTextObjectManager.h"
-#include "KoNamedVariable.h"
-#include <KoXmlNS.h>
-#include <KoXmlReader.h>
-#include <KoXmlWriter.h>
-
-class KoVariableManagerPrivate
-{
-public:
- KoVariableManagerPrivate()
- : lastId(KoInlineObject::VariableManagerStart) { }
- KoInlineTextObjectManager *inlineObjectManager;
- QHash<QString, int> variableMapping;
- QHash<int, QString> userTypes;
- QStringList variableNames;
- QStringList userVariableNames;
- int lastId;
-};
-
-KoVariableManager::KoVariableManager(KoInlineTextObjectManager *inlineObjectManager)
- : d(new KoVariableManagerPrivate)
-{
- d->inlineObjectManager = inlineObjectManager;
-}
-
-KoVariableManager::~KoVariableManager()
-{
- delete d;
-}
-
-void KoVariableManager::setValue(const QString &name, const QString &value, const QString &type)
-{
- int key;
- // we store the mapping from name to key
- if (d->variableMapping.contains(name)) {
- key = d->variableMapping.value(name);
- } else {
- key = d->lastId++;
- d->variableMapping.insert(name, key);
- if (type.isEmpty()) {
- Q_ASSERT(!d->variableNames.contains(name));
- d->variableNames.append(name);
- } else {
- Q_ASSERT(!d->userVariableNames.contains(name));
- d->userVariableNames.append(name);
- }
- }
- if (!type.isEmpty()) {
- d->userTypes.insert(key, type);
- }
- // the variable manager stores the actual value of the variable.
- d->inlineObjectManager->setProperty(static_cast<KoInlineObject::Property>(key), value);
- emit valueChanged();
-}
-
-QString KoVariableManager::value(const QString &name) const
-{
- int key = d->variableMapping.value(name);
- if (key == 0) {
- return QString();
- }
- return d->inlineObjectManager->stringProperty(static_cast<KoInlineObject::Property>(key));
-}
-
-QString KoVariableManager::userType(const QString &name) const
-{
- int key = d->variableMapping.value(name);
- if (key == 0) {
- return QString();
- }
- QHash<int, QString>::const_iterator it = d->userTypes.constFind(key);
- if (it == d->userTypes.constEnd()) {
- return QString();
- }
- return it.value();
-}
-
-void KoVariableManager::remove(const QString &name)
-{
- int key = d->variableMapping.value(name);
- if (key == 0) {
- return;
- }
- d->variableMapping.remove(name);
- d->userTypes.remove(key);
- d->variableNames.removeOne(name);
- d->userVariableNames.removeOne(name);
- d->inlineObjectManager->removeProperty(static_cast<KoInlineObject::Property>(key));
-}
-
-KoVariable *KoVariableManager::createVariable(const QString &name) const
-{
- int key = d->variableMapping.value(name);
- if (key == 0) {
- return 0;
- }
- return new KoNamedVariable(static_cast<KoInlineObject::Property>(key), name);
-}
-
-QList<QString> KoVariableManager::variables() const
-{
- return d->variableNames;
-}
-
-QList<QString> KoVariableManager::userVariables() const
-{
- return d->userVariableNames;
-}
-
-#include "TextDebug.h"
-
-void KoVariableManager::loadOdf(const KoXmlElement &bodyElement)
-{
- KoXmlElement element = KoXml::namedItemNS(bodyElement, KoXmlNS::text, "user-field-decls", KoXmlTextContentPrelude);
- if (element.isNull())
- return;
- KoXmlElement e;
- forEachElement(e, element) {
- if (e.namespaceURI() != KoXmlNS::text || e.localName() != "user-field-decl")
- continue;
- const QString name = e.attributeNS(KoXmlNS::text, "name");
- QString type = e.attributeNS(KoXmlNS::office, "value-type");
- QString value;
- if (type == "string") {
- if (e.hasAttributeNS(KoXmlNS::office, "string-value"))
- value = e.attributeNS(KoXmlNS::office, "string-value");
- else // if the string-value is not present then the content defines the value
- value = e.toText().data();
- } else if (type == "boolean") {
- value = e.attributeNS(KoXmlNS::office, "boolean-value");
- } else if (type == "currency") {
- value = e.attributeNS(KoXmlNS::office, "currency");
- } else if (type == "date") {
- value = e.attributeNS(KoXmlNS::office, "date-value");
- } else if (type == "float") {
- value = e.attributeNS(KoXmlNS::office, "value");
- } else if (type == "percentage") {
- value = e.attributeNS(KoXmlNS::office, "value");
- } else if (type == "time") {
- value = e.attributeNS(KoXmlNS::office, "time-value");
- } else if (type == "void") {
- value = e.attributeNS(KoXmlNS::office, "value");
- } else if (e.hasAttributeNS(KoXmlNS::text, "formula")) {
- type = "formula";
- value = e.attributeNS(KoXmlNS::text, "formula");
- } else {
- warnText << "Unknown user-field-decl value-type=" << type;
- continue;
- }
- setValue(name, value, type);
- }
-}
-
-void KoVariableManager::saveOdf(KoXmlWriter *bodyWriter)
-{
- if (userVariables().isEmpty()) {
- return;
- }
- bodyWriter->startElement("text:user-field-decls");
- foreach (const QString &name, userVariables()) {
- bodyWriter->startElement("text:user-field-decl");
- bodyWriter->addAttribute("text:name", name);
- QByteArray tag;
- QString type = userType(name);
- if (type == "formula") {
- tag = "text:formula";
- } else {
- if (type == "string") {
- tag = "office:string-value";
- } else if (type == "boolean") {
- tag = "office:boolean-value";
- } else if (type == "currency") {
- tag = "office:boolean-value";
- } else if (type == "date") {
- tag = "office:date-value";
- } else if (type == "float") {
- tag = "office:value";
- } else if (type == "percentage") {
- tag = "office:value";
- } else if (type == "time") {
- tag = "office:time-value";
- } else if (type == "void") {
- tag = "office:value";
- } else {
- tag = "office:string-value";
- type = "string";
- }
- bodyWriter->addAttribute("office:value-type", type);
- }
- bodyWriter->addAttribute(tag, value(name));
- bodyWriter->endElement();
- }
- bodyWriter->endElement();
-}
diff --git a/plugins/flake/textshape/kotext/KoVariableManager.h b/plugins/flake/textshape/kotext/KoVariableManager.h
deleted file mode 100644
index 7b4de38fd0..0000000000
--- a/plugins/flake/textshape/kotext/KoVariableManager.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008, 2011 Sebastian Sauer <mail@dipe.org>
- * Copyright (C) 2011 Robert Mathias Marmorstein <robert@narnia.homeunix.com>
- *
- * 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 KOVARIABLEMANAGER_H
-#define KOVARIABLEMANAGER_H
-
-#include "kritatext_export.h"
-
-#include <QObject>
-#include <QString>
-#include <KoXmlReaderForward.h>
-
-class KoXmlWriter;
-class KoVariable;
-class KoInlineTextObjectManager;
-class KoVariableManagerPrivate;
-
-/**
- * A document can maintain a list of name-value pairs, which we call variables.
- * These initially exist solely in the variableManager as such name/value pairs
- * and can be managed by setValue(), value() and remove().
- * When the user chooses to use one of these pairs in the text-document they can create a
- * new KoNamedVariable by calling KoVariableManager::createVariable()
- * use that and insert that into the text-document.
- * Changing the value will lead to directly change the value of all variables
- * inserted into the document.
- * @see KoInlineTextObjectManager::createInsertVariableActions()
- * @see KoInlineTextObjectManager::variableManager()
- */
-class KRITATEXT_EXPORT KoVariableManager : public QObject
-{
- Q_OBJECT
-public:
- /// constructor
- explicit KoVariableManager(KoInlineTextObjectManager *inlineObjectManager);
- ~KoVariableManager() override;
-
- /**
- * Set or create a variable to the new value.
- * @param name the name of the variable.
- * @param value the new value.
- * @param type The type of the value. This is only set for user-defined variables.
- * For non user defined variables the value is empty. If set then it should be one
- * of the following values;
- * \li string
- * \li boolean
- * \li currency
- * \li date
- * \li float
- * \li percentage
- * \li time
- * \li void
- * \li formula
- */
- void setValue(const QString &name, const QString &value, const QString &type = QString());
-
- /**
- * Remove a variable from the store.
- * Variables that were created and inserted into text will no longer get updated, but will keep
- * showing the proper text.
- * @see usageCount()
- */
- void remove(const QString &name);
-
- /**
- * Return the value a named variable currently has. Or an empty string if none.
- */
- QString value(const QString &name) const;
-
- /**
- * Return the type of a user defined variable. If the variable does not exist or
- * is not a user defined variable then an empty string is returned.
- */
- QString userType(const QString &name) const;
-
- /**
- * Create a new variable that can be inserted into the document using
- * KoInlineTextObjectManager::insertInlineObject()
- * This is a factory method that creates a visible variable object of an already existing
- * name/value pair previously inserted into the manager.
- * @param name the named variable.
- * @return the new variable, or 0 when the name was not previously set on this manager
- * @see setValue()
- */
- KoVariable *createVariable(const QString &name) const;
-
- /// return a list of all variable names.
- QList<QString> variables() const;
- /// return a list of all user defined variable names.
- QList<QString> userVariables() const;
-
- /**
- * Load user defined variable declarations from the ODF body-element.
- */
- void loadOdf(const KoXmlElement &bodyElement);
-
- /**
- * Save user defined variable declarations into the ODF writer.
- */
- void saveOdf(KoXmlWriter *bodyWriter);
-
-Q_SIGNALS:
- void valueChanged();
-
-private:
- KoVariableManagerPrivate * const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/Mainpage.dox b/plugins/flake/textshape/kotext/Mainpage.dox
deleted file mode 100644
index 0d4bc2771e..0000000000
--- a/plugins/flake/textshape/kotext/Mainpage.dox
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * \mainpage
- *
- * KritaText is a library for general use that extends the QText framework
- * (codenamed scribe) with an enhanced text-layout which adds features
- * required by ODF and general word-processing applications.
- *
- * You can use KritaText at all places where you would normally use a
- * QTextDocument as the main text layout class in scribe can be replaced
- * on any QTextDocument instance using QTextDocument::setDocumentLayout().
- * This means you can use the Qt API as normal, but you will be
- * able to use extra features like the plugins, the variables and the
- * ODF loading and saving for all the ODF text-layout features.
- *
- * TextShape Flake-Plugin
- *
- * Closely coupled with the kotext library is the text plugin that is
- * build on flake technology. All the user interaction dialogs and code
- * will reside in that plugin, and the actual heavy lifting of the
- * layout also is present only in that plugin. In other words; this
- * library will supply you with the APIs but without having the text
- * shape plugin loaded you can't show or layout the text. The goal is
- * to keep it cheap to link to this library and only provide the bare
- * minimum of functionality is the way to get there. The feature-
- * package will be completed by the optional text-plugin.
- *
- * QTextDocument compatibility
- *
- * The actual content is stored in the QTextDocument, as mentioned before.
- * In KoText we support a lot more features than Qt does in its layout
- * and this library will allow you to enrich your document with those
- * features. The core design goal is that you can use an externally
- * created QTextDocument with KoText. This has the implication that all
- * the extra content is stored inside the document. We add QTextFormat
- * based properties for that as can be seen in the styles (see
- * KoParagraphStyle::Properties for instance), and we allow managers to
- * be stored on the document too. So for example a KoStyleManager will
- * be stored as a property on the QTextDocument and you can access that
- * using the KoTextDocument API. Note that you can use the
- * KoTextDocument class while using only a QTextDocument instance.
- *
- * Plugins
- *
- * There are various plugins for KoText that make it possible for 3rd
- * parties to extend the KoText functionality, see the techbase page;
- * http://techbase.kde.org/Development/Tutorials/Calligra_Overview#Text_Plugins
- *
- * ODF compatibility
- *
- * Loading and saving of documents can be done to and from ODF using the
- * open document classes.
- *
- * Important classes;
- *
- * KoTextDocumentLayout the main layout class to be set on the QTextDocument.
- *
- * KoInlineTextObject plugin base for inline objects (and variables)
- *
- * KoTextEditingPlugin plugin base for text editing plugins.
- *
- * KoText namespace.
- */
-
-// DOXYGEN_SET_PROJECT_NAME = KritaText
-// DOXYGEN_SET_IGNORE_PREFIX = Ko K
diff --git a/plugins/flake/textshape/kotext/OdfTextTrackStyles.cpp b/plugins/flake/textshape/kotext/OdfTextTrackStyles.cpp
deleted file mode 100644
index 5dac209872..0000000000
--- a/plugins/flake/textshape/kotext/OdfTextTrackStyles.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006, 2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2012-2014 C. Boemann <cbo@boemann.dk>
- *
- * 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 "OdfTextTrackStyles.h"
-#include "KoTextDocument.h"
-#include "KoParagraphStyle.h"
-#include "KoCharacterStyle.h"
-
-#include <QTextDocument>
-#include "TextDebug.h"
-
-
-QMap<QObject *, OdfTextTrackStyles *> OdfTextTrackStyles::instances;
-
-OdfTextTrackStyles *OdfTextTrackStyles::instance(KoStyleManager *manager)
-{
- if (! instances.contains(manager)) {
- instances[manager] = new OdfTextTrackStyles(manager);
- connect(manager,SIGNAL(destroyed(QObject*)),instances[manager], SLOT(styleManagerDied(QObject*)));
- }
-
- return instances[manager];
-}
-
-void OdfTextTrackStyles::registerDocument(QTextDocument *qDoc)
-{
- if (! m_documents.contains(qDoc)) {
- m_documents.append(qDoc);
- connect(qDoc,SIGNAL(destroyed(QObject*)), this, SLOT(documentDied(QObject*)));
- }
-}
-
-void OdfTextTrackStyles::unregisterDocument(QTextDocument *qDoc)
-{
- if (m_documents.contains(qDoc)) {
- m_documents.removeOne(qDoc);
- }
-}
-
-OdfTextTrackStyles::OdfTextTrackStyles(KoStyleManager *manager)
- : QObject(manager)
- , m_styleManager(manager)
- , m_changeCommand(0)
-{
- connect(manager, SIGNAL(editHasBegun()), this, SLOT(beginEdit()));
- connect(manager, SIGNAL(editHasEnded()), this, SLOT(endEdit()));
- connect(manager, SIGNAL(styleHasChanged(int,const KoCharacterStyle*,const KoCharacterStyle*)), this, SLOT(recordStyleChange(int,const KoCharacterStyle*,const KoCharacterStyle*)));
- connect(manager, SIGNAL(styleHasChanged(int,const KoParagraphStyle*,const KoParagraphStyle*)), this, SLOT(recordStyleChange(int,const KoParagraphStyle*,const KoParagraphStyle*)));
-}
-
-OdfTextTrackStyles::~OdfTextTrackStyles()
-{
- delete m_changeCommand;
-}
-
-void OdfTextTrackStyles::beginEdit()
-{
- Q_ASSERT(m_changeCommand == 0);
- m_changeCommand = new ChangeStylesMacroCommand(m_documents, m_styleManager.data());
-}
-
-void OdfTextTrackStyles::endEdit()
-{
- if (m_documents.length() > 0) {
- KUndo2Stack *undoStack= KoTextDocument(m_documents.first()).undoStack();
- if (undoStack) {
- undoStack->push(m_changeCommand);
- }
- } else
- delete m_changeCommand;
-
- m_changeCommand = 0;
-}
-
-void OdfTextTrackStyles::recordStyleChange(int id, const KoParagraphStyle *origStyle, const KoParagraphStyle *newStyle)
-{
- m_changeCommand->changedStyle(id);
-
- if (origStyle != newStyle) {
- m_changeCommand->origStyle(origStyle->clone());
- m_changeCommand->changedStyle(newStyle->clone());
- }
-}
-
-void OdfTextTrackStyles::recordStyleChange(int id, const KoCharacterStyle *origStyle, const KoCharacterStyle *newStyle)
-{
- m_changeCommand->changedStyle(id);
-
- if (origStyle != newStyle) {
- m_changeCommand->origStyle(origStyle->clone());
- m_changeCommand->changedStyle(newStyle->clone());
- }
-}
-
-void OdfTextTrackStyles::styleManagerDied(QObject *manager)
-{
- OdfTextTrackStyles::instances.remove(manager);
-}
-
-void OdfTextTrackStyles::documentDied(QObject *document)
-{
- unregisterDocument(static_cast<QTextDocument *>(document));
-}
diff --git a/plugins/flake/textshape/kotext/OdfTextTrackStyles.h b/plugins/flake/textshape/kotext/OdfTextTrackStyles.h
deleted file mode 100644
index 82cc4a06ed..0000000000
--- a/plugins/flake/textshape/kotext/OdfTextTrackStyles.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006 Thomas Zander <zander@kde.org>
- * Copyright (C) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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 CHANGEFOLLOWER_H
-#define CHANGEFOLLOWER_H
-
-#include "commands/ChangeStylesMacroCommand.h"
-
-#include <KoStyleManager.h>
-
-#include <QObject>
-#include <QWeakPointer>
-#include <QSet>
-#include <QTextDocument>
-
-/**
- * OdfTextTrackStyles is used to update a list of qtextdocument with
- * any changes made in the style manager.
- *
- * It also creates undo commands and adds them to the undo stack
- *
- * Style changes affect a lot of qtextdocuments and we store the changes and apply
- * the changes to every qtextdocument, so every KoTextDocument has to
- * register their QTextDocument to us.
- *
- * We use the QObject principle of children getting deleted when the
- * parent gets deleted. Thus we die when the KoStyleManager dies.
- */
-class OdfTextTrackStyles : public QObject
-{
-
- Q_OBJECT
-
-public:
- static OdfTextTrackStyles *instance(KoStyleManager *manager);
-
-private:
- static QMap<QObject *, OdfTextTrackStyles *> instances;
-
- OdfTextTrackStyles(KoStyleManager *manager);
-
- /// Destructor, called when the parent is deleted.
- ~OdfTextTrackStyles() override;
-
-private Q_SLOTS:
- void beginEdit();
- void endEdit();
- void recordStyleChange(int id, const KoParagraphStyle *origStyle, const KoParagraphStyle *newStyle);
- void recordStyleChange(int id, const KoCharacterStyle *origStyle, const KoCharacterStyle *newStyle);
- void styleManagerDied(QObject *manager);
- void documentDied(QObject *manager);
-
-public:
- void registerDocument(QTextDocument *qDoc);
- void unregisterDocument(QTextDocument *qDoc);
-
-private:
- QList<QTextDocument *> m_documents;
- QWeakPointer<KoStyleManager> m_styleManager;
- ChangeStylesMacroCommand *m_changeCommand;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/TextDebug.cpp b/plugins/flake/textshape/kotext/TextDebug.cpp
deleted file mode 100644
index 0bb3587900..0000000000
--- a/plugins/flake/textshape/kotext/TextDebug.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2015 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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 "TextDebug.h"
-
-const QLoggingCategory &TEXT_LOG() \
-{
- static const QLoggingCategory category("krita.lib.text", QtInfoMsg);
- return category;
-}
-
-
diff --git a/plugins/flake/textshape/kotext/TextDebug.h b/plugins/flake/textshape/kotext/TextDebug.h
deleted file mode 100644
index 57bd3d8394..0000000000
--- a/plugins/flake/textshape/kotext/TextDebug.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2015 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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 TEXT_DEBUG_H_
-#define TEXT_DEBUG_H_
-
-#include <QDebug>
-#include <QLoggingCategory>
-#include <kritatext_export.h>
-
-extern const KRITATEXT_EXPORT QLoggingCategory &TEXT_LOG();
-
-#define debugText qCDebug(TEXT_LOG)
-#define warnText qCWarning(TEXT_LOG)
-#define errorText qCCritical(TEXT_LOG)
-
-#endif
diff --git a/plugins/flake/textshape/kotext/ToCBibGeneratorInfo.cpp b/plugins/flake/textshape/kotext/ToCBibGeneratorInfo.cpp
deleted file mode 100644
index 9e7da167e6..0000000000
--- a/plugins/flake/textshape/kotext/ToCBibGeneratorInfo.cpp
+++ /dev/null
@@ -1,339 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Smit Patel <smitpatel24@gmail.com>
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 "ToCBibGeneratorInfo.h"
-
-#include <KoXmlWriter.h>
-#include <KoUnit.h>
-
-IndexEntry::IndexEntry(const QString &_styleName, IndexEntry::IndexEntryName _name)
- : styleName(_styleName),
- name(_name)
-{
-
-}
-
-IndexEntry *IndexEntry::clone()
-{
- IndexEntry *newIndexEntry = new IndexEntry(styleName, name);
- return newIndexEntry;
-}
-
-IndexEntry::~IndexEntry()
-{
-
-}
-
-
-void IndexEntry::addAttributes(KoXmlWriter* writer) const
-{
- Q_UNUSED(writer);
-}
-
-void IndexEntry::saveOdf(KoXmlWriter* writer) const
-{
- switch (name) {
- case LINK_START:
- writer->startElement("text:index-entry-link-start");
- break;
- case CHAPTER:
- writer->startElement("text:index-entry-chapter");
- break;
- case BIBLIOGRAPHY:
- writer->startElement("text:index-entry-bibliography");
- break;
- case SPAN:
- writer->startElement("text:index-entry-span");
- break;
- case TEXT:
- writer->startElement("text:index-entry-text");
- break;
- case TAB_STOP:
- writer->startElement("text:index-entry-tab-stop");
- break;
- case PAGE_NUMBER:
- writer->startElement("text:index-entry-page-number");
- break;
- case LINK_END:
- writer->startElement("text:index-entry-link-end");
- break;
- case UNKNOWN:
- break;
- }
-
- if (!styleName.isNull()) {
- writer->addAttribute("text:style-name", styleName);
- }
-
- addAttributes(writer);
- writer->endElement();
-}
-
-IndexEntryBibliography::IndexEntryBibliography(const QString &_styleName)
- : IndexEntry(_styleName, IndexEntry::BIBLIOGRAPHY)
- , dataField(QString())
-{
-
-}
-
-IndexEntry *IndexEntryBibliography::clone()
-{
- IndexEntryBibliography *newIndexEntry = new IndexEntryBibliography(styleName);
- newIndexEntry->dataField = dataField;
- return newIndexEntry;
-}
-
-void IndexEntryBibliography::addAttributes(KoXmlWriter* writer) const
-{
- if (!dataField.isNull()) {
- writer->addAttribute("text:bibliography-data-field", dataField);
- }
-}
-
-
-IndexEntrySpan::IndexEntrySpan(const QString &_styleName): IndexEntry(_styleName, IndexEntry::SPAN)
-{
-}
-
-IndexEntry *IndexEntrySpan::clone()
-{
- IndexEntrySpan *newIndexEntry = new IndexEntrySpan(styleName);
- newIndexEntry->text = text;
- return newIndexEntry;
-}
-
-void IndexEntrySpan::addAttributes(KoXmlWriter* writer) const
-{
- if (!text.isNull() && !text.isEmpty()) {
- writer->addTextNode(text);
- }
-}
-
-IndexEntryTabStop::IndexEntryTabStop(const QString &_styleName): IndexEntry(_styleName, IndexEntry::TAB_STOP)
-{
-
-}
-
-IndexEntry *IndexEntryTabStop::clone()
-{
- IndexEntryTabStop *newIndexEntry = new IndexEntryTabStop(styleName);
- newIndexEntry->tab = tab;
- newIndexEntry->m_position = m_position;
- return newIndexEntry;
-}
-
-void IndexEntryTabStop::addAttributes(KoXmlWriter* writer) const
-{
- writer->addAttribute("style:leader-char",tab.leaderText);
- // If the value of this attribute is left, the style:position attribute shall also be present.
- // Otherwise, this attribute shall be omitted.
- if (tab.type == QTextOption::LeftTab) {
- writer->addAttribute("style:type", "left");
- writer->addAttribute("style:position", m_position);
- } else {
- Q_ASSERT(tab.type == QTextOption::RightTab);
- writer->addAttribute("style:type", "right");
- }
-}
-
-
-void IndexEntryTabStop::setPosition(const QString& position)
-{
- m_position = position;
- tab.position = KoUnit::parseValue(position);
-}
-
-void BibliographyEntryTemplate::saveOdf(KoXmlWriter* writer) const
-{
- writer->startElement("text:bibliography-entry-template");
- writer->addAttribute("text:style-name", styleName);
- writer->addAttribute("text:bibliography-type", bibliographyType);
- Q_FOREACH (IndexEntry* e,indexEntries) {
- e->saveOdf(writer);
- }
-
- writer->endElement();
-}
-
-void IndexTitleTemplate::saveOdf(KoXmlWriter* writer) const
-{
- writer->startElement("text:index-title-template");
- writer->addAttribute("text:style-name", styleName);
- if (!text.isEmpty() && !text.isNull()) {
- writer->addTextNode(text);
- }
- writer->endElement();
-}
-
-IndexSourceStyle::IndexSourceStyle()
-{
-}
-
-IndexSourceStyle::IndexSourceStyle(const IndexSourceStyle& indexSourceStyle)
-{
- styleName = indexSourceStyle.styleName;
- styleId = indexSourceStyle.styleId;
-}
-
-void IndexSourceStyle::saveOdf(KoXmlWriter* writer) const
-{
- writer->startElement("text:index-source-style");
- if (!styleName.isNull()) {
- writer->addAttribute("text:style-name",styleName);
- }
- writer->endElement();
-}
-
-IndexSourceStyles::IndexSourceStyles()
-{
-}
-
-IndexSourceStyles::IndexSourceStyles(const IndexSourceStyles &indexSourceStyles)
-{
- outlineLevel = indexSourceStyles.outlineLevel;
-
- foreach (const IndexSourceStyle &style, indexSourceStyles.styles) {
- styles.append(style);
- }
-}
-
-void IndexSourceStyles::saveOdf(KoXmlWriter* writer) const
-{
- writer->startElement("text:index-source-styles");
- writer->addAttribute("text:outline-level", outlineLevel);
- Q_FOREACH (const IndexSourceStyle &s, styles) {
- s.saveOdf(writer);
- }
- writer->endElement();
-}
-
-IndexEntryPageNumber::IndexEntryPageNumber(const QString &_styleName): IndexEntry(_styleName, IndexEntry::PAGE_NUMBER)
-{
-
-}
-
-IndexEntry *IndexEntryPageNumber::clone()
-{
- IndexEntryPageNumber *newIndexEntry = new IndexEntryPageNumber(styleName);
- return newIndexEntry;
-}
-
-IndexEntryLinkEnd::IndexEntryLinkEnd(const QString &_styleName): IndexEntry(_styleName, IndexEntry::LINK_END)
-{
-
-}
-
-IndexEntry *IndexEntryLinkEnd::clone()
-{
- IndexEntryLinkEnd *newIndexEntry = new IndexEntryLinkEnd(styleName);
- return newIndexEntry;
-}
-
-TocEntryTemplate::TocEntryTemplate()
-{
-}
-
-TocEntryTemplate::TocEntryTemplate(const TocEntryTemplate &entryTemplate)
-{
- outlineLevel = entryTemplate.outlineLevel;
- styleName = entryTemplate.styleName;
- styleId = entryTemplate.styleId;
-
- foreach (IndexEntry *entry, entryTemplate.indexEntries) {
- indexEntries.append(entry->clone());
- }
-}
-
-void TocEntryTemplate::saveOdf(KoXmlWriter* writer) const
-{
- writer->startElement("text:table-of-content-entry-template");
- writer->addAttribute("text:outline-level", outlineLevel);
- writer->addAttribute("text:style-name", styleName);
-
- Q_FOREACH (IndexEntry* e,indexEntries) {
- e->saveOdf(writer);
- }
-
- writer->endElement();
-}
-
-IndexEntryText::IndexEntryText(const QString &_styleName): IndexEntry(_styleName,IndexEntry::TEXT)
-{
-
-}
-
-IndexEntry *IndexEntryText::clone()
-{
- IndexEntryText *newIndexEntry = new IndexEntryText(styleName);
- return newIndexEntry;
-}
-
-IndexEntryLinkStart::IndexEntryLinkStart(const QString &_styleName)
- : IndexEntry(_styleName, IndexEntry::LINK_START)
-{
-
-}
-
-IndexEntry *IndexEntryLinkStart::clone()
-{
- return new IndexEntryLinkStart(styleName);
-}
-
-
-IndexEntryChapter::IndexEntryChapter(const QString &_styleName)
- : IndexEntry(_styleName, IndexEntry::CHAPTER)
- , display(QString())
- , outlineLevel(INVALID_OUTLINE_LEVEL)
-{
-
-}
-
-IndexEntry *IndexEntryChapter::clone()
-{
- IndexEntryChapter *newIndexEntry = new IndexEntryChapter(styleName);
- newIndexEntry->outlineLevel = outlineLevel;
- newIndexEntry->display = display;
- return newIndexEntry;
-}
-
-void IndexEntryChapter::addAttributes(KoXmlWriter* writer) const
-{
- if (!display.isNull()) {
- writer->addAttribute("text:display", display);
- }
- writer->addAttribute("text:outline-level", outlineLevel);
-}
-
-BibliographyEntryTemplate::BibliographyEntryTemplate()
-{
-}
-
-BibliographyEntryTemplate::BibliographyEntryTemplate(const BibliographyEntryTemplate &entryTemplate)
-{
- styleName = entryTemplate.styleName;
- styleId = entryTemplate.styleId;
-
- foreach (IndexEntry *entry, entryTemplate.indexEntries) {
- indexEntries.append(entry->clone());
- }
-
- bibliographyType = entryTemplate.bibliographyType;
-}
-
diff --git a/plugins/flake/textshape/kotext/ToCBibGeneratorInfo.h b/plugins/flake/textshape/kotext/ToCBibGeneratorInfo.h
deleted file mode 100644
index 8fea2cd403..0000000000
--- a/plugins/flake/textshape/kotext/ToCBibGeneratorInfo.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Smit Patel <smitpatel24@gmail.com>
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 TOCBIBGENERATORINFO_H
-#define TOCBIBGENERATORINFO_H
-
-#include <KoText.h>
-
-const int INVALID_OUTLINE_LEVEL = 0;
-
-class KoXmlWriter;
-
-class KRITATEXT_EXPORT IndexEntry
-{
-public:
- enum IndexEntryName {UNKNOWN, LINK_START, CHAPTER, SPAN, TEXT, TAB_STOP, PAGE_NUMBER, LINK_END, BIBLIOGRAPHY};
-
- explicit IndexEntry(const QString &_styleName, IndexEntryName _name = IndexEntry::UNKNOWN);
- virtual IndexEntry *clone();
- virtual ~IndexEntry();
- virtual void addAttributes(KoXmlWriter * writer) const;
- void saveOdf(KoXmlWriter * writer) const;
-
- QString styleName;
- IndexEntryName name;
-};
-
-
-class IndexEntryLinkStart : public IndexEntry
-{
-public:
- explicit IndexEntryLinkStart(const QString &_styleName);
- IndexEntry *clone() override;
-};
-
-
-class IndexEntryChapter : public IndexEntry
-{
-public:
- explicit IndexEntryChapter(const QString &_styleName);
- IndexEntry *clone() override;
- void addAttributes(KoXmlWriter* writer) const override;
-
- QString display;
- int outlineLevel;
-};
-
-
-class KRITATEXT_EXPORT IndexEntrySpan : public IndexEntry
-{
-public:
- explicit IndexEntrySpan(const QString &_styleName);
- IndexEntry *clone() override;
- void addAttributes(KoXmlWriter* writer) const override;
-
- QString text;
-};
-
-
-class IndexEntryText : public IndexEntry
-{
-public:
- explicit IndexEntryText(const QString &_styleName);
- IndexEntry *clone() override;
-};
-
-
-class KRITATEXT_EXPORT IndexEntryTabStop : public IndexEntry
-{
-public:
- explicit IndexEntryTabStop(const QString &_styleName);
- IndexEntry *clone() override;
- void addAttributes(KoXmlWriter* writer) const override;
- // for saving let's save the original unit,
- // for KoText::Tab we need to convert to PostScript points
- void setPosition(const QString &position);
-
- KoText::Tab tab;
- QString m_position;
-};
-
-
-class IndexEntryPageNumber : public IndexEntry
-{
-public:
- explicit IndexEntryPageNumber(const QString &_styleName);
- IndexEntry *clone() override;
-};
-
-
-class IndexEntryLinkEnd : public IndexEntry
-{
-public:
- explicit IndexEntryLinkEnd(const QString &_styleName);
- IndexEntry *clone() override;
-};
-
-class KRITATEXT_EXPORT TocEntryTemplate
-{
-public:
- TocEntryTemplate();
- TocEntryTemplate(const TocEntryTemplate &other);
- void saveOdf(KoXmlWriter * writer) const;
-
- int outlineLevel;
- QString styleName;
- int styleId;
- QList<IndexEntry*> indexEntries;
-};
-
-
-class KRITATEXT_EXPORT IndexTitleTemplate
-{
-public:
- void saveOdf(KoXmlWriter * writer) const;
-
- QString styleName;
- int styleId;
- QString text;
-};
-
-
-class KRITATEXT_EXPORT IndexSourceStyle
-{
-public:
- IndexSourceStyle(const IndexSourceStyle& indexSourceStyle);
- IndexSourceStyle();
- void saveOdf(KoXmlWriter * writer) const;
-
- QString styleName;
- int styleId;
-};
-
-
-class KRITATEXT_EXPORT IndexSourceStyles
-{
-public:
- IndexSourceStyles();
- IndexSourceStyles(const IndexSourceStyles &indexSourceStyles);
- void saveOdf(KoXmlWriter * writer) const;
-
- int outlineLevel;
- QList<IndexSourceStyle> styles;
-};
-
-class KRITATEXT_EXPORT IndexEntryBibliography : public IndexEntry
-{
-public:
- explicit IndexEntryBibliography(const QString &_styleName);
- IndexEntry *clone() override;
- void addAttributes(KoXmlWriter* writer) const override;
-
- QString dataField;
-};
-
-class KRITATEXT_EXPORT BibliographyEntryTemplate
-{
-public:
- BibliographyEntryTemplate();
- BibliographyEntryTemplate(const BibliographyEntryTemplate &other);
- void saveOdf(KoXmlWriter * writer) const;
-
- QString styleName;
- int styleId;
- QList<IndexEntry*> indexEntries;
- QString bibliographyType;
-};
-
-Q_DECLARE_METATYPE(IndexEntry::IndexEntryName)
-#endif // TOCBIBGENERATORINFO_H
diff --git a/plugins/flake/textshape/kotext/changetracker/KoChangeTracker.cpp b/plugins/flake/textshape/kotext/changetracker/KoChangeTracker.cpp
deleted file mode 100644
index 9b527937a1..0000000000
--- a/plugins/flake/textshape/kotext/changetracker/KoChangeTracker.cpp
+++ /dev/null
@@ -1,668 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Pierre Stirnweiss \pierre.stirnweiss_calligra@gadz.org>
- * Copyright (C) 2011 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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 "KoChangeTracker.h"
-
-//Calligra includes
-#include "styles/KoCharacterStyle.h"
-#include "KoChangeTrackerElement.h"
-#include <KoXmlReader.h>
-#include <KoXmlNS.h>
-#include <KoInlineTextObjectManager.h>
-#include <KoTextDocument.h>
-#include <KoList.h>
-#include <KoListStyle.h>
-#include <KoParagraphStyle.h>
-#include <KoGenChanges.h>
-#include "KoFormatChangeInformation.h"
-#include <kundo2magicstring.h>
-
-//KDE includes
-#include "TextDebug.h"
-#include <klocalizedstring.h>
-
-//Qt includes
-#include <QColor>
-#include <QList>
-#include <QString>
-#include <QHash>
-#include <QMultiHash>
-#include <QTextCursor>
-#include <QTextFormat>
-#include <QTextDocument>
-#include <QTextDocumentFragment>
-#include <QTextList>
-#include <QTextTable>
-#include <QDateTime>
-#include <QLocale>
-
-class Q_DECL_HIDDEN KoChangeTracker::Private
-{
-public:
- Private()
- : changeId(1),
- recordChanges(false),
- displayChanges(false),
- insertionBgColor(101,255,137),
- deletionBgColor(255,185,185),
- formatChangeBgColor(195,195,255),
- changeSaveFormat(UNKNOWN)
-
- {
- }
- ~Private() { }
-
- QMultiHash<int, int> children;
- QMultiHash<int, int> duplicateIds;
- QHash<int, int> parents;
- QHash<int, KoChangeTrackerElement *> changes;
- QHash<QString, int> loadedChanges;
- QHash<int, KoFormatChangeInformation *> changeInformation;
- QList<int> saveChanges;
- QList<int> acceptedRejectedChanges;
- int changeId;
- bool recordChanges;
- bool displayChanges;
- QColor insertionBgColor, deletionBgColor, formatChangeBgColor;
- QString changeAuthorName;
- KoChangeTracker::ChangeSaveFormat changeSaveFormat;
-};
-
-KoChangeTracker::KoChangeTracker(QObject *parent)
- : QObject(parent),
- d(new Private())
-{
- d->changeId = 1;
-}
-
-KoChangeTracker::~KoChangeTracker()
-{
- delete d;
-}
-
-void KoChangeTracker::setRecordChanges(bool enabled)
-{
- d->recordChanges = enabled;
-}
-
-bool KoChangeTracker::recordChanges() const
-{
- return d->recordChanges;
-}
-
-void KoChangeTracker::setDisplayChanges(bool enabled)
-{
- d->displayChanges = enabled;
-}
-
-bool KoChangeTracker::displayChanges() const
-{
- return d->displayChanges;
-}
-
-QString KoChangeTracker::authorName() const
-{
- return d->changeAuthorName;
-}
-
-void KoChangeTracker::setAuthorName(const QString &authorName)
-{
- d->changeAuthorName = authorName;
-}
-
-KoChangeTracker::ChangeSaveFormat KoChangeTracker::saveFormat() const
-{
- return d->changeSaveFormat;
-}
-
-void KoChangeTracker::setSaveFormat(ChangeSaveFormat saveFormat)
-{
- d->changeSaveFormat = saveFormat;
-}
-
-int KoChangeTracker::getFormatChangeId(const KUndo2MagicString &title, const QTextFormat &format, const QTextFormat &prevFormat, int existingChangeId)
-{
- if ( existingChangeId ) {
- d->children.insert(existingChangeId, d->changeId);
- d->parents.insert(d->changeId, existingChangeId);
- }
-
- KoChangeTrackerElement *changeElement = new KoChangeTrackerElement(title, KoGenChange::FormatChange);
- changeElement->setChangeFormat(format);
- changeElement->setPrevFormat(prevFormat);
-
- QLocale l;
- changeElement->setDate(l.toString(QDateTime::currentDateTime()).replace(QLocale().decimalPoint(), QString(".")));
-
- changeElement->setCreator(d->changeAuthorName);
-
- changeElement->setEnabled(d->recordChanges);
-
- d->changes.insert(d->changeId, changeElement);
-
- return d->changeId++;
-}
-
-int KoChangeTracker::getInsertChangeId(const KUndo2MagicString &title, int existingChangeId)
-{
- if ( existingChangeId ) {
- d->children.insert(existingChangeId, d->changeId);
- d->parents.insert(d->changeId, existingChangeId);
- }
-
- KoChangeTrackerElement *changeElement = new KoChangeTrackerElement(title, KoGenChange::InsertChange);
-
- QLocale l;
- changeElement->setDate(l.toString(QDateTime::currentDateTime()).replace(QLocale().decimalPoint(), QString(".")));
-
- changeElement->setCreator(d->changeAuthorName);
-
- changeElement->setEnabled(d->recordChanges);
-
- d->changes.insert(d->changeId, changeElement);
-
- return d->changeId++;
-}
-
-int KoChangeTracker::getDeleteChangeId(const KUndo2MagicString &title, const QTextDocumentFragment &selection, int existingChangeId)
-{
- if ( existingChangeId ) {
- d->children.insert(existingChangeId, d->changeId);
- d->parents.insert(d->changeId, existingChangeId);
- }
-
- KoChangeTrackerElement *changeElement = new KoChangeTrackerElement(title, KoGenChange::DeleteChange);
-
- QLocale l;
- changeElement->setDate(l.toString(QDateTime::currentDateTime()).replace(QLocale().decimalPoint(), QString(".")));
-
- changeElement->setCreator(d->changeAuthorName);
- changeElement->setDeleteData(selection);
-
- changeElement->setEnabled(d->recordChanges);
-
- d->changes.insert(d->changeId, changeElement);
-
- return d->changeId++;
-}
-
-KoChangeTrackerElement* KoChangeTracker::elementById(int id) const
-{
- if (isDuplicateChangeId(id)) {
- id = originalChangeId(id);
- }
- return d->changes.value(id);
-}
-
-bool KoChangeTracker::removeById(int id, bool freeMemory)
-{
- if (freeMemory) {
- KoChangeTrackerElement *temp = d->changes.value(id);
- delete temp;
- }
- return d->changes.remove(id);
-}
-
-bool KoChangeTracker::containsInlineChanges(const QTextFormat &format) const
-{
- if (format.property(KoCharacterStyle::ChangeTrackerId).toInt())
- return true;
-
- return false;
-}
-
-int KoChangeTracker::mergeableId(KoGenChange::Type type, const KUndo2MagicString &title, int existingId) const
-{
- if (!existingId || !d->changes.value(existingId))
- return 0;
-
- if (d->changes.value(existingId)->getChangeType() == type && d->changes.value(existingId)->getChangeTitle() == title) {
- return existingId;
- }
- else {
- if (d->parents.contains(existingId)) {
- return mergeableId(type, title, d->parents.value(existingId));
- }
- else {
- return 0;
- }
- }
-}
-
-int KoChangeTracker::split(int changeId)
-{
- KoChangeTrackerElement *element = new KoChangeTrackerElement(*d->changes.value(changeId));
- d->changes.insert(d->changeId, element);
- return d->changeId++;
-}
-
-bool KoChangeTracker::isParent(int testedParentId, int testedChildId) const
-{
- if ((testedParentId == testedChildId) && !d->acceptedRejectedChanges.contains(testedParentId))
- return true;
- else if (d->parents.contains(testedChildId))
- return isParent(testedParentId, d->parents.value(testedChildId));
- else
- return false;
-}
-
-void KoChangeTracker::setParent(int child, int parent)
-{
- if (!d->children.values(parent).contains(child)) {
- d->children.insert(parent, child);
- }
- if (!d->parents.contains(child)) {
- d->parents.insert(child, parent);
- }
-}
-
-int KoChangeTracker::parent(int changeId) const
-{
- if (!d->parents.contains(changeId))
- return 0;
- if (d->acceptedRejectedChanges.contains(d->parents.value(changeId)))
- return parent(d->parents.value(changeId));
- return d->parents.value(changeId);
-}
-
-int KoChangeTracker::createDuplicateChangeId(int existingChangeId)
-{
- int duplicateChangeId = d->changeId;
- d->changeId++;
-
- d->duplicateIds.insert(existingChangeId, duplicateChangeId);
-
- return duplicateChangeId;
-}
-
-bool KoChangeTracker::isDuplicateChangeId(int duplicateChangeId) const
-{
- return d->duplicateIds.values().contains(duplicateChangeId);
-}
-
-int KoChangeTracker::originalChangeId(int duplicateChangeId) const
-{
- int originalChangeId = 0;
- QMultiHash<int, int>::const_iterator i = d->duplicateIds.constBegin();
-
- while (i != d->duplicateIds.constEnd()) {
- if (duplicateChangeId == i.value()) {
- originalChangeId = i.key();
- break;
- }
- ++i;
- }
-
- return originalChangeId;
-}
-
-void KoChangeTracker::acceptRejectChange(int changeId, bool set)
-{
- if (set) {
- if (!d->acceptedRejectedChanges.contains(changeId))
- d->acceptedRejectedChanges.append(changeId);
- }
- else {
- if (d->acceptedRejectedChanges.contains(changeId))
- d->acceptedRejectedChanges.removeAll(changeId);
- }
-
- d->changes.value(changeId)->setAcceptedRejected(set);
-}
-
-bool KoChangeTracker::saveInlineChange(int changeId, KoGenChange &change)
-{
- if (!d->changes.contains(changeId))
- return false;
-
- change.setType(d->changes.value(changeId)->getChangeType());
- change.addChangeMetaData("dc-creator", d->changes.value(changeId)->getCreator());
- change.addChangeMetaData("dc-date", d->changes.value(changeId)->getDate());
- if (d->changes.value(changeId)->hasExtraMetaData())
- change.addChildElement("changeMetaData", d->changes.value(changeId)->getExtraMetaData());
-
- return true;
-}
-
-QMap<int, QString> KoChangeTracker::saveInlineChanges(QMap<int, QString> changeTransTable, KoGenChanges &genChanges)
-{
- foreach (int changeId, d->changes.keys()) {
-
- // return if the id we find in the changetranstable already has a length.
- if (changeTransTable.value(changeId).length()) {
- continue;
- }
-
- if ((elementById(changeId)->getChangeType() == KoGenChange::DeleteChange) &&
- (saveFormat() == KoChangeTracker::ODF_1_2)) {
- continue;
- }
-
- KoGenChange change;
- if (saveFormat() == KoChangeTracker::ODF_1_2) {
- change.setChangeFormat(KoGenChange::ODF_1_2);
- } else {
- change.setChangeFormat(KoGenChange::DELTAXML);
- }
-
- saveInlineChange(changeId, change);
- QString changeName = genChanges.insert(change);
- changeTransTable.insert(changeId, changeName);
- }
- return changeTransTable;
-}
-
-void KoChangeTracker::setFormatChangeInformation(int formatChangeId, KoFormatChangeInformation *formatInformation)
-{
- d->changeInformation.insert(formatChangeId, formatInformation);
-}
-
-KoFormatChangeInformation *KoChangeTracker::formatChangeInformation(int formatChangeId) const
-{
- return d->changeInformation.value(formatChangeId);
-}
-
-void KoChangeTracker::loadOdfChanges(const KoXmlElement& )
-{
-}
-
-int KoChangeTracker::getLoadedChangeId(const QString &odfId) const
-{
- return d->loadedChanges.value(odfId);
-}
-
-int KoChangeTracker::getDeletedChanges(QVector<KoChangeTrackerElement *>& deleteVector) const
-{
- int numAppendedItems = 0;
- foreach (KoChangeTrackerElement *element, d->changes.values()) {
- if(element->getChangeType() == KoGenChange::DeleteChange && !element->acceptedRejected()) {
- deleteVector << element;
- numAppendedItems++;
- }
- }
-
- return numAppendedItems;
-}
-
-QColor KoChangeTracker::getInsertionBgColor() const
-{
- return d->insertionBgColor;
-}
-
-QColor KoChangeTracker::getDeletionBgColor() const
-{
- return d->deletionBgColor;
-}
-
-QColor KoChangeTracker::getFormatChangeBgColor() const
-{
- return d->formatChangeBgColor;
-}
-
-void KoChangeTracker::setInsertionBgColor(const QColor& bgColor)
-{
- d->insertionBgColor = bgColor;
-}
-
-void KoChangeTracker::setDeletionBgColor(const QColor& bgColor)
-{
- d->deletionBgColor = bgColor;
-}
-
-void KoChangeTracker::setFormatChangeBgColor(const QColor& bgColor)
-{
- d->formatChangeBgColor = bgColor;
-}
-
-////A convenience function to get a ListIdType from a format
-//static KoListStyle::ListIdType ListId(const QTextListFormat &format)
-//{
-// KoListStyle::ListIdType listId;
-
-// if (sizeof(KoListStyle::ListIdType) == sizeof(uint)) {
-// listId = format.property(KoListStyle::ListId).toUInt();
-// }
-// else {
-// listId = format.property(KoListStyle::ListId).toULongLong();
-// }
-
-// return listId;
-//}
-
-QTextDocumentFragment KoChangeTracker::generateDeleteFragment(const QTextCursor &cursor)
-{
- QTextCursor editCursor(cursor);
- QTextDocument *document = cursor.document();
-
- QTextDocument deletedDocument;
- QTextDocument deleteCursor(&deletedDocument);
-
- KoInlineTextObjectManager *textObjectManager = KoTextDocument(document).inlineTextObjectManager();
- if (textObjectManager) {
- for (int i = cursor.anchor();i <= cursor.position(); i++) {
- if (document->characterAt(i) == QChar::ObjectReplacementCharacter) {
- editCursor.setPosition(i+1);
- }
- }
- }
-
- QTextBlock currentBlock = document->findBlock(cursor.anchor());
- QTextBlock startBlock = currentBlock;
- QTextBlock endBlock = document->findBlock(cursor.position()).next();
-
- currentBlock = document->findBlock(cursor.anchor());
- startBlock = currentBlock;
- endBlock = document->findBlock(cursor.position()).next();
-
- for (;currentBlock != endBlock; currentBlock = currentBlock.next()) {
- editCursor.setPosition(currentBlock.position());
- if (editCursor.currentTable()) {
- QTextTableFormat tableFormat = editCursor.currentTable()->format();
- editCursor.currentTable()->setFormat(tableFormat);
- }
-
- if (currentBlock != startBlock) {
- QTextBlockFormat blockFormat;
- editCursor.mergeBlockFormat(blockFormat);
- }
- }
-
- return cursor.selection();
-}
-
-bool KoChangeTracker::checkListDeletion(const QTextList &list, const QTextCursor &cursor)
-{
- int startOfList = (list.item(0).position() - 1);
- int endOfList = list.item(list.count() -1).position() + list.item(list.count() -1).length() - 1;
- if ((cursor.anchor() <= startOfList) && (cursor.position() >= endOfList))
- return true;
- else {
- /***************************************************************************************************/
- /* Qt Quirk Work-Around */
- /***************************************************************************************************/
- if ((cursor.anchor() == (startOfList + 1)) && (cursor.position() > endOfList)) {
- return true;
- /***************************************************************************************************/
- } else if((cursor.anchor() <= startOfList) && (list.count() == 1)) {
- return true;
- } else {
- return false;
- }
- }
-}
-
-void KoChangeTracker::insertDeleteFragment(QTextCursor &cursor)
-{
- QTextDocument tempDoc;
- QTextCursor tempCursor(&tempDoc);
-
- bool deletedListItem = false;
-
- for (QTextBlock currentBlock = tempDoc.begin(); currentBlock != tempDoc.end(); currentBlock = currentBlock.next()) {
- //This condition is for the work-around for a Qt behaviour
- //Even if a delete ends at the end of a table, the fragment will have an empty block after the table
- //If such a block is detected then, just ignore it
- if ((currentBlock.next() == tempDoc.end()) && (currentBlock.text().length() == 0) && (QTextCursor(currentBlock.previous()).currentTable())) {
- continue;
- }
-
- tempCursor.setPosition(currentBlock.position());
- QTextList *textList = tempCursor.currentList();
- int outlineLevel = currentBlock.blockFormat().property(KoParagraphStyle::OutlineLevel).toInt();
-
- KoList *currentList = KoTextDocument(cursor.document()).list(cursor.block());
- int docOutlineLevel = cursor.block().blockFormat().property(KoParagraphStyle::OutlineLevel).toInt();
- if (docOutlineLevel) {
- //Even though we got a list, it is actually a list for storing headings. So don't consider it
- currentList = 0;
- }
-
- QTextList *previousTextList = currentBlock.previous().isValid() ? QTextCursor(currentBlock.previous()).currentList():0;
- if (textList && previousTextList && (textList != previousTextList) && (KoList::level(currentBlock) == KoList::level(currentBlock.previous()))) {
- //Even though we are already in a list, the QTextList* of the current block is different from that of the previous block
- //Also the levels of the list-items ( previous and current ) are the same.
- //This can happen only when two lists are merged together without any intermediate content.
- //So we need to create a new list.
- currentList = 0;
- }
-
- if (textList) {
- if (deletedListItem && currentBlock != tempDoc.begin()) {
- // Found a deleted list item in the fragment. So insert a new list-item
- int deletedListItemLevel = KoList::level(currentBlock);
-
- if (!(QTextCursor(currentBlock.previous()).currentTable())) {
- cursor.insertBlock(currentBlock.blockFormat(), currentBlock.charFormat());
- } else {
- cursor.mergeBlockFormat(currentBlock.blockFormat());
- }
-
- if(!currentList) {
- if (!outlineLevel) {
- //This happens when a part of a paragraph and a succeeding list-item are deleted together
- //So go to the next block and insert it in the list there.
- QTextCursor tmp(cursor);
- tmp.setPosition(tmp.block().next().position());
- currentList = KoTextDocument(tmp.document()).list(tmp.block());
- } else {
- // This is a heading. So find the KoList for heading and add the block there
- KoList *headingList = KoTextDocument(cursor.document()).headingList();
- currentList = headingList;
- }
- }
- currentList->add(cursor.block(), deletedListItemLevel);
- }
- } else if (tempCursor.currentTable()) {
- QTextTable *deletedTable = tempCursor.currentTable();
- int numRows = deletedTable->rows();
- int numColumns = deletedTable->columns();
- QTextTable *insertedTable = cursor.insertTable(numRows, numColumns, deletedTable->format());
- for (int i=0; i<numRows; i++) {
- for (int j=0; j<numColumns; j++) {
- tempCursor.setPosition(deletedTable->cellAt(i,j).firstCursorPosition().position());
- tempCursor.setPosition(deletedTable->cellAt(i,j).lastCursorPosition().position(), QTextCursor::KeepAnchor);
- insertedTable->cellAt(i,j).setFormat(deletedTable->cellAt(i,j).format().toTableCellFormat());
- cursor.setPosition(insertedTable->cellAt(i,j).firstCursorPosition().position());
- cursor.insertFragment(tempCursor.selection());
- }
- }
- tempCursor.setPosition(deletedTable->cellAt(numRows-1,numColumns-1).lastCursorPosition().position());
- currentBlock = tempCursor.block();
- //Move the cursor outside of table
- cursor.setPosition(cursor.position() + 1);
- continue;
- } else {
- // This block does not contain a list. So no special work here.
- if ((currentBlock != tempDoc.begin()) && !(QTextCursor(currentBlock.previous()).currentTable())) {
- cursor.insertBlock(currentBlock.blockFormat(), currentBlock.charFormat());
- }
-
- if (QTextCursor(currentBlock.previous()).currentTable()) {
- cursor.mergeBlockFormat(currentBlock.blockFormat());
- }
- }
-
- /********************************************************************************************************************/
- /*This section of code is a work-around for a bug in the Qt. This work-around is safe. If and when the bug is fixed */
- /*the if condition would never be true and the code would never get executed */
- /********************************************************************************************************************/
- if ((KoList::level(cursor.block()) != KoList::level(currentBlock)) && currentBlock.text().length()) {
- if (!currentList) {
- QTextCursor tmp(cursor);
- tmp.setPosition(tmp.block().previous().position());
- currentList = KoTextDocument(tmp.document()).list(tmp.block());
- }
- currentList->add(cursor.block(), KoList::level(currentBlock));
- }
- /********************************************************************************************************************/
-
- // Finally insert all the contents of the block into the main document.
- QTextBlock::iterator it;
- for (it = currentBlock.begin(); !(it.atEnd()); ++it) {
- QTextFragment currentFragment = it.fragment();
- if (currentFragment.isValid()) {
- cursor.insertText(currentFragment.text(), currentFragment.charFormat());
- }
- }
- }
-}
-
-int KoChangeTracker::fragmentLength(const QTextDocumentFragment &fragment)
-{
- QTextDocument tempDoc;
- QTextCursor tempCursor(&tempDoc);
- tempCursor.insertFragment(fragment);
- int length = 0;
- bool deletedListItem = false;
- for (QTextBlock currentBlock = tempDoc.begin(); currentBlock != tempDoc.end(); currentBlock = currentBlock.next()) {
- tempCursor.setPosition(currentBlock.position());
- if (tempCursor.currentList()) {
- if (currentBlock != tempDoc.begin() && deletedListItem)
- length += 1; //For the Block separator
- } else if (tempCursor.currentTable()) {
- QTextTable *deletedTable = tempCursor.currentTable();
- int numRows = deletedTable->rows();
- int numColumns = deletedTable->columns();
- for (int i=0; i<numRows; i++) {
- for (int j=0; j<numColumns; j++) {
- length += 1;
- length += (deletedTable->cellAt(i,j).lastCursorPosition().position() - deletedTable->cellAt(i,j).firstCursorPosition().position());
- }
- }
- tempCursor.setPosition(deletedTable->cellAt(numRows-1,numColumns-1).lastCursorPosition().position());
- currentBlock = tempCursor.block();
- length += 1;
- continue;
- } else {
- if ((currentBlock != tempDoc.begin()) && !(QTextCursor(currentBlock.previous()).currentTable()))
- length += 1; //For the Block Separator
- }
-
-
- QTextBlock::iterator it;
- for (it = currentBlock.begin(); !(it.atEnd()); ++it) {
- QTextFragment currentFragment = it.fragment();
- if (currentFragment.isValid())
- length += currentFragment.text().length();
- }
- }
-
- return length;
-}
diff --git a/plugins/flake/textshape/kotext/changetracker/KoChangeTracker.h b/plugins/flake/textshape/kotext/changetracker/KoChangeTracker.h
deleted file mode 100644
index 5592230eb4..0000000000
--- a/plugins/flake/textshape/kotext/changetracker/KoChangeTracker.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Pierre Stirnweiss <pierre.stirnweiss_calligra@gadz.org>
- * Copyright (C) 2011 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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 KOCHANGETRACKER_H
-#define KOCHANGETRACKER_H
-
-#include "kritatext_export.h"
-#include <KoXmlReaderForward.h>
-
-#include <QObject>
-#include <QMetaType>
-#include <QVector>
-
-#include <KoGenChange.h>
-
-class KUndo2MagicString;
-
-class KoGenChanges;
-class KoChangeTrackerElement;
-class KoFormatChangeInformation;
-
-class QTextCursor;
-class QTextFormat;
-class QString;
-class QTextDocumentFragment;
-class QTextList;
-
-class KRITATEXT_EXPORT KoChangeTracker : public QObject
-{
- Q_OBJECT
-public:
-
- enum ChangeSaveFormat {
- ODF_1_2 = 0,
- DELTAXML,
- UNKNOWN = 9999
- };
-
- explicit KoChangeTracker(QObject *parent = 0);
- ~KoChangeTracker() override;
-
- void setRecordChanges(bool enabled);
- bool recordChanges() const;
-
- void setDisplayChanges(bool enabled);
- bool displayChanges() const;
-
- /// XXX: these three are called "getXXX" but do change the state of the change tracker
- int getFormatChangeId(const KUndo2MagicString &title, const QTextFormat &format, const QTextFormat &prevFormat, int existingChangeId);
- int getInsertChangeId(const KUndo2MagicString &title, int existingChangeId);
- int getDeleteChangeId(const KUndo2MagicString &title, const QTextDocumentFragment &selection, int existingChangeId);
-
- void setFormatChangeInformation(int formatChangeId, KoFormatChangeInformation *formatInformation);
- KoFormatChangeInformation *formatChangeInformation(int formatChangeId) const;
-
- KoChangeTrackerElement* elementById(int id) const;
- bool removeById(int id, bool freeMemory = true);
-
- //Returns all the deleted changes
- int getDeletedChanges(QVector<KoChangeTrackerElement *>& deleteVector) const;
-
- bool containsInlineChanges(const QTextFormat &format) const;
- int mergeableId(KoGenChange::Type type, const KUndo2MagicString &title, int existingId) const;
-
- QColor getInsertionBgColor() const;
- QColor getDeletionBgColor() const;
- QColor getFormatChangeBgColor() const;
-
- void setInsertionBgColor(const QColor& bgColor);
- void setDeletionBgColor(const QColor& color);
- void setFormatChangeBgColor(const QColor& color);
-
- /// Splits a changeElement. This creates a duplicate changeElement with a different changeId. This is used because we do not support overlapping change regions. The function returns the new changeId
- int split(int changeId);
-
- bool isParent(int testedParentId, int testedChildId) const;
- void setParent(int child, int parent);
- int parent(int changeId) const;
-
- int createDuplicateChangeId(int existingChangeId);
- bool isDuplicateChangeId(int duplicateChangeId) const;
- int originalChangeId(int duplicateChangeId) const;
-
- void acceptRejectChange(int changeId, bool set);
-
- /// Load/save methods
- bool saveInlineChange(int changeId, KoGenChange &change);
-
- /**
- * @brief saveInlineChanges saves all the changes in the internal map, except
- * for the delete changes, which are changed independently using saveInlineChange.
- * @return an updated table of numerical, internal changeid's to xml:id strings.
- */
- QMap<int, QString> saveInlineChanges(QMap<int, QString> changeTransTable, KoGenChanges &genChanges);
-
- void loadOdfChanges(const KoXmlElement& element);
- int getLoadedChangeId(const QString &odfId) const;
-
- static QTextDocumentFragment generateDeleteFragment(const QTextCursor& cursor);
- static void insertDeleteFragment(QTextCursor &cursor);
- static int fragmentLength(const QTextDocumentFragment &fragment);
-
- QString authorName() const;
- void setAuthorName(const QString &authorName);
-
- ChangeSaveFormat saveFormat() const;
- void setSaveFormat(ChangeSaveFormat saveFormat);
-
-private:
-
- static bool checkListDeletion(const QTextList &list, const QTextCursor &cursor);
- class Private;
- Private* const d;
-};
-
-Q_DECLARE_METATYPE(KoChangeTracker*)
-
-#endif
diff --git a/plugins/flake/textshape/kotext/changetracker/KoChangeTrackerElement.cpp b/plugins/flake/textshape/kotext/changetracker/KoChangeTrackerElement.cpp
deleted file mode 100644
index 52b59b2e1d..0000000000
--- a/plugins/flake/textshape/kotext/changetracker/KoChangeTrackerElement.cpp
+++ /dev/null
@@ -1,213 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Pierre Stirnweiss \pierre.stirnweiss_calligra@gadz.org>
- *
- * 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 "KoChangeTrackerElement.h"
-
-#include "TextDebug.h"
-#include <kundo2magicstring.h>
-
-#include <QTextFormat>
-#include <QTextDocumentFragment>
-
-class Q_DECL_HIDDEN KoChangeTrackerElement::Private
-{
-public:
- Private() {}
- ~Private() {}
-
- KUndo2MagicString title;
- KoGenChange::Type type;
- QTextFormat changeFormat;
- QTextFormat prevFormat;
-
- QString creator;
- QString date;
- QString extraMetaData;
- //These two elements are valid for delete changes. Need to move it to a sub-class
- QTextDocumentFragment deleteFragment;
-
- bool enabled;
- bool acceptedRejected;
- bool valid;
-};
-
-KoChangeTrackerElement::KoChangeTrackerElement(const KUndo2MagicString& title, KoGenChange::Type type)
- :d(new Private())
-{
- d->title = title;
- d->type = type;
- d->acceptedRejected = false;
- d->valid = true;
-}
-
-KoChangeTrackerElement::KoChangeTrackerElement()
- :d(new Private())
-{
-}
-
-KoChangeTrackerElement::KoChangeTrackerElement(const KoChangeTrackerElement& other)
- :d(new Private())
-{
- d->title = other.d->title;
- d->type = other.d->type;
- d->changeFormat = other.d->changeFormat;
- d->prevFormat = other.d->prevFormat;
- d->creator = other.d->creator;
- d->date = other.d->date;
- d->extraMetaData = other.d->extraMetaData;
- d->deleteFragment = other.d->deleteFragment;
- d->enabled = other.d->enabled;
- d->acceptedRejected = other.d->acceptedRejected;
- d->valid = other.d->valid;
-}
-
-KoChangeTrackerElement::~KoChangeTrackerElement()
-{
- delete d;
-}
-
-void KoChangeTrackerElement::setEnabled(bool enabled)
-{
- d->enabled = enabled;
-}
-
-bool KoChangeTrackerElement::isEnabled() const
-{
- return d->enabled;
-}
-
-void KoChangeTrackerElement::setAcceptedRejected(bool set)
-{
- d->acceptedRejected = set;
-}
-
-bool KoChangeTrackerElement::acceptedRejected()
-{
- return d->acceptedRejected;
-}
-
-void KoChangeTrackerElement::setValid(bool valid)
-{
- d->valid = valid;
-}
-
-bool KoChangeTrackerElement::isValid() const
-{
- return d->valid;
-}
-
-void KoChangeTrackerElement::setChangeType(KoGenChange::Type type)
-{
- d->type = type;
-}
-
-KoGenChange::Type KoChangeTrackerElement::getChangeType() const
-{
- return d->type;
-}
-
-void KoChangeTrackerElement::setChangeTitle(const KUndo2MagicString& title)
-{
- d->title = title;
-}
-
-KUndo2MagicString KoChangeTrackerElement::getChangeTitle() const
-{
- return d->title;
-}
-
-void KoChangeTrackerElement::setChangeFormat(const QTextFormat &format)
-{
- d->changeFormat = format;
-}
-
-QTextFormat KoChangeTrackerElement::getChangeFormat() const
-{
- return d->changeFormat;
-}
-
-void KoChangeTrackerElement::setPrevFormat(const QTextFormat &format)
-{
- d->prevFormat = format;
-}
-
-QTextFormat KoChangeTrackerElement::getPrevFormat() const
-{
- return d->prevFormat;
-}
-
-bool KoChangeTrackerElement::hasCreator() const
-{
- return !d->creator.isEmpty();
-}
-
-void KoChangeTrackerElement::setCreator(const QString& creator)
-{
- d->creator = creator;
-}
-
-QString KoChangeTrackerElement::getCreator() const
-{
- return d->creator;
-}
-
-bool KoChangeTrackerElement::hasDate() const
-{
- return !d->date.isEmpty();
-}
-
-void KoChangeTrackerElement::setDate(const QString& date)
-{
- d->date = date;
-}
-
-QString KoChangeTrackerElement::getDate() const
-{
- return d->date;
-}
-
-bool KoChangeTrackerElement::hasExtraMetaData() const
-{
- return !d->extraMetaData.isEmpty();
-}
-
-void KoChangeTrackerElement::setExtraMetaData(const QString& metaData)
-{
- d->extraMetaData = metaData;
-}
-
-QString KoChangeTrackerElement::getExtraMetaData() const
-{
- return d->extraMetaData;
-}
-
-bool KoChangeTrackerElement::hasDeleteData() const
-{
- return !d->deleteFragment.isEmpty();
-}
-
-void KoChangeTrackerElement::setDeleteData(const QTextDocumentFragment& fragment)
-{
- d->deleteFragment = fragment;
-}
-
-QTextDocumentFragment KoChangeTrackerElement::getDeleteData() const
-{
- return d->deleteFragment;
-}
diff --git a/plugins/flake/textshape/kotext/changetracker/KoChangeTrackerElement.h b/plugins/flake/textshape/kotext/changetracker/KoChangeTrackerElement.h
deleted file mode 100644
index df019d7a0d..0000000000
--- a/plugins/flake/textshape/kotext/changetracker/KoChangeTrackerElement.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Pierre Stirnweiss \pierre.stirnweiss_calligra@gadz.org>
- *
- * 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 KOCHANGETRACKERELEMENT_H
-#define KOCHANGETRACKERELEMENT_H
-
-#include <KoGenChange.h>
-
-#include "kritatext_export.h"
-
-class KUndo2MagicString;
-class QString;
-class QTextFormat;
-class QTextDocumentFragment;
-
-
-class KRITATEXT_EXPORT KoChangeTrackerElement
-{
-public:
-
- KoChangeTrackerElement(const KUndo2MagicString& title, KoGenChange::Type type);
-
- KoChangeTrackerElement();
-
- KoChangeTrackerElement(const KoChangeTrackerElement &other);
-
- ~KoChangeTrackerElement();
-
- void setEnabled(bool enabled);
- bool isEnabled() const;
-
- ///This flag is used when a change is accepted or rejected. When set, the change becomes transparent to functions like KoChangeTracker::isParent,... The KoChangeTrackerElement behaves like it has been destroyed. This is not done because of the undo/redo. A KoChangeTrackerElement can only be destroyed when its accept/reject command is destroyed.
- void setAcceptedRejected(bool set);
- bool acceptedRejected();
-
- void setValid(bool valid);
- bool isValid() const;
-
- void setChangeType(KoGenChange::Type type);
- KoGenChange::Type getChangeType() const;
-
- void setChangeTitle(const KUndo2MagicString& title);
- KUndo2MagicString getChangeTitle() const;
-
- void setChangeFormat(const QTextFormat &format);
- QTextFormat getChangeFormat() const;
-
- void setPrevFormat(const QTextFormat &prevFormat);
- QTextFormat getPrevFormat() const;
-
- bool hasCreator() const;
- void setCreator(const QString& creator);
- QString getCreator() const;
-
- bool hasDate() const;
- void setDate(const QString& date);
- QString getDate() const;
-
- bool hasExtraMetaData()const;
- void setExtraMetaData(const QString& metaData);
- QString getExtraMetaData() const;
-
- bool hasDeleteData() const;
- void setDeleteData(const QTextDocumentFragment& fragment);
- QTextDocumentFragment getDeleteData() const;
-
-
-private:
- class Private;
- Private* const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/changetracker/KoDeletedCellData.cpp b/plugins/flake/textshape/kotext/changetracker/KoDeletedCellData.cpp
deleted file mode 100644
index c1f3432008..0000000000
--- a/plugins/flake/textshape/kotext/changetracker/KoDeletedCellData.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Ganesh Paramasivam <ganesh@crystalfab.com>
- *
- * 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 "KoDeletedCellData.h"
-
-
-KoDeletedCellData::KoDeletedCellData(int rowNumber, int columnNumber)
-{
- this->row_number = rowNumber;
- this->column_number = columnNumber;
-}
-
-KoDeletedCellData::~KoDeletedCellData()
-{
-}
-
-int KoDeletedCellData::rowNumber() const
-{
- return row_number;
-}
-
-int KoDeletedCellData::columnNumber() const
-{
- return column_number;
-}
-
-void KoDeletedCellData::setCellFormat(const QTextTableCellFormat &cellFormat)
-{
- this->cell_format = cellFormat;
-}
-
-const QTextTableCellFormat& KoDeletedCellData::cellFormat() const
-{
- return this->cell_format;
-}
-
-void KoDeletedCellData::setCellContent(const QTextDocumentFragment &cellContent)
-{
- this->cell_content = cellContent;
-}
-
-const QTextDocumentFragment& KoDeletedCellData::cellContent() const
-{
- return this->cell_content;
-}
-
diff --git a/plugins/flake/textshape/kotext/changetracker/KoDeletedCellData.h b/plugins/flake/textshape/kotext/changetracker/KoDeletedCellData.h
deleted file mode 100644
index ac9f96cb4e..0000000000
--- a/plugins/flake/textshape/kotext/changetracker/KoDeletedCellData.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Ganesh Paramasivam <ganesh@crystalfab.com>
- *
- * 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 __KODELETEDCELLDATA_H__
-#define __KODELETEDCELLDATA_H__
-
-#include <QTextTableCellFormat>
-#include <QTextDocumentFragment>
-
-class KoDeletedCellData
-{
- public:
- KoDeletedCellData(int rowNumber, int columnNumber);
-
- ~KoDeletedCellData();
-
- int rowNumber() const;
-
- int columnNumber() const;
-
- void setCellFormat(const QTextTableCellFormat &cellFormat);
-
- const QTextTableCellFormat& cellFormat() const;
-
- void setCellContent(const QTextDocumentFragment &cellContent);
-
- const QTextDocumentFragment& cellContent() const;
-
- private:
- int row_number;
- int column_number;
- QTextTableCellFormat cell_format;
- QTextDocumentFragment cell_content;
-};
-#endif
diff --git a/plugins/flake/textshape/kotext/changetracker/KoDeletedColumnData.cpp b/plugins/flake/textshape/kotext/changetracker/KoDeletedColumnData.cpp
deleted file mode 100644
index 277cface77..0000000000
--- a/plugins/flake/textshape/kotext/changetracker/KoDeletedColumnData.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Ganesh Paramasivam <ganesh@crystalfab.com>
- *
- * 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 "KoDeletedColumnData.h"
-
-#include <QTextCursor>
-#include <QTextTable>
-
-#include "KoDeletedCellData.h"
-
-#include <styles/KoTableColumnStyle.h>
-
-KoDeletedColumnData::KoDeletedColumnData(int columnNumber)
-{
- this->column_number = columnNumber;
-}
-
-KoDeletedColumnData::~KoDeletedColumnData()
-{
- KoDeletedCellData *cellData;
- foreach (cellData, deleted_cells) {
- delete cellData;
- }
-}
-
-int KoDeletedColumnData::columnNumber()
-{
- return column_number;
-}
-
-void KoDeletedColumnData::setColumnStyle(KoTableColumnStyle *columnStyle)
-{
- this->column_style = columnStyle;
-}
-
-KoTableColumnStyle *KoDeletedColumnData::columnStyle()
-{
- return column_style;
-}
-
-const QVector<KoDeletedCellData *>& KoDeletedColumnData::deletedCells()
-{
- return deleted_cells;
-}
-
-void KoDeletedColumnData::storeDeletedCells(QTextTable *table)
-{
- QTextCursor cursor(table->document());
- int rows = table->rows();
-
- for (int i=0; i < rows; i++) {
- KoDeletedCellData *cellData = new KoDeletedCellData(i, column_number);
- QTextTableCell cell = table->cellAt(i, column_number);
- cursor.setPosition(cell.firstCursorPosition().position());
- cursor.setPosition(cell.lastCursorPosition().position(), QTextCursor::KeepAnchor);
- cellData->setCellFormat(cell.format().toTableCellFormat());
- cellData->setCellContent(cursor.selection());
- deleted_cells.push_back(cellData);
- }
-}
-
diff --git a/plugins/flake/textshape/kotext/changetracker/KoDeletedColumnData.h b/plugins/flake/textshape/kotext/changetracker/KoDeletedColumnData.h
deleted file mode 100644
index 18b0ab233e..0000000000
--- a/plugins/flake/textshape/kotext/changetracker/KoDeletedColumnData.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Ganesh Paramasivam <ganesh@crystalfab.com>
- *
- * 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 __KODELETEDCOLUMNDATA_H__
-#define __KODELETEDCOLUMNDATA_H__
-
-#include <QVector>
-
-class KoDeletedCellData;
-class KoTableColumnStyle;
-class QTextTable;
-
-class KoDeletedColumnData
-{
- public:
- explicit KoDeletedColumnData(int columnNumber);
-
- ~KoDeletedColumnData();
-
- int columnNumber();
-
- void setColumnStyle(KoTableColumnStyle *columnStyle);
-
- KoTableColumnStyle *columnStyle();
-
- const QVector<KoDeletedCellData *>& deletedCells();
-
- void storeDeletedCells(QTextTable *table);
-
- private:
- int column_number;
-
- KoTableColumnStyle *column_style;
-
- QVector<KoDeletedCellData *> deleted_cells;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/changetracker/KoDeletedRowColumnDataStore.cpp b/plugins/flake/textshape/kotext/changetracker/KoDeletedRowColumnDataStore.cpp
deleted file mode 100644
index cb896ce593..0000000000
--- a/plugins/flake/textshape/kotext/changetracker/KoDeletedRowColumnDataStore.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Ganesh Paramasivam <ganesh@crystalfab.com>
- *
- * 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 "KoDeletedRowColumnDataStore.h"
-
-#include "KoDeletedRowData.h"
-#include "KoDeletedColumnData.h"
-
-KoDeletedRowColumnDataStore::KoDeletedRowColumnDataStore()
-{
-}
-
-KoDeletedRowColumnDataStore::~KoDeletedRowColumnDataStore()
-{
-}
-
-KoDeletedRowData *KoDeletedRowColumnDataStore::addDeletedRow(QTextTable *table, int rowNumber, int changeId)
-{
- KoDeletedRowData *deletedRowData = new KoDeletedRowData(rowNumber);
- deletedRowDataMap.insert(changeId, deletedRowData);
- QVector<int> *tableChangeIds = tableChangeIdsMap.value(table, 0);
- if (!tableChangeIds) {
- tableChangeIds = new QVector<int>();
- tableChangeIdsMap.insert(table, tableChangeIds);
- }
- tableChangeIds->push_back(changeId);
- return deletedRowData;
-}
-
-KoDeletedColumnData *KoDeletedRowColumnDataStore::addDeletedColumn(QTextTable *table, int columnNumber, int changeId)
-{
- KoDeletedColumnData *deletedColumnData = new KoDeletedColumnData(columnNumber);
- deletedColumnDataMap.insert(changeId, deletedColumnData);
- QVector<int> *tableChangeIds = tableChangeIdsMap.value(table, 0);
- if (!tableChangeIds) {
- tableChangeIds = new QVector<int>();
- tableChangeIdsMap.insert(table, tableChangeIds);
- }
- tableChangeIds->push_back(changeId);
- return deletedColumnData;
-}
-
-const QVector<int> *KoDeletedRowColumnDataStore::deletedRowColumnChangeIds(QTextTable *table)
-{
- return tableChangeIdsMap.value(table, 0);
-}
-
-KoDeletedRowColumnDataStore::DeleteType KoDeletedRowColumnDataStore::deleteType(int changeId)
-{
- KoDeletedRowColumnDataStore::DeleteType retValue;
- if (deletedRowDataMap.value(changeId, 0)) {
- retValue = KoDeletedRowColumnDataStore::eDeletedRow;
- } else if(deletedColumnDataMap.value(changeId, 0)) {
- retValue = KoDeletedRowColumnDataStore::eDeletedColumn;
- } else {
- retValue = KoDeletedRowColumnDataStore::eUnknownDeleteType;
- }
-
- return retValue;
-}
-
-KoDeletedRowData *KoDeletedRowColumnDataStore::deletedRowData(int changeId)
-{
- return deletedRowDataMap.value(changeId, 0);
-}
-
-KoDeletedColumnData *KoDeletedRowColumnDataStore::deletedColumnData(int changeId)
-{
- return deletedColumnDataMap.value(changeId, 0);
-}
-
diff --git a/plugins/flake/textshape/kotext/changetracker/KoDeletedRowColumnDataStore.h b/plugins/flake/textshape/kotext/changetracker/KoDeletedRowColumnDataStore.h
deleted file mode 100644
index 324642396a..0000000000
--- a/plugins/flake/textshape/kotext/changetracker/KoDeletedRowColumnDataStore.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Ganesh Paramasivam <ganesh@crystalfab.com>
- *
- * 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 __KODELETEDROWCOLUMNDATASTORE_H__
-#define __KODELETEDROWCOLUMNDATASTORE_H__
-
-#include <QVector>
-#include <QMap>
-
-class KoDeletedRowData;
-class KoDeletedColumnData;
-class QTextTable;
-
-class KoDeletedRowColumnDataStore {
- public:
- typedef enum {
- eDeletedRow,
- eDeletedColumn,
- eUnknownDeleteType
- } DeleteType;
-
- KoDeletedRowColumnDataStore();
-
- ~KoDeletedRowColumnDataStore();
-
- KoDeletedRowData *addDeletedRow(QTextTable *table, int rowNumber, int changeId);
-
- KoDeletedColumnData *addDeletedColumn(QTextTable *table, int columnNumber, int changeId);
-
- const QVector<int> *deletedRowColumnChangeIds(QTextTable *table);
-
- DeleteType deleteType(int changeId);
-
- KoDeletedRowData *deletedRowData(int changeId);
-
- KoDeletedColumnData *deletedColumnData(int changeId);
-
- private:
-
- QMap<QTextTable *, QVector<int> *> tableChangeIdsMap;
-
- QMap<int, KoDeletedRowData *> deletedRowDataMap;
-
- QMap<int, KoDeletedColumnData *> deletedColumnDataMap;
-};
-#endif
diff --git a/plugins/flake/textshape/kotext/changetracker/KoDeletedRowData.cpp b/plugins/flake/textshape/kotext/changetracker/KoDeletedRowData.cpp
deleted file mode 100644
index fce3163b79..0000000000
--- a/plugins/flake/textshape/kotext/changetracker/KoDeletedRowData.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Ganesh Paramasivam <ganesh@crystalfab.com>
- *
- * 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 "KoDeletedRowData.h"
-
-#include <QTextCursor>
-#include <QTextTable>
-
-#include "KoDeletedCellData.h"
-
-#include <styles/KoTableRowStyle.h>
-
-KoDeletedRowData::KoDeletedRowData(int rowNumber)
-{
- this->row_number = rowNumber;
-}
-
-KoDeletedRowData::~KoDeletedRowData()
-{
- KoDeletedCellData *cellData;
- foreach (cellData, deleted_cells) {
- delete cellData;
- }
-}
-
-int KoDeletedRowData::rowNumber()
-{
- return row_number;
-}
-
-void KoDeletedRowData::setRowStyle(KoTableRowStyle *rowStyle)
-{
- this->row_style = rowStyle;
-}
-
-KoTableRowStyle *KoDeletedRowData::rowStyle()
-{
- return row_style;
-}
-
-const QVector<KoDeletedCellData *>& KoDeletedRowData::deletedCells()
-{
- return deleted_cells;
-}
-
-void KoDeletedRowData::storeDeletedCells(QTextTable *table)
-{
- QTextCursor cursor(table->document());
- int columns = table->columns();
-
- for (int i=0; i<columns; i++) {
- KoDeletedCellData *cellData = new KoDeletedCellData(row_number, i);
- QTextTableCell cell = table->cellAt(row_number, i);
- cursor.setPosition(cell.firstCursorPosition().position());
- cursor.setPosition(cell.lastCursorPosition().position(), QTextCursor::KeepAnchor);
- cellData->setCellFormat(cell.format().toTableCellFormat());
- cellData->setCellContent(cursor.selection());
- deleted_cells.push_back(cellData);
- }
-}
-
diff --git a/plugins/flake/textshape/kotext/changetracker/KoDeletedRowData.h b/plugins/flake/textshape/kotext/changetracker/KoDeletedRowData.h
deleted file mode 100644
index a792283f7b..0000000000
--- a/plugins/flake/textshape/kotext/changetracker/KoDeletedRowData.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Ganesh Paramasivam <ganesh@crystalfab.com>
- *
- * 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 __KODELETEDROWDATA_H__
-#define __KODELETEDROWDATA_H__
-
-#include <QVector>
-
-class KoDeletedCellData;
-class KoTableRowStyle;
-class QTextTable;
-
-class KoDeletedRowData
-{
- public:
- explicit KoDeletedRowData(int rowNumber);
-
- ~KoDeletedRowData();
-
- int rowNumber();
-
- void setRowStyle(KoTableRowStyle *rowStyle);
-
- KoTableRowStyle *rowStyle();
-
- const QVector<KoDeletedCellData *>& deletedCells();
-
- void storeDeletedCells(QTextTable *table);
-
- private:
- int row_number;
-
- KoTableRowStyle *row_style;
-
- QVector<KoDeletedCellData *> deleted_cells;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/changetracker/KoFormatChangeInformation.cpp b/plugins/flake/textshape/kotext/changetracker/KoFormatChangeInformation.cpp
deleted file mode 100644
index 85e5a14326..0000000000
--- a/plugins/flake/textshape/kotext/changetracker/KoFormatChangeInformation.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Ganesh Paramasivam <ganesh@crystalfab.com>
- *
- * 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 "KoFormatChangeInformation.h"
-
-KoFormatChangeInformation::KoFormatChangeInformation(KoFormatChangeInformation::FormatChangeType formatChangeType)
-{
- this->formatChangeType = formatChangeType;
-}
-
-KoFormatChangeInformation::FormatChangeType KoFormatChangeInformation::formatType()
-{
- return formatChangeType;
-}
-
-KoTextStyleChangeInformation::KoTextStyleChangeInformation(KoFormatChangeInformation::FormatChangeType formatChangeType):
- KoFormatChangeInformation(formatChangeType)
-{
-}
-
-void KoTextStyleChangeInformation::setPreviousCharFormat(QTextCharFormat &previousFormat)
-{
- this->previousTextCharFormat = previousFormat;
-}
-
-QTextCharFormat& KoTextStyleChangeInformation::previousCharFormat()
-{
- return this->previousTextCharFormat;
-}
-
-KoParagraphStyleChangeInformation::KoParagraphStyleChangeInformation():
- KoTextStyleChangeInformation(KoFormatChangeInformation::eParagraphStyleChange)
-{
-}
-
-void KoParagraphStyleChangeInformation::setPreviousBlockFormat(QTextBlockFormat &previousFormat)
-{
- this->previousTextBlockFormat = previousFormat;
-}
-
-QTextBlockFormat& KoParagraphStyleChangeInformation::previousBlockFormat()
-{
- return this->previousTextBlockFormat;
-}
-
-KoListItemNumChangeInformation::KoListItemNumChangeInformation(KoListItemNumChangeInformation::ListItemNumChangeType type):
- KoFormatChangeInformation(KoFormatChangeInformation::eListItemNumberingChange),
- eSubType(type)
-{
-}
-
-void KoListItemNumChangeInformation::setPreviousStartNumber(int oldStartNumber)
-{
- this->oldStartNumber = oldStartNumber;
-}
-
-KoListItemNumChangeInformation::ListItemNumChangeType KoListItemNumChangeInformation::listItemNumChangeType()
-{
- return eSubType;
-}
-
-int KoListItemNumChangeInformation::previousStartNumber()
-{
- return oldStartNumber;
-}
-
diff --git a/plugins/flake/textshape/kotext/changetracker/KoFormatChangeInformation.h b/plugins/flake/textshape/kotext/changetracker/KoFormatChangeInformation.h
deleted file mode 100644
index 0a87cefaf0..0000000000
--- a/plugins/flake/textshape/kotext/changetracker/KoFormatChangeInformation.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Ganesh Paramasivam <ganesh@crystalfab.com>
- *
- * 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 __FORMAT_CHANGE_INFORMATION_H__
-#define __FORMAT_CHANGE_INFORMATION_H__
-
-#include <QTextCharFormat>
-#include <QTextBlockFormat>
-
-class KoFormatChangeInformation {
- public:
- typedef enum {
- eTextStyleChange = 0,
- eParagraphStyleChange,
- eListItemNumberingChange
- }FormatChangeType;
-
- KoFormatChangeInformation::FormatChangeType formatType();
-
- protected:
- explicit KoFormatChangeInformation(KoFormatChangeInformation::FormatChangeType formatChangeType);
-
- private:
- KoFormatChangeInformation::FormatChangeType formatChangeType;
-};
-
-class KoTextStyleChangeInformation:public KoFormatChangeInformation {
- public:
- explicit KoTextStyleChangeInformation(KoFormatChangeInformation::FormatChangeType formatChangeType = KoFormatChangeInformation::eTextStyleChange);
- void setPreviousCharFormat(QTextCharFormat &oldFormat);
- QTextCharFormat& previousCharFormat();
- private:
- QTextCharFormat previousTextCharFormat;
-};
-
-class KoParagraphStyleChangeInformation:public KoTextStyleChangeInformation {
- public:
- KoParagraphStyleChangeInformation();
- void setPreviousBlockFormat(QTextBlockFormat &oldFormat);
- QTextBlockFormat& previousBlockFormat();
- private:
- QTextBlockFormat previousTextBlockFormat;
-};
-
-class KoListItemNumChangeInformation:public KoFormatChangeInformation {
- public:
- typedef enum {
- eNumberingRestarted = 0,
- eRestartRemoved
- }ListItemNumChangeType;
- explicit KoListItemNumChangeInformation(KoListItemNumChangeInformation::ListItemNumChangeType eSubType);
- void setPreviousStartNumber(int oldRestartNumber);
- KoListItemNumChangeInformation::ListItemNumChangeType listItemNumChangeType();
- int previousStartNumber();
- private:
- int oldStartNumber;
- KoListItemNumChangeInformation::ListItemNumChangeType eSubType;
-};
-#endif
diff --git a/plugins/flake/textshape/kotext/commands/AddAnnotationCommand.cpp b/plugins/flake/textshape/kotext/commands/AddAnnotationCommand.cpp
deleted file mode 100644
index 215f92be6a..0000000000
--- a/plugins/flake/textshape/kotext/commands/AddAnnotationCommand.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2009 Ganesh Paramasivam <ganesh@crystalfab.com>
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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 "AddAnnotationCommand.h"
-
-#include <KoAnnotation.h>
-#include <KoShapeController.h>
-#include <KoShapeControllerBase.h>
-#include <KoTextDocument.h>
-
-AddAnnotationCommand::AddAnnotationCommand(KoAnnotation *annotation, KUndo2Command *parent)
- : AddTextRangeCommand(annotation, parent)
- , m_annotation(annotation)
- , m_shape(0)
-{
- setText(kundo2_noi18n("internal step"));
-}
-
-void AddAnnotationCommand::undo()
-{
- AddTextRangeCommand::undo();
- KoShapeController *shapeController = KoTextDocument(m_annotation->document()).shapeController();
- m_shape = m_annotation->annotationShape();
- shapeController->documentBase()->removeShape(m_shape);
-}
-
-void AddAnnotationCommand::redo()
-{
- AddTextRangeCommand::redo();
-
- KoShapeController *shapeController = KoTextDocument(m_annotation->document()).shapeController();
- shapeController->documentBase()->addShape(m_annotation->annotationShape());
-
- m_shape = 0;
-
- //it's a textrange so we need to ask for a layout so we know where it is
- m_annotation->document()->markContentsDirty(m_annotation->rangeStart(), 0);
-}
-
-
-AddAnnotationCommand::~AddAnnotationCommand()
-{
- // We delete shape at KoShapeDeleteCommand.
- //delete m_annotation->annotationShape();
-}
diff --git a/plugins/flake/textshape/kotext/commands/AddAnnotationCommand.h b/plugins/flake/textshape/kotext/commands/AddAnnotationCommand.h
deleted file mode 100644
index cd108a8308..0000000000
--- a/plugins/flake/textshape/kotext/commands/AddAnnotationCommand.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * This file is part of the KDE project
- * Copyright (C) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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 ADDANNOTATIONCOMMAND_H
-#define ADDANNOTATIONCOMMAND_H
-
-#include "AddTextRangeCommand.h"
-
-class KoAnnotation;
-class KoShape;
-
-class AddAnnotationCommand : public AddTextRangeCommand
-{
-public:
- explicit AddAnnotationCommand(KoAnnotation *range, KUndo2Command *parent = 0);
- ~AddAnnotationCommand() override;
-
- void undo() override;
- void redo() override;
-
-private:
- KoAnnotation *m_annotation;
- KoShape *m_shape;
-};
-
-#endif // ADDANNOTATIONCOMMAND_H
diff --git a/plugins/flake/textshape/kotext/commands/AddTextRangeCommand.cpp b/plugins/flake/textshape/kotext/commands/AddTextRangeCommand.cpp
deleted file mode 100644
index 359417d491..0000000000
--- a/plugins/flake/textshape/kotext/commands/AddTextRangeCommand.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2009 Ganesh Paramasivam <ganesh@crystalfab.com>
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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 "AddTextRangeCommand.h"
-
-#include <klocalizedstring.h>
-#include "TextDebug.h"
-
-#include <KoTextRangeManager.h>
-#include <KoTextRange.h>
-
-AddTextRangeCommand::AddTextRangeCommand(KoTextRange * range, KUndo2Command *parent)
- : KUndo2Command(kundo2_noi18n("internal step"), parent)
- , m_range(range)
-{
-}
-
-void AddTextRangeCommand::undo()
-{
- KUndo2Command::undo();
- m_range->manager()->remove(m_range);
-}
-
-void AddTextRangeCommand::redo()
-{
- KUndo2Command::redo();
- m_range->manager()->insert(m_range);
-}
-
-
-AddTextRangeCommand::~AddTextRangeCommand()
-{
-}
diff --git a/plugins/flake/textshape/kotext/commands/AddTextRangeCommand.h b/plugins/flake/textshape/kotext/commands/AddTextRangeCommand.h
deleted file mode 100644
index 64bba245e3..0000000000
--- a/plugins/flake/textshape/kotext/commands/AddTextRangeCommand.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * This file is part of the KDE project
- * Copyright (C) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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 ADDTEXTRANGECOMMAND_H
-#define ADDTEXTRANGECOMMAND_H
-
-#include <kundo2command.h>
-
-class KoTextRange;
-
-class AddTextRangeCommand : public KUndo2Command
-{
-public:
- explicit AddTextRangeCommand(KoTextRange *range, KUndo2Command *parent = 0);
- ~AddTextRangeCommand() override;
-
- void undo() override;
- void redo() override;
-
-private:
- KoTextRange *m_range;
-};
-
-#endif // ADDTEXTRANGECOMMAND_H
diff --git a/plugins/flake/textshape/kotext/commands/ChangeAnchorPropertiesCommand.cpp b/plugins/flake/textshape/kotext/commands/ChangeAnchorPropertiesCommand.cpp
deleted file mode 100644
index 192b3b8dd3..0000000000
--- a/plugins/flake/textshape/kotext/commands/ChangeAnchorPropertiesCommand.cpp
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright (c) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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 "ChangeAnchorPropertiesCommand.h"
-
-#include "KoAnchorInlineObject.h"
-#include "KoAnchorTextRange.h"
-
-#include <KoTextEditor.h>
-#include <KoShapeContainer.h>
-#include <KoTextShapeDataBase.h>
-#include <KoTextDocument.h>
-#include <KoInlineTextObjectManager.h>
-#include <KoTextRangeManager.h>
-
-ChangeAnchorPropertiesCommand::ChangeAnchorPropertiesCommand(KoShapeAnchor *anchor, const KoShapeAnchor &newAnchorData, KoShapeContainer *newParent, KUndo2Command *parent)
- : KUndo2Command(kundo2_noi18n("Change Anchor Properties"), parent)
- , m_anchor(anchor)
- , m_oldAnchor(0)
- , m_newAnchor(0)
- , m_oldParent(anchor->shape()->parent())
- , m_newParent(newParent)
- , m_oldLocation(anchor->textLocation())
- , m_newLocation(0)
- , m_first(true)
- , m_undone(false)
-{
- copyLayoutProperties(anchor, &m_oldAnchor);
- copyLayoutProperties(&newAnchorData, &m_newAnchor);
-}
-
-ChangeAnchorPropertiesCommand::~ChangeAnchorPropertiesCommand()
-{
- if (m_undone) {
- delete m_newLocation;
- } else {
- delete m_oldLocation;
- }
-}
-
-void ChangeAnchorPropertiesCommand::copyLayoutProperties(const KoShapeAnchor *from, KoShapeAnchor *to)
-{
- to->setAnchorType(from->anchorType());
- to->setOffset(from->offset());
- to->setVerticalPos(from->verticalPos());
- to->setVerticalRel(from->verticalRel());
- to->setHorizontalPos(from->horizontalPos());
- to->setHorizontalRel(from->horizontalRel());
-}
-
-void ChangeAnchorPropertiesCommand::redo()
-{
- KoTextShapeDataBase *textData = 0;
- if (m_oldParent) {
- textData = qobject_cast<KoTextShapeDataBase*>(m_oldParent->userData());
- } else if (m_newParent) {
- textData = qobject_cast<KoTextShapeDataBase*>(m_newParent->userData());
- }
-
- KUndo2Command::redo();
-
- copyLayoutProperties(&m_newAnchor, m_anchor);
-
- m_anchor->shape()->update();
- if (m_first) {
- m_oldAbsPos = m_anchor->shape()->absolutePosition();
- m_anchor->shape()->setParent(m_newParent);
- // let's just set the old absolute position so it doesn't look like it's moving around
- m_anchor->shape()->setAbsolutePosition(m_oldAbsPos);
- } else {
- m_anchor->shape()->setParent(m_newParent);
- m_anchor->shape()->setAbsolutePosition(m_newAbsPos);
- m_anchor->shape()->update();
- }
-
- if (m_newAnchor.anchorType() != m_oldAnchor.anchorType()) {
- Q_ASSERT(textData);
- KoTextDocument doc(textData->document());
- KoInlineTextObjectManager *inlineManager = doc.inlineTextObjectManager();
- Q_ASSERT(inlineManager);
- KoTextRangeManager *rangeManager = doc.textRangeManager();
- Q_ASSERT(rangeManager);
-
- // First remove from the old location
- switch (m_oldAnchor.anchorType()) {
- case KoShapeAnchor::AnchorPage:
- // nothing we need to do to clean up old
- break;
-
- case KoShapeAnchor::AnchorAsCharacter:
- if (m_first) {
- //first time we need to remove the character manually
- QTextCursor cursor(textData->document());
- cursor.setPosition(m_oldLocation->position());
- cursor.deleteChar();
- }
- inlineManager->removeInlineObject(dynamic_cast<KoInlineObject *>(m_oldLocation));
- break;
-
- case KoShapeAnchor::AnchorParagraph:
- case KoShapeAnchor::AnchorToCharacter:
- rangeManager->remove(dynamic_cast<KoTextRange *>(m_oldLocation));
-
- // we need to mark dirty manually as it's a textrange
- textData->document()->markContentsDirty(m_oldLocation->position(), 0);
- break;
- }
-
- // And then set the new location
- switch (m_newAnchor.anchorType()) {
- case KoShapeAnchor::AnchorPage:
- m_anchor->setTextLocation(0);
- break;
-
- case KoShapeAnchor::AnchorAsCharacter:
- if (m_first) {
- KoTextEditor *editor = doc.textEditor();
- QTextCursor cursor(textData->document());
- cursor.setPosition(editor->position());
-
- m_newLocation = new KoAnchorInlineObject(m_anchor);
-
- inlineManager->insertInlineObject(cursor, dynamic_cast<KoInlineObject *>(m_newLocation));
- } else {
- // only insert in manager as qt re-inserts the character
- inlineManager->addInlineObject(dynamic_cast<KoInlineObject *>(m_newLocation));
- }
- m_anchor->setTextLocation(m_newLocation);
- break;
-
- case KoShapeAnchor::AnchorParagraph:
- case KoShapeAnchor::AnchorToCharacter:
- if (m_first) {
- KoTextEditor *editor = doc.textEditor();
- QTextCursor cursor(textData->document());
- cursor.setPosition(editor->position());
-
- KoAnchorTextRange *anchorRange = new KoAnchorTextRange(m_anchor, cursor);
- anchorRange->setManager(rangeManager);
- rangeManager->insert(anchorRange);
-
- m_newLocation = anchorRange;
- rangeManager->insert(anchorRange);
- } else {
- rangeManager->insert(dynamic_cast<KoTextRange *>(m_newLocation));
- }
- m_anchor->setTextLocation(m_newLocation);
-
- // we need to mark dirty manually as it's a textrange
- textData->document()->markContentsDirty(m_newLocation->position(), 0);
- break;
- }
- } else if (m_newAnchor.anchorType() != KoShapeAnchor::AnchorPage) {
- if (textData) {
- Q_ASSERT(m_anchor->textLocation());
- textData->document()->markContentsDirty(m_anchor->textLocation()->position(), 0);
- }
- }
-
- m_first = false;
- m_undone = false;
-
- m_anchor->shape()->notifyChanged();
-}
-
-void ChangeAnchorPropertiesCommand::undo()
-{
- KoTextShapeDataBase *textData = 0;
- if (m_oldParent) {
- textData = qobject_cast<KoTextShapeDataBase*>(m_oldParent->userData());
- } else if (m_newParent) {
- textData = qobject_cast<KoTextShapeDataBase*>(m_newParent->userData());
- }
-
- copyLayoutProperties(&m_oldAnchor, m_anchor);
-
- m_newAbsPos = m_anchor->shape()->absolutePosition();
-
- m_anchor->shape()->update();
- m_anchor->shape()->setParent(m_oldParent);
- m_anchor->shape()->setAbsolutePosition(m_oldAbsPos);
- m_anchor->shape()->update();
-
- if (m_newAnchor.anchorType() != m_oldAnchor.anchorType()) {
- Q_ASSERT(textData);
- KoTextDocument doc(textData->document());
- KoInlineTextObjectManager *inlineManager = doc.inlineTextObjectManager();
- Q_ASSERT(inlineManager);
- KoTextRangeManager *rangeManager = doc.textRangeManager();
- Q_ASSERT(rangeManager);
-
- // First unset the 'new' (current) location
- switch (m_newAnchor.anchorType()) {
- case KoShapeAnchor::AnchorPage:
- // nothing we need to do to clean up old
- break;
-
- case KoShapeAnchor::AnchorAsCharacter:
- // only remove in manager as qt removes the character
- inlineManager->removeInlineObject(dynamic_cast<KoInlineObject *>(m_newLocation));
- break;
-
- case KoShapeAnchor::AnchorParagraph:
- case KoShapeAnchor::AnchorToCharacter:
- rangeManager->remove(dynamic_cast<KoTextRange *>(m_newLocation));
-
- // we need to mark dirty manually as it's a textrange
- textData->document()->markContentsDirty(m_newLocation->position(), 0);
- break;
- }
-
- // Them re-insert the old (about to be restored) location
- switch (m_oldAnchor.anchorType()) {
- case KoShapeAnchor::AnchorPage:
- // nothing we need to do to clean up old
- m_anchor->setTextLocation(0);
- break;
-
- case KoShapeAnchor::AnchorAsCharacter:
- // only insert in manager as qt re-inserts the character
- inlineManager->addInlineObject(dynamic_cast<KoInlineObject *>(m_oldLocation));
- m_anchor->setTextLocation(m_oldLocation);
- break;
-
- case KoShapeAnchor::AnchorParagraph:
- case KoShapeAnchor::AnchorToCharacter:
- rangeManager->insert(dynamic_cast<KoTextRange *>(m_oldLocation));
-
- // we need to mark dirty manually as it's a textrange
- textData->document()->markContentsDirty(m_oldLocation->position(), 0);
- m_anchor->setTextLocation(m_oldLocation);
- break;
- }
- } else if (m_newAnchor.anchorType() != KoShapeAnchor::AnchorPage) {
- if (textData) {
- Q_ASSERT(m_anchor->textLocation());
- textData->document()->markContentsDirty(m_anchor->textLocation()->position(), 0);
- }
- }
-
- KUndo2Command::undo();
-
- m_undone = true;
-
- m_anchor->shape()->notifyChanged();
-}
diff --git a/plugins/flake/textshape/kotext/commands/ChangeAnchorPropertiesCommand.h b/plugins/flake/textshape/kotext/commands/ChangeAnchorPropertiesCommand.h
deleted file mode 100644
index 7f807b590a..0000000000
--- a/plugins/flake/textshape/kotext/commands/ChangeAnchorPropertiesCommand.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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.
- */
-
-#ifndef CHANGEANCHORPROPERTIESCOMMAND_H
-#define CHANGEANCHORPROPERTIESCOMMAND_H
-
-#include <kundo2command.h>
-#include "kritatext_export.h"
-#include "KoShapeAnchor.h"
-
-#include <QPointF>
-
-class KoShapeContainer;
-
-
-class KRITATEXT_EXPORT ChangeAnchorPropertiesCommand : public KUndo2Command
-{
-public:
- ChangeAnchorPropertiesCommand(KoShapeAnchor *anchor, const KoShapeAnchor &newAnchorData, KoShapeContainer *newParent, KUndo2Command *parent);
- ~ChangeAnchorPropertiesCommand() override;
-
- /// redo the command
- void redo() override;
- /// revert the actions done in redo
- void undo() override;
-private:
- void copyLayoutProperties(const KoShapeAnchor *from, KoShapeAnchor *to);
-
- KoShapeAnchor *m_anchor;
- KoShapeAnchor m_oldAnchor;
- KoShapeAnchor m_newAnchor;
- KoShapeContainer *m_oldParent;
- KoShapeContainer *m_newParent;
- QPointF m_oldAbsPos;
- QPointF m_newAbsPos;
- KoShapeAnchor::TextLocation *m_oldLocation;
- KoShapeAnchor::TextLocation *m_newLocation;
- bool m_first;
- bool m_undone;
-};
-
-#endif // CHANGEANCHORPROPERTIESCOMMAND_H
diff --git a/plugins/flake/textshape/kotext/commands/ChangeListCommand.cpp b/plugins/flake/textshape/kotext/commands/ChangeListCommand.cpp
deleted file mode 100644
index 013176915a..0000000000
--- a/plugins/flake/textshape/kotext/commands/ChangeListCommand.cpp
+++ /dev/null
@@ -1,373 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- *
- * 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 "ChangeListCommand.h"
-
-#include <KoTextBlockData.h>
-#include <KoTextDocument.h>
-#include <QTextCursor>
-#include <KoParagraphStyle.h>
-#include <KoList.h>
-
-#include <klocalizedstring.h>
-#include "TextDebug.h"
-
-#define MARGIN_DEFAULT 18 // we consider it the default value
-
-ChangeListCommand::ChangeListCommand(const QTextCursor &cursor, const KoListLevelProperties &levelProperties,
- KoTextEditor::ChangeListFlags flags, KUndo2Command *parent)
- : KoTextCommandBase(parent),
- m_flags(flags),
- m_first(true),
- m_alignmentMode(false)
-{
- setText(kundo2_i18n("Change List"));
-
- const bool styleCompletelySetAlready = extractTextBlocks(cursor, levelProperties.level(), levelProperties.style());
- QSet<int> levels = m_levels.values().toSet();
- KoListStyle::Style style = levelProperties.style();
- KoListStyle listStyle;
-
- // If the style is already completely set, we unset it instead
- if (styleCompletelySetAlready && !(m_flags & KoTextEditor::DontUnsetIfSame))
- style = KoListStyle::None;
-
- foreach (int lev, levels) {
- KoListLevelProperties llp;
- llp.setLevel(lev);
- llp.setStyle(style);
- llp.setListItemPrefix(levelProperties.listItemPrefix());
- llp.setListItemSuffix(levelProperties.listItemSuffix());
-
- if (KoListStyle::isNumberingStyle(style)) {
- llp.setStartValue(1);
- llp.setRelativeBulletSize(100); //we take the default value for numbering bullets as 100
- if (llp.listItemSuffix().isEmpty()) {
- llp.setListItemSuffix(".");
- }
- }
- else if (style == KoListStyle::CustomCharItem) {
- llp.setRelativeBulletSize(100); //we take the default value for numbering bullets as 100
- llp.setBulletCharacter(levelProperties.bulletCharacter());
- } else if (style == KoListStyle::ImageItem) {
- llp.setBulletImage(levelProperties.bulletImage());
- llp.setWidth(levelProperties.width());
- llp.setHeight(levelProperties.height());
- }
-
- llp.setAlignmentMode(true); // when creating a new list we create it in this mode
- llp.setLabelFollowedBy(KoListStyle::ListTab);
- llp.setDisplayLevel(levelProperties.displayLevel());
-
- llp.setTabStopPosition(MARGIN_DEFAULT*(lev+2));
- llp.setMargin(MARGIN_DEFAULT*(lev+2));
- llp.setTextIndent(- MARGIN_DEFAULT);
-
- listStyle.setLevelProperties(llp);
- }
-
- initList(&listStyle);
-
- setText(kundo2_i18n("Change List"));
-}
-
-ChangeListCommand::ChangeListCommand(const QTextCursor &cursor, KoListStyle *style, int level,
- KoTextEditor::ChangeListFlags flags, KUndo2Command *parent)
- : KoTextCommandBase(parent),
- m_flags(flags),
- m_first(true),
- m_alignmentMode(false)
-{
- Q_ASSERT(style);
- extractTextBlocks(cursor, level); // don't care about return value
- initList(style);
- setText(kundo2_i18n("Change List"));
-}
-
-ChangeListCommand::~ChangeListCommand()
-{
-}
-
-bool ChangeListCommand::extractTextBlocks(const QTextCursor &cursor, int level, KoListStyle::Style newStyle)
-{
- int selectionStart = qMin(cursor.anchor(), cursor.position());
- int selectionEnd = qMax(cursor.anchor(), cursor.position());
- bool styleCompletelySetAlready = true;
-
- QTextBlock block = cursor.block().document()->findBlock(selectionStart);
-
- bool oneOf = (selectionStart == selectionEnd); //ensures the block containing the cursor is selected in that case
-
- while (block.isValid() && ((block.position() < selectionEnd) || oneOf)) {
- m_blocks.append(block);
- if (block.textList()) {
- KoListLevelProperties prop = KoListLevelProperties::fromTextList(block.textList());
- m_alignmentMode=prop.alignmentMode();
- m_formerProperties.insert((m_blocks.size() - 1), prop);
- m_levels.insert((m_blocks.size() - 1), detectLevel(block, level));
- if (prop.style() != newStyle)
- styleCompletelySetAlready = false;
- }
- else {
- KoListLevelProperties prop;
- prop.setStyle(KoListStyle::None);
- prop.setAlignmentMode(true);
- m_alignmentMode=prop.alignmentMode();
- m_formerProperties.insert((m_blocks.size() - 1), prop);
- m_levels.insert((m_blocks.size() - 1), level);
- styleCompletelySetAlready = false;
- }
- oneOf = false;
- block = block.next();
- }
- return styleCompletelySetAlready;
-}
-
-int ChangeListCommand::detectLevel(const QTextBlock &block, int givenLevel)
-{
- if (givenLevel != 0)
- return givenLevel;
- if (block.textList()) {
- if (block.blockFormat().hasProperty(KoParagraphStyle::ListLevel))
- return block.blockFormat().intProperty(KoParagraphStyle::ListLevel);
- else
- return block.textList()->format().intProperty(KoListStyle::Level);
- }
- return 1;
-}
-
-bool ChangeListCommand::formatsEqual(const KoListLevelProperties &llp, const QTextListFormat &format)
-{
- if (m_flags & KoTextEditor::MergeExactly) {
- QTextListFormat listFormat;
- llp.applyStyle(listFormat);
- return listFormat == format;
- } else {
- return (int) llp.style() == (int) format.style();
- }
-}
-
-void ChangeListCommand::initList(KoListStyle *listStyle)
-{
- KoTextDocument document(m_blocks.first().document());
-
- KoList *mergeableList = 0;
- KoList *newList = 0;
- //First check if we could merge with previous or next list
- if (m_flags & KoTextEditor::MergeWithAdjacentList) {
- QSet<int> levels = m_levels.values().toSet();
- // attempt to merge with previous block
- QTextBlock prev = m_blocks.value(0).previous();
- bool isMergeable = true;
- foreach (int lev, levels) {
- KoListLevelProperties llp = listStyle->levelProperties(lev);
- // checks format compatibility
- isMergeable = (isMergeable && prev.isValid() && prev.textList() && (formatsEqual(llp, prev.textList()->format())));
- }
- if (isMergeable)
- mergeableList = document.list(prev);
-
- if (!mergeableList) {
- // attempt to merge with next block if previous failed
- isMergeable = true;
- QTextBlock next = m_blocks.value(m_blocks.size()-1).next();
- foreach (int lev, levels) {
- KoListLevelProperties llp = listStyle->levelProperties(lev);
- isMergeable = (isMergeable && next.isValid() && next.textList() && (formatsEqual(llp, next.textList()->format())));
- }
- if (isMergeable)
- mergeableList = document.list(next);
- }
- }
- // Now iterates over the blocks and set-up the various lists
- for (int i = 0; i < m_blocks.size(); ++i) {
- m_list.insert(i, 0);
- m_oldList.insert(i, document.list(m_blocks.at(i)));
- m_newProperties.insert(i, listStyle->levelProperties(m_levels.value(i)));
- // First check if we want to remove a list
- if (m_newProperties.value(i).style() == KoListStyle::None) {
- m_actions.insert(i, ChangeListCommand::RemoveList);
- continue;
- }
- // Then check if we want to modify an existing list.
- // The behaviour chosen for modifying a list is the following. If the selection contains more than one block, a new list is always created. If the selection only contains one block, the behaviour depends on the flag.
- if ((m_flags & KoTextEditor::ModifyExistingList) && (m_blocks.size() == 1)) {
- m_list.insert(i, document.list(m_blocks.at(i)));
- if (m_list.value(i)) {
- m_actions.insert(i, ChangeListCommand::ModifyExisting);
- continue;
- }
- }
- // Then check if we can merge with an existing list. The actual check was done before, here we just check the result.
- if (mergeableList) {
- m_list.insert(i, mergeableList);
- m_actions.insert(i, ChangeListCommand::MergeList);
- continue;
- }
- // All else failing, we need to create a new list.
- KoList::Type type = m_flags & KoTextEditor::CreateNumberedParagraph ? KoList::NumberedParagraph : KoList::TextList;
- if (!newList)
- newList = new KoList(m_blocks.at(i).document(), listStyle, type);
- m_list.insert(i, newList);
- m_actions.insert(i, ChangeListCommand::CreateNew);
- }
-}
-
-void ChangeListCommand::redo()
-{
- if (!m_first) {
- for (int i = 0; i < m_blocks.size(); ++i) { // We invalidate the lists before calling redo on the QTextDocument
- if (m_actions.value(i) == ChangeListCommand::RemoveList) {
- //if the block is not part of a list continue
- if (!m_blocks.at(i).textList()) {
- continue;
- }
- for (int j = 0; j < m_blocks.at(i).textList()->count(); j++) {
- if (m_blocks.at(i).textList()->item(j) != m_blocks.at(i)) {
- QTextBlock currentBlock = m_blocks.at(i).textList()->item(j);
- KoTextBlockData userData(currentBlock);
- userData.setCounterWidth(-1.0);
- break;
- }
- }
- }
- }
- KoTextCommandBase::redo();
- UndoRedoFinalizer finalizer(this);
- for (int i = 0; i < m_blocks.size(); ++i) {
- if ((m_actions.value(i) == ChangeListCommand::ModifyExisting) || (m_actions.value(i) == ChangeListCommand::CreateNew)
- || (m_actions.value(i) == ChangeListCommand::MergeList)) {
- m_list.value(i)->updateStoredList(m_blocks.at(i));
- KoListStyle *listStyle = m_list.value(i)->style();
- listStyle->refreshLevelProperties(m_newProperties.value(i));
- for (int j = 0; j < m_blocks.at(i).textList()->count(); j++) {
- if (m_blocks.at(i).textList()->item(j) != m_blocks.at(i)) {
- QTextBlock currentBlock = m_blocks.at(i).textList()->item(j);
- KoTextBlockData userData(currentBlock);
- userData.setCounterWidth(-1.0);
- break;
- }
- }
- }
- QTextBlock currentBlock = m_blocks.at(i);
- KoTextBlockData userData(currentBlock);
- userData.setCounterWidth(-1.0);
- }
- }
- else {
- for (int i = 0; i < m_blocks.size(); ++i) {
- if (m_actions.value(i) == ChangeListCommand::RemoveList) {
- //if the block is not part of a list continue
- if (!m_blocks.at(i).textList()) {
- continue;
- }
- KoList::remove(m_blocks.at(i));
- }
- else if (m_actions.value(i) == ChangeListCommand::ModifyExisting) {
- KoListStyle *listStyle = m_list.value(i)->style();
- listStyle->setLevelProperties(m_newProperties.value(i));
- QTextCursor cursor(m_blocks.at(i));
- QTextBlockFormat format = m_blocks.at(i).blockFormat();
- format.clearProperty(KoParagraphStyle::UnnumberedListItem);
- cursor.setBlockFormat(format);
- }
- else {
- //(ChangeListCommand::CreateNew)
- //(ChangeListCommand::MergeList)
- m_list.value(i)->add(m_blocks.at(i), m_newProperties.value(i).level());
- QTextCursor cursor(m_blocks.at(i));
- QTextBlockFormat format = m_blocks.at(i).blockFormat();
- format.clearProperty(KoParagraphStyle::UnnumberedListItem);
- cursor.setBlockFormat(format);
- }
- }
- }
- m_first = false;
-}
-
-void ChangeListCommand::undo()
-{
- KoTextCommandBase::undo();
- UndoRedoFinalizer finalizer(this);
-
- for (int i = 0; i < m_blocks.size(); ++i) {
- // command to undo:
- if (m_actions.value(i) == ChangeListCommand::RemoveList) {
- //if the block is not part of a list continue
- if (!m_blocks.at(i).textList()) {
- continue;
- }
- m_oldList.value(i)->updateStoredList(m_blocks.at(i));
- if ((m_flags & KoTextEditor::ModifyExistingList) && (m_formerProperties.value(i).style() != KoListStyle::None)) {
- KoListStyle *listStyle = m_oldList.value(i)->style();
- listStyle->refreshLevelProperties(m_formerProperties.value(i));
- }
- for (int j = 0; j < m_blocks.at(i).textList()->count(); j++) {
- if (m_blocks.at(i).textList()->item(j) != m_blocks.at(i)) {
- QTextBlock currentBlock = m_blocks.at(i).textList()->item(j);
- KoTextBlockData userData(currentBlock);
- userData.setCounterWidth(-1.0);
- break;
- }
- }
- }
- else if (m_actions.value(i) == ChangeListCommand::ModifyExisting) {
- m_list.value(i)->updateStoredList(m_blocks.at(i));
- if ((m_flags & KoTextEditor::ModifyExistingList) && (m_formerProperties.value(i).style() != KoListStyle::None)) {
- KoListStyle *listStyle = m_oldList.value(i)->style();
- listStyle->refreshLevelProperties(m_formerProperties.value(i));
- }
- for (int j = 0; j < m_blocks.at(i).textList()->count(); j++) {
- if (m_blocks.at(i).textList()->item(j) != m_blocks.at(i)) {
- QTextBlock currentBlock = m_blocks.at(i).textList()->item(j);
- KoTextBlockData userData(currentBlock);
- userData.setCounterWidth(-1.0);
- break;
- }
- }
- }
- else {
- //(ChangeListCommand::CreateNew)
- //(ChangeListCommand::MergeList)
-
- //if the new/merged list replaced an existing list, the pointer to QTextList in oldList needs updating.
- if ((m_oldList.value(i))) {
- m_oldList.value(i)->updateStoredList(m_blocks.at(i));
- for (int j = 0; j < m_blocks.at(i).textList()->count(); j++) {
- if (m_blocks.at(i).textList()->item(j) != m_blocks.at(i)) {
- QTextBlock currentBlock = m_blocks.at(i).textList()->item(j);
- KoTextBlockData userData(currentBlock);
- userData.setCounterWidth(-1.0);
- break;
- }
- }
- }
- }
-
- QTextBlock currentBlock = m_blocks.at(i);
- KoTextBlockData userData(currentBlock);
- userData.setCounterWidth(-1.0);
- }
-}
-
-bool ChangeListCommand::mergeWith(const KUndo2Command *)
-{
- return false;
-}
diff --git a/plugins/flake/textshape/kotext/commands/ChangeListCommand.h b/plugins/flake/textshape/kotext/commands/ChangeListCommand.h
deleted file mode 100644
index 0aacc97fc4..0000000000
--- a/plugins/flake/textshape/kotext/commands/ChangeListCommand.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- *
- * 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 CHANGELISTCOMMAND
-#define CHANGELISTCOMMAND
-
-#include "KoTextCommandBase.h"
-#include "KoListStyle.h"
-#include "KoTextEditor.h"
-#include "KoListLevelProperties.h"
-
-#include <QTextBlock>
-#include <QList>
-#include <QHash>
-
-class KoList;
-
-/**
- * This command is useful to alter the list-association of a single textBlock.
- */
-class ChangeListCommand : public KoTextCommandBase
-{
-public:
-
- /**
- * Change the list command.
- * @param cursor text cursor properties.
- * @param levelProperties level properties.
- * @param flags the list flags.
- * @param parent the parent undo command for macro functionality
- */
- ChangeListCommand(const QTextCursor &cursor,
- const KoListLevelProperties &levelProperties,
- KoTextEditor::ChangeListFlags flags,
- KUndo2Command *parent = 0);
-
- /**
- * Change the list command.
- * @param cursor text cursor properties.
- * @param style the style to apply.
- * @param level the level in the list.
- * @param flags the list flags.
- * @param parent the parent undo command for macro functionality
- */
- ChangeListCommand(const QTextCursor &cursor, KoListStyle *style, int level,
- KoTextEditor::ChangeListFlags flags,
- KUndo2Command *parent = 0);
- ~ChangeListCommand() override;
-
- /// redo the command
- void redo() override;
- /// revert the actions done in redo
- void undo() override;
-
- /// reimplemented from KUndo2Command
- int id() const override {
- return 58450687;
- }
- /// reimplemented from KUndo2Command
- bool mergeWith(const KUndo2Command *other) override;
-
-private:
- enum CommandAction {
- CreateNew,
- ModifyExisting,
- ReparentList,
- MergeList,
- RemoveList
- };
- bool extractTextBlocks(const QTextCursor &cursor, int level, KoListStyle::Style newStyle = KoListStyle::None);
- int detectLevel(const QTextBlock &block, int givenLevel);
- void initList(KoListStyle *style);
- bool formatsEqual(const KoListLevelProperties &llp, const QTextListFormat &format);
-
- int m_flags;
- bool m_first;
- bool m_alignmentMode;
-
- QList<QTextBlock> m_blocks;
- QHash<int, KoListLevelProperties> m_formerProperties;
- QHash<int, KoListLevelProperties> m_newProperties;
- QHash<int, int> m_levels;
- QHash<int, KoList*> m_list;
- QHash<int, KoList*> m_oldList;
- QHash<int, CommandAction> m_actions;
-};
-
-
-
-#endif
diff --git a/plugins/flake/textshape/kotext/commands/ChangeStylesCommand.cpp b/plugins/flake/textshape/kotext/commands/ChangeStylesCommand.cpp
deleted file mode 100644
index cd68b3180d..0000000000
--- a/plugins/flake/textshape/kotext/commands/ChangeStylesCommand.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (c) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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 "ChangeStylesCommand.h"
-
-#include "KoList.h"
-
-#include <KoStyleManager.h>
-#include <KoCharacterStyle.h>
-#include <KoParagraphStyle.h>
-#include <KoTextDocument.h>
-#include <KoTextEditor.h>
-
-#include <QTextDocument>
-#include <QTextCursor>
-#include <QTextBlock>
-
-ChangeStylesCommand::ChangeStylesCommand(QTextDocument *qDoc
- , const QList<KoCharacterStyle *> &origCharacterStyles
- , const QList<KoParagraphStyle *> &origParagraphStyles
- , const QSet<int> &changedStyles
- , KUndo2Command *parent)
- : KUndo2Command(kundo2_noi18n("stylechangecommand"),parent)
- , m_origCharacterStyles(origCharacterStyles)
- , m_origParagraphStyles(origParagraphStyles)
- , m_changedStyles(changedStyles)
- , m_document(qDoc)
- , m_first(true)
-{
- // TODO optimization strategy; store the formatid of the formats we checked into
- // a qset for 'hits' and 'ignores' and avoid the copying of the format
- // (fragment.charFormat() / block.blockFormat()) when the formatId is
- // already checked previously
-
- KoStyleManager *sm = KoTextDocument(m_document).styleManager();
- QTextCursor cursor(m_document);
- QTextBlock block = cursor.block();
- Memento *memento = new Memento;
-
- while (block.isValid()) {
- memento->blockPosition = block.position();
- memento->blockParentCharFormat = block.charFormat();
- memento->blockParentFormat = KoTextDocument(m_document).frameBlockFormat();
- memento->paragraphStyleId = 0;
-
- if (!memento->blockParentCharFormat.isTableCellFormat()) {
- memento->blockParentCharFormat = KoTextDocument(m_document).frameCharFormat();
- }
-
- bool blockChanged = false;
- int id = block.blockFormat().intProperty(KoParagraphStyle::StyleId);
- if (id > 0 && changedStyles.contains(id)) {
- KoParagraphStyle *style = sm->paragraphStyle(id);
- Q_ASSERT(style);
-
- // Calculate block format of direct formatting.
- memento->blockDirectFormat = block.blockFormat(); // frame + style + direct
- style->applyStyle(memento->blockParentFormat);
- clearCommonProperties(&memento->blockDirectFormat, memento->blockParentFormat);
-
- // Calculate char format of direct formatting.
- memento->blockDirectCharFormat = block.charFormat(); // frame + style + direct
- style->KoCharacterStyle::applyStyle(memento->blockParentCharFormat);
- style->KoCharacterStyle::ensureMinimalProperties(memento->blockParentCharFormat);
- clearCommonProperties(&memento->blockDirectCharFormat, memento->blockParentCharFormat);
-
- memento->paragraphStyleId = id;
- blockChanged = true;
- }
-
- QTextBlock::iterator iter = block.begin();
- while (!iter.atEnd()) {
- QTextFragment fragment = iter.fragment();
- QTextCharFormat cf(fragment.charFormat());
- id = cf.intProperty(KoCharacterStyle::StyleId);
- if (blockChanged || (id > 0 && changedStyles.contains(id))) {
- // create selection
- cursor.setPosition(fragment.position());
- cursor.setPosition(fragment.position() + fragment.length(), QTextCursor::KeepAnchor);
- QTextCharFormat blockCharFormat = block.charFormat(); // with old parstyle applied
-
- KoCharacterStyle *style = sm->characterStyle(id);
- if (style) {
- style->applyStyle(blockCharFormat);
- style->ensureMinimalProperties(blockCharFormat);
- }
-
- clearCommonProperties(&cf, blockCharFormat);
-
- memento->fragmentStyleId.append(id);
- memento->fragmentDirectFormats.append(cf);
- memento->fragmentCursors.append(cursor);
- }
- ++iter;
- }
- if (blockChanged || memento->fragmentCursors.length()) {
- m_mementos.append(memento);
- memento = new Memento;
- }
- block = block.next();
- }
-
- delete memento; // we always have one that is unused
-}
-
-ChangeStylesCommand::~ChangeStylesCommand()
-{
-}
-
-void ChangeStylesCommand::redo()
-{
- KUndo2Command::redo();
-
- if (m_first) {
- m_first = false;
- KoStyleManager *sm = KoTextDocument(m_document).styleManager();
-
- QTextCursor cursor(m_document);
- foreach (Memento *memento, m_mementos) {
-
- cursor.setPosition(memento->blockPosition);
- QTextBlock block = cursor.block();
-
- if (memento->paragraphStyleId > 0) {
- KoParagraphStyle *style = sm->paragraphStyle(memento->paragraphStyleId);
- Q_ASSERT(style);
-
- // apply paragraph style with direct formatting on top.
- style->applyStyle(memento->blockParentFormat);
- memento->blockParentFormat.merge(memento->blockDirectFormat);
- cursor.setBlockFormat(memento->blockParentFormat);
-
- // apply list style formatting
- if (KoTextDocument(m_document).list(block.textList())) {
- if (style->list() == KoTextDocument(m_document).list(block.textList())) {
- style->applyParagraphListStyle(block, memento->blockParentFormat);
- }
- } else {
- style->applyParagraphListStyle(block, memento->blockParentFormat);
- }
-
- // apply character style with direct formatting on top.
- style->KoCharacterStyle::applyStyle(memento->blockParentCharFormat);
- style->KoCharacterStyle::ensureMinimalProperties(memento->blockParentCharFormat);
- memento->blockParentCharFormat.merge(memento->blockDirectCharFormat);
-
- cursor.setBlockCharFormat(memento->blockParentCharFormat);
- }
-
- QList<QTextCharFormat>::Iterator fmtIt = memento->fragmentDirectFormats.begin();
- QList<int>::Iterator idIt = memento->fragmentStyleId.begin();
- Q_FOREACH (QTextCursor fragCursor, memento->fragmentCursors) {
- QTextCharFormat cf(block.charFormat()); // start with block formatting
-
- if (*idIt > 0) {
- KoCharacterStyle *style = sm->characterStyle(*idIt);
- if (style) {
- style->applyStyle(cf); // possibly apply charstyle formatting
- }
- }
-
- cf.merge(*fmtIt); //apply direct formatting
-
- fragCursor.setCharFormat(cf);
-
- ++idIt;
- ++fmtIt;
- }
- }
- qDeleteAll(m_mementos);
- m_mementos.clear();
- }
-}
-
-void ChangeStylesCommand::undo()
-{
- KUndo2Command::undo();
-}
-
-
-void ChangeStylesCommand::clearCommonProperties(QTextFormat *firstFormat, const QTextFormat &secondFormat)
-{
- Q_ASSERT(firstFormat);
- Q_FOREACH (int key, secondFormat.properties().keys()) {
- if (firstFormat->property(key) == secondFormat.property(key)) {
- firstFormat->clearProperty(key);
- }
- }
-}
-
diff --git a/plugins/flake/textshape/kotext/commands/ChangeStylesCommand.h b/plugins/flake/textshape/kotext/commands/ChangeStylesCommand.h
deleted file mode 100644
index 0d781b8229..0000000000
--- a/plugins/flake/textshape/kotext/commands/ChangeStylesCommand.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (c) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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.
- */
-
-#ifndef CHANGESTYLESCOMMAND_H
-#define CHANGESTYLESCOMMAND_H
-
-#include <kundo2command.h>
-
-#include <QList>
-#include <QSet>
-#include <QTextBlockFormat>
-#include <QTextCharFormat>
-
-class KoCharacterStyle;
-class KoParagraphStyle;
-class QTextDocument;
-
-class ChangeStylesCommand : public KUndo2Command
-{
-public:
- ChangeStylesCommand(QTextDocument *qDoc
- , const QList<KoCharacterStyle *> &origCharacterStyles
- , const QList<KoParagraphStyle *> &origParagraphStyles
- , const QSet<int> &changedStyles
- , KUndo2Command *parent);
- ~ChangeStylesCommand() override;
-
- /// redo the command
- void redo() override;
- /// revert the actions done in redo
- void undo() override;
-private:
- /**
- * Helper function for clearing common properties.
- *
- * Clears properties in @a firstFormat that have the same value in @a secondFormat.
- */
- void clearCommonProperties(QTextFormat *firstFormat, const QTextFormat &secondFormat);
-
-private:
- struct Memento // documents all change to the textdocument by a single style change
- {
- QTextDocument *document;
- int blockPosition;
- int paragraphStyleId;
- QTextBlockFormat blockDirectFormat;
- QTextBlockFormat blockParentFormat;
- QTextCharFormat blockDirectCharFormat;
- QTextCharFormat blockParentCharFormat;
- QList<QTextCharFormat> fragmentDirectFormats;
- QList<QTextCursor> fragmentCursors;
- QList<int> fragmentStyleId;
- };
- QList<Memento *> m_mementos;
-
-private:
- QList<KoCharacterStyle *> m_origCharacterStyles;
- QList<KoParagraphStyle *> m_origParagraphStyles;
- QSet<int> m_changedStyles;
- QTextDocument *m_document;
- bool m_first;
-};
-
-#endif // CHANGESTYLESCOMMAND_H
diff --git a/plugins/flake/textshape/kotext/commands/ChangeStylesMacroCommand.cpp b/plugins/flake/textshape/kotext/commands/ChangeStylesMacroCommand.cpp
deleted file mode 100644
index a23e04f345..0000000000
--- a/plugins/flake/textshape/kotext/commands/ChangeStylesMacroCommand.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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 "ChangeStylesMacroCommand.h"
-
-#include "KoStyleManager.h"
-#include "ChangeStylesCommand.h"
-#include "KoCharacterStyle.h"
-#include "KoParagraphStyle.h"
-#include "OdfTextTrackStyles.h"
-
-#include <KoTextDocument.h>
-#include <KoTextEditor.h>
-
-#include <klocalizedstring.h>
-
-#include <QTextDocument>
-
-ChangeStylesMacroCommand::ChangeStylesMacroCommand(const QList<QTextDocument *> &documents
- , KoStyleManager *styleManager)
- : KUndo2Command(kundo2_i18n("Change Styles"))
- , m_documents(documents)
- , m_styleManager(styleManager)
- , m_first(true)
-{
-}
-
-ChangeStylesMacroCommand::~ChangeStylesMacroCommand()
-{
-}
-
-// on first pass the subcommands are created (where they collect needed info)
-// then styles are changed in the styleManager
-// finally the new styles are applied to the documents through super::redo()
-void ChangeStylesMacroCommand::redo()
-{
- QList<ChangeStylesCommand *> commands;
- if (m_first) {
- // IMPORTANT: the sub commands needs to be created now so the can collect
- // info before we change the styles
- Q_FOREACH (QTextDocument *qDoc, m_documents) {
- commands.append(new ChangeStylesCommand(qDoc, m_origCharacterStyles, m_origParagraphStyles, m_changedStyles, this));
- }
- }
-
- // Okay so now it's safe to change the styles and this should always be done
- Q_FOREACH (KoCharacterStyle *newStyle, m_changedCharacterStyles) {
- int id = newStyle->styleId();
- m_styleManager->characterStyle(id)->copyProperties(newStyle);
- }
-
- Q_FOREACH (KoParagraphStyle *newStyle, m_changedParagraphStyles) {
- int id = newStyle->styleId();
- m_styleManager->paragraphStyle(id)->copyProperties(newStyle);
- }
-
- if (m_first) {
- int i = 0;
- Q_FOREACH (QTextDocument *qDoc, m_documents) {
- //add and execute it's redo
- // ToC documents doesn't have a texteditor so make sure we ignore that
- if (KoTextDocument(qDoc).textEditor()) {
- KoTextDocument(qDoc).textEditor()->addCommand(commands[i]);
- }
- i++;
- }
- m_first = false;
- } else {
- KUndo2Command::redo(); // calls redo on all children
- }
-}
-
-void ChangeStylesMacroCommand::undo()
-{
- Q_FOREACH (KoCharacterStyle *oldStyle, m_origCharacterStyles) {
- int id = oldStyle->styleId();
- m_styleManager->characterStyle(id)->copyProperties(oldStyle);
- }
-
- Q_FOREACH (KoParagraphStyle *oldStyle, m_origParagraphStyles) {
- int id = oldStyle->styleId();
- m_styleManager->paragraphStyle(id)->copyProperties(oldStyle);
- }
-
- KUndo2Command::undo(); // calls undo on all children
-}
diff --git a/plugins/flake/textshape/kotext/commands/ChangeStylesMacroCommand.h b/plugins/flake/textshape/kotext/commands/ChangeStylesMacroCommand.h
deleted file mode 100644
index fff43364f6..0000000000
--- a/plugins/flake/textshape/kotext/commands/ChangeStylesMacroCommand.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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.
- */
-
-#ifndef CHANGESTYLESMACROCOMMAND_H
-#define CHANGESTYLESMACROCOMMAND_H
-
-#include <kundo2command.h>
-
-#include <QList>
-#include <QSet>
-
-class QTextDocument;
-class KoCharacterStyle;
-class KoParagraphStyle;
-class KoStyleManager;
-
-class ChangeStylesMacroCommand : public KUndo2Command
-{
-public:
- ChangeStylesMacroCommand(const QList<QTextDocument *> &documents, KoStyleManager *styleManager);
-
- ~ChangeStylesMacroCommand() override;
-
- /// redo the command
- void redo() override;
-
- /// revert the actions done in redo
- void undo() override;
-
- void changedStyle(KoCharacterStyle *s) {m_changedCharacterStyles.append(s);}
- void origStyle(KoCharacterStyle *s) {m_origCharacterStyles.append(s);}
- void changedStyle(KoParagraphStyle *s) {m_changedParagraphStyles.append(s);}
- void origStyle(KoParagraphStyle *s) {m_origParagraphStyles.append(s);}
- void changedStyle(int id) {m_changedStyles.insert(id);}
-
-private:
- QList<QTextDocument *> m_documents;
- QList<KoCharacterStyle *> m_origCharacterStyles;
- QList<KoCharacterStyle *> m_changedCharacterStyles;
- QList<KoParagraphStyle *> m_origParagraphStyles;
- QList<KoParagraphStyle *> m_changedParagraphStyles;
- QSet<int> m_changedStyles;
- KoStyleManager *m_styleManager;
- bool m_first;
-};
-
-#endif // CHANGESTYLESMACROCOMMAND_H
diff --git a/plugins/flake/textshape/kotext/commands/ChangeTrackedDeleteCommand.cpp b/plugins/flake/textshape/kotext/commands/ChangeTrackedDeleteCommand.cpp
deleted file mode 100644
index 50330fed12..0000000000
--- a/plugins/flake/textshape/kotext/commands/ChangeTrackedDeleteCommand.cpp
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2009 Ganesh Paramasivam <ganesh@crystalfab.com>
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2010 Thomas Zander <zander@kde.org>
- *
- * 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 "ChangeTrackedDeleteCommand.h"
-
-#include "TextPasteCommand.h"
-#include "ListItemNumberingCommand.h"
-#include "ChangeListCommand.h"
-
-#include <KoTextEditor.h>
-#include <KoChangeTracker.h>
-#include <KoChangeTrackerElement.h>
-#include <KoTextDocument.h>
-#include <KoInlineTextObjectManager.h>
-#include <KoShapeController.h>
-#include <KoList.h>
-#include <KoParagraphStyle.h>
-#include <KoTextOdfSaveHelper.h>
-#include <KoTextDrag.h>
-#include <KoOdf.h>
-#include <KoDocumentRdfBase.h>
-
-#include <QTextDocumentFragment>
-
-#include <klocalizedstring.h>
-
-#include "TextDebug.h"
-
-//A convenience function to get a ListIdType from a format
-
-static KoListStyle::ListIdType ListId(const QTextListFormat &format)
-{
- KoListStyle::ListIdType listId;
-
- if (sizeof(KoListStyle::ListIdType) == sizeof(uint))
- listId = format.property(KoListStyle::ListId).toUInt();
- else
- listId = format.property(KoListStyle::ListId).toULongLong();
-
- return listId;
-}
-
-using namespace std;
-ChangeTrackedDeleteCommand::ChangeTrackedDeleteCommand(DeleteMode mode,
- QTextDocument *document,
- KoShapeController *shapeController,
- KUndo2Command *parent) :
- KoTextCommandBase (parent),
- m_document(document),
- m_rdf(0),
- m_shapeController(shapeController),
- m_first(true),
- m_undone(false),
- m_canMerge(true),
- m_mode(mode),
- m_removedElements()
-{
- setText(kundo2_i18n("Delete"));
- m_rdf = qobject_cast<KoDocumentRdfBase*>(shapeController->resourceManager()->resource(KoText::DocumentRdf).value<QObject*>());
-}
-
-void ChangeTrackedDeleteCommand::undo()
-{
- if (m_document.isNull()) return;
-
- KoTextCommandBase::undo();
- UndoRedoFinalizer finalizer(this);
-
- KoTextDocument textDocument(m_document.data());
- textDocument.changeTracker()->elementById(m_addedChangeElement)->setValid(false);
- foreach (int changeId, m_removedElements) {
- textDocument.changeTracker()->elementById(changeId)->setValid(true);
- }
- updateListChanges();
- m_undone = true;
-}
-
-void ChangeTrackedDeleteCommand::redo()
-{
- if (!m_document.isNull()) return;
-
- m_undone = false;
- KoTextDocument textDocument(m_document.data());
-
- if (!m_first) {
- KoTextCommandBase::redo();
- UndoRedoFinalizer finalizer(this);
- textDocument.changeTracker()->elementById(m_addedChangeElement)->setValid(true);
- foreach (int changeId, m_removedElements) {
- textDocument.changeTracker()->elementById(changeId)->setValid(false);
- }
- } else {
- m_first = false;
- textDocument.textEditor()->beginEditBlock();
- if(m_mode == PreviousChar)
- deletePreviousChar();
- else
- deleteChar();
- textDocument.textEditor()->endEditBlock();
- }
-}
-
-void ChangeTrackedDeleteCommand::deleteChar()
-{
- if (m_document.isNull()) return;
-
- KoTextEditor *editor = KoTextDocument(m_document).textEditor();
-
- if (editor->atEnd() && !editor->hasSelection())
- return;
-
- if (!editor->hasSelection())
- editor->movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
-
- deleteSelection(editor);
-}
-
-void ChangeTrackedDeleteCommand::deletePreviousChar()
-{
- if (m_document.isNull()) return;
-
- KoTextEditor *editor = KoTextDocument(m_document).textEditor();
-
- if (editor->atStart() && !editor->hasSelection())
- return;
-
- if (!editor->hasSelection()
- && editor->block().textList()
- && (editor->position() == editor->block().position())) {
- handleListItemDelete(editor);
- return;
- }
-
- if (!editor->hasSelection()) {
- editor->movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
- }
- deleteSelection(editor);
-}
-
-void ChangeTrackedDeleteCommand::handleListItemDelete(KoTextEditor *editor)
-{
- if (m_document.isNull()) return;
-
- m_canMerge = false;
- bool numberedListItem = false;
- if (!editor->blockFormat().boolProperty(KoParagraphStyle::UnnumberedListItem))
- numberedListItem = true;
-
- // Mark the complete list-item
- QTextBlock block = m_document.data()->findBlock(editor->position());
- editor->movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, (block.length() - 1));
-
- // Copy the marked item
- int from = editor->anchor();
- int to = editor->position();
- KoTextOdfSaveHelper saveHelper(m_document.data(), from, to);
- KoTextDrag drag;
-#ifdef SHOULD_BUILD_RDF
- if (m_rdf) {
- saveHelper.setRdfModel(m_rdf->model());
- }
-#endif
- drag.setOdf(KoOdf::mimeType(KoOdf::Text), saveHelper);
- QTextDocumentFragment fragment = editor->selection();
- drag.setData("text/html", fragment.toHtml("utf-8").toUtf8());
- drag.setData("text/plain", fragment.toPlainText().toUtf8());
-
- // Delete the marked section
- editor->setPosition(editor->anchor() -1);
- editor->movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, block.length());
- deleteSelection(editor);
- // Mark it as inserted content
- QTextCharFormat format = editor->charFormat();
- editor->registerTrackedChange(*editor->cursor(), KoGenChange::InsertChange, i18n("Key Press"), format, format, false);
- //Paste the selected text from the clipboard... (XXX: is this really correct here?)
- TextPasteCommand *pasteCommand =
- new TextPasteCommand(drag.mimeData(),
- m_document.data(),
- m_shapeController,
- this);
-
- pasteCommand->redo();
-
- // Convert it into a un-numbered list-item or a paragraph
- if (numberedListItem) {
- ListItemNumberingCommand *changeNumberingCommand = new ListItemNumberingCommand(editor->block(), false, this);
- changeNumberingCommand->redo();
- } else {
- KoListLevelProperties llp;
- llp.setStyle(KoListStyle::None);
- llp.setLevel(0);
- ChangeListCommand *changeListCommand = new ChangeListCommand(*editor->cursor(), llp,
- KoTextEditor::ModifyExistingList | KoTextEditor::MergeWithAdjacentList,
- this);
- changeListCommand->redo();
- }
- editor->setPosition(editor->block().position());
-}
-
-void ChangeTrackedDeleteCommand::deleteSelection(KoTextEditor *editor)
-{
- if (m_document.isNull()) return;
-
- // XXX: don't allow anyone to steal our cursor!
- QTextCursor *selection = editor->cursor();
- QTextCursor checker = QTextCursor(*editor->cursor());
-
- bool backwards = (checker.anchor() > checker.position());
- int selectionBegin = qMin(checker.anchor(), checker.position());
- int selectionEnd = qMax(checker.anchor(), checker.position());
- int changeId;
-
- QList<KoShape *> shapesInSelection;
-
- checker.setPosition(selectionBegin);
-
- KoTextDocument textDocument(m_document.data());
- KoInlineTextObjectManager *inlineTextObjectManager = textDocument.inlineTextObjectManager();
-
- while ((checker.position() < selectionEnd) && (!checker.atEnd())) {
- QChar charAtPos = m_document.data()->characterAt(checker.position());
- checker.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
- if (inlineTextObjectManager->inlineTextObject(checker) && charAtPos == QChar::ObjectReplacementCharacter) {
- /* This has changed but since this entire command is going away - let's not bother
- KoTextAnchor *anchor = dynamic_cast<KoTextAnchor *>(inlineTextObjectManager->inlineTextObject(checker));
- if (anchor)
- shapesInSelection.push_back(anchor->shape());
- */
- }
- checker.setPosition(checker.position());
- }
-
- checker.setPosition(selectionBegin);
-
- if (!KoTextDocument(m_document).changeTracker()->displayChanges()) {
- QChar charAtPos = m_document.data()->characterAt(checker.position() - 1);
- }
-
- if (KoTextDocument(m_document).changeTracker()->containsInlineChanges(checker.charFormat())) {
- int changeId = checker.charFormat().property(KoCharacterStyle::ChangeTrackerId).toInt();
- if (KoTextDocument(m_document).changeTracker()->elementById(changeId)->getChangeType() == KoGenChange::DeleteChange) {
- QTextDocumentFragment prefix = KoTextDocument(m_document).changeTracker()->elementById(changeId)->getDeleteData();
- selectionBegin -= (KoChangeTracker::fragmentLength(prefix) + 1 );
- KoTextDocument(m_document).changeTracker()->elementById(changeId)->setValid(false);
- m_removedElements.push_back(changeId);
- }
- }
-
- checker.setPosition(selectionEnd);
- if (!checker.atEnd()) {
- QChar charAtPos = m_document.data()->characterAt(checker.position());
- checker.movePosition(QTextCursor::NextCharacter);
- }
-
- selection->setPosition(selectionBegin);
- selection->setPosition(selectionEnd, QTextCursor::KeepAnchor);
- QTextDocumentFragment deletedFragment;
- changeId = KoTextDocument(m_document).changeTracker()->getDeleteChangeId(i18n("Delete"), deletedFragment, 0);
- KoChangeTrackerElement *element = KoTextDocument(m_document).changeTracker()->elementById(changeId);
-
- QTextCharFormat charFormat;
- charFormat.setProperty(KoCharacterStyle::ChangeTrackerId, changeId);
- selection->mergeCharFormat(charFormat);
-
- deletedFragment = KoChangeTracker::generateDeleteFragment(*selection);
- element->setDeleteData(deletedFragment);
-
- //Store the position and length. Will be used in updateListChanges()
- m_position = (selection->anchor() < selection->position()) ? selection->anchor():selection->position();
- m_length = qAbs(selection->anchor() - selection->position());
-
- updateListIds(*editor->cursor());
-
- m_addedChangeElement = changeId;
-
- //Insert the deleted data again after the marker with the charformat set to the change-id
- if (KoTextDocument(m_document).changeTracker()->displayChanges()) {
- int startPosition = selection->position();
- KoChangeTracker::insertDeleteFragment(*selection);
- QTextCursor tempCursor(*selection);
- tempCursor.setPosition(startPosition);
- tempCursor.setPosition(selection->position(), QTextCursor::KeepAnchor);
- // XXX: why was this commented out?
- //tempCursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, fragmentLength(deletedFragment));
- updateListIds(tempCursor);
- if (backwards) {
- selection->movePosition(QTextCursor::PreviousCharacter, QTextCursor::MoveAnchor, KoChangeTracker::fragmentLength(deletedFragment) + 1);
- }
- } else {
- if (backwards) {
- selection->movePosition(QTextCursor::PreviousCharacter, QTextCursor::MoveAnchor,1);
- }
-
- foreach (KoShape *shape, shapesInSelection) {
- KUndo2Command *shapeDeleteCommand = m_shapeController->removeShape(shape, this);
- shapeDeleteCommand->redo();
- m_canMerge = false;
- }
- }
-}
-
-int ChangeTrackedDeleteCommand::id() const
-{
- return 98765;
-}
-
-bool ChangeTrackedDeleteCommand::mergeWith( const KUndo2Command *command)
-{
- class UndoTextCommand : public KUndo2Command
- {
- public:
- UndoTextCommand(QTextDocument *document, KUndo2Command *parent = 0)
- : KUndo2Command(kundo2_i18n("Text"), parent),
- m_document(document)
- {}
-
- void undo() {
- QTextDocument *doc = const_cast<QTextDocument*>(m_document.data());
- if (doc)
- doc->undo(KoTextDocument(doc).textEditor()->cursor());
- }
-
- void redo() {
- QTextDocument *doc = const_cast<QTextDocument*>(m_document.data());
- if (doc)
- doc->redo(KoTextDocument(doc).textEditor()->cursor());
- }
-
- QWeakPointer<QTextDocument> m_document;
- };
-
- if (command->id() != id())
- return false;
-
- ChangeTrackedDeleteCommand *other = const_cast<ChangeTrackedDeleteCommand *>(static_cast<const ChangeTrackedDeleteCommand *>(command));
-
- if (other->m_canMerge == false)
- return false;
-
- if (other->m_removedElements.contains(m_addedChangeElement)) {
- removeChangeElement(m_addedChangeElement);
- other->m_removedElements.removeAll(m_addedChangeElement);
- m_addedChangeElement = other->m_addedChangeElement;
-
- m_removedElements += other->m_removedElements;
- other->m_removedElements.clear();
-
- m_newListIds = other->m_newListIds;
-
- m_position = other->m_position;
- m_length = other->m_length;
-
- for(int i=0; i < command->childCount(); i++) {
- new UndoTextCommand(m_document.data(), this);
- }
-
- return true;
- }
- return false;
-}
-
-void ChangeTrackedDeleteCommand::updateListIds(QTextCursor &cursor)
-{
- if (m_document.isNull()) return;
-
- m_newListIds.clear();
- QTextCursor tempCursor(m_document.data());
- QTextBlock startBlock = m_document.data()->findBlock(cursor.anchor());
- QTextBlock endBlock = m_document.data()->findBlock(cursor.position());
- QTextList *currentList;
-
- for (QTextBlock currentBlock = startBlock; currentBlock != endBlock.next(); currentBlock = currentBlock.next()) {
- tempCursor.setPosition(currentBlock.position());
- currentList = tempCursor.currentList();
- if (currentList) {
- KoListStyle::ListIdType listId = ListId(currentList->format());
- m_newListIds.push_back(listId);
- }
- }
-}
-void ChangeTrackedDeleteCommand::updateListChanges()
-{
- if (m_document.isNull()) return;
-
- QTextCursor tempCursor(m_document.data());
- QTextBlock startBlock = m_document.data()->findBlock(m_position);
- QTextBlock endBlock = m_document.data()->findBlock(m_position + m_length);
- QTextList *currentList;
- int newListIdsCounter = 0;
-
- for (QTextBlock currentBlock = startBlock; currentBlock != endBlock.next(); currentBlock = currentBlock.next()) {
- tempCursor.setPosition(currentBlock.position());
- currentList = tempCursor.currentList();
- if (currentList) {
- KoListStyle::ListIdType listId = m_newListIds[newListIdsCounter];
- if (!KoTextDocument(m_document).list(currentBlock)) {
- KoList *list = KoTextDocument(m_document).list(listId);
- if (list)
- list->updateStoredList(currentBlock);
- }
- newListIdsCounter++;
- }
- }
-}
-
-ChangeTrackedDeleteCommand::~ChangeTrackedDeleteCommand()
-{
- if (m_undone) {
- removeChangeElement(m_addedChangeElement);
- } else {
- foreach (int changeId, m_removedElements) {
- removeChangeElement(changeId);
- }
- }
-}
-
-void ChangeTrackedDeleteCommand::removeChangeElement(int changeId)
-{
- KoTextDocument textDocument(m_document);
- KoChangeTrackerElement *element = textDocument.changeTracker()->elementById(changeId);
- KoTextDocument(m_document).changeTracker()->removeById(changeId);
-}
diff --git a/plugins/flake/textshape/kotext/commands/ChangeTrackedDeleteCommand.h b/plugins/flake/textshape/kotext/commands/ChangeTrackedDeleteCommand.h
deleted file mode 100644
index 6b64e37ce0..0000000000
--- a/plugins/flake/textshape/kotext/commands/ChangeTrackedDeleteCommand.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2009 Ganesh Paramasivam <ganesh@crystalfab.com>
- *
- * 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 CHANGETRACKEDDELETECOMMAND_H
-#define CHANGETRACKEDDELETECOMMAND_H
-
-#include "KoTextCommandBase.h"
-#include <KoListStyle.h>
-#include <QList>
-#include <QWeakPointer>
-
-class QTextDocument;
-class QTextCursor;
-class KoShapeController;
-class KoDocumentRdfBase;
-class KoTextEditor;
-
-class ChangeTrackedDeleteCommand : public KoTextCommandBase
-{
-public:
- enum DeleteMode {
- PreviousChar,
- NextChar
- };
-
- ChangeTrackedDeleteCommand(DeleteMode mode,
- QTextDocument *document,
- KoShapeController *shapeController,
- KUndo2Command* parent = 0);
- virtual ~ChangeTrackedDeleteCommand();
-
- virtual void undo();
- virtual void redo();
-
- virtual int id() const;
- virtual bool mergeWith ( const KUndo2Command *command);
-
-private:
- QWeakPointer<QTextDocument> m_document;
- KoDocumentRdfBase *m_rdf;
- KoShapeController *m_shapeController;
- bool m_first;
- bool m_undone;
- bool m_canMerge;
- DeleteMode m_mode;
- QList<int> m_removedElements;
- QList<KoListStyle::ListIdType> m_newListIds;
- int m_position, m_length;
- int m_addedChangeElement;
-
- virtual void deleteChar();
- virtual void deletePreviousChar();
- virtual void deleteSelection(KoTextEditor *editor);
- virtual void removeChangeElement(int changeId);
- virtual void updateListIds(QTextCursor &cursor);
- virtual void updateListChanges();
- virtual void handleListItemDelete(KoTextEditor *editor);
-};
-
-#endif // CHANGETRACKEDDELETECOMMAND_H
diff --git a/plugins/flake/textshape/kotext/commands/DeleteAnchorsCommand.cpp b/plugins/flake/textshape/kotext/commands/DeleteAnchorsCommand.cpp
deleted file mode 100644
index 6c370847f3..0000000000
--- a/plugins/flake/textshape/kotext/commands/DeleteAnchorsCommand.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 "DeleteAnchorsCommand.h"
-
-#include <QTextCursor>
-#include "KoAnchorInlineObject.h"
-#include "KoAnchorTextRange.h"
-#include "KoTextDocument.h"
-#include "KoInlineTextObjectManager.h"
-#include "KoTextRangeManager.h"
-
-#include "TextDebug.h"
-
-bool sortAnchor(KoAnchorInlineObject *a1, KoAnchorInlineObject *a2)
-{
- return a1->position() > a2->position();
-}
-
-DeleteAnchorsCommand::DeleteAnchorsCommand(const QList<KoShapeAnchor*> &anchorObjects, QTextDocument *document, KUndo2Command *parent)
-: KUndo2Command(parent)
-, m_document(document)
-, m_first(true)
-, m_deleteAnchors(false)
-{
- foreach (KoShapeAnchor *anchor, anchorObjects) {
- KoAnchorInlineObject *anchorObject = dynamic_cast<KoAnchorInlineObject *>(anchor->textLocation());
- KoAnchorTextRange *anchorRange = dynamic_cast<KoAnchorTextRange *>(anchor->textLocation());
- if (anchorObject && anchorObject->document() == document) {
- m_anchorObjects.append(anchorObject);
- } else if (anchorRange && anchorRange->document() == document) {
- m_anchorRanges.append(anchorRange);
- }
- }
- std::sort(m_anchorObjects.begin(), m_anchorObjects.end(), sortAnchor);
-}
-
-DeleteAnchorsCommand::~DeleteAnchorsCommand()
-{
- if (m_deleteAnchors) {
- qDeleteAll(m_anchorRanges);
- }
-}
-
-void DeleteAnchorsCommand::redo()
-{
- KUndo2Command::redo();
- m_deleteAnchors = true;
- if (m_first) {
- m_first = false;
- foreach (KoAnchorInlineObject *anchorObject, m_anchorObjects) {
- QTextCursor cursor(m_document);
- cursor.setPosition(anchorObject->position());
- cursor.deleteChar();
- }
- }
- KoInlineTextObjectManager *manager = KoTextDocument(m_document).inlineTextObjectManager();
- Q_ASSERT(manager);
- if (manager) {
- foreach (KoAnchorInlineObject *anchorObject, m_anchorObjects) {
- manager->removeInlineObject(anchorObject);
- }
- }
- KoTextRangeManager *rangeManager = KoTextDocument(m_document).textRangeManager();
- if (rangeManager) {
- foreach (KoAnchorTextRange *anchorRange, m_anchorRanges) {
- rangeManager->remove(anchorRange);
- m_document->markContentsDirty(anchorRange->position(), 0);
- }
- }
-}
-
-void DeleteAnchorsCommand::undo()
-{
- KoInlineTextObjectManager *manager = KoTextDocument(m_document).inlineTextObjectManager();
- Q_ASSERT(manager);
- if (manager) {
- foreach (KoAnchorInlineObject *anchorObject, m_anchorObjects) {
- manager->addInlineObject(anchorObject);
- }
- }
- KUndo2Command::undo();
- KoTextRangeManager *rangeManager = KoTextDocument(m_document).textRangeManager();
- if (rangeManager) {
- foreach (KoAnchorTextRange *anchorRange, m_anchorRanges) {
- rangeManager->insert(anchorRange);
- m_document->markContentsDirty(anchorRange->position(), 0);
- }
- }
- m_deleteAnchors = false;
-}
diff --git a/plugins/flake/textshape/kotext/commands/DeleteAnchorsCommand.h b/plugins/flake/textshape/kotext/commands/DeleteAnchorsCommand.h
deleted file mode 100644
index c9ad1a1961..0000000000
--- a/plugins/flake/textshape/kotext/commands/DeleteAnchorsCommand.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 DELETEANCHORSCOMMAND_H
-#define DELETEANCHORSCOMMAND_H
-
-#include <kundo2command.h>
-
-#include <QList>
-
-class QTextDocument;
-class KoShapeAnchor;
-class KoAnchorInlineObject;
-class KoAnchorTextRange;
-
-class DeleteAnchorsCommand : public KUndo2Command
-{
-public:
- DeleteAnchorsCommand(const QList<KoShapeAnchor *> &anchors, QTextDocument *document, KUndo2Command *parent);
- ~DeleteAnchorsCommand() override;
-
- void redo() override;
- void undo() override;
-
-private:
- QList<KoAnchorInlineObject *> m_anchorObjects;
- QList<KoAnchorTextRange *> m_anchorRanges;
- QTextDocument *m_document;
- bool m_first;
- bool m_deleteAnchors;
-};
-
-#endif /* DELETEANCHORSCOMMAND_H */
diff --git a/plugins/flake/textshape/kotext/commands/DeleteAnnotationsCommand.cpp b/plugins/flake/textshape/kotext/commands/DeleteAnnotationsCommand.cpp
deleted file mode 100644
index f95b4e23af..0000000000
--- a/plugins/flake/textshape/kotext/commands/DeleteAnnotationsCommand.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 "DeleteAnnotationsCommand.h"
-
-#include "KoAnnotation.h"
-#include "KoTextDocument.h"
-#include "KoTextRangeManager.h"
-
-#include "TextDebug.h"
-
-DeleteAnnotationsCommand::DeleteAnnotationsCommand(const QList<KoAnnotation *> &annotations, QTextDocument *document, KUndo2Command *parent)
- : KUndo2Command(parent)
- , m_annotations(annotations)
- , m_document(document)
- , m_deleteAnnotations(false)
-{
-}
-
-DeleteAnnotationsCommand::~DeleteAnnotationsCommand()
-{
- if (m_deleteAnnotations) {
- qDeleteAll(m_annotations);
- }
-}
-
-void DeleteAnnotationsCommand::redo()
-{
- KUndo2Command::redo();
- m_deleteAnnotations = true;
- KoTextRangeManager *rangeManager = KoTextDocument(m_document).textRangeManager();
- if (rangeManager) {
- foreach (KoAnnotation *annotation, m_annotations) {
- rangeManager->remove(annotation);
- }
- }
-}
-
-void DeleteAnnotationsCommand::undo()
-{
- KUndo2Command::undo();
- KoTextRangeManager *rangeManager = KoTextDocument(m_document).textRangeManager();
- if (rangeManager) {
- foreach (KoAnnotation *annotation, m_annotations) {
- rangeManager->insert(annotation);
- //it's a textrange so we need to ask for a layout so we know where it is
- m_document->markContentsDirty(annotation->rangeStart(), 0);
- }
- }
-
- m_deleteAnnotations = false;
-}
diff --git a/plugins/flake/textshape/kotext/commands/DeleteAnnotationsCommand.h b/plugins/flake/textshape/kotext/commands/DeleteAnnotationsCommand.h
deleted file mode 100644
index 8d891e4c03..0000000000
--- a/plugins/flake/textshape/kotext/commands/DeleteAnnotationsCommand.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Thorsten Zachmann <zachmann@kde.org>
- *
- * 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 DELETEANNOTATIONSCOMMAND_H
-#define DELETEANNOTATIONSCOMMAND_H
-
-#include <kundo2command.h>
-
-#include <QList>
-
-class QTextDocument;
-class KoAnnotation;
-
-class DeleteAnnotationsCommand : public KUndo2Command
-{
-public:
- DeleteAnnotationsCommand(const QList<KoAnnotation *> &annotations, QTextDocument *document, KUndo2Command *parent);
- ~DeleteAnnotationsCommand() override;
-
- void redo() override;
- void undo() override;
-
-private:
- QList<KoAnnotation *> m_annotations;
- QTextDocument *m_document;
- bool m_deleteAnnotations;
-};
-
-#endif /* DELETEANNOTATIONSCOMMAND_H */
diff --git a/plugins/flake/textshape/kotext/commands/DeleteCommand.cpp b/plugins/flake/textshape/kotext/commands/DeleteCommand.cpp
deleted file mode 100644
index 3a44e2e245..0000000000
--- a/plugins/flake/textshape/kotext/commands/DeleteCommand.cpp
+++ /dev/null
@@ -1,613 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2009 Ganesh Paramasivam <ganesh@crystalfab.com>
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2012 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2014-2015 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 "DeleteCommand.h"
-
-#include <klocalizedstring.h>
-
-#include <KoList.h>
-#include <KoTextEditor.h>
-#include <KoTextEditor_p.h>
-#include <KoTextDocument.h>
-#include <KoInlineTextObjectManager.h>
-#include <KoTextRangeManager.h>
-#include <KoAnchorInlineObject.h>
-#include <KoAnchorTextRange.h>
-#include <KoAnnotation.h>
-#include <KoSection.h>
-#include <KoSectionUtils.h>
-#include <KoSectionModel.h>
-#include <KoSectionEnd.h>
-#include <KoShapeController.h>
-
-bool DeleteCommand::SectionDeleteInfo::operator<(const DeleteCommand::SectionDeleteInfo &other) const
-{
- // At first we remove sections that lays deeper in tree
- // On one level we delete sections by descending order of their childIdx
- // That is needed on undo, cuz we want it to be simply done by inserting
- // sections back in reverse order of their deletion.
- // Without childIdx compare it is possible that we will want to insert
- // section on position 2 while the number of children is less than 2.
-
- if (section->level() != other.section->level()) {
- return section->level() > other.section->level();
- }
- return childIdx > other.childIdx;
-}
-
-DeleteCommand::DeleteCommand(DeleteMode mode,
- QTextDocument *document,
- KoShapeController *shapeController,
- KUndo2Command *parent)
- : KoTextCommandBase (parent)
- , m_document(document)
- , m_shapeController(shapeController)
- , m_first(true)
- , m_mode(mode)
- , m_mergePossible(true)
-{
- setText(kundo2_i18n("Delete"));
-}
-
-void DeleteCommand::undo()
-{
- KoTextCommandBase::undo();
- UndoRedoFinalizer finalizer(this); // Look at KoTextCommandBase documentation
-
- // KoList
- updateListChanges();
-
- // KoTextRange
- KoTextRangeManager *rangeManager = KoTextDocument(m_document).textRangeManager();
- foreach (KoTextRange *range, m_rangesToRemove) {
- rangeManager->insert(range);
- }
-
- // KoInlineObject
- foreach (KoInlineObject *object, m_invalidInlineObjects) {
- object->manager()->addInlineObject(object);
- }
-
- // KoSectionModel
- insertSectionsToModel();
-}
-
-void DeleteCommand::redo()
-{
- if (!m_first) {
- KoTextCommandBase::redo();
- UndoRedoFinalizer finalizer(this); // Look at KoTextCommandBase documentation
-
- // KoTextRange
- KoTextRangeManager *rangeManager = KoTextDocument(m_document).textRangeManager();
- foreach (KoTextRange *range, m_rangesToRemove) {
- rangeManager->remove(range);
- }
-
- // KoSectionModel
- deleteSectionsFromModel();
-
- // TODO: there is nothing for InlineObjects and Lists. Is it OK?
- } else {
- m_first = false;
- if (m_document) {
- KoTextEditor *textEditor = KoTextDocument(m_document).textEditor();
- if (textEditor) {
- textEditor->beginEditBlock();
- doDelete();
- textEditor->endEditBlock();
- }
- }
- }
-}
-
-// Section handling algorithm:
-// At first, we go though the all section starts and ends
-// that are in selection, and delete all pairs, because
-// they will be deleted.
-// Then we have multiple cases: selection start split some block
-// or don't split any block.
-// In the first case all formatting info will be stored in the
-// split block(it has startBlockNum number).
-// In the second case it will be stored in the block pointed by the
-// selection end(it has endBlockNum number).
-// Also there is a trivial case, when whole selection is inside
-// one block, in this case hasEntirelyInsideBlock will be false
-// and we will do nothing.
-
-class DeleteVisitor : public KoTextVisitor
-{
-public:
- DeleteVisitor(KoTextEditor *editor, DeleteCommand *command)
- : KoTextVisitor(editor)
- , m_first(true)
- , m_command(command)
- , m_startBlockNum(-1)
- , m_endBlockNum(-1)
- , m_hasEntirelyInsideBlock(false)
- {
- }
-
- void visitBlock(QTextBlock &block, const QTextCursor &caret) override
- {
- for (QTextBlock::iterator it = block.begin(); it != block.end(); ++it) {
- QTextCursor fragmentSelection(caret);
- fragmentSelection.setPosition(qMax(caret.selectionStart(), it.fragment().position()));
- fragmentSelection.setPosition(
- qMin(caret.selectionEnd(), it.fragment().position() + it.fragment().length()),
- QTextCursor::KeepAnchor
- );
-
- if (fragmentSelection.anchor() >= fragmentSelection.position()) {
- continue;
- }
-
- visitFragmentSelection(fragmentSelection);
- }
-
- // Section handling below
- bool doesBeginInside = false;
- bool doesEndInside = false;
- if (block.position() >= caret.selectionStart()) { // Begin of the block is inside selection.
- doesBeginInside = true;
- QList<KoSection *> openList = KoSectionUtils::sectionStartings(block.blockFormat());
- foreach (KoSection *sec, openList) {
- m_curSectionDelimiters.push_back(SectionHandle(sec->name(), sec));
- }
- }
-
- if (block.position() + block.length() <= caret.selectionEnd()) { // End of the block is inside selection.
- doesEndInside = true;
- QList<KoSectionEnd *> closeList = KoSectionUtils::sectionEndings(block.blockFormat());
- foreach (KoSectionEnd *se, closeList) {
- if (!m_curSectionDelimiters.empty() && m_curSectionDelimiters.last().name == se->name()) {
- KoSection *section = se->correspondingSection();
- int childIdx = KoTextDocument(m_command->m_document).sectionModel()
- ->findRowOfChild(section);
-
- m_command->m_sectionsToRemove.push_back(
- DeleteCommand::SectionDeleteInfo(
- section,
- childIdx
- )
- );
- m_curSectionDelimiters.pop_back(); // This section will die
- } else {
- m_curSectionDelimiters.push_back(SectionHandle(se->name(), se));
- }
- }
- }
-
- if (!doesBeginInside && doesEndInside) {
- m_startBlockNum = block.blockNumber();
- } else if (doesBeginInside && !doesEndInside) {
- m_endBlockNum = block.blockNumber();
- } else if (doesBeginInside && doesEndInside) {
- m_hasEntirelyInsideBlock = true;
- }
- }
-
- void visitFragmentSelection(QTextCursor &fragmentSelection) override
- {
- if (m_first) {
- m_firstFormat = fragmentSelection.charFormat();
- m_first = false;
- }
-
- if (m_command->m_mergePossible && fragmentSelection.charFormat() != m_firstFormat) {
- m_command->m_mergePossible = false;
- }
-
- // Handling InlineObjects below
- KoTextDocument textDocument(fragmentSelection.document());
- KoInlineTextObjectManager *manager = textDocument.inlineTextObjectManager();
-
- QString selected = fragmentSelection.selectedText();
- fragmentSelection.setPosition(fragmentSelection.selectionStart() + 1);
- int position = fragmentSelection.position();
- const QChar *data = selected.constData();
- for (int i = 0; i < selected.length(); i++) {
- if (data->unicode() == QChar::ObjectReplacementCharacter) {
- fragmentSelection.setPosition(position + i);
- KoInlineObject *object = manager->inlineTextObject(fragmentSelection);
- m_command->m_invalidInlineObjects.insert(object);
- }
- data++;
- }
- }
-
- enum SectionHandleAction
- {
- SectionClose, ///< Denotes close of the section.
- SectionOpen ///< Denotes start or beginning of the section.
- };
-
- /// Helper struct for handling sections.
- struct SectionHandle {
- QString name; ///< Name of the section.
- SectionHandleAction type; ///< Action of a SectionHandle.
-
- KoSection *dataSec; ///< Pointer to KoSection.
- KoSectionEnd *dataSecEnd; ///< Pointer to KoSectionEnd.
-
- SectionHandle(QString _name, KoSection *_data)
- : name(_name)
- , type(SectionOpen)
- , dataSec(_data)
- , dataSecEnd(0)
- {
- }
-
- SectionHandle(QString _name, KoSectionEnd *_data)
- : name(_name)
- , type(SectionClose)
- , dataSec(0)
- , dataSecEnd(_data)
- {
- }
- };
-
- bool m_first;
- DeleteCommand *m_command;
- QTextCharFormat m_firstFormat;
- int m_startBlockNum;
- int m_endBlockNum;
- bool m_hasEntirelyInsideBlock;
- QList<SectionHandle> m_curSectionDelimiters;
-};
-
-void DeleteCommand::finalizeSectionHandling(QTextCursor *cur, DeleteVisitor &v)
-{
- // Lets handle pointers from block formats first
- // It means that selection isn't within one block.
- if (v.m_hasEntirelyInsideBlock || v.m_startBlockNum != -1 || v.m_endBlockNum != -1) {
- QList<KoSection *> openList;
- QList<KoSectionEnd *> closeList;
- foreach (const DeleteVisitor::SectionHandle &handle, v.m_curSectionDelimiters) {
- if (handle.type == v.SectionOpen) { // Start of the section.
- openList << handle.dataSec;
- } else { // End of the section.
- closeList << handle.dataSecEnd;
- }
- }
-
- // We're expanding ends in affected blocks to the end of the start block,
- // delete all sections, that are entirely in affected blocks,
- // and move ends, we have, to the begin of the next after the end block.
- if (v.m_startBlockNum != -1) {
- QTextBlockFormat fmt = cur->document()->findBlockByNumber(v.m_startBlockNum).blockFormat();
- QTextBlockFormat fmt2 = cur->document()->findBlockByNumber(v.m_endBlockNum + 1).blockFormat();
- fmt.clearProperty(KoParagraphStyle::SectionEndings);
-
- // m_endBlockNum != -1 in this case.
- QList<KoSectionEnd *> closeListEndBlock = KoSectionUtils::sectionEndings(
- cur->document()->findBlockByNumber(v.m_endBlockNum).blockFormat());
-
- while (!openList.empty() && !closeListEndBlock.empty()
- && openList.last()->name() == closeListEndBlock.first()->name()) {
-
- int childIdx = KoTextDocument(m_document)
- .sectionModel()->findRowOfChild(openList.back());
- m_sectionsToRemove.push_back(
- DeleteCommand::SectionDeleteInfo(
- openList.back(),
- childIdx
- )
- );
-
- openList.pop_back();
- closeListEndBlock.pop_front();
- }
- openList << KoSectionUtils::sectionStartings(fmt2);
- closeList << closeListEndBlock;
-
- // We leave open section of start block untouched.
- KoSectionUtils::setSectionStartings(fmt2, openList);
- KoSectionUtils::setSectionEndings(fmt, closeList);
-
- QTextCursor changer = *cur;
- changer.setPosition(cur->document()->findBlockByNumber(v.m_startBlockNum).position());
- changer.setBlockFormat(fmt);
- if (v.m_endBlockNum + 1 < cur->document()->blockCount()) {
- changer.setPosition(cur->document()->findBlockByNumber(v.m_endBlockNum + 1).position());
- changer.setBlockFormat(fmt2);
- }
- } else { // v.m_startBlockNum == -1
- // v.m_endBlockNum != -1 in this case.
- // We're pushing all new section info to the end block.
- QTextBlockFormat fmt = cur->document()->findBlockByNumber(v.m_endBlockNum).blockFormat();
- QList<KoSection *> allStartings = KoSectionUtils::sectionStartings(fmt);
- fmt.clearProperty(KoParagraphStyle::SectionStartings);
-
- QList<KoSectionEnd *> pairedEndings;
- QList<KoSectionEnd *> unpairedEndings;
-
- foreach (KoSectionEnd *se, KoSectionUtils::sectionEndings(fmt)) {
- KoSection *sec = se->correspondingSection();
-
- if (allStartings.contains(sec)) {
- pairedEndings << se;
- } else {
- unpairedEndings << se;
- }
- }
-
- if (cur->selectionStart()) {
- QTextCursor changer = *cur;
- changer.setPosition(cur->selectionStart() - 1);
-
- QTextBlockFormat prevFmt = changer.blockFormat();
- QList<KoSectionEnd *> prevEndings = KoSectionUtils::sectionEndings(prevFmt);
-
- prevEndings = prevEndings + closeList;
-
- KoSectionUtils::setSectionEndings(prevFmt, prevEndings);
- changer.setBlockFormat(prevFmt);
- }
-
- KoSectionUtils::setSectionStartings(fmt, openList);
- KoSectionUtils::setSectionEndings(fmt, pairedEndings + unpairedEndings);
-
- QTextCursor changer = *cur;
- changer.setPosition(cur->document()->findBlockByNumber(v.m_endBlockNum).position());
- changer.setBlockFormat(fmt);
- }
- }
-
- // Now lets deal with KoSectionModel
- std::sort(m_sectionsToRemove.begin(), m_sectionsToRemove.end());
- deleteSectionsFromModel();
-}
-
-void DeleteCommand::deleteSectionsFromModel()
-{
- KoSectionModel *model = KoTextDocument(m_document).sectionModel();
- foreach (const SectionDeleteInfo &info, m_sectionsToRemove) {
- model->deleteFromModel(info.section);
- }
-}
-
-void DeleteCommand::insertSectionsToModel()
-{
- KoSectionModel *model = KoTextDocument(m_document).sectionModel();
- QList<SectionDeleteInfo>::iterator it = m_sectionsToRemove.end();
- while (it != m_sectionsToRemove.begin()) {
- it--;
- model->insertToModel(it->section, it->childIdx);
- }
-}
-
-void DeleteCommand::doDelete()
-{
- KoTextEditor *textEditor = KoTextDocument(m_document).textEditor();
- Q_ASSERT(textEditor);
- QTextCursor *caret = textEditor->cursor();
- QTextCharFormat charFormat = caret->charFormat();
- bool caretAtBeginOfBlock = (caret->position() == caret->block().position());
-
- if (!textEditor->hasSelection()) {
- if (m_mode == PreviousChar) {
- caret->movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
- } else {
- caret->movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
- }
- }
-
- DeleteVisitor visitor(textEditor, this);
- textEditor->recursivelyVisitSelection(m_document.data()->rootFrame()->begin(), visitor);
-
- // Sections Model
- finalizeSectionHandling(caret, visitor); // Finalize section handling routine.
-
- // InlineObjects
- foreach (KoInlineObject *object, m_invalidInlineObjects) {
- deleteInlineObject(object);
- }
-
- // Ranges
- KoTextRangeManager *rangeManager = KoTextDocument(m_document).textRangeManager();
-
- m_rangesToRemove = rangeManager->textRangesChangingWithin(
- textEditor->document(),
- textEditor->selectionStart(),
- textEditor->selectionEnd(),
- textEditor->selectionStart(),
- textEditor->selectionEnd()
- );
-
- foreach (KoTextRange *range, m_rangesToRemove) {
- KoAnchorTextRange *anchorRange = dynamic_cast<KoAnchorTextRange *>(range);
- KoAnnotation *annotation = dynamic_cast<KoAnnotation *>(range);
- if (anchorRange) {
- // we should only delete the anchor if the selection is covering it... not if the selection is
- // just adjacent to the anchor. This is more in line with what other wordprocessors do
- if (anchorRange->position() != textEditor->selectionStart()
- && anchorRange->position() != textEditor->selectionEnd()) {
- KoShape *shape = anchorRange->anchor()->shape();
- if (m_shapeController) {
- KUndo2Command *shapeDeleteCommand = m_shapeController->removeShape(shape, this);
- shapeDeleteCommand->redo();
- }
- // via m_shapeController->removeShape a DeleteAnchorsCommand should be created that
- // also calls rangeManager->remove(range), so we shouldn't do that here as well
- }
- } else if (annotation) {
- KoShape *shape = annotation->annotationShape();
- if (m_shapeController) {
- KUndo2Command *shapeDeleteCommand = m_shapeController->removeShape(shape, this);
- shapeDeleteCommand->redo();
- }
- // via m_shapeController->removeShape a DeleteAnnotationsCommand should be created that
- // also calls rangeManager->remove(range), so we shouldn't do that here as well
- } else {
- rangeManager->remove(range);
- }
- }
-
- // Check: is merge possible?
- if (textEditor->hasComplexSelection()) {
- m_mergePossible = false;
- }
-
- //FIXME: lets forbid merging of "section affecting" deletions by now
- if (!m_sectionsToRemove.empty()) {
- m_mergePossible = false;
- }
-
- if (m_mergePossible) {
- // Store various info needed for checkMerge
- m_format = textEditor->charFormat();
- m_position = textEditor->selectionStart();
- m_length = textEditor->selectionEnd() - textEditor->selectionStart();
- }
-
- // Actual deletion of text
- caret->deleteChar();
-
- if (m_mode != PreviousChar || !caretAtBeginOfBlock) {
- caret->setCharFormat(charFormat);
- }
-}
-
-void DeleteCommand::deleteInlineObject(KoInlineObject *object)
-{
- if (object) {
- KoAnchorInlineObject *anchorObject = dynamic_cast<KoAnchorInlineObject *>(object);
- if (anchorObject) {
- KoShape *shape = anchorObject->anchor()->shape();
- KUndo2Command *shapeDeleteCommand = m_shapeController->removeShape(shape, this);
- shapeDeleteCommand->redo();
- } else {
- object->manager()->removeInlineObject(object);
- }
- }
-}
-
-int DeleteCommand::id() const
-{
- // Should be an enum declared somewhere. KoTextCommandBase.h ???
- return 56789;
-}
-
-bool DeleteCommand::mergeWith(const KUndo2Command *command)
-{
- class UndoTextCommand : public KUndo2Command
- {
- public:
- UndoTextCommand(QTextDocument *document, KUndo2Command *parent = 0)
- : KUndo2Command(kundo2_i18n("Text"), parent),
- m_document(document)
- {}
-
- void undo() override {
- QTextDocument *doc = m_document.data();
- if (doc)
- doc->undo(KoTextDocument(doc).textEditor()->cursor());
- }
-
- void redo() override {
- QTextDocument *doc = m_document.data();
- if (doc)
- doc->redo(KoTextDocument(doc).textEditor()->cursor());
- }
-
- QWeakPointer<QTextDocument> m_document;
- };
-
- KoTextEditor *textEditor = KoTextDocument(m_document).textEditor();
- if (textEditor == 0)
- return false;
-
- if (command->id() != id())
- return false;
-
- if (!checkMerge(command))
- return false;
-
- DeleteCommand *other = const_cast<DeleteCommand *>(static_cast<const DeleteCommand *>(command));
-
- m_invalidInlineObjects += other->m_invalidInlineObjects;
- other->m_invalidInlineObjects.clear();
-
- for (int i=0; i < command->childCount(); i++)
- new UndoTextCommand(const_cast<QTextDocument*>(textEditor->document()), this);
-
- return true;
-}
-
-bool DeleteCommand::checkMerge(const KUndo2Command *command)
-{
- DeleteCommand *other = const_cast<DeleteCommand *>(static_cast<const DeleteCommand *>(command));
-
- if (!(m_mergePossible && other->m_mergePossible))
- return false;
-
- if (m_position == other->m_position && m_format == other->m_format) {
- m_length += other->m_length;
- return true;
- }
-
- if ((other->m_position + other->m_length == m_position)
- && (m_format == other->m_format)) {
- m_position = other->m_position;
- m_length += other->m_length;
- return true;
- }
- return false;
-}
-
-void DeleteCommand::updateListChanges()
-{
- KoTextEditor *textEditor = KoTextDocument(m_document).textEditor();
- if (textEditor == 0)
- return;
- QTextDocument *document = const_cast<QTextDocument*>(textEditor->document());
- QTextCursor tempCursor(document);
- QTextBlock startBlock = document->findBlock(m_position);
- QTextBlock endBlock = document->findBlock(m_position + m_length);
- if (endBlock != document->end())
- endBlock = endBlock.next();
- QTextList *currentList;
-
- for (QTextBlock currentBlock = startBlock; currentBlock != endBlock; currentBlock = currentBlock.next()) {
- tempCursor.setPosition(currentBlock.position());
- currentList = tempCursor.currentList();
- if (currentList) {
- KoListStyle::ListIdType listId;
- if (sizeof(KoListStyle::ListIdType) == sizeof(uint))
- listId = currentList->format().property(KoListStyle::ListId).toUInt();
- else
- listId = currentList->format().property(KoListStyle::ListId).toULongLong();
-
- if (!KoTextDocument(document).list(currentBlock)) {
- KoList *list = KoTextDocument(document).list(listId);
- if (list) {
- list->updateStoredList(currentBlock);
- }
- }
- }
- }
-}
-
-DeleteCommand::~DeleteCommand()
-{
-}
diff --git a/plugins/flake/textshape/kotext/commands/DeleteCommand.h b/plugins/flake/textshape/kotext/commands/DeleteCommand.h
deleted file mode 100644
index b1fb0cd25e..0000000000
--- a/plugins/flake/textshape/kotext/commands/DeleteCommand.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2009 Ganesh Paramasivam <ganesh@crystalfab.com>
- * Copyright (C) 2012 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2014-2015 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 DELETECOMMAND_H
-#define DELETECOMMAND_H
-
-#include "KoTextCommandBase.h"
-
-#include <QTextCharFormat>
-#include <QHash>
-#include <QSet>
-#include <QWeakPointer>
-
-class QTextDocument;
-
-class KoShapeController;
-class KoInlineObject;
-class KoTextRange;
-class KoSection;
-
-class DeleteVisitor;
-
-class DeleteCommand : public KoTextCommandBase
-{
-public:
- enum DeleteMode {
- PreviousChar,
- NextChar
- };
-
- DeleteCommand(DeleteMode mode, QTextDocument *document, KoShapeController *shapeController, KUndo2Command* parent = 0);
- ~DeleteCommand() override;
-
- void undo() override;
- void redo() override;
-
- int id() const override;
- bool mergeWith(const KUndo2Command *command) override;
-
-private:
- friend class DeleteVisitor;
-
- struct SectionDeleteInfo {
- SectionDeleteInfo(KoSection *_section, int _childIdx)
- : section(_section)
- , childIdx(_childIdx)
- {
- }
-
- bool operator<(const SectionDeleteInfo &other) const;
-
- KoSection *section; ///< Section to remove
- int childIdx; ///< Position of section in parent's children() list
- };
-
- QWeakPointer<QTextDocument> m_document;
- KoShapeController *m_shapeController;
-
- QSet<KoInlineObject *> m_invalidInlineObjects;
- QList<QTextCursor> m_cursorsToWholeDeleteBlocks;
- QHash<int, KoTextRange *> m_rangesToRemove;
- QList<SectionDeleteInfo> m_sectionsToRemove;
-
- bool m_first;
- DeleteMode m_mode;
- int m_position;
- int m_length;
- QTextCharFormat m_format;
- bool m_mergePossible;
-
- void doDelete();
- void deleteInlineObject(KoInlineObject *object);
- bool checkMerge(const KUndo2Command *command);
- void updateListChanges();
- void finalizeSectionHandling(QTextCursor *caret, DeleteVisitor &visitor);
- void deleteSectionsFromModel();
- void insertSectionsToModel();
-};
-
-#endif // DELETECOMMAND_H
diff --git a/plugins/flake/textshape/kotext/commands/DeleteTableColumnCommand.cpp b/plugins/flake/textshape/kotext/commands/DeleteTableColumnCommand.cpp
deleted file mode 100644
index eae206ffec..0000000000
--- a/plugins/flake/textshape/kotext/commands/DeleteTableColumnCommand.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2010 C. Boemann <cbo@boemann.dk>
- *
- * 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 "DeleteTableColumnCommand.h"
-
-#include <KoTextEditor.h>
-#include "KoTableColumnAndRowStyleManager.h"
-
-#include <QTextTableCell>
-#include <QTextTable>
-
-#include <klocalizedstring.h>
-#include "TextDebug.h"
-
-DeleteTableColumnCommand::DeleteTableColumnCommand(KoTextEditor *te, QTextTable *t, KUndo2Command *parent)
- : KUndo2Command (parent)
- ,m_first(true)
- ,m_textEditor(te)
- ,m_table(t)
-{
- setText(kundo2_i18n("Delete Column"));
-}
-
-void DeleteTableColumnCommand::undo()
-{
- KoTableColumnAndRowStyleManager carsManager = KoTableColumnAndRowStyleManager::getManager(m_table);
- for (int i = 0; i < m_selectionColumnSpan; ++i) {
- carsManager.insertColumns(m_selectionColumn + i, 1, m_deletedStyles.at(i));
- }
-
- KUndo2Command::undo();
-}
-
-void DeleteTableColumnCommand::redo()
-{
- KoTableColumnAndRowStyleManager carsManager = KoTableColumnAndRowStyleManager::getManager(m_table);
- if (!m_first) {
- carsManager.removeColumns(m_selectionColumn, m_selectionColumnSpan);
- KUndo2Command::redo();
- } else {
- m_first = false;
- int selectionRow;
- int selectionRowSpan;
- if(m_textEditor->hasComplexSelection()) {
- m_textEditor->cursor()->selectedTableCells(&selectionRow, &selectionRowSpan, &m_selectionColumn, &m_selectionColumnSpan);
- } else {
- QTextTableCell cell = m_table->cellAt(*m_textEditor->cursor());
- m_selectionColumn = cell.column();
- m_selectionColumnSpan = 1;
- }
-
- m_table->removeColumns(m_selectionColumn, m_selectionColumnSpan);
-
- for (int i = m_selectionColumn; i < m_selectionColumn + m_selectionColumnSpan; ++i) {
- m_deletedStyles.append(carsManager.columnStyle(i));
- }
- carsManager.removeColumns(m_selectionColumn, m_selectionColumnSpan);
- }
-}
diff --git a/plugins/flake/textshape/kotext/commands/DeleteTableColumnCommand.h b/plugins/flake/textshape/kotext/commands/DeleteTableColumnCommand.h
deleted file mode 100644
index c11193d82a..0000000000
--- a/plugins/flake/textshape/kotext/commands/DeleteTableColumnCommand.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2010 C. Boemann <cbo@boemann.dk>
- *
- * 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 DELETETABLECOLUMNCOMMAND_H
-#define DELETETABLECOLUMNCOMMAND_H
-
-#include <kundo2command.h>
-#include <QList>
-#include <KoTableColumnStyle.h>
-
-class KoTextEditor;
-class QTextTable;
-
-class DeleteTableColumnCommand : public KUndo2Command
-{
-public:
-
- DeleteTableColumnCommand(KoTextEditor *te, QTextTable *t, KUndo2Command *parent = 0);
-
- void undo() override;
- void redo() override;
-
-private:
- bool m_first;
- KoTextEditor *m_textEditor;
- QTextTable *m_table;
- int m_selectionColumn;
- int m_selectionColumnSpan;
- QList<KoTableColumnStyle> m_deletedStyles;
-};
-
-#endif // DELETETABLEROWCOMMAND_H
diff --git a/plugins/flake/textshape/kotext/commands/DeleteTableRowCommand.cpp b/plugins/flake/textshape/kotext/commands/DeleteTableRowCommand.cpp
deleted file mode 100644
index b9d98d7099..0000000000
--- a/plugins/flake/textshape/kotext/commands/DeleteTableRowCommand.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2010 C. Boemann <cbo@boemann.dk>
- *
- * 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 "DeleteTableRowCommand.h"
-
-#include <KoTextEditor.h>
-#include "KoTableColumnAndRowStyleManager.h"
-
-#include <QTextTableCell>
-#include <QTextTable>
-
-#include <klocalizedstring.h>
-#include "TextDebug.h"
-
-DeleteTableRowCommand::DeleteTableRowCommand(KoTextEditor *te, QTextTable *t, KUndo2Command *parent) :
- KUndo2Command (parent)
- ,m_first(true)
- ,m_textEditor(te)
- ,m_table(t)
-{
- setText(kundo2_i18n("Delete Row"));
-}
-
-void DeleteTableRowCommand::undo()
-{
- KoTableColumnAndRowStyleManager carsManager = KoTableColumnAndRowStyleManager::getManager(m_table);
- for (int i = 0; i < m_selectionRowSpan; ++i) {
- carsManager.insertRows(m_selectionRow + i, 1, m_deletedStyles.at(i));
- }
- KUndo2Command::undo();
-}
-
-void DeleteTableRowCommand::redo()
-{
- KoTableColumnAndRowStyleManager carsManager = KoTableColumnAndRowStyleManager::getManager(m_table);
- if (!m_first) { carsManager.removeRows(m_selectionRow, m_selectionRowSpan);
- KUndo2Command::redo();
- } else {
- m_first = false;
- int selectionColumn;
- int selectionColumnSpan;
- if(m_textEditor->hasComplexSelection()) {
- m_textEditor->cursor()->selectedTableCells(&m_selectionRow, &m_selectionRowSpan, &selectionColumn, &selectionColumnSpan);
- } else {
- QTextTableCell cell = m_table->cellAt(*m_textEditor->cursor());
- m_selectionRow = cell.row();
- m_selectionRowSpan = 1;
- }
-
- for (int i = m_selectionRow; i < m_selectionRow + m_selectionRowSpan; ++i) {
- m_deletedStyles.append(carsManager.rowStyle(i));
- }
- carsManager.removeRows(m_selectionRow, m_selectionRowSpan);
-
- m_table->removeRows(m_selectionRow, m_selectionRowSpan);
- }
-}
diff --git a/plugins/flake/textshape/kotext/commands/DeleteTableRowCommand.h b/plugins/flake/textshape/kotext/commands/DeleteTableRowCommand.h
deleted file mode 100644
index 05892efdd5..0000000000
--- a/plugins/flake/textshape/kotext/commands/DeleteTableRowCommand.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2010 C. Boemann <cbo@boemann.dk>
- *
- * 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 DELETETABLEROWCOMMAND_H
-#define DELETETABLEROWCOMMAND_H
-
-#include <kundo2command.h>
-#include <QList>
-#include <KoTableRowStyle.h>
-
-class KoTextEditor;
-class QTextTable;
-
-class DeleteTableRowCommand : public KUndo2Command
-{
-public:
-
- DeleteTableRowCommand(KoTextEditor *te, QTextTable *t, KUndo2Command *parent = 0);
-
- void undo() override;
- void redo() override;
-
-private:
- bool m_first;
- KoTextEditor *m_textEditor;
- QTextTable *m_table;
- int m_selectionRow;
- int m_selectionRowSpan;
- QList<KoTableRowStyle> m_deletedStyles;
-};
-
-#endif // DELETETABLEROWCOMMAND_H
diff --git a/plugins/flake/textshape/kotext/commands/InsertDeleteChangesCommand.cpp b/plugins/flake/textshape/kotext/commands/InsertDeleteChangesCommand.cpp
deleted file mode 100644
index f1512cae9b..0000000000
--- a/plugins/flake/textshape/kotext/commands/InsertDeleteChangesCommand.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2011 C. Boemann <cbo@boemann.dk>
- *
- * 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 "InsertDeleteChangesCommand.h"
-
-#include "KoChangeTrackerElement.h"
-#include <KoTextDocument.h>
-#include <KoChangeTracker.h>
-
-#include <QVector>
-#include <QTextDocument>
-
-
-InsertDeleteChangesCommand::InsertDeleteChangesCommand(QTextDocument *document, KUndo2Command *parent)
- : KUndo2Command("Insert Delete Changes", parent)
- , m_document(document)
-{
-}
-
-void InsertDeleteChangesCommand::redo()
-{
- insertDeleteChanges();
-}
-
-
-void InsertDeleteChangesCommand::insertDeleteChanges()
-{
- int numAddedChars = 0;
- QVector<KoChangeTrackerElement *> elementVector;
- KoTextDocument(m_document).changeTracker()->getDeletedChanges(elementVector);
- qSort(elementVector.begin(), elementVector.end());
-
-
-}
diff --git a/plugins/flake/textshape/kotext/commands/InsertDeleteChangesCommand.h b/plugins/flake/textshape/kotext/commands/InsertDeleteChangesCommand.h
deleted file mode 100644
index dec6aac3b4..0000000000
--- a/plugins/flake/textshape/kotext/commands/InsertDeleteChangesCommand.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2011 C. Boemann <cbo@boemann.dk>
- *
- * 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.
- */
-
-#ifndef INSERTDELETECHANGESCOMMAND_H
-#define INSERTDELETECHANGESCOMMAND_H
-
-#include <kundo2command.h>
-#include <QWeakPointer>
-
-class QTextDocument;
-
-class InsertDeleteChangesCommand : public KUndo2Command
-{
-public:
- explicit InsertDeleteChangesCommand(QTextDocument *document, KUndo2Command *parent = 0);
- void redo();
-
-private:
- QWeakPointer<QTextDocument> m_document;
- void insertDeleteChanges();
-};
-
-
-#endif // INSERTDELETECHANGESCOMMAND_H
diff --git a/plugins/flake/textshape/kotext/commands/InsertInlineObjectCommand.cpp b/plugins/flake/textshape/kotext/commands/InsertInlineObjectCommand.cpp
deleted file mode 100644
index 9db38e695b..0000000000
--- a/plugins/flake/textshape/kotext/commands/InsertInlineObjectCommand.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2011 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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 "InsertInlineObjectCommand.h"
-
-#include "KoTextEditor.h"
-#include "KoTextDocument.h"
-#include "KoInlineTextObjectManager.h"
-#include "KoInlineObject.h"
-
-InsertInlineObjectCommand::InsertInlineObjectCommand(KoInlineObject *inlineObject, QTextDocument *document, KUndo2Command *parent)
- : KUndo2Command(parent)
- , m_inlineObject(inlineObject)
- , m_document(document)
- , m_first(true)
- , m_position(-1)
-{
-}
-
-InsertInlineObjectCommand::~InsertInlineObjectCommand()
-{
- if (m_deleteInlineObject) {
- delete m_inlineObject;
- }
-}
-
-void InsertInlineObjectCommand::redo()
-{
- KUndo2Command::redo();
-
- KoTextDocument doc(m_document);
- KoTextEditor *editor = doc.textEditor();
- if (m_first) {
- doc.inlineTextObjectManager()->insertInlineObject(*editor->cursor(), m_inlineObject);
- m_position = editor->cursor()->position();
- m_first = false;
- }
- else {
- doc.inlineTextObjectManager()->addInlineObject(m_inlineObject);
- }
- editor->setPosition(m_position);
- QTextCharFormat format = editor->charFormat();
- m_inlineObject->updatePosition(m_document, m_position, format);
-
- m_deleteInlineObject = false;
-}
-
-void InsertInlineObjectCommand::undo()
-{
- KUndo2Command::undo();
- KoTextDocument(m_document).inlineTextObjectManager()->removeInlineObject(m_inlineObject);
- m_deleteInlineObject = true;
-}
diff --git a/plugins/flake/textshape/kotext/commands/InsertInlineObjectCommand.h b/plugins/flake/textshape/kotext/commands/InsertInlineObjectCommand.h
deleted file mode 100644
index 9e24ad9b37..0000000000
--- a/plugins/flake/textshape/kotext/commands/InsertInlineObjectCommand.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2011 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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.
- */
-
-#ifndef INSERTINLINEOBJECTCOMMAND_H
-#define INSERTINLINEOBJECTCOMMAND_H
-
-#include <kundo2command.h>
-
-class KoInlineObject;
-class QTextDocument;
-
-class InsertInlineObjectCommand : public KUndo2Command
-{
-public:
- InsertInlineObjectCommand(KoInlineObject *inlineObject, QTextDocument *document, KUndo2Command *parent);
- ~InsertInlineObjectCommand() override;
-
- /// redo the command
- void redo() override;
- /// revert the actions done in redo
- void undo() override;
-private:
-
- KoInlineObject *m_inlineObject;
- QTextDocument *m_document;
- bool m_deleteInlineObject;
- bool m_first;
- int m_position;
-};
-
-#endif // INSERTINLINEOBJECTCOMMAND_H
diff --git a/plugins/flake/textshape/kotext/commands/InsertNoteCommand.cpp b/plugins/flake/textshape/kotext/commands/InsertNoteCommand.cpp
deleted file mode 100644
index b155c689d9..0000000000
--- a/plugins/flake/textshape/kotext/commands/InsertNoteCommand.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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 "InsertNoteCommand.h"
-
-#include <klocalizedstring.h>
-
-#include <KoTextEditor.h>
-#include <KoTextDocument.h>
-#include <KoInlineTextObjectManager.h>
-#include <KoInlineNote.h>
-
-
-InsertNoteCommand::InsertNoteCommand(KoInlineNote::Type type, QTextDocument *document)
- : KUndo2Command ()
- , m_document(document)
- , m_first(true)
-{
- if (type == KoInlineNote::Footnote) {
- setText(kundo2_i18n("Insert Footnote"));
- } else if (type == KoInlineNote::Endnote) {
- setText(kundo2_i18n("Insert Endnote"));
- }
- m_inlineNote = new KoInlineNote(type);
-}
-
-InsertNoteCommand::~InsertNoteCommand()
-{
-}
-
-void InsertNoteCommand::undo()
-{
- KUndo2Command::undo();
-}
-
-void InsertNoteCommand::redo()
-{
- if (!m_first) {
- KUndo2Command::redo();
- QTextCursor cursor(m_document.data());
- cursor.setPosition(m_framePosition);
- m_inlineNote->setTextFrame(cursor.currentFrame());
- m_inlineNote->setMotherFrame(KoTextDocument(m_document).auxillaryFrame());
- } else {
- m_first = false;
- if (m_document) {
- KoTextEditor *textEditor = KoTextDocument(m_document).textEditor();
- if (textEditor) {
- textEditor->beginEditBlock();
- QTextCursor *caret = textEditor->cursor();
- if (textEditor->hasSelection()) {
- textEditor->deleteChar(false, this);
- }
- KoInlineTextObjectManager *manager = KoTextDocument(m_document).inlineTextObjectManager();
- manager->insertInlineObject(*caret, m_inlineNote);
- m_inlineNote->setMotherFrame(KoTextDocument(m_document).auxillaryFrame());
- m_framePosition = m_inlineNote->textFrame()->lastPosition();
- textEditor->setPosition(m_framePosition);
-
- textEditor->endEditBlock();
- }
- }
- }
-}
diff --git a/plugins/flake/textshape/kotext/commands/InsertNoteCommand.h b/plugins/flake/textshape/kotext/commands/InsertNoteCommand.h
deleted file mode 100644
index f34af2735c..0000000000
--- a/plugins/flake/textshape/kotext/commands/InsertNoteCommand.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2009 Ganesh Paramasivam <ganesh@crystalfab.com>
- * Copyright (C) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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 INSERTNOTECOMMAND_H
-#define INSERTNOTECOMMAND_H
-
-#include "KoInlineNote.h"
-
-#include <kundo2command.h>
-
-#include <QWeakPointer>
-
-class QTextDocument;
-
-class InsertNoteCommand : public KUndo2Command
-{
-public:
-
- InsertNoteCommand(KoInlineNote::Type type, QTextDocument *document);
- ~InsertNoteCommand() override;
-
- void undo() override;
- void redo() override;
-
- KoInlineNote *m_inlineNote;
-private:
- QWeakPointer<QTextDocument> m_document;
- bool m_first;
- int m_framePosition; // a cursor position inside the frame at the time of creation
-};
-
-#endif // INSERTNODECOMMAND_H
diff --git a/plugins/flake/textshape/kotext/commands/InsertTableColumnCommand.cpp b/plugins/flake/textshape/kotext/commands/InsertTableColumnCommand.cpp
deleted file mode 100644
index a7ff78130a..0000000000
--- a/plugins/flake/textshape/kotext/commands/InsertTableColumnCommand.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2010-2011 C. Boemann <cbo@boemann.dk>
- *
- * 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 "InsertTableColumnCommand.h"
-
-#include <KoTextEditor.h>
-#include "KoTableColumnAndRowStyleManager.h"
-
-#include <QTextTableCell>
-#include <QTextTable>
-
-#include <klocalizedstring.h>
-#include "TextDebug.h"
-
-InsertTableColumnCommand::InsertTableColumnCommand(KoTextEditor *te, QTextTable *t, bool right, KUndo2Command *parent)
- : KUndo2Command (parent)
- ,m_first(true)
- ,m_textEditor(te)
- ,m_table(t)
- ,m_right(right)
-{
- if(right) {
- setText(kundo2_i18n("Insert Column Right"));
- } else {
- setText(kundo2_i18n("Insert Column Left"));
- }
-}
-
-void InsertTableColumnCommand::undo()
-{
- KoTableColumnAndRowStyleManager carsManager = KoTableColumnAndRowStyleManager::getManager(m_table);
-
- carsManager.removeColumns(m_column, 1);
-
- KUndo2Command::undo();
-}
-
-void InsertTableColumnCommand::redo()
-{
- KoTableColumnAndRowStyleManager carsManager = KoTableColumnAndRowStyleManager::getManager(m_table);
- if (!m_first) {
- carsManager.insertColumns(m_column, 1, m_style);
- KUndo2Command::redo();
- } else {
- m_first = false;
- QTextTableCell cell = m_table->cellAt(*m_textEditor->cursor());
- m_column = cell.column() + (m_right ? 1 : 0);
- m_style = carsManager.columnStyle(cell.column());
- m_table->insertColumns(m_column, 1);
- carsManager.insertColumns(m_column, 1, m_style);
-
- if (m_right && m_column == m_table->columns()-1) {
- // Copy the cell style. for the bottomright cell which Qt doesn't
- QTextTableCell cell = m_table->cellAt(m_table->rows()-1, m_column - 1);
- QTextCharFormat format = cell.format();
- cell = m_table->cellAt(m_table->rows()-1, m_column);
- cell.setFormat(format);
- }
-
- }
-}
diff --git a/plugins/flake/textshape/kotext/commands/InsertTableColumnCommand.h b/plugins/flake/textshape/kotext/commands/InsertTableColumnCommand.h
deleted file mode 100644
index 4f2d56f296..0000000000
--- a/plugins/flake/textshape/kotext/commands/InsertTableColumnCommand.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2010-2011 C. Boemann <cbo@boemann.dk>
- *
- * 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 INSERTTABLECOLUMNCOMMAND_H
-#define INSERTTABLECOLUMNCOMMAND_H
-
-#include <kundo2command.h>
-#include <KoTableColumnStyle.h>
-
-class KoTextEditor;
-class QTextTable;
-
-class InsertTableColumnCommand : public KUndo2Command
-{
-public:
-
- InsertTableColumnCommand(KoTextEditor *te, QTextTable *t, bool right, KUndo2Command *parent = 0);
-
- void undo() override;
- void redo() override;
-
-private:
- bool m_first;
- KoTextEditor *m_textEditor;
- QTextTable *m_table;
- int m_column;
- bool m_right;
- KoTableColumnStyle m_style;
-};
-
-#endif // INSERTTABLECOLUMNCOMMAND_H
diff --git a/plugins/flake/textshape/kotext/commands/InsertTableRowCommand.cpp b/plugins/flake/textshape/kotext/commands/InsertTableRowCommand.cpp
deleted file mode 100644
index c1beb81d74..0000000000
--- a/plugins/flake/textshape/kotext/commands/InsertTableRowCommand.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2010-2011 C. Boemann <cbo@boemann.dk>
- *
- * 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 "InsertTableRowCommand.h"
-
-#include <KoTextEditor.h>
-#include "KoTableColumnAndRowStyleManager.h"
-
-#include <QTextTableCell>
-#include <QTextTable>
-
-#include <klocalizedstring.h>
-#include "TextDebug.h"
-
-InsertTableRowCommand::InsertTableRowCommand(KoTextEditor *te, QTextTable *t, bool below, KUndo2Command *parent)
- : KUndo2Command(parent)
- ,m_first(true)
- ,m_textEditor(te)
- ,m_table(t)
- ,m_below(below)
-{
- if(below) {
- setText(kundo2_i18n("Insert Row Below"));
- } else {
- setText(kundo2_i18n("Insert Row Above"));
- }
-}
-
-void InsertTableRowCommand::undo()
-{
- KoTableColumnAndRowStyleManager carsManager = KoTableColumnAndRowStyleManager::getManager(m_table);
-
- carsManager.removeRows(m_row, 1);
-
- KUndo2Command::undo();
-}
-
-void InsertTableRowCommand::redo()
-{
- KoTableColumnAndRowStyleManager carsManager = KoTableColumnAndRowStyleManager::getManager(m_table);
- if (!m_first) {
- carsManager.insertRows(m_row, 1, m_style);
- KUndo2Command::redo();
- } else {
- m_first = false;
- QTextTableCell cell = m_table->cellAt(*m_textEditor->cursor());
- m_row = cell.row() + (m_below ? 1 : 0);
- m_style = carsManager.rowStyle(cell.row());
- m_table->insertRows(m_row, 1);
- carsManager.insertRows(m_row, 1, m_style);
-
- if (m_below && m_row == m_table->rows()-1) {
- // Copy the cells styles. when Qt doesn't do it for us
- for (int col = 0; col < m_table->columns(); ++col) {
- QTextTableCell cell = m_table->cellAt(m_row - 1, col);
- QTextCharFormat format = cell.format();
- cell = m_table->cellAt(m_row, col);
- cell.setFormat(format);
- }
- }
- }
-}
diff --git a/plugins/flake/textshape/kotext/commands/InsertTableRowCommand.h b/plugins/flake/textshape/kotext/commands/InsertTableRowCommand.h
deleted file mode 100644
index e7251cf0c5..0000000000
--- a/plugins/flake/textshape/kotext/commands/InsertTableRowCommand.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2010-2011 C. Boemann <cbo@boemann.dk>
- *
- * 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 INSERTTABLEROWCOMMAND_H
-#define INSERTTABLEROWCOMMAND_H
-
-#include <kundo2command.h>
-#include <KoTableRowStyle.h>
-
-class KoTextEditor;
-class QTextTable;
-
-class InsertTableRowCommand : public KUndo2Command
-{
-public:
-
- InsertTableRowCommand(KoTextEditor *te, QTextTable *t, bool below, KUndo2Command *parent = 0);
-
- void undo() override;
- void redo() override;
-
-private:
- bool m_first;
- KoTextEditor *m_textEditor;
- QTextTable *m_table;
- int m_row;
- bool m_below;
- KoTableRowStyle m_style;
-};
-
-#endif // INSERTTABLEROWCOMMAND_H
diff --git a/plugins/flake/textshape/kotext/commands/ListItemNumberingCommand.cpp b/plugins/flake/textshape/kotext/commands/ListItemNumberingCommand.cpp
deleted file mode 100644
index 83c990e79f..0000000000
--- a/plugins/flake/textshape/kotext/commands/ListItemNumberingCommand.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- *
- * 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 "ListItemNumberingCommand.h"
-
-#include <klocalizedstring.h>
-
-#include <KoParagraphStyle.h>
-#include <KoTextBlockData.h>
-#include <QTextCursor>
-
-ListItemNumberingCommand::ListItemNumberingCommand(const QTextBlock &block, bool numbered, KUndo2Command *parent)
- : KoTextCommandBase(parent),
- m_block(block),
- m_numbered(numbered),
- m_first(true)
-{
- m_wasNumbered = !block.blockFormat().boolProperty(KoParagraphStyle::UnnumberedListItem);
- setText(kundo2_i18n("Change List Numbering"));
-}
-
-ListItemNumberingCommand::~ListItemNumberingCommand()
-{
-}
-
-void ListItemNumberingCommand::setNumbered(bool numbered)
-{
- QTextCursor cursor(m_block);
- QTextBlockFormat blockFormat = cursor.blockFormat();
- if (numbered) {
- blockFormat.clearProperty(KoParagraphStyle::UnnumberedListItem);
- } else {
- blockFormat.setProperty(KoParagraphStyle::UnnumberedListItem, true);
- }
- cursor.setBlockFormat(blockFormat);
-
- KoTextBlockData data(m_block);
- data.setCounterWidth(-1.0);
-}
-
-void ListItemNumberingCommand::redo()
-{
- if (!m_first) {
- KoTextCommandBase::redo();
- UndoRedoFinalizer finalizer(this);
-
- KoTextBlockData data(m_block);
- data.setCounterWidth(-1.0);
- } else {
- setNumbered(m_numbered);
- }
- m_first = false;
-}
-
-void ListItemNumberingCommand::undo()
-{
- KoTextCommandBase::undo();
- UndoRedoFinalizer finalizer(this);
-
- KoTextBlockData data(m_block);
- data.setCounterWidth(-1.0);
-}
-
-bool ListItemNumberingCommand::mergeWith(const KUndo2Command *other)
-{
- Q_UNUSED(other);
- return false;
-}
diff --git a/plugins/flake/textshape/kotext/commands/ListItemNumberingCommand.h b/plugins/flake/textshape/kotext/commands/ListItemNumberingCommand.h
deleted file mode 100644
index 219ed71716..0000000000
--- a/plugins/flake/textshape/kotext/commands/ListItemNumberingCommand.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- *
- * 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 LISTITEMNUMBERINGCOMMAND
-#define LISTITEMNUMBERINGCOMMAND
-
-#include "KoTextCommandBase.h"
-
-#include <QTextBlock>
-
-/**
- * This command is useful to mark a block as numbered or unnumbered list-item.
- */
-class ListItemNumberingCommand : public KoTextCommandBase
-{
-public:
- /**
- * Change the list property of 'block'.
- * @param block the paragraph to change the list property of
- * @param numbered indicates if the block is an numbered list item
- * @param parent the parent undo command for macro functionality
- */
- ListItemNumberingCommand(const QTextBlock &block, bool numbered, KUndo2Command *parent = 0);
-
- ~ListItemNumberingCommand() override;
-
- /// redo the command
- void redo() override;
- /// revert the actions done in redo
- void undo() override;
-
- /// reimplemented from KUndo2Command
- int id() const override {
- return 58450688;
- }
- /// reimplemented from KUndo2Command
- bool mergeWith(const KUndo2Command *other) override;
-
-private:
- void setNumbered(bool numbered);
-
- QTextBlock m_block;
- bool m_numbered;
- bool m_wasNumbered;
- bool m_first;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/commands/NewSectionCommand.cpp b/plugins/flake/textshape/kotext/commands/NewSectionCommand.cpp
deleted file mode 100644
index 6af3051eca..0000000000
--- a/plugins/flake/textshape/kotext/commands/NewSectionCommand.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * This file is part of the KDE project
- * Copyright (C) 2014-2015 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 "NewSectionCommand.h"
-#include <KoSection.h>
-#include <KoSectionEnd.h>
-#include <KoTextDocument.h>
-#include <KoParagraphStyle.h>
-#include <KoTextEditor.h>
-#include <KoSectionUtils.h>
-#include <KoSectionModel.h>
-
-#include <klocalizedstring.h>
-#include <kundo2command.h>
-
-NewSectionCommand::NewSectionCommand(QTextDocument *document)
- : KUndo2Command ()
- , m_first(true)
- , m_document(document)
-{
- setText(kundo2_i18n("New Section"));
-}
-
-NewSectionCommand::~NewSectionCommand()
-{
-}
-
-void NewSectionCommand::undo()
-{
- KUndo2Command::undo();
- //FIXME: if it will go to KoTextCommandBase, place UndoRedoFinalizer here
-
- // All formatting changes will be undone automatically.
- // Lets handle Model Level (see KoSectionModel).
- KoTextDocument(m_document).sectionModel()->deleteFromModel(m_section);
-}
-
-void NewSectionCommand::redo()
-{
- KoTextDocument koDocument(m_document);
- KoSectionModel *sectionModel = koDocument.sectionModel();
-
- if (!m_first) {
- KUndo2Command::redo();
- //FIXME: if it will go to KoTextCommandBase, place UndoRedoFinalizer here
-
- // All formatting changes will be redone automatically.
- // Lets handle Model Level (see KoSectionModel).
- sectionModel->insertToModel(m_section, m_childIdx);
- } else {
- m_first = false;
-
- KoTextEditor *editor = koDocument.textEditor();
- editor->newLine();
-
- m_section = sectionModel->createSection(
- editor->constCursor(),
- sectionModel->sectionAtPosition(editor->constCursor().position())
- );
- m_childIdx = sectionModel->findRowOfChild(m_section);
-
- KoSectionEnd *sectionEnd = sectionModel->createSectionEnd(m_section);
- QTextBlockFormat fmt = editor->blockFormat();
-
- QList<KoSection *> sectionStartings = KoSectionUtils::sectionStartings(fmt);
- QList<KoSectionEnd *> sectionEndings = KoSectionUtils::sectionEndings(fmt);
-
- sectionStartings.append(m_section);
- sectionEndings.prepend(sectionEnd);
-
- KoSectionUtils::setSectionStartings(fmt, sectionStartings);
- KoSectionUtils::setSectionEndings(fmt, sectionEndings);
-
- editor->setBlockFormat(fmt);
- }
-}
diff --git a/plugins/flake/textshape/kotext/commands/NewSectionCommand.h b/plugins/flake/textshape/kotext/commands/NewSectionCommand.h
deleted file mode 100644
index 81b6d51e4a..0000000000
--- a/plugins/flake/textshape/kotext/commands/NewSectionCommand.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * This file is part of the KDE project
- * Copyright (C) 2014 Denis Kuplaykov <dener.kup@gmail.com>
- *
- * 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 NEWSECTIONCOMMAND_H
-#define NEWSECTIONCOMMAND_H
-
-#include <kundo2command.h>
-
-class KoSection;
-class QTextDocument;
-
-//FIXME: why it is not going from KoTextCommandBase?
-// If it will be changed to KoTextCommandBase,
-// don't forget to add UndoRedoFinalizer.
-class NewSectionCommand : public KUndo2Command
-{
-public:
-
- explicit NewSectionCommand(QTextDocument *document);
- ~NewSectionCommand() override;
-
- void undo() override;
- void redo() override;
-
-private:
- bool m_first; ///< Checks first call of redo
- QTextDocument *m_document; ///< Pointer to document
- KoSection *m_section; ///< Inserted section
- int m_childIdx; ///< Position of inserted section in parent, after inserting
-};
-
-#endif // NEWSECTIONCOMMAND_H
diff --git a/plugins/flake/textshape/kotext/commands/ParagraphFormattingCommand.cpp b/plugins/flake/textshape/kotext/commands/ParagraphFormattingCommand.cpp
deleted file mode 100644
index e45d2f86db..0000000000
--- a/plugins/flake/textshape/kotext/commands/ParagraphFormattingCommand.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2013 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 "ParagraphFormattingCommand.h"
-
-#include <KoTextDocument.h>
-#include <KoTextEditor.h>
-#include "KoTextEditor_p.h"
-
-#include <klocalizedstring.h>
-
-class MergeAutoParagraphStyleVisitor : public KoTextVisitor
-{
-public:
- MergeAutoParagraphStyleVisitor(KoTextEditor *editor, const QTextCharFormat &deltaCharFormat, const QTextBlockFormat &deltaBlockFormat)
- : KoTextVisitor(editor)
- , m_deltaCharFormat(deltaCharFormat)
- , m_deltaBlockFormat(deltaBlockFormat)
- {
- }
-
- void visitBlock(QTextBlock &block, const QTextCursor &caret) override
- {
- for (QTextBlock::iterator it = block.begin(); it != block.end(); ++it) {
- QTextCursor fragmentSelection(caret);
- fragmentSelection.setPosition(it.fragment().position());
- fragmentSelection.setPosition(it.fragment().position() + it.fragment().length(), QTextCursor::KeepAnchor);
-
- if (fragmentSelection.anchor() >= fragmentSelection.position()) {
- continue;
- }
-
- visitFragmentSelection(fragmentSelection);
- }
-
- QList<QTextCharFormat>::Iterator it = m_formats.begin();
- Q_FOREACH (QTextCursor cursor, m_cursors) {
- QTextFormat prevFormat(cursor.charFormat());
- cursor.setCharFormat(*it);
- editor()->registerTrackedChange(cursor, KoGenChange::FormatChange, kundo2_i18n("Formatting"), *it, prevFormat, false);
- ++it;
- }
- QTextCursor cursor(caret);
- cursor.mergeBlockFormat(m_deltaBlockFormat);
- cursor.mergeBlockCharFormat(m_deltaCharFormat);
- }
-
- void visitFragmentSelection(QTextCursor &fragmentSelection) override
- {
- QTextCharFormat format = fragmentSelection.charFormat();
- format.merge(m_deltaCharFormat);
-
- m_formats.append(format);
- m_cursors.append(fragmentSelection);
- }
-
- QTextCharFormat m_deltaCharFormat;
- QTextBlockFormat m_deltaBlockFormat;
- QList<QTextCharFormat> m_formats;
- QList<QTextCursor> m_cursors;
-};
-
-ParagraphFormattingCommand::ParagraphFormattingCommand(KoTextEditor *editor,
- const QTextCharFormat &characterFormat,
- const QTextBlockFormat &blockFormat,
- const KoListLevelProperties &llp,
- KUndo2Command *parent)
- :KUndo2Command(parent),
- m_first(true),
- m_editor(editor),
- m_charFormat(characterFormat),
- m_blockFormat(blockFormat),
- m_levelProperties(llp)
-{
- Q_ASSERT(editor);
-
- setText(kundo2_i18n("Direct Paragraph Formatting"));
-}
-
-ParagraphFormattingCommand::~ParagraphFormattingCommand()
-{
-}
-
-void ParagraphFormattingCommand::undo()
-{
- KUndo2Command::undo();
-}
-
-void ParagraphFormattingCommand::redo()
-{
- if (!m_first) {
- KUndo2Command::redo();
- } else {
- MergeAutoParagraphStyleVisitor visitor(m_editor, m_charFormat, m_blockFormat);
-
- m_editor->recursivelyVisitSelection(m_editor->document()->rootFrame()->begin(), visitor);
-
- KoTextEditor::ChangeListFlags flags(KoTextEditor::AutoListStyle | KoTextEditor::DontUnsetIfSame);
-
- m_editor->setListProperties(m_levelProperties, flags, this);
-
- m_first = false;
- }
-}
diff --git a/plugins/flake/textshape/kotext/commands/ParagraphFormattingCommand.h b/plugins/flake/textshape/kotext/commands/ParagraphFormattingCommand.h
deleted file mode 100644
index 0001e59927..0000000000
--- a/plugins/flake/textshape/kotext/commands/ParagraphFormattingCommand.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2013 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 PARAGRAPHFORMATTINGCOMMAND_H
-#define PARAGRAPHFORMATTINGCOMMAND_H
-
-#include <KoListLevelProperties.h>
-
-#include "kundo2command.h"
-
-class KoTextEditor;
-class QTextCharFormat;
-class QTextBlockFormat;
-
-/**
- * This command is used to apply paragraph settings
- */
-class ParagraphFormattingCommand : public KUndo2Command
-{
-public:
- ParagraphFormattingCommand(KoTextEditor *editor,
- const QTextCharFormat &characterFormat,
- const QTextBlockFormat &blockFormat,
- const KoListLevelProperties &llp,
- KUndo2Command *parent = 0);
-
- ~ParagraphFormattingCommand() override;
-
- /// redo the command
- void redo() override;
- /// revert the actions done in redo
- void undo() override;
-
-private:
- bool m_first;
- KoTextEditor *m_editor;
- QTextCharFormat m_charFormat;
- QTextBlockFormat m_blockFormat;
- KoListLevelProperties m_levelProperties;
-};
-
-#endif
-
diff --git a/plugins/flake/textshape/kotext/commands/RemoveDeleteChangesCommand.cpp b/plugins/flake/textshape/kotext/commands/RemoveDeleteChangesCommand.cpp
deleted file mode 100644
index 1859d0b394..0000000000
--- a/plugins/flake/textshape/kotext/commands/RemoveDeleteChangesCommand.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2011 C. Boemann <cbo@boemann.dk>
- *
- * 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 "RemoveDeleteChangesCommand.h"
-
-#include <QTextDocument>
-#include <QVector>
-
-#include <KoChangeTracker.h>
-#include <KoChangeTrackerElement.h>
-#include <KoTextDocument.h>
-
-RemoveDeleteChangesCommand::RemoveDeleteChangesCommand(QTextDocument *document,
- KUndo2Command *parent)
- : KUndo2Command("Insert Delete Changes", parent)
- , m_document(document)
-{
-}
-
-void RemoveDeleteChangesCommand::redo()
-{
- removeDeleteChanges();
-}
-
-void RemoveDeleteChangesCommand::removeDeleteChanges()
-{
- int numDeletedChars = 0;
- QVector<KoChangeTrackerElement *> elementVector;
- KoTextDocument(m_document).changeTracker()->getDeletedChanges(elementVector);
- qSort(elementVector.begin(), elementVector.end());
-
-}
diff --git a/plugins/flake/textshape/kotext/commands/RemoveDeleteChangesCommand.h b/plugins/flake/textshape/kotext/commands/RemoveDeleteChangesCommand.h
deleted file mode 100644
index 5c4752a7d8..0000000000
--- a/plugins/flake/textshape/kotext/commands/RemoveDeleteChangesCommand.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2011 C. Boemann <cbo@boemann.dk>
- *
- * 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.
- */
-
-#ifndef REMOVEDELETECHANGESCOMMAND_H
-#define REMOVEDELETECHANGESCOMMAND_H
-
-#include <kundo2command.h>
-#include <QWeakPointer>
-
-class QTextDocument;
-
-class RemoveDeleteChangesCommand : public KUndo2Command
-{
-public:
- explicit RemoveDeleteChangesCommand(QTextDocument *document, KUndo2Command *parent = 0);
- void redo();
-
-private:
- QWeakPointer<QTextDocument> m_document;
- void removeDeleteChanges();
-};
-
-#endif // REMOVEDELETECHANGESCOMMAND_H
diff --git a/plugins/flake/textshape/kotext/commands/RenameSectionCommand.cpp b/plugins/flake/textshape/kotext/commands/RenameSectionCommand.cpp
deleted file mode 100644
index c34e479418..0000000000
--- a/plugins/flake/textshape/kotext/commands/RenameSectionCommand.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * This file is part of the KDE project
- * Copyright (C) 2014-2015 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 "RenameSectionCommand.h"
-#include <KoSection.h>
-#include <KoTextDocument.h>
-#include <KoSectionModel.h>
-
-#include <klocalizedstring.h>
-#include <kundo2command.h>
-
-RenameSectionCommand::RenameSectionCommand(KoSection *section, const QString &newName, QTextDocument *document)
- : KUndo2Command()
- , m_sectionModel(KoTextDocument(document).sectionModel())
- , m_section(section)
- , m_newName(newName)
- , m_first(true)
-{
- setText(kundo2_i18n("Rename Section"));
-}
-
-RenameSectionCommand::~RenameSectionCommand()
-{
-}
-
-void RenameSectionCommand::undo()
-{
- KUndo2Command::undo();
- m_sectionModel->setName(m_section, m_oldName);
-}
-
-void RenameSectionCommand::redo()
-{
- if (!m_first) {
- KUndo2Command::redo();
- }
- m_oldName = m_section->name();
- m_sectionModel->setName(m_section, m_newName);
- m_first = false;
-}
-
-int RenameSectionCommand::id() const
-{
- //FIXME: extract this to some enum shared across all commands
- return 34537684;
-}
-
-bool RenameSectionCommand::mergeWith(const KUndo2Command *other)
-{
- if (other->id() != id()) {
- return false;
- }
-
- const RenameSectionCommand *command = static_cast<const RenameSectionCommand *>(other);
- if (command->m_section != m_section || m_newName != command->m_oldName) {
- return false;
- }
- m_newName = command->m_oldName;
- return true;
-}
diff --git a/plugins/flake/textshape/kotext/commands/RenameSectionCommand.h b/plugins/flake/textshape/kotext/commands/RenameSectionCommand.h
deleted file mode 100644
index 028cc5ea25..0000000000
--- a/plugins/flake/textshape/kotext/commands/RenameSectionCommand.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * This file is part of the KDE project
- * Copyright (C) 2014-2015 Denis Kuplaykov <dener.kup@gmail.com>
- *
- * 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 RENAMESECTIONCOMMAND_H
-#define RENAMESECTIONCOMMAND_H
-
-#include <QString>
-
-#include <kundo2qstack.h>
-
-class QTextDocument;
-
-class KoSection;
-class KoSectionModel;
-
-class RenameSectionCommand : public KUndo2Command
-{
-public:
-
- RenameSectionCommand(KoSection *section, const QString &newName, QTextDocument *document);
- ~RenameSectionCommand() override;
-
- void undo() override;
- void redo() override;
-
- bool mergeWith(const KUndo2Command *other) override;
- int id() const override;
-
-private:
- KoSectionModel *m_sectionModel; ///< Pointer to document's KoSectionModel
- KoSection *m_section; ///< Section to rename
- QString m_newName; ///< New section name
- QString m_oldName; ///< Old section name (needed to undo)
- bool m_first; ///< Checks first call of redo
-};
-
-#endif // RENAMESECTIONCOMMAND_H
diff --git a/plugins/flake/textshape/kotext/commands/ResizeTableCommand.cpp b/plugins/flake/textshape/kotext/commands/ResizeTableCommand.cpp
deleted file mode 100644
index cf818d8dc7..0000000000
--- a/plugins/flake/textshape/kotext/commands/ResizeTableCommand.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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 "ResizeTableCommand.h"
-
-#include "KoTableColumnAndRowStyleManager.h"
-#include "KoTableColumnStyle.h"
-#include "KoTableRowStyle.h"
-
-#include <QTextTable>
-#include <QTextCursor>
-#include <QTextDocument>
-
-#include <klocalizedstring.h>
-#include "TextDebug.h"
-
-ResizeTableCommand::ResizeTableCommand(QTextTable *t, bool horizontal, int band, qreal size, KUndo2Command *parent) :
- KUndo2Command (parent)
- , m_first(true)
- , m_tablePosition(t->firstPosition())
- , m_document(t->document())
- , m_horizontal(horizontal)
- , m_band(band)
- , m_size(size)
- , m_oldColumnStyle(0)
- , m_oldRowStyle(0)
-{
- if (horizontal) {
- setText(kundo2_i18n("Adjust Column Width"));
- } else {
- setText(kundo2_i18n("Adjust Row Height"));
- }
-}
-
-ResizeTableCommand::~ResizeTableCommand()
-{
- delete m_oldColumnStyle;
- delete m_oldRowStyle;
-}
-
-void ResizeTableCommand::undo()
-{
- QTextCursor c(m_document);
- c.setPosition(m_tablePosition);
- QTextTable *table = c.currentTable();
-
- KoTableColumnAndRowStyleManager carsManager = KoTableColumnAndRowStyleManager::getManager(table);
-
- if (m_oldColumnStyle) {
- KoTableColumnStyle style = carsManager.columnStyle(m_band);
- style.copyProperties(m_oldColumnStyle);
- carsManager.setColumnStyle(m_band, style);
- }
- if (m_oldRowStyle) {
- KoTableRowStyle style = carsManager.rowStyle(m_band);
- style.copyProperties(m_oldRowStyle);
- carsManager.setRowStyle(m_band, style);
- }
- KUndo2Command::undo();
- m_document->markContentsDirty(m_tablePosition, table->lastPosition()-table->firstPosition());
-}
-
-void ResizeTableCommand::redo()
-{
- QTextCursor c(m_document);
- c.setPosition(m_tablePosition);
- QTextTable *table = c.currentTable();
-
- KoTableColumnAndRowStyleManager carsManager = KoTableColumnAndRowStyleManager::getManager(table);
-
- if (!m_first) {
- if (m_horizontal) {
- KoTableColumnStyle style = carsManager.columnStyle(m_band);
- style.copyProperties(m_newColumnStyle);
- carsManager.setColumnStyle(m_band, style);
- } else {
- KoTableRowStyle style = carsManager.rowStyle(m_band);
- style.copyProperties(m_newRowStyle);
- carsManager.setRowStyle(m_band, style);
- }
- KUndo2Command::redo();
- } else {
- m_first = false;
- if (m_horizontal) {
- m_oldColumnStyle = carsManager.columnStyle(m_band).clone();
- // make sure the style is set (could have been a default style)
- carsManager.setColumnStyle(m_band, carsManager.columnStyle(m_band));
-
- KoTableColumnStyle style = carsManager.columnStyle(m_band);
- style.setColumnWidth(m_size);
- carsManager.setColumnStyle(m_band, style);
-
- m_newColumnStyle = carsManager.columnStyle(m_band).clone();
- } else {
- m_oldRowStyle = carsManager.rowStyle(m_band).clone();
-
- // make sure the style is set (could have been a default style)
- carsManager.setRowStyle(m_band, carsManager.rowStyle(m_band));
-
- KoTableRowStyle style = carsManager.rowStyle(m_band);
- style.setMinimumRowHeight(m_size);
- carsManager.setRowStyle(m_band, style);
-
- m_newRowStyle = carsManager.rowStyle(m_band).clone();
- }
- }
- m_document->markContentsDirty(m_tablePosition, table->lastPosition()-table->firstPosition());
-}
diff --git a/plugins/flake/textshape/kotext/commands/ResizeTableCommand.h b/plugins/flake/textshape/kotext/commands/ResizeTableCommand.h
deleted file mode 100644
index adea096f07..0000000000
--- a/plugins/flake/textshape/kotext/commands/ResizeTableCommand.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2012 C. Boemann <cbo@boemann.dk>
- *
- * 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 RESIZETABLECOMMAND_H
-#define RESIZETABLECOMMAND_H
-
-#include <kundo2command.h>
-
-class QTextDocument;
-class QTextTable;
-class KoTableColumnStyle;
-class KoTableRowStyle;
-
-class ResizeTableCommand : public KUndo2Command
-{
-public:
- ResizeTableCommand(QTextTable *t, bool horizontal, int band, qreal size, KUndo2Command *parent = 0);
- ~ResizeTableCommand() override;
-
- void undo() override;
- void redo() override;
-
-private:
- bool m_first;
- int m_tablePosition;
- QTextDocument *m_document;
- bool m_horizontal;
- int m_band;
- qreal m_size;
- KoTableColumnStyle *m_oldColumnStyle;
- KoTableColumnStyle *m_newColumnStyle;
- KoTableRowStyle *m_oldRowStyle;
- KoTableRowStyle *m_newRowStyle;
-};
-
-#endif // RESIZETABLECOMMAND_H
diff --git a/plugins/flake/textshape/kotext/commands/SplitSectionsCommand.cpp b/plugins/flake/textshape/kotext/commands/SplitSectionsCommand.cpp
deleted file mode 100644
index 43d2adf363..0000000000
--- a/plugins/flake/textshape/kotext/commands/SplitSectionsCommand.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * This file is part of the KDE project
- * Copyright (C) 2014-2015 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 "SplitSectionsCommand.h"
-#include <KoSection.h>
-#include <KoSectionEnd.h>
-#include <KoTextDocument.h>
-#include <KoParagraphStyle.h>
-#include <KoTextEditor.h>
-#include <KoSectionUtils.h>
-
-#include <klocalizedstring.h>
-#include <kundo2command.h>
-
-SplitSectionsCommand::SplitSectionsCommand(QTextDocument *document, SplitType type, int splitPosition)
- : KUndo2Command ()
- , m_first(true)
- , m_document(document)
- , m_type(type)
- , m_splitPosition(splitPosition)
-{
- if (m_type == Startings) {
- setText(kundo2_i18n("Split sections startings"));
- } else { // Endings
- setText(kundo2_i18n("Split sections endings"));
- }
-}
-
-SplitSectionsCommand::~SplitSectionsCommand()
-{
-}
-
-void SplitSectionsCommand::undo()
-{
- KUndo2Command::undo();
- //FIXME: if it will go to KoTextCommandBase, place UndoRedoFinalizer here
-
- // All formatting changes will be undone automatically.
- // Model Level is untouched.
-}
-
-void SplitSectionsCommand::redo()
-{
- KoTextDocument koDocument(m_document);
-
- if (!m_first) {
- KUndo2Command::redo();
- //FIXME: if it will go to KoTextCommandBase, place UndoRedoFinalizer here
-
- // All formatting changes will be redone automatically.
- // Model level is untouched.
- } else {
- m_first = false;
-
- KoTextEditor *editor = koDocument.textEditor();
-
- if (m_type == Startings) {
- editor->movePosition(QTextCursor::StartOfBlock);
- editor->newLine();
- editor->movePosition(QTextCursor::PreviousBlock);
-
- QTextBlockFormat fmt = editor->blockFormat();
- KoSectionUtils::setSectionEndings(fmt, QList<KoSectionEnd *>());
- QList<KoSection *> firstBlockStartings = KoSectionUtils::sectionStartings(fmt).mid(0, m_splitPosition);
- QList<KoSection *> moveForward = KoSectionUtils::sectionStartings(fmt).mid(m_splitPosition);
- KoSectionUtils::setSectionStartings(fmt, firstBlockStartings);
- editor->setBlockFormat(fmt);
- editor->movePosition(QTextCursor::NextBlock);
- fmt = editor->blockFormat();
- KoSectionUtils::setSectionStartings(fmt, moveForward);
- editor->setBlockFormat(fmt);
- editor->movePosition(QTextCursor::PreviousBlock);
- } else { // Endings
- editor->movePosition(QTextCursor::EndOfBlock);
- editor->newLine();
-
- QTextBlockFormat fmt = editor->blockFormat();
- QList<KoSectionEnd *> secondBlockEndings = KoSectionUtils::sectionEndings(fmt).mid(m_splitPosition + 1);
- QList<KoSectionEnd *> moveBackward = KoSectionUtils::sectionEndings(fmt).mid(0, m_splitPosition + 1);
- KoSectionUtils::setSectionEndings(fmt, secondBlockEndings);
- editor->setBlockFormat(fmt);
- editor->movePosition(QTextCursor::PreviousBlock);
- fmt = editor->blockFormat();
- KoSectionUtils::setSectionEndings(fmt, moveBackward);
- editor->setBlockFormat(fmt);
- editor->movePosition(QTextCursor::NextBlock);
- }
- }
-}
diff --git a/plugins/flake/textshape/kotext/commands/SplitSectionsCommand.h b/plugins/flake/textshape/kotext/commands/SplitSectionsCommand.h
deleted file mode 100644
index ef38f2e9aa..0000000000
--- a/plugins/flake/textshape/kotext/commands/SplitSectionsCommand.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * This file is part of the KDE project
- * Copyright (C) 2015 Denis Kuplaykov <dener.kup@gmail.com>
- *
- * 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 SPLITSECTIONSCOMMAND_H
-#define SPLITSECTIONSCOMMAND_H
-
-#include <kundo2command.h>
-
-class KoSection;
-class QTextDocument;
-
-//FIXME: why it is not going from KoTextCommandBase?
-// If it will be changed to KoTextCommandBase,
-// don't forget to add UndoRedoFinalizer.
-class SplitSectionsCommand : public KUndo2Command
-{
-public:
- enum SplitType
- {
- Startings,
- Endings
- };
-
- explicit SplitSectionsCommand(QTextDocument *document, SplitType type, int splitPosition);
- ~SplitSectionsCommand() override;
-
- void undo() override;
- void redo() override;
-
-private:
- bool m_first; ///< Checks first call of redo
- QTextDocument *m_document; ///< Pointer to document
- SplitType m_type; ///< Split type
- int m_splitPosition; ///< Split position
-};
-
-#endif // SPLITSECTIONSCOMMAND_H
diff --git a/plugins/flake/textshape/kotext/commands/TextPasteCommand.cpp b/plugins/flake/textshape/kotext/commands/TextPasteCommand.cpp
deleted file mode 100644
index fbbbce2e11..0000000000
--- a/plugins/flake/textshape/kotext/commands/TextPasteCommand.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2011 Boudewijn Rempt <boud@kde.org>
- *
- * 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 "TextPasteCommand.h"
-
-#include <KoText.h>
-#include <KoTextEditor.h>
-#include <KoTextDocument.h>
-#include <KoShapeController.h>
-#include <KoParagraphStyle.h>
-
-#include <klocalizedstring.h>
-#include "TextDebug.h"
-
-#include <QTextDocument>
-#include <QMimeData>
-
-#include "DeleteCommand.h"
-#include "KoDocumentRdfBase.h"
-
-#include <KoOdf.h>
-#include <kis_assert.h>
-
-#ifdef SHOULD_BUILD_RDF
-#include <Soprano/Soprano>
-#else
-namespace Soprano
-{
- class Model
- {
- };
-}
-#endif
-
-TextPasteCommand::TextPasteCommand(const QMimeData *mimeData,
- QTextDocument *document,
- KoShapeController *shapeController,
- KoCanvasBase *canvas, KUndo2Command *parent, bool pasteAsText)
- : KUndo2Command (parent),
- m_mimeData(mimeData),
- m_document(document),
- m_rdf(0),
- m_shapeController(shapeController),
- m_canvas(canvas),
- m_pasteAsText(pasteAsText),
- m_first(true)
-{
- m_rdf = qobject_cast<KoDocumentRdfBase*>(shapeController->resourceManager()->resource(KoText::DocumentRdf).value<QObject*>());
-
- if (m_pasteAsText)
- setText(kundo2_i18n("Paste As Text"));
- else
- setText(kundo2_i18n("Paste"));
-}
-
-void TextPasteCommand::undo()
-{
- KUndo2Command::undo();
-}
-
-void TextPasteCommand::redo()
-{
- if (m_document.isNull()) return;
-
- KoTextDocument textDocument(m_document);
- KoTextEditor *editor = textDocument.textEditor();
-
- if (!m_first) {
- KUndo2Command::redo();
- } else {
- editor->beginEditBlock(); //this is needed so Qt does not merge successive paste actions together
- m_first = false;
- if (editor->hasSelection()) { //TODO
- editor->addCommand(new DeleteCommand(DeleteCommand::NextChar, m_document.data(), m_shapeController, this));
- }
-
- // check for mime type
- if (m_mimeData->hasFormat(KoOdf::mimeType(KoOdf::Text))
- || m_mimeData->hasFormat(KoOdf::mimeType(KoOdf::OpenOfficeClipboard)) ) {
- KoOdf::DocumentType odfType = KoOdf::Text;
- if (!m_mimeData->hasFormat(KoOdf::mimeType(odfType))) {
- odfType = KoOdf::OpenOfficeClipboard;
- }
-
- if (editor->blockFormat().hasProperty(KoParagraphStyle::HiddenByTable)) {
- editor->insertText(QString());
- }
-
- if (m_pasteAsText) {
- editor->insertText(m_mimeData->text());
- } else {
-
- QSharedPointer<Soprano::Model> rdfModel;
-#ifdef SHOULD_BUILD_RDF
- if(!m_rdf) {
- rdfModel = QSharedPointer<Soprano::Model>(Soprano::createModel());
- } else {
- rdfModel = m_rdf->model();
- }
-#endif
-
- KIS_SAFE_ASSERT_RECOVER_NOOP(0 && "Pasting of text is not implemented yet!");
-
- //KoTextPaste paste(editor, m_shapeController, rdfModel, m_canvas, this);
- //paste.paste(odfType, m_mimeData);
-
-#ifdef SHOULD_BUILD_RDF
- if (m_rdf) {
- m_rdf->updateInlineRdfStatements(editor->document());
- }
-#endif
- }
- } else if (!m_pasteAsText && m_mimeData->hasHtml()) {
- editor->insertHtml(m_mimeData->html());
- } else if (m_pasteAsText || m_mimeData->hasText()) {
- editor->insertText(m_mimeData->text());
- }
- editor->endEditBlock(); //see above beginEditBlock
- }
-}
diff --git a/plugins/flake/textshape/kotext/commands/TextPasteCommand.h b/plugins/flake/textshape/kotext/commands/TextPasteCommand.h
deleted file mode 100644
index 7b5fce819f..0000000000
--- a/plugins/flake/textshape/kotext/commands/TextPasteCommand.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- This file is part of the KDE project
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- *
- * 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 TEXTPASTECOMMAND_H
-#define TEXTPASTECOMMAND_H
-
-#include <QPointer>
-#include <QClipboard>
-#include <QWeakPointer>
-#include <kundo2command.h>
-#include <KoCanvasBase.h>
-
-class QTextDocument;
-class KoDocumentRdfBase;
-class KoShapeController;
-class QMimeData;
-
-class TextPasteCommand : public KUndo2Command
-{
-public:
-
- TextPasteCommand(const QMimeData *mimeData,
- QTextDocument *document,
- KoShapeController *shapeController,
- KoCanvasBase *canvas, KUndo2Command *parent = 0,
- bool pasteAsText = false);
-
- void undo() override;
-
- void redo() override;
-
-private:
- const QMimeData *m_mimeData;
- QWeakPointer<QTextDocument> m_document;
- KoDocumentRdfBase *m_rdf;
- KoShapeController *m_shapeController;
- QPointer<KoCanvasBase> m_canvas;
- bool m_pasteAsText;
- bool m_first;
-};
-
-#endif // TEXTPASTECOMMAND_H
diff --git a/plugins/flake/textshape/kotext/opendocument/KoTextLoader.cpp b/plugins/flake/textshape/kotext/opendocument/KoTextLoader.cpp
deleted file mode 100644
index 25c40b9e58..0000000000
--- a/plugins/flake/textshape/kotext/opendocument/KoTextLoader.cpp
+++ /dev/null
@@ -1,1529 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2001-2006 David Faure <faure@kde.org>
- * Copyright (C) 2007,2009,2011 Thomas Zander <zander@kde.org>
- * Copyright (C) 2007 Sebastian Sauer <mail@dipe.org>
- * Copyright (C) 2007,2011 Pierre Ducroquet <pinaraf@pinaraf.info>
- * Copyright (C) 2007-2011 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009-2012 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2010 KO GmbH <ben.martin@kogmbh.com>
- * Copyright (C) 2011 Pavol Korinek <pavol.korinek@ixonos.com>
- * Copyright (C) 2011 Lukáš Tvrdý <lukas.tvrdy@ixonos.com>
- * Copyright (C) 2011 Boudewijn Rempt <boud@valdyas.org>
- * Copyright (C) 2011-2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- * Copyright (C) 2012 Inge Wallin <inge@lysator.liu.se>
- * Copyright (C) 2009-2012 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2014-2015 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 "KoTextLoader.h"
-
-#include <KoTextMeta.h>
-#include <KoBookmark.h>
-#include <KoBookmarkManager.h>
-#include <KoAnnotation.h>
-#include <KoAnnotationManager.h>
-#include <KoInlineNote.h>
-#include <KoInlineCite.h>
-#include <KoTextRangeManager.h>
-#include <KoInlineTextObjectManager.h>
-#include "KoList.h"
-#include <KoOdfLoadingContext.h>
-#include <KoOdfStylesReader.h>
-#include <KoOdfLineNumberingConfiguration.h>
-#include <KoShapeContainer.h>
-#include <KoShapeFactoryBase.h>
-#include <KoShapeLoadingContext.h>
-#include <KoShapeRegistry.h>
-#include <KoTableColumnAndRowStyleManager.h>
-#include <KoAnchorInlineObject.h>
-#include <KoAnchorTextRange.h>
-#include <KoTextBlockData.h>
-#include "KoTextDebug.h"
-#include "KoTextDocument.h"
-#include "KoTextSharedLoadingData.h"
-#include <KoOdfBibliographyConfiguration.h>
-#include <KoVariable.h>
-#include <KoVariableManager.h>
-#include <KoInlineObjectRegistry.h>
-#include <KoXmlNS.h>
-#include <KoXmlReader.h>
-#include "KoTextInlineRdf.h"
-#include "KoTableOfContentsGeneratorInfo.h"
-#include "KoBibliographyInfo.h"
-#include "KoSection.h"
-#include "KoSectionEnd.h"
-#include "KoTextSoftPageBreak.h"
-#include "KoDocumentRdfBase.h"
-#include "KoElementReference.h"
-#include "KoTextTableTemplate.h"
-
-#include "styles/KoStyleManager.h"
-#include "styles/KoParagraphStyle.h"
-#include "styles/KoCharacterStyle.h"
-#include "styles/KoListStyle.h"
-#include "styles/KoListLevelProperties.h"
-#include "styles/KoTableStyle.h"
-#include "styles/KoTableColumnStyle.h"
-#include "styles/KoTableCellStyle.h"
-#include "styles/KoSectionStyle.h"
-#include <KoSectionUtils.h>
-#include <KoSectionModel.h>
-
-#include <klocalizedstring.h>
-#include "TextDebug.h"
-
-#include <QList>
-#include <QVector>
-#include <QMap>
-#include <QRect>
-#include <QStack>
-#include <QTextBlock>
-#include <QTextCursor>
-#include <QTextList>
-#include <QTextTable>
-#include <QTime>
-#include <QString>
-#include <QTextInlineObject>
-#include <QTextStream>
-
-// if defined then debugging is enabled
-// #define KOOPENDOCUMENTLOADER_DEBUG
-
-/// \internal d-pointer class.
-class Q_DECL_HIDDEN KoTextLoader::Private
-{
-public:
- KoShapeLoadingContext &context;
- KoTextSharedLoadingData *textSharedData;
- // store it here so that you don't need to get it all the time from
- // the KoOdfLoadingContext.
- bool stylesDotXml;
-
- QTextBlockFormat defaultBlockFormat;
- QTextCharFormat defaultCharFormat;
- int bodyProgressTotal;
- int bodyProgressValue;
- int nextProgressReportMs;
- QTime progressTime;
-
- QVector<KoList *> currentLists;
- KoListStyle *currentListStyle;
- int currentListLevel;
- // Two lists that follow the same style are considered as one for numbering purposes
- // This hash keeps all the lists that have the same style in one KoList.
- QHash<KoListStyle *, KoList *> lists;
-
- KoCharacterStyle *endCharStyle; // charstyle from empty span used at end of paragraph
-
- KoStyleManager *styleManager;
-
- KoShape *shape;
-
- int loadSpanLevel;
- int loadSpanInitialPos;
-
- QVector<QString> nameSpacesList;
- QList<KoSection *> openingSections;
- QStack<KoSection *> sectionStack; // Used to track the parent of current section
-
- QMap<QString, KoList *> xmlIdToListMap;
- QVector<KoList *> m_previousList;
-
- QMap<QString, KoList *> numberedParagraphListId;
-
- QStringList rdfIdList;
-
- /// level is between 1 and 10
- void setCurrentList(KoList *currentList, int level);
- /// level is between 1 and 10
- KoList *previousList(int level);
-
- explicit Private(KoShapeLoadingContext &context, KoShape *s)
- : context(context),
- textSharedData(0),
- // stylesDotXml says from where the office:automatic-styles are to be picked from:
- // the content.xml or the styles.xml (in a multidocument scenario). It does not
- // decide from where the office:styles are to be picked (always picked from styles.xml).
- // For our use here, stylesDotXml is always false (see ODF1.1 spec §2.1).
- stylesDotXml(context.odfLoadingContext().useStylesAutoStyles()),
- bodyProgressTotal(0),
- bodyProgressValue(0),
- nextProgressReportMs(0),
- currentLists(10),
- currentListStyle(0),
- currentListLevel(1),
- endCharStyle(0),
- styleManager(0),
- shape(s),
- loadSpanLevel(0),
- loadSpanInitialPos(0)
- , m_previousList(10)
- {
- progressTime.start();
- }
-
- ~Private() {
- debugText << "Loading took" << (float)(progressTime.elapsed()) / 1000 << " seconds";
- }
-
- KoList *list(const QTextDocument *document, KoListStyle *listStyle, bool mergeSimilarStyledList);
-};
-
-KoList *KoTextLoader::Private::list(const QTextDocument *document, KoListStyle *listStyle, bool mergeSimilarStyledList)
-{
- //TODO: Remove mergeSimilarStyledList parameter by finding a way to put the numbered-paragraphs of same level
- // to a single QTextList while loading rather than maintaining a hash list
- if (mergeSimilarStyledList) {
- if (lists.contains(listStyle)) {
- return lists[listStyle];
- }
- }
- KoList *newList = new KoList(document, listStyle);
- lists[listStyle] = newList;
- return newList;
-}
-
-void KoTextLoader::Private::setCurrentList(KoList *currentList, int level)
-{
- Q_ASSERT(level > 0 && level <= 10);
- currentLists[level - 1] = currentList;
- m_previousList[level - 1] = currentList;
-}
-
-KoList *KoTextLoader::Private::previousList(int level)
-{
- Q_ASSERT(level > 0 && level <= 10);
-
- if (m_previousList.size() < level) {
- return 0;
- }
-
- return m_previousList.at(level - 1);
-}
-
-inline static bool isspace(ushort ch)
-{
- // options are ordered by likelihood
- return ch == ' ' || ch== '\n' || ch == '\r' || ch == '\t';
-}
-
-QString KoTextLoader::normalizeWhitespace(const QString &in, bool leadingSpace)
-{
- QString textstring = in;
- ushort *text = (ushort*)textstring.data(); // this detaches from the string 'in'
- int r, w = 0;
- int len = textstring.length();
- for (r = 0; r < len; ++r) {
- const ushort ch = text[r];
- // check for space, tab, line feed, carriage return
- if (isspace(ch)) {
- // if we were lead by whitespace in some parent or previous sibling element,
- // we completely collapse this space
- if (r != 0 || !leadingSpace)
- text[w++] = ' ';
- // find the end of the whitespace run
- while (r < len && isspace(text[r]))
- ++r;
- // and then record the next non-whitespace character
- if (r < len)
- text[w++] = text[r];
- } else {
- text[w++] = ch;
- }
- }
- // and now trim off the unused part of the string
- textstring.truncate(w);
- return textstring;
-}
-
-/////////////KoTextLoader
-
-KoTextLoader::KoTextLoader(KoShapeLoadingContext &context, KoShape *shape)
- : QObject()
- , d(new Private(context, shape))
-{
- KoSharedLoadingData *sharedData = context.sharedData(KOTEXT_SHARED_LOADING_ID);
- if (sharedData) {
- d->textSharedData = dynamic_cast<KoTextSharedLoadingData *>(sharedData);
- }
-
- //debugText << "sharedData" << sharedData << "textSharedData" << d->textSharedData;
-
- if (!d->textSharedData) {
- d->textSharedData = new KoTextSharedLoadingData();
- KoDocumentResourceManager *rm = context.documentResourceManager();
- KoStyleManager *styleManager = rm->resource(KoText::StyleManager).value<KoStyleManager*>();
- d->textSharedData->loadOdfStyles(context, styleManager);
- if (!sharedData) {
- context.addSharedData(KOTEXT_SHARED_LOADING_ID, d->textSharedData);
- } else {
- warnText << "A different type of sharedData was found under the" << KOTEXT_SHARED_LOADING_ID;
- Q_ASSERT(false);
- }
- }
-
- if (context.documentRdf()) {
- d->rdfIdList = qobject_cast<KoDocumentRdfBase*>(context.documentRdf())->idrefList();
- }
-}
-
-KoTextLoader::~KoTextLoader()
-{
- delete d;
-}
-
-void KoTextLoader::loadBody(const KoXmlElement &bodyElem, QTextCursor &cursor, LoadBodyMode mode)
-{
- const QTextDocument *document = cursor.block().document();
-
- static int rootCallChecker = 0;
- if (rootCallChecker == 0) {
- if (document->resource(KoTextDocument::FrameCharFormat, KoTextDocument::FrameCharFormatUrl).isValid()) {
- d->defaultBlockFormat = KoTextDocument(document).frameBlockFormat();
- d->defaultCharFormat = KoTextDocument(document).frameCharFormat();
- } else {
- // This is the first call of loadBody on the document.
- // Store the default block and char formats
- // Will be used whenever a new block is inserted
- d->defaultCharFormat = cursor.charFormat();
- KoTextDocument(document).setFrameCharFormat(cursor.blockCharFormat());
- d->defaultBlockFormat = cursor.blockFormat();
- KoTextDocument(document).setFrameBlockFormat(cursor.blockFormat());
- }
- }
- rootCallChecker++;
-
- cursor.beginEditBlock();
-
- // If we are pasting text, we should handle sections correctly
- // we are saving which sections end in current block
- // and put their ends after the inserted text.
- QList<KoSectionEnd *> oldSectionEndings;
- if (mode == PasteMode) {
- QTextBlockFormat fmt = cursor.blockFormat();
- oldSectionEndings = KoSectionUtils::sectionEndings(fmt);
- fmt.clearProperty(KoParagraphStyle::SectionEndings);
- cursor.setBlockFormat(fmt);
- }
-
- if (!d->openingSections.isEmpty()) {
- QTextBlockFormat format = cursor.block().blockFormat();
- d->openingSections << KoSectionUtils::sectionStartings(format); // if we had some already we need to append the new ones
- KoSectionUtils::setSectionStartings(format, d->openingSections);
- cursor.setBlockFormat(format);
- d->openingSections.clear();
- }
-
- KoOdfLineNumberingConfiguration *lineNumberingConfiguration =
- new KoOdfLineNumberingConfiguration(d->context.odfLoadingContext()
- .stylesReader()
- .lineNumberingConfiguration());
- KoTextDocument(document).setLineNumberingConfiguration(lineNumberingConfiguration);
-
- KoOdfBibliographyConfiguration *bibConfiguration =
- new KoOdfBibliographyConfiguration(d->context.odfLoadingContext()
- .stylesReader()
- .globalBibliographyConfiguration());
- KoTextDocument(document).styleManager()->setBibliographyConfiguration(bibConfiguration);
-
- d->styleManager = KoTextDocument(document).styleManager();
-
-#ifdef KOOPENDOCUMENTLOADER_DEBUG
- debugText << "text-style:" << KoTextDebug::textAttributes(cursor.blockCharFormat());
-#endif
- bool usedParagraph = false; // set to true if we found a tag that used the paragraph, indicating that the next round needs to start a new one.
-
- if (bodyElem.namespaceURI() == KoXmlNS::table && bodyElem.localName() == "table") {
-
- loadTable(bodyElem, cursor);
- }
- else {
- startBody(KoXml::childNodesCount(bodyElem));
-
- KoXmlElement tag;
- for (KoXmlNode _node = bodyElem.firstChild(); !_node.isNull(); _node = _node.nextSibling() ) {
- if (!(tag = _node.toElement()).isNull()) {
- const QString localName = tag.localName();
-
- if (tag.namespaceURI() == KoXmlNS::text) {
- if ((usedParagraph) && (tag.localName() != "table"))
- cursor.insertBlock(d->defaultBlockFormat, d->defaultCharFormat);
- usedParagraph = true;
-
- if (localName == "p") { // text paragraph
- loadParagraph(tag, cursor);
- } else if (localName == "h") { // heading
- loadHeading(tag, cursor);
- } else if (localName == "unordered-list" || localName == "ordered-list" // OOo-1.1
- || localName == "list" || localName == "numbered-paragraph") { // OASIS
- loadList(tag, cursor);
- } else if (localName == "section") {
- loadSection(tag, cursor);
- } else if (localName == "table-of-content") {
- loadTableOfContents(tag, cursor);
- } else if (localName == "bibliography") {
- loadBibliography(tag, cursor);
- } else {
- KoInlineObject *obj = KoInlineObjectRegistry::instance()->createFromOdf(tag, d->context);
- if (obj) {
- KoInlineTextObjectManager *textObjectManager = KoTextDocument(cursor.block().document()).inlineTextObjectManager();
- if (textObjectManager) {
- KoVariableManager *varManager = textObjectManager->variableManager();
- if (varManager) {
- textObjectManager->insertInlineObject(cursor, obj);
- }
- }
- } else {
- usedParagraph = false;
- warnText << "unhandled text:" << localName;
- }
- }
- } else if (tag.namespaceURI() == KoXmlNS::draw
- || tag.namespaceURI() == KoXmlNS::dr3d) {
- loadShape(tag, cursor);
- } else if (tag.namespaceURI() == KoXmlNS::table) {
- if (localName == "table") {
- loadTable(tag, cursor);
- usedParagraph = false;
-
- } else {
- warnText << "KoTextLoader::loadBody unhandled table::" << localName;
- }
- }
- processBody();
- }
- }
- endBody();
- }
-
- rootCallChecker--;
-
- // Here we put old endings after text insertion.
- if (mode == PasteMode) {
- QTextBlockFormat fmt = cursor.blockFormat();
- oldSectionEndings = KoSectionUtils::sectionEndings(fmt);
- KoSectionUtils::setSectionEndings(fmt, oldSectionEndings);
- cursor.setBlockFormat(fmt);
- }
-
- cursor.endEditBlock();
-
- KoTextRangeManager *textRangeManager = KoTextDocument(cursor.block().document()).textRangeManager();
- Q_UNUSED(textRangeManager);
- //debugText << "text ranges::";
- //Q_FOREACH (KoTextRange *range, textRangeManager->textRanges()) {
- //debugText << range->id();
- //}
-
- if (!rootCallChecker) {
- // Allow to move end bounds of sections with inserting text
- KoTextDocument(cursor.block().document()).sectionModel()->allowMovingEndBound();
- }
-}
-
-void KoTextLoader::loadParagraph(const KoXmlElement &element, QTextCursor &cursor)
-{
- // TODO use the default style name a default value?
- const QString styleName = element.attributeNS(KoXmlNS::text, "style-name",
- QString());
-
- KoParagraphStyle *paragraphStyle = d->textSharedData->paragraphStyle(styleName, d->stylesDotXml);
-
- Q_ASSERT(d->styleManager);
- if (!paragraphStyle) {
- // Either the paragraph has no style or the style-name could not be found.
- // Fix up the paragraphStyle to be our default paragraph style in either case.
- if (!styleName.isEmpty())
- warnText << "paragraph style " << styleName << "not found - using default style";
- paragraphStyle = d->styleManager->defaultParagraphStyle();
-
- }
-
- QTextCharFormat cf = cursor.charFormat(); // store the current cursor char format
-
- if (paragraphStyle && (cursor.position() == cursor.block().position())) {
- QTextBlock block = cursor.block();
- // Apply list style when loading a list but we don't have a list style
- paragraphStyle->applyStyle(block, d->currentLists[d->currentListLevel - 1] && !d->currentListStyle);
- // Clear the outline level property. If a default-outline-level was set, it should not
- // be applied when loading a document, only on user action.
- block.blockFormat().clearProperty(KoParagraphStyle::OutlineLevel);
- }
-
- // Some paragraph have id's defined which we need to store so that we can eg
- // attach text animations to this specific paragraph later on
- KoElementReference id;
- id.loadOdf(element);
-
- if (id.isValid() && d->shape) {
- QTextBlock block = cursor.block();
- KoTextBlockData data(block); // this sets the user data, so don't remove
- d->context.addShapeSubItemId(d->shape, QVariant::fromValue(block.userData()), id.toString());
- }
-
- // attach Rdf to cursor.block()
- // remember inline Rdf metadata -- if the xml-id is actually
- // about rdf.
- if (element.hasAttributeNS(KoXmlNS::xhtml, "property")
- || d->rdfIdList.contains(id.toString()))
- {
- QTextBlock block = cursor.block();
- KoTextInlineRdf* inlineRdf =
- new KoTextInlineRdf((QTextDocument*)block.document(), block);
- if (inlineRdf->loadOdf(element)) {
- KoTextInlineRdf::attach(inlineRdf, cursor);
- }
- else {
- delete inlineRdf;
- inlineRdf = 0;
- }
- }
-
-#ifdef KOOPENDOCUMENTLOADER_DEBUG
- debugText << "text-style:" << KoTextDebug::textAttributes(cursor.blockCharFormat()) << d->currentLists[d->currentListLevel - 1] << d->currentListStyle;
-#endif
-
- bool stripLeadingSpace = true;
- loadSpan(element, cursor, &stripLeadingSpace);
- QTextBlock block = cursor.block();
- QString text = block.text();
- if (text.length() == 0 || text.at(text.length()-1) == QChar(0x2028)) {
- if (d->endCharStyle) {
- QTextBlockFormat blockFormat = block.blockFormat();
- blockFormat.setProperty(KoParagraphStyle::EndCharStyle, QVariant::fromValue< QSharedPointer<KoCharacterStyle> >(QSharedPointer<KoCharacterStyle>(d->endCharStyle->clone())));
- cursor.setBlockFormat(blockFormat);
- }
- }
- d->endCharStyle = 0;
-
- cursor.setCharFormat(cf); // restore the cursor char format
-}
-
-void KoTextLoader::loadHeading(const KoXmlElement &element, QTextCursor &cursor)
-{
- Q_ASSERT(d->styleManager);
- int level = qMax(-1, element.attributeNS(KoXmlNS::text, "outline-level", "-1").toInt());
- // This will fallback to the default-outline-level applied by KoParagraphStyle
-
- QString styleName = element.attributeNS(KoXmlNS::text, "style-name", QString());
-
- QTextBlock block = cursor.block();
- // Set the paragraph-style on the block
- KoParagraphStyle *paragraphStyle = d->textSharedData->paragraphStyle(styleName, d->stylesDotXml);
- if (!paragraphStyle) {
- paragraphStyle = d->styleManager->defaultParagraphStyle();
- }
- if (paragraphStyle) {
- // Apply list style when loading a list but we don't have a list style
- paragraphStyle->applyStyle(block, (d->currentListLevel > 1) &&
- d->currentLists[d->currentListLevel - 2] && !d->currentListStyle);
- }
-
- QTextCharFormat cf = cursor.charFormat(); // store the current cursor char format
-
- bool stripLeadingSpace = true;
- loadSpan(element, cursor, &stripLeadingSpace);
- cursor.setCharFormat(cf); // restore the cursor char format
-
- if ((block.blockFormat().hasProperty(KoParagraphStyle::OutlineLevel)) && (level == -1)) {
- level = block.blockFormat().property(KoParagraphStyle::OutlineLevel).toInt();
- } else {
- if (level == -1)
- level = 1;
- QTextBlockFormat blockFormat;
- blockFormat.setProperty(KoParagraphStyle::OutlineLevel, level);
- cursor.mergeBlockFormat(blockFormat);
- }
-
- if (element.hasAttributeNS(KoXmlNS::text, "is-list-header")) {
- QTextBlockFormat blockFormat;
- blockFormat.setProperty(KoParagraphStyle::IsListHeader, element.attributeNS(KoXmlNS::text, "is-list-header") == "true");
- cursor.mergeBlockFormat(blockFormat);
- }
-
- //we are defining our default behaviour here
- //Case 1: If text:outline-style is specified then we use the outline style to determine the numbering style
- //Case 2: If text:outline-style is not specified then if the <text:h> element is inside a <text:list> then it is numbered
- // otherwise it is not
- KoListStyle *outlineStyle = d->styleManager->outlineStyle();
- if (!outlineStyle) {
- outlineStyle = d->styleManager->defaultOutlineStyle()->clone();
- d->styleManager->setOutlineStyle(outlineStyle);
- }
-
- //if outline style is not specified and this is not inside a list then we do not number it
- if (outlineStyle->styleId() == d->styleManager->defaultOutlineStyle()->styleId()) {
- if (d->currentListLevel <= 1) {
- QTextBlockFormat blockFormat;
- blockFormat.setProperty(KoParagraphStyle::UnnumberedListItem, true);
- cursor.mergeBlockFormat(blockFormat);
- } else { //inside a list then take the numbering from the list style
- int level = d->currentListLevel - 1;
- KoListLevelProperties llp;
- if (!d->currentListStyle->hasLevelProperties(level)) {
- // Look if one of the lower levels are defined to we can copy over that level.
- for(int i = level - 1; i >= 0; --i) {
- if(d->currentLists[level - 1]->style()->hasLevelProperties(i)) {
- llp = d->currentLists[level - 1]->style()->levelProperties(i);
- break;
- }
- }
- } else {
- llp = d->currentListStyle->levelProperties(level);
- }
- llp.setLevel(level);
- outlineStyle->setLevelProperties(llp);
- }
- }
-
- KoList *list = KoTextDocument(block.document()).headingList();
- if (!list) {
- list = d->list(block.document(), outlineStyle, false);
- KoTextDocument(block.document()).setHeadingList(list);
- }
- list->setStyle(outlineStyle);
- list->add(block, level);
-
- // attach Rdf to cursor.block()
- // remember inline Rdf metadata
- KoElementReference id;
- id.loadOdf(element);
-
- if (element.hasAttributeNS(KoXmlNS::xhtml, "property")
- || d->rdfIdList.contains(id.toString())) {
- QTextBlock block = cursor.block();
- KoTextInlineRdf* inlineRdf =
- new KoTextInlineRdf((QTextDocument*)block.document(), block);
- if (inlineRdf->loadOdf(element)) {
- KoTextInlineRdf::attach(inlineRdf, cursor);
- }
- else {
- delete inlineRdf;
- inlineRdf = 0;
- }
- }
-
-#ifdef KOOPENDOCUMENTLOADER_DEBUG
- debugText << "text-style:" << KoTextDebug::textAttributes(cursor.blockCharFormat());
-#endif
-}
-
-void KoTextLoader::loadList(const KoXmlElement &element, QTextCursor &cursor)
-{
- const bool numberedParagraph = element.localName() == "numbered-paragraph";
-
- QString styleName = element.attributeNS(KoXmlNS::text, "style-name", QString());
- KoListStyle *listStyle = d->textSharedData->listStyle(styleName, d->stylesDotXml);
- KoList *continuedList = 0;
- int level;
-
- if (d->currentLists[d->currentListLevel - 1] || d->currentListLevel == 1) {
- d->currentLists[d->currentListLevel - 1] = 0;
- } else {
- d->currentLists[d->currentListLevel - 1] = d->currentLists[d->currentListLevel - 2];
- }
-
- if (element.hasAttributeNS(KoXmlNS::text, "continue-list")) {
- if (d->xmlIdToListMap.contains(element.attributeNS(KoXmlNS::text, "continue-list", QString()))) {
- continuedList = d->xmlIdToListMap.value(element.attributeNS(KoXmlNS::text, "continue-list", QString()));
- }
- } else {
- //the ODF spec says that continue-numbering is considered only if continue-list is not specified
- if (element.hasAttributeNS(KoXmlNS::text, "continue-numbering")) {
- const QString continueNumbering = element.attributeNS(KoXmlNS::text, "continue-numbering", QString());
- if (continueNumbering == "true") {
- //since ODF spec says "and the numbering style of the preceding list is the same as the current list"
- KoList *prevList = d->previousList(d->currentListLevel);
- if (prevList && listStyle && prevList->style()->hasLevelProperties(d->currentListLevel)
- && listStyle->hasLevelProperties(d->currentListLevel)
- && (prevList->style()->levelProperties(d->currentListLevel).style() ==
- listStyle->levelProperties(d->currentListLevel).style())) {
- continuedList = prevList;
- }
- }
- }
- }
-
- // TODO: get level from the style, if it has a style:list-level attribute (new in ODF-1.2)
- if (numberedParagraph) {
- if (element.hasAttributeNS(KoXmlNS::text, "list-id")) {
- QString listId = element.attributeNS(KoXmlNS::text, "list-id");
- if (d->numberedParagraphListId.contains(listId)) {
- d->currentLists.fill(d->numberedParagraphListId.value(listId));
- } else {
- KoList *currentList = d->list(cursor.block().document(), listStyle, false);
- d->currentLists.fill(currentList);
- d->numberedParagraphListId.insert(listId, currentList);
- }
- } else {
- d->currentLists.fill(d->list(cursor.block().document(), listStyle, true));
- }
-
- level = element.attributeNS(KoXmlNS::text, "level", "1").toInt();
-
- d->currentListStyle = listStyle;
- } else {
- if (!listStyle)
- listStyle = d->currentListStyle;
- level = d->currentListLevel++;
-
- KoList *currentList = d->currentLists[d->currentListLevel - 2];
- if (!currentList) {
- currentList = d->list(cursor.block().document(), listStyle, false);
- currentList->setListContinuedFrom(continuedList);
- d->currentLists[d->currentListLevel - 2] = currentList;
- }
- d->currentListStyle = listStyle;
- }
-
- if (element.hasAttributeNS(KoXmlNS::xml, "id")) {
- d->xmlIdToListMap.insert(element.attributeNS(KoXmlNS::xml, "id", QString()), d->currentLists[d->currentListLevel - 2]);
- }
-
- if (level < 0 || level > 10) { // should not happen but if it does then we should not crash/assert
- warnText << "Out of bounds list-level=" << level;
- level = qBound(0, level, 10);
- }
-
- if (! numberedParagraph) {
- d->setCurrentList(d->currentLists[d->currentListLevel - 2], level);
- }
-
-#ifdef KOOPENDOCUMENTLOADER_DEBUG
- if (d->currentListStyle)
- debugText << "styleName =" << styleName << "listStyle =" << d->currentListStyle->name()
- << "level =" << level << "hasLevelProperties =" << d->currentListStyle->hasLevelProperties(level)
- //<<" style="<<props.style()<<" prefix="<<props.listItemPrefix()<<" suffix="<<props.listItemSuffix()
- ;
- else
- debugText << "styleName =" << styleName << " currentListStyle = 0";
-#endif
-
- KoXmlElement e;
- QList<KoXmlElement> childElementsList;
-
- for (KoXmlNode _node = element.firstChild(); !_node.isNull(); _node = _node.nextSibling()) {
- if (!(e = _node.toElement()).isNull()) {
- childElementsList.append(e);
- }
- }
-
- // Iterate over list items and add them to the textlist
- bool firstTime = true;
- foreach (e, childElementsList) {
- if (e.localName() != "removed-content") {
- if (!firstTime && !numberedParagraph)
- cursor.insertBlock(d->defaultBlockFormat, d->defaultCharFormat);
- firstTime = false;
- loadListItem(e, cursor, level);
- }
- }
-
- if (numberedParagraph || --d->currentListLevel == 1) {
- d->currentListStyle = 0;
- d->currentLists.fill(0);
- }
-}
-
-void KoTextLoader::loadListItem(const KoXmlElement &e, QTextCursor &cursor, int level)
-{
- bool numberedParagraph = e.parentNode().toElement().localName() == "numbered-paragraph";
-
- if (e.isNull() || e.namespaceURI() != KoXmlNS::text)
- return;
-
- const bool listHeader = e.tagName() == "list-header";
-
- if (!numberedParagraph && e.tagName() != "list-item" && !listHeader)
- return;
-
- QTextBlock current = cursor.block();
-
- QTextBlockFormat blockFormat;
- if (numberedParagraph) {
- if (e.localName() == "p") {
- loadParagraph(e, cursor);
- } else if (e.localName() == "h") {
- loadHeading(e, cursor);
- }
- blockFormat.setProperty(KoParagraphStyle::ListLevel, level);
- } else {
- loadBody(e, cursor);
- }
-
- if (!cursor.blockFormat().boolProperty(KoParagraphStyle::ForceDisablingList)) {
- if (!current.textList()) {
- if (!d->currentLists[level - 1]->style()->hasLevelProperties(level)) {
- KoListLevelProperties llp;
- // Look if one of the lower levels are defined to we can copy over that level.
- for(int i = level - 1; i >= 0; --i) {
- if(d->currentLists[level - 1]->style()->hasLevelProperties(i)) {
- llp = d->currentLists[level - 1]->style()->levelProperties(i);
- break;
- }
- }
- llp.setLevel(level);
- // TODO make the 10 configurable
- llp.setIndent(level * 10.0);
- d->currentLists[level - 1]->style()->setLevelProperties(llp);
- }
-
- d->currentLists[level - 1]->add(current, level);
- }
-
- if (listHeader)
- blockFormat.setProperty(KoParagraphStyle::IsListHeader, true);
-
- if (e.hasAttributeNS(KoXmlNS::text, "start-value")) {
- int startValue = e.attributeNS(KoXmlNS::text, "start-value", QString()).toInt();
- blockFormat.setProperty(KoParagraphStyle::ListStartValue, startValue);
- }
-
-
- // mark intermediate paragraphs as unnumbered items
- QTextCursor c(current);
- c.mergeBlockFormat(blockFormat);
- while (c.block() != cursor.block()) {
- c.movePosition(QTextCursor::NextBlock);
- if (c.block().textList()) // a sublist
- break;
- blockFormat = c.blockFormat();
- blockFormat.setProperty(listHeader ? KoParagraphStyle::IsListHeader : KoParagraphStyle::UnnumberedListItem, true);
- c.setBlockFormat(blockFormat);
- d->currentLists[level - 1]->add(c.block(), level);
- }
- }
- debugText << "text-style:" << KoTextDebug::textAttributes(cursor.blockCharFormat());
-}
-
-void KoTextLoader::loadSection(const KoXmlElement &sectionElem, QTextCursor &cursor)
-{
- KoSection *parent = d->sectionStack.empty() ? 0 : d->sectionStack.top();
- KoSection *section = d->context.sectionModel()->createSection(cursor, parent);
- if (!section->loadOdf(sectionElem, d->textSharedData, d->stylesDotXml)) {
- delete section;
- warnText << "Could not load section";
- return;
- }
-
- d->sectionStack << section;
- d->openingSections << section;
-
- loadBody(sectionElem, cursor);
-
- // Close the section on the last block of text we have loaded just now.
- QTextBlockFormat format = cursor.block().blockFormat();
- KoSectionUtils::setSectionEndings(format,
- KoSectionUtils::sectionEndings(format) << d->context.sectionModel()->createSectionEnd(section));
- d->sectionStack.pop();
-
- cursor.setBlockFormat(format);
-
- section->setKeepEndBound(true); // This bound should stop moving with new text
-}
-
-void KoTextLoader::loadNote(const KoXmlElement &noteElem, QTextCursor &cursor)
-{
- KoInlineTextObjectManager *textObjectManager = KoTextDocument(cursor.block().document()).inlineTextObjectManager();
- if (textObjectManager) {
- QString className = noteElem.attributeNS(KoXmlNS::text, "note-class");
- KoInlineNote *note = 0;
- int position = cursor.position(); // need to store this as the following might move is
- if (className == "footnote") {
- note = new KoInlineNote(KoInlineNote::Footnote);
- note->setMotherFrame(KoTextDocument(cursor.block().document()).auxillaryFrame());
- } else {
- note = new KoInlineNote(KoInlineNote::Endnote);
- note->setMotherFrame(KoTextDocument(cursor.block().document()).auxillaryFrame());
- }
- if (note->loadOdf(noteElem, d->context)) {
- cursor.setPosition(position); // restore the position before inserting the note
- textObjectManager->insertInlineObject(cursor, note);
- } else {
- cursor.setPosition(position); // restore the position
- delete note;
- }
- }
-}
-
-void KoTextLoader::loadCite(const KoXmlElement &noteElem, QTextCursor &cursor)
-{
- KoInlineTextObjectManager *textObjectManager = KoTextDocument(cursor.block().document()).inlineTextObjectManager();
- if (textObjectManager) {
- //Now creating citation with default type KoInlineCite::Citation.
- KoInlineCite *cite = new KoInlineCite(KoInlineCite::Citation);
-
- // the manager is needed during loading so set it now
- cite->setManager(textObjectManager);
- if (cite->loadOdf(noteElem, d->context)) {
- textObjectManager->insertInlineObject(cursor, cite);
- } else {
- delete cite;
- }
- }
-}
-
-void KoTextLoader::loadText(const QString &fulltext, QTextCursor &cursor,
- bool *stripLeadingSpace, bool isLastNode)
-{
- QString text = normalizeWhitespace(fulltext, *stripLeadingSpace);
-#ifdef KOOPENDOCUMENTLOADER_DEBUG
- debugText << " <text> text=" << text << text.length() << *stripLeadingSpace;
-#endif
-
- if (!text.isEmpty()) {
- // if present text ends with a space,
- // we can remove the leading space in the next text
- *stripLeadingSpace = text[text.length() - 1].isSpace();
-
- cursor.insertText(text);
-
- if (d->loadSpanLevel == 1 && isLastNode
- && cursor.position() > d->loadSpanInitialPos) {
- QTextCursor tempCursor(cursor);
- tempCursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, 1); // select last char loaded
- if (tempCursor.selectedText() == " " && *stripLeadingSpace) { // if it's a collapsed blankspace
- tempCursor.removeSelectedText(); // remove it
- }
- }
- }
-}
-
-void KoTextLoader::loadSpan(const KoXmlElement &element, QTextCursor &cursor, bool *stripLeadingSpace)
-{
-#ifdef KOOPENDOCUMENTLOADER_DEBUG
- debugText << "text-style:" << KoTextDebug::textAttributes(cursor.blockCharFormat());
-#endif
- Q_ASSERT(stripLeadingSpace);
- if (d->loadSpanLevel++ == 0)
- d->loadSpanInitialPos = cursor.position();
-
- for (KoXmlNode node = element.firstChild(); !node.isNull(); node = node.nextSibling()) {
- KoXmlElement ts = node.toElement();
- const QString localName(ts.localName());
- const bool isTextNS = ts.namespaceURI() == KoXmlNS::text;
- const bool isDrawNS = ts.namespaceURI() == KoXmlNS::draw;
- const bool isDr3dNS = ts.namespaceURI() == KoXmlNS::dr3d;
- const bool isOfficeNS = ts.namespaceURI() == KoXmlNS::office;
-
- //if (isOfficeNS)
- debugText << "office:"<<isOfficeNS << localName;
-
-#ifdef KOOPENDOCUMENTLOADER_DEBUG
- debugText << "load" << localName << *stripLeadingSpace << node.toText().data();
-#endif
-
- if (!(isTextNS && localName == "span")) {
- d->endCharStyle = 0;
- }
-
- if (node.isText()) {
- bool isLastNode = node.nextSibling().isNull();
- loadText(node.toText().data(), cursor, stripLeadingSpace,
- isLastNode);
- } else if (isTextNS && localName == "span") { // text:span
-#ifdef KOOPENDOCUMENTLOADER_DEBUG
- debugText << " <span> localName=" << localName;
-#endif
- QString styleName = ts.attributeNS(KoXmlNS::text, "style-name", QString());
-
- QTextCharFormat cf = cursor.charFormat(); // store the current cursor char format
-
- KoCharacterStyle *characterStyle = d->textSharedData->characterStyle(styleName, d->stylesDotXml);
- if (characterStyle) {
- characterStyle->applyStyle(&cursor);
- if (ts.firstChild().isNull()) {
- // empty span so let's save the characterStyle for possible use at end of par
- d->endCharStyle = characterStyle;
- }
- } else if (!styleName.isEmpty()) {
- warnText << "character style " << styleName << " not found";
- }
-
- loadSpan(ts, cursor, stripLeadingSpace); // recurse
- cursor.setCharFormat(cf); // restore the cursor char format
- } else if (isTextNS && localName == "s") { // text:s
- int howmany = 1;
- if (ts.hasAttributeNS(KoXmlNS::text, "c")) {
- howmany = ts.attributeNS(KoXmlNS::text, "c", QString()).toInt();
- }
- cursor.insertText(QString().fill(32, howmany));
- *stripLeadingSpace = false;
- } else if ( (isTextNS && localName == "note")) { // text:note
- loadNote(ts, cursor);
- } else if (isTextNS && localName == "bibliography-mark") { // text:bibliography-mark
- loadCite(ts,cursor);
- } else if (isTextNS && localName == "tab") { // text:tab
- cursor.insertText("\t");
- *stripLeadingSpace = false;
- } else if (isTextNS && localName == "a") { // text:a
- QString target = ts.attributeNS(KoXmlNS::xlink, "href");
- QString styleName = ts.attributeNS(KoXmlNS::text, "style-name", QString());
- QTextCharFormat cf = cursor.charFormat(); // store the current cursor char format
-
- if (!styleName.isEmpty()) {
- KoCharacterStyle *characterStyle = d->textSharedData->characterStyle(styleName, d->stylesDotXml);
- if (characterStyle) {
- characterStyle->applyStyle(&cursor);
- } else {
- warnText << "character style " << styleName << " not found";
- }
- }
- QTextCharFormat newCharFormat = cursor.charFormat();
- newCharFormat.setAnchor(true);
- newCharFormat.setProperty(KoCharacterStyle::AnchorType, KoCharacterStyle::Anchor);
- newCharFormat.setAnchorHref(target);
- cursor.setCharFormat(newCharFormat);
-
- loadSpan(ts, cursor, stripLeadingSpace); // recurse
- cursor.setCharFormat(cf); // restore the cursor char format
-
- } else if (isTextNS && localName == "line-break") { // text:line-break
-#ifdef KOOPENDOCUMENTLOADER_DEBUG
- debugText << " <line-break> Node localName=" << localName;
-#endif
- cursor.insertText(QChar(0x2028));
- *stripLeadingSpace = false;
- } else if (isTextNS && localName == "soft-page-break") { // text:soft-page-break
- KoInlineTextObjectManager *textObjectManager = KoTextDocument(cursor.block().document()).inlineTextObjectManager();
- if (textObjectManager) {
- textObjectManager->insertInlineObject(cursor, new KoTextSoftPageBreak());
- }
- } else if (isTextNS && localName == "meta") {
-#ifdef KOOPENDOCUMENTLOADER_DEBUG
- debugText << "loading a text:meta";
-#endif
- KoInlineTextObjectManager *textObjectManager = KoTextDocument(cursor.block().document()).inlineTextObjectManager();
- if (textObjectManager) {
- const QTextDocument *document = cursor.block().document();
- KoTextMeta* startmark = new KoTextMeta(document);
- textObjectManager->insertInlineObject(cursor, startmark);
-
- // Add inline Rdf here.
- KoElementReference id;
- id.loadOdf(ts);
-
- if (ts.hasAttributeNS(KoXmlNS::xhtml, "property")
- || (id.isValid() && d->rdfIdList.contains(id.toString()))) {
- KoTextInlineRdf* inlineRdf =
- new KoTextInlineRdf((QTextDocument*)document, startmark);
- if (inlineRdf->loadOdf(ts)) {
- startmark->setInlineRdf(inlineRdf);
- }
- else {
- delete inlineRdf;
- inlineRdf = 0;
- }
- }
-
- loadSpan(ts, cursor, stripLeadingSpace); // recurse
-
- KoTextMeta* endmark = new KoTextMeta(document);
- textObjectManager->insertInlineObject(cursor, endmark);
- startmark->setEndBookmark(endmark);
- }
- }
- // text:bookmark, text:bookmark-start and text:bookmark-end
- else if (isTextNS && (localName == "bookmark" || localName == "bookmark-start" || localName == "bookmark-end")) {
- KoTextRangeManager *textRangeManager = KoTextDocument(cursor.block().document()).textRangeManager();
-
- if (localName == "bookmark-end") {
- KoBookmark *bookmark = textRangeManager->bookmarkManager()->bookmark(KoBookmark::createUniqueBookmarkName(textRangeManager->bookmarkManager(), ts.attribute("name"), true));
- if (bookmark) {
- bookmark->setRangeEnd(cursor.position());
- }
- } else {
- KoBookmark *bookmark = new KoBookmark(cursor);
- bookmark->setManager(textRangeManager);
- if (textRangeManager && bookmark->loadOdf(ts, d->context)) {
- textRangeManager->insert(bookmark);
- }
- else {
- warnText << "Could not load bookmark";
- delete bookmark;
- }
- }
- } else if (isTextNS && localName == "bookmark-ref") {
- QString bookmarkName = ts.attribute("ref-name");
- QTextCharFormat cf = cursor.charFormat(); // store the current cursor char format
- if (!bookmarkName.isEmpty()) {
- QTextCharFormat linkCf(cf); // and copy it to alter it
- linkCf.setAnchor(true);
- linkCf.setProperty(KoCharacterStyle::AnchorType, KoCharacterStyle::Bookmark);
- QStringList anchorName;
- anchorName << bookmarkName;
- linkCf.setAnchorHref('#'+ bookmarkName);
- cursor.setCharFormat(linkCf);
- }
- // TODO add support for loading text:reference-format
- loadSpan(ts, cursor, stripLeadingSpace); // recurse
- cursor.setCharFormat(cf); // restore the cursor char format
- }
- // text:annotation and text:annotation-end
- else if (isOfficeNS && (localName == "annotation" || localName == "annotation-end")) {
- debugText << "------> annotation found" << localName;
-
- KoTextRangeManager *textRangeManager = KoTextDocument(cursor.block().document()).textRangeManager();
-
- if (localName == "annotation-end") {
- // If the tag is annotation-end, there should already be a KoAnnotation
- // with the same name as this one. If so, just find it and set the end
- // of the range to the current position.
- KoAnnotation *annotation = textRangeManager->annotationManager()->annotation(KoAnnotation::createUniqueAnnotationName(textRangeManager->annotationManager(), ts.attribute("name"), true));
- if (annotation) {
- annotation->setRangeEnd(cursor.position());
- }
- } else {
- // if the tag is "annotation" then create a KoAnnotation
- // and an annotation shape and call loadOdf() in them.
- KoAnnotation *annotation = new KoAnnotation(cursor);
- annotation->setManager(textRangeManager);
- if (textRangeManager && annotation->loadOdf(ts, d->context)) {
- textRangeManager->insert(annotation);
-
- KoShape *shape = KoShapeRegistry::instance()->createShapeFromOdf(ts, d->context);
- // Don't show it before it's being laid out.
- //
- // Also this hides it in all applications but
- // those that have an annotation layout manager
- // (currently: words, author).
- shape->setVisible(false);
-
- d->textSharedData->shapeInserted(shape, element, d->context);
- annotation->setAnnotationShape(shape);
- }
- else {
- warnText << "Could not load annotation";
- delete annotation;
- }
- }
- }
- else if (isTextNS && localName == "number") { // text:number
- /* ODF Spec, §4.1.1, Formatted Heading Numbering
- If a heading has a numbering applied, the text of the formatted number can be included in a
- <text:number> element. This text can be used by applications that do not support numbering of
- headings, but it will be ignored by applications that support numbering. */
- } else if (isTextNS && localName == "dde-connection") {
- // TODO: load actual connection (or at least preserve it)
- // For now: just load the text
- for (KoXmlNode n = ts.firstChild(); !n.isNull(); n = n.nextSibling()) {
- if (n.isText()) {
- loadText(n.toText().data(), cursor, stripLeadingSpace, false);
- }
- }
- } else if ((isDrawNS) && localName == "a") { // draw:a
- loadShapeWithHyperLink(ts, cursor);
- } else if (isDrawNS || isDr3dNS) {
- loadShape(ts, cursor);
- } else {
- KoInlineObject *obj = KoInlineObjectRegistry::instance()->createFromOdf(ts, d->context);
-
- KoInlineTextObjectManager *textObjectManager = KoTextDocument(cursor.block().document()).inlineTextObjectManager();
- if (obj && textObjectManager) {
- KoVariableManager *varManager = textObjectManager->variableManager();
- if (varManager) {
- textObjectManager->insertInlineObject(cursor, obj);
- // we need to update whitespace stripping here so we don't remove to many whitespaces.
- // this is simplified as it assumes the first child it the text item but that should be the case
- // most of the time with variables so it should be fine.
- KoXmlNode child = ts.firstChild();
- if (child.isText()) {
- QString text = normalizeWhitespace(child.toText().data(), *stripLeadingSpace);
- if (!text.isEmpty()) {
- // if present text ends with a space,
- // we can remove the leading space in the next text
- *stripLeadingSpace = text[text.length() - 1].isSpace();
- }
- }
- }
- } else {
-#if 0 //1.6:
- bool handled = false;
- // Check if it's a variable
- KoVariable *var = context.variableCollection().loadOasisField(textDocument(), ts, context);
- if (var) {
- textData = "#"; // field placeholder
- customItem = var;
- handled = true;
- }
- if (!handled) {
- handled = textDocument()->loadSpanTag(ts, context, this, pos, textData, customItem);
- if (!handled) {
- warnText << "Ignoring tag " << ts.tagName();
- context.styleStack().restore();
- continue;
- }
- }
-#else
-#ifdef KOOPENDOCUMENTLOADER_DEBUG
- debugText << "Node '" << localName << "' unhandled";
-#endif
- }
-#endif
- }
- }
- --d->loadSpanLevel;
-}
-
-void KoTextLoader::loadTable(const KoXmlElement &tableElem, QTextCursor &cursor)
-{
- QTextTableFormat tableFormat;
- QString tableStyleName = tableElem.attributeNS(KoXmlNS::table, "style-name", "");
- if (!tableStyleName.isEmpty()) {
- KoTableStyle *tblStyle = d->textSharedData->tableStyle(tableStyleName, d->stylesDotXml);
- if (tblStyle)
- tblStyle->applyStyle(tableFormat);
- }
-
- QString tableTemplateName = tableElem.attributeNS(KoXmlNS::table, "template-name", "");
- if (! tableTemplateName.isEmpty()) {
- if(KoTextTableTemplate *tableTemplate = d->styleManager->tableTemplate(tableTemplateName)) {
- tableFormat.setProperty(KoTableStyle::TableTemplate, tableTemplate->styleId());
- }
- }
-
- if (tableElem.attributeNS(KoXmlNS::table, "use-banding-columns-styles", "false") == "true") {
- tableFormat.setProperty(KoTableStyle::UseBandingColumnStyles, true);
- }
-
- if (tableElem.attributeNS(KoXmlNS::table, "use-banding-rows-styles", "false") == "true") {
- tableFormat.setProperty(KoTableStyle::UseBandingRowStyles, true);
- }
-
- if (tableElem.attributeNS(KoXmlNS::table, "use-first-column-styles", "false") == "true") {
- tableFormat.setProperty(KoTableStyle::UseFirstColumnStyles, true);
- }
-
- if (tableElem.attributeNS(KoXmlNS::table, "use-first-row-styles", "false") == "true") {
- tableFormat.setProperty(KoTableStyle::UseFirstRowStyles, true);
- }
-
- if (tableElem.attributeNS(KoXmlNS::table, "use-last-column-styles", "false") == "true") {
- tableFormat.setProperty(KoTableStyle::UseLastColumnStyles, true);
- }
-
- if (tableElem.attributeNS(KoXmlNS::table, "use-last-row-styles", "false") == "true") {
- tableFormat.setProperty(KoTableStyle::UseLastRowStyles, true);
- }
-
- // Let's try to figure out when to hide the current block
- QTextBlock currentBlock = cursor.block();
- QTextTable *outerTable = cursor.currentTable();
- bool hide = cursor.position() == 0;
- if (outerTable) {
- QTextTableCell cell = outerTable->cellAt(cursor.position());
- if (cursor.position() == cell.firstCursorPosition().position()) {
- hide = true;
- }
- }
- if (!hide) {
- // Let's insert an extra block so that will be the one we hide instead
- cursor.insertBlock(cursor.blockFormat(), cursor.blockCharFormat());
- currentBlock = cursor.block();
- }
-
- if (tableElem.attributeNS(KoXmlNS::table, "protected", "false") == "true") {
- tableFormat.setProperty(KoTableStyle::TableIsProtected, true);
- }
- QTextTable *tbl = cursor.insertTable(1, 1, tableFormat);
-
- // 'Hide' the block before the table (possibly the extra block we just inserted)
- QTextBlockFormat blockFormat;
- //blockFormat.setFont(currentBlock.blockFormat().font());
- QTextCursor tmpCursor(currentBlock);
- blockFormat.setProperty(KoParagraphStyle::HiddenByTable, true);
- QVariant masterStyle = tableFormat.property(KoTableStyle::MasterPageName);
- if (!masterStyle.isNull()) {
- // if table has a master page style property, copy it to block before table, because
- // this block is a hidden block so let's make it belong to the same masterpage
- // so we don't end up with a page break at the wrong place
- blockFormat.setProperty(KoParagraphStyle::MasterPageName, masterStyle);
- }
- tmpCursor.setBlockFormat(blockFormat);
-
- KoTableColumnAndRowStyleManager tcarManager = KoTableColumnAndRowStyleManager::getManager(tbl);
- int rows = 0;
- int columns = 0;
- QList<QRect> spanStore; //temporary list to store spans until the entire table have been created
- KoXmlElement tblTag;
- int headingRowCounter = 0;
- QList<KoXmlElement> rowTags;
-
- forEachElement(tblTag, tableElem) {
- if (! tblTag.isNull()) {
- const QString tblLocalName = tblTag.localName();
- if (tblTag.namespaceURI() == KoXmlNS::table) {
- if (tblLocalName == "table-column") {
- loadTableColumn(tblTag, tbl, columns);
- } else if (tblLocalName == "table-columns") {
- KoXmlElement e;
- forEachElement(e, tblTag) {
- if (e.localName() == "table-column") {
- loadTableColumn(e, tbl, columns);
- }
- }
- } else if (tblLocalName == "table-row") {
- loadTableRow(tblTag, tbl, spanStore, cursor, rows);
- } else if (tblLocalName == "table-rows") {
- KoXmlElement subTag;
- forEachElement(subTag, tblTag) {
- if (!subTag.isNull()) {
- if ((subTag.namespaceURI() == KoXmlNS::table) && (subTag.localName() == "table-row")) {
- loadTableRow(subTag, tbl, spanStore, cursor, rows);
- }
- }
- }
- } else if (tblLocalName == "table-header-rows") {
- KoXmlElement subTag;
- forEachElement(subTag, tblTag) {
- if (!subTag.isNull()) {
- if ((subTag.namespaceURI() == KoXmlNS::table) && (subTag.localName() == "table-row")) {
- headingRowCounter++;
- loadTableRow(subTag, tbl, spanStore, cursor, rows);
- }
- }
- }
- }
- }
- }
- }
-
- if (headingRowCounter > 0) {
- QTextTableFormat fmt = tbl->format();
- fmt.setProperty(KoTableStyle::NumberHeadingRows, headingRowCounter);
- tbl->setFormat(fmt);
- }
-
- // Finally create spans
- Q_FOREACH (const QRect &span, spanStore) {
- tbl->mergeCells(span.y(), span.x(), span.height(), span.width()); // for some reason Qt takes row, column
- }
- cursor = tbl->lastCursorPosition();
- cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 1);
-}
-
-void KoTextLoader::loadTableColumn(const KoXmlElement &tblTag, QTextTable *tbl, int &columns)
-{
- KoTableColumnAndRowStyleManager tcarManager = KoTableColumnAndRowStyleManager::getManager(tbl);
- int rows = tbl->rows();
- int repeatColumn = tblTag.attributeNS(KoXmlNS::table, "number-columns-repeated", "1").toInt();
- QString columnStyleName = tblTag.attributeNS(KoXmlNS::table, "style-name", "");
- if (!columnStyleName.isEmpty()) {
- KoTableColumnStyle *columnStyle = d->textSharedData->tableColumnStyle(columnStyleName, d->stylesDotXml);
- if (columnStyle) {
- for (int c = columns; c < columns + repeatColumn; c++) {
- tcarManager.setColumnStyle(c, *columnStyle);
- }
- }
- }
-
- QString defaultCellStyleName = tblTag.attributeNS(KoXmlNS::table, "default-cell-style-name", "");
- if (!defaultCellStyleName.isEmpty()) {
- KoTableCellStyle *cellStyle = d->textSharedData->tableCellStyle(defaultCellStyleName, d->stylesDotXml);
- for (int c = columns; c < columns + repeatColumn; c++) {
- tcarManager.setDefaultColumnCellStyle(c, cellStyle);
- }
- }
-
- columns = columns + repeatColumn;
- if (rows > 0)
- tbl->resize(rows, columns);
- else
- tbl->resize(1, columns);
-}
-
-void KoTextLoader::loadTableRow(const KoXmlElement &tblTag, QTextTable *tbl, QList<QRect> &spanStore, QTextCursor &cursor, int &rows)
-{
- KoTableColumnAndRowStyleManager tcarManager = KoTableColumnAndRowStyleManager::getManager(tbl);
-
- int columns = tbl->columns();
- QString rowStyleName = tblTag.attributeNS(KoXmlNS::table, "style-name", "");
- if (!rowStyleName.isEmpty()) {
- KoTableRowStyle *rowStyle = d->textSharedData->tableRowStyle(rowStyleName, d->stylesDotXml);
- if (rowStyle) {
- tcarManager.setRowStyle(rows, *rowStyle);
- }
- }
-
- QString defaultCellStyleName = tblTag.attributeNS(KoXmlNS::table, "default-cell-style-name", "");
- if (!defaultCellStyleName.isEmpty()) {
- KoTableCellStyle *cellStyle = d->textSharedData->tableCellStyle(defaultCellStyleName, d->stylesDotXml);
- tcarManager.setDefaultRowCellStyle(rows, cellStyle);
- }
-
- rows++;
- if (columns > 0)
- tbl->resize(rows, columns);
- else
- tbl->resize(rows, 1);
-
- // Added a row
- int currentCell = 0;
- KoXmlElement rowTag;
- forEachElement(rowTag, tblTag) {
- if (!rowTag.isNull()) {
- const QString rowLocalName = rowTag.localName();
- if (rowTag.namespaceURI() == KoXmlNS::table) {
- if (rowLocalName == "table-cell") {
- loadTableCell(rowTag, tbl, spanStore, cursor, currentCell);
- currentCell++;
- } else if (rowLocalName == "covered-table-cell") {
- currentCell++;
- }
- }
- }
- }
-}
-
-void KoTextLoader::loadTableCell(const KoXmlElement &rowTag, QTextTable *tbl, QList<QRect> &spanStore, QTextCursor &cursor, int &currentCell)
-{
- KoTableColumnAndRowStyleManager tcarManager = KoTableColumnAndRowStyleManager::getManager(tbl);
- const int currentRow = tbl->rows() - 1;
- QTextTableCell cell = tbl->cellAt(currentRow, currentCell);
-
- // store spans until entire table have been loaded
- int rowsSpanned = rowTag.attributeNS(KoXmlNS::table, "number-rows-spanned", "1").toInt();
- int columnsSpanned = rowTag.attributeNS(KoXmlNS::table, "number-columns-spanned", "1").toInt();
- spanStore.append(QRect(currentCell, currentRow, columnsSpanned, rowsSpanned));
-
- if (cell.isValid()) {
- QString cellStyleName = rowTag.attributeNS(KoXmlNS::table, "style-name", "");
- KoTableCellStyle *cellStyle = 0;
- if (!cellStyleName.isEmpty()) {
- cellStyle = d->textSharedData->tableCellStyle(cellStyleName, d->stylesDotXml);
- } else if (tcarManager.defaultRowCellStyle(currentRow)) {
- cellStyle = tcarManager.defaultRowCellStyle(currentRow);
- } else if (tcarManager.defaultColumnCellStyle(currentCell)) {
- cellStyle = tcarManager.defaultColumnCellStyle(currentCell);
- }
-
- if (cellStyle)
- cellStyle->applyStyle(cell);
-
- QTextTableCellFormat cellFormat = cell.format().toTableCellFormat();
-
- if (rowTag.attributeNS(KoXmlNS::table, "protected", "false") == "true") {
- cellFormat.setProperty(KoTableCellStyle::CellIsProtected, true);
- }
-
- cell.setFormat(cellFormat);
-
- // handle inline Rdf
- // rowTag is the current table cell.
- KoElementReference id;
- id.loadOdf(rowTag);
-
- if (rowTag.hasAttributeNS(KoXmlNS::xhtml, "property") || d->rdfIdList.contains(id.toString())) {
- KoTextInlineRdf* inlineRdf = new KoTextInlineRdf((QTextDocument*)cursor.block().document(),cell);
- if (inlineRdf->loadOdf(rowTag)) {
- QTextTableCellFormat cellFormat = cell.format().toTableCellFormat();
- cellFormat.setProperty(KoTableCellStyle::InlineRdf,QVariant::fromValue(inlineRdf));
- cell.setFormat(cellFormat);
- }
- else {
- delete inlineRdf;
- inlineRdf = 0;
- }
- }
-
- cursor = cell.firstCursorPosition();
- loadBody(rowTag, cursor);
- }
-}
-
-void KoTextLoader::loadShapeWithHyperLink(const KoXmlElement &element, QTextCursor& cursor)
-{
- // get the hyperlink
- QString hyperLink = element.attributeNS(KoXmlNS::xlink, "href");
- KoShape *shape = 0;
-
- //load the shape for hyperlink
- KoXmlNode node = element.firstChild();
- if (!node.isNull()) {
- KoXmlElement ts = node.toElement();
- shape = loadShape(ts, cursor);
- if (shape) {
- shape->setHyperLink(hyperLink);
- }
- }
-}
-
-KoShape *KoTextLoader::loadShape(const KoXmlElement &element, QTextCursor &cursor)
-{
- KoShape *shape = KoShapeRegistry::instance()->createShapeFromOdf(element, d->context);
- if (!shape) {
- debugText << "shape '" << element.localName() << "' unhandled";
- return 0;
- }
-
- KoShapeAnchor *anchor = new KoShapeAnchor(shape);
- anchor->loadOdf(element, d->context);
- // shape->setAnchor(anchor); // undefined in Krita!
- d->textSharedData->shapeInserted(shape, element, d->context);
-
- // page anchored shapes are handled differently
- if (anchor->anchorType() == KoShapeAnchor::AnchorPage) {
- // nothing else to do
- delete anchor;
- } else if (anchor->anchorType() == KoShapeAnchor::AnchorAsCharacter) {
- KoAnchorInlineObject *anchorObject = new KoAnchorInlineObject(anchor);
-
- KoInlineTextObjectManager *textObjectManager = KoTextDocument(cursor.block().document()).inlineTextObjectManager();
- if (textObjectManager) {
- textObjectManager->insertInlineObject(cursor, anchorObject);
- }
- } else { // KoShapeAnchor::AnchorToCharacter or KoShapeAnchor::AnchorParagraph
- KoAnchorTextRange *anchorRange = new KoAnchorTextRange(anchor, cursor);
-
- KoTextRangeManager *textRangeManager = KoTextDocument(cursor.block().document()).textRangeManager();
-
- anchorRange->setManager(textRangeManager);
- textRangeManager->insert(anchorRange);
- }
- return shape;
-}
-
-
-void KoTextLoader::loadTableOfContents(const KoXmlElement &/*element*/, QTextCursor &/*cursor*/)
-{
-}
-
-void KoTextLoader::loadBibliography(const KoXmlElement &/*element*/, QTextCursor &/*cursor*/)
-{
-}
-
-void KoTextLoader::startBody(int total)
-{
- d->bodyProgressTotal += total;
-}
-
-void KoTextLoader::processBody()
-{
- d->bodyProgressValue++;
- if (d->progressTime.elapsed() >= d->nextProgressReportMs) { // update based on elapsed time, don't saturate the queue
- d->nextProgressReportMs = d->progressTime.elapsed() + 333; // report 3 times per second
- Q_ASSERT(d->bodyProgressTotal > 0);
- const int percent = d->bodyProgressValue * 100 / d->bodyProgressTotal;
- emit sigProgress(percent);
- }
-}
-
-void KoTextLoader::endBody()
-{
-}
diff --git a/plugins/flake/textshape/kotext/opendocument/KoTextLoader.h b/plugins/flake/textshape/kotext/opendocument/KoTextLoader.h
deleted file mode 100644
index 2a4e9f9567..0000000000
--- a/plugins/flake/textshape/kotext/opendocument/KoTextLoader.h
+++ /dev/null
@@ -1,223 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2001-2006 David Faure <faure@kde.org>
- * Copyright (C) 2007 Sebastian Sauer <mail@dipe.org>
- * Copyright (C) 2007 Pierre Ducroquet <pinaraf@gmail.com>
- * Copyright (C) 2007-2009 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2010 KO GmbH <ben.martin@kogmbh.com>
- * Copyright (C) 2011 Pavol Korinek <pavol.korinek@ixonos.com>
- * Copyright (C) 2011 Lukáš Tvrdý <lukas.tvrdy@ixonos.com>
- *
- * 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 KOTEXTLOADER_H
-#define KOTEXTLOADER_H
-
-#include <QObject>
-
-#include "kritatext_export.h"
-#include <KoXmlReaderForward.h>
-
-class QTextCursor;
-class QTextTable;
-class QRect;
-
-class KoShapeLoadingContext;
-class KoShape;
-
-/**
- * The KoTextLoader loads is use to load text for one and only one textdocument or shape
- * to the scribe text-engine using QTextCursor objects. So if you have two shapes 2 different
- * KoTextLoader are used for that. Also if you have a frame with text inside a text a new
- * KoTextLoader is used.
- *
- * If you want to use the KoTextLoader for text that needs styles from styles.xml. e.g.
- * test shapes on master pages, you need to set KoOdfLoadingContext::setUseStylesAutoStyles( true ).
- *
- * Don't forget to unset it if you later want to load text that needs content.xml.
- */
-class KRITATEXT_EXPORT KoTextLoader : public QObject
-{
- Q_OBJECT
-public:
-
- /**
- * Normalizes the whitespaces in the string \p in according to the ODF ruleset
- * for stripping whitespaces and returns the result. If \p leadingSpace is
- * true a leading space is stripped too.
- *
- * This is different from QString::simplifyWhiteSpace() because that one removes
- * leading and trailing whitespace, but such whitespace is significant in ODF.
- * So we use this function to compress sequences of space characters into single
- * spaces.
- */
- static QString normalizeWhitespace(const QString &in, bool leadingSpace);
-
- /**
- * Constructor.
- * Notice that despite this being a QObject there is no 'parent' available for
- * memory management here.
- *
- * @param context The context the KoTextLoader is called in
- */
- explicit KoTextLoader(KoShapeLoadingContext &context, KoShape *shape = 0);
-
- /**
- * Destructor.
- */
- ~KoTextLoader() override;
-
- enum LoadBodyMode
- {
- LoadMode,
- PasteMode
- };
- /**
- * Load the body from the \p element into the \p cursor .
- *
- * This method got called e.g. at the \a KoTextShapeData::loadOdf() method if a TextShape
- * instance likes to load an ODF element.
- *
- * @param element the element to start loading at
- * @param cursor the text cursor to insert the body after
- * @param pasteMode does special handling of section needed, in case we are pasting text
- */
- void loadBody(const KoXmlElement &element, QTextCursor &cursor, LoadBodyMode pasteMode = LoadMode);
-
-Q_SIGNALS:
-
- /**
- * This signal is emitted during loading with a percentage within 1-100 range
- * \param percent the progress as a percentage
- */
- void sigProgress(int percent);
-
-private:
-
- /**
- * Load the paragraph from the \p element into the \p cursor .
- */
- void loadParagraph(const KoXmlElement &element, QTextCursor &cursor);
-
- /**
- * Load the heading from the \p element into the \p cursor .
- */
- void loadHeading(const KoXmlElement &element, QTextCursor &cursor);
-
- /**
- * Load the list from the \p element into the \p cursor .
- */
- void loadList(const KoXmlElement &element, QTextCursor &cursor);
-
- /**
- * Load a list-item into the cursor
- */
- void loadListItem(const KoXmlElement &e, QTextCursor &cursor, int level);
-
- /**
- * Load the section from the \p element into the \p cursor .
- */
- void loadSection(const KoXmlElement &element, QTextCursor &cursor);
-
- /**
- * Load the text into the \p cursor .
- */
- void loadText(const QString &text, QTextCursor &cursor,
- bool *stripLeadingSpace, bool isLastNode);
-
- /**
- * Load the span from the \p element into the \p cursor .
- */
- void loadSpan(const KoXmlElement &element, QTextCursor &cursor, bool *leadingSpace);
-
- /**
- * Load the table from the \p element into the \p cursor.
- *
- * The table and its contents are placed in a new shape.
- */
- void loadTable(const KoXmlElement &element, QTextCursor& cursor);
-
- /**
- * Loads a table column
- */
- void loadTableColumn(const KoXmlElement &element, QTextTable *table, int &columns);
-
- /**
- * Loads a table-row into the cursor
- */
- void loadTableRow(const KoXmlElement &element, QTextTable *table, QList<QRect> &spanStore, QTextCursor &cursor, int &rows);
-
- /**
- * Loads a table-cell into the cursor
- */
- void loadTableCell(const KoXmlElement &element, QTextTable *table, QList<QRect> &spanStore, QTextCursor &cursor, int &currentCell);
-
- /**
- * Load a note \p element into the \p cursor.
- */
- void loadNote(const KoXmlElement &element, QTextCursor& cursor);
-
- /**
- * Load a citation \p element into the \p cursor.
- */
- void loadCite(const KoXmlElement &element, QTextCursor& cursor);
-
- /**
- * Load the shape element and assign hyperlink to it \p element into the \p cursor .
- */
- void loadShapeWithHyperLink(const KoXmlElement &element, QTextCursor& cursor);
-
- /**
- * Load the shape element \p element into the \p cursor .
- */
- KoShape *loadShape(const KoXmlElement &element, QTextCursor& cursor);
-
- /**
- * Load the table of content element \p element into the \p cursor .
- */
- void loadTableOfContents(const KoXmlElement &element, QTextCursor& cursor);
-
- /**
- * Load the bibliography element \p element into the \p cursor .
- */
- void loadBibliography(const KoXmlElement &element, QTextCursor& cursor);
-
- /**
- * This is called in loadBody before reading the body starts.
- */
- void startBody(int total);
-
- /**
- * This is called in loadBody on each item that is read within the body.
- */
- void processBody();
-
- /**
- * This is called in loadBody once the body was read.
- */
- void endBody();
-
- /// \internal d-pointer class.
- class Private;
- /// \internal d-pointer instance.
- Private* const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/opendocument/KoTextSharedLoadingData.cpp b/plugins/flake/textshape/kotext/opendocument/KoTextSharedLoadingData.cpp
deleted file mode 100644
index 3fedb59184..0000000000
--- a/plugins/flake/textshape/kotext/opendocument/KoTextSharedLoadingData.cpp
+++ /dev/null
@@ -1,712 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2004-2006 David Faure <faure@kde.org>
- * Copyright (C) 2007, 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2007 Sebastian Sauer <mail@dipe.org>
- * Copyright (C) 2007 Pierre Ducroquet <pinaraf@gmail.com>
- * Copyright (C) 2007-2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- *
- * 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 "KoTextSharedLoadingData.h"
-
-#include <QString>
-#include <QHash>
-
-
-#include <KoXmlReader.h>
-#include <KoXmlNS.h>
-#include <KoOdfStylesReader.h>
-#include <KoOdfLoadingContext.h>
-#include <KoShapeLoadingContext.h>
-#include <KoOdfWorkaround.h>
-
-#include "styles/KoStyleManager.h"
-#include "styles/KoParagraphStyle.h"
-#include "styles/KoCharacterStyle.h"
-#include "styles/KoListStyle.h"
-#include "styles/KoListLevelProperties.h"
-#include "styles/KoTableStyle.h"
-#include "styles/KoTableColumnStyle.h"
-#include "styles/KoTableRowStyle.h"
-#include "styles/KoTableCellStyle.h"
-#include "styles/KoSectionStyle.h"
-#include "KoOdfNotesConfiguration.h"
-#include "KoOdfBibliographyConfiguration.h"
-#include "KoTextTableTemplate.h"
-
-#include "TextDebug.h"
-
-class Q_DECL_HIDDEN KoTextSharedLoadingData::Private
-{
-public:
- Private()
- : defaultCharacterStyle(0)
- , defaultParagraphStyle(0)
- {}
- ~Private() {
- qDeleteAll(paragraphStylesToDelete);
- qDeleteAll(characterStylesToDelete);
- qDeleteAll(listStylesToDelete);
- qDeleteAll(tableStylesToDelete);
- qDeleteAll(tableCellStylesToDelete);
- qDeleteAll(tableColumnStylesToDelete);
- qDeleteAll(tableRowStylesToDelete);
- qDeleteAll(sectionStylesToDelete);
- qDeleteAll(tableTemplatesToDelete);
- }
-
- // It is possible that automatic-styles in content.xml and styles.xml have the same name
- // within the same family. Therefore we have to keep them separate. The office:styles are
- // added to the autostyles so that only one lookup is needed to get the style. This is
- // about 30% faster than having a special data structure for office:styles.
- QHash<QString, KoParagraphStyle *> paragraphContentDotXmlStyles;
- QHash<QString, KoCharacterStyle *> characterContentDotXmlStyles;
- QHash<QString, KoListStyle *> listContentDotXmlStyles;
- QHash<QString, KoTableStyle *> tableContentDotXmlStyles;
- QHash<QString, KoTableColumnStyle *> tableColumnContentDotXmlStyles;
- QHash<QString, KoTableRowStyle *> tableRowContentDotXmlStyles;
- QHash<QString, KoTableCellStyle *> tableCellContentDotXmlStyles;
- QHash<QString, KoSectionStyle *> sectionContentDotXmlStyles;
- QHash<QString, KoParagraphStyle *> paragraphStylesDotXmlStyles;
- QHash<QString, KoCharacterStyle *> characterStylesDotXmlStyles;
- QHash<QString, KoListStyle *> listStylesDotXmlStyles;
- QHash<QString, KoListStyle *> outlineStylesDotXmlStyles;
- QHash<QString, KoTableStyle *> tableStylesDotXmlStyles;
- QHash<QString, KoTableColumnStyle *> tableColumnStylesDotXmlStyles;
- QHash<QString, KoTableRowStyle *> tableRowStylesDotXmlStyles;
- QHash<QString, KoTableCellStyle *> tableCellStylesDotXmlStyles;
- QHash<QString, KoSectionStyle *> sectionStylesDotXmlStyles;
- QHash<QString, KoTextTableTemplate *> tableTemplates;
-
- QList<KoParagraphStyle *> paragraphStylesToDelete;
- QList<KoCharacterStyle *> characterStylesToDelete;
- QList<KoListStyle *> listStylesToDelete;
- QList<KoTableStyle *> tableStylesToDelete;
- QList<KoTableCellStyle *> tableCellStylesToDelete;
- QList<KoTableColumnStyle *> tableColumnStylesToDelete;
- QList<KoTableRowStyle *> tableRowStylesToDelete;
- QList<KoSectionStyle *> sectionStylesToDelete;
- QList<KoTextTableTemplate *> tableTemplatesToDelete;
- QHash<QString, KoParagraphStyle*> namedParagraphStyles;
- KoOdfBibliographyConfiguration bibliographyConfiguration;
- KoCharacterStyle *defaultCharacterStyle;
- KoParagraphStyle *defaultParagraphStyle;
-
- QList<KoShape *> insertedShapes;
-};
-
-KoTextSharedLoadingData::KoTextSharedLoadingData()
- : d(new Private())
-{
-}
-
-KoTextSharedLoadingData::~KoTextSharedLoadingData()
-{
- delete d;
-}
-
-void KoTextSharedLoadingData::addDefaultCharacterStyle(KoShapeLoadingContext &context, const KoXmlElement *styleElem, const KoXmlElement *appDefault, KoStyleManager *styleManager)
-{
- if (styleManager) {
- if (styleElem) {
- styleManager->defaultCharacterStyle()->loadOdf(styleElem, context);
- } else if (appDefault) {
- styleManager->defaultCharacterStyle()->loadOdf(appDefault, context);
- }
- d->defaultCharacterStyle = styleManager->defaultCharacterStyle();
- }
-}
-
-void KoTextSharedLoadingData::addDefaultParagraphStyle(KoShapeLoadingContext &context, const KoXmlElement *styleElem, const KoXmlElement *appDefault, KoStyleManager *styleManager)
-{
- if (styleManager) {
- if (styleElem) {
- styleManager->defaultParagraphStyle()->loadOdf(styleElem, context);
- } else if (appDefault) {
- styleManager->defaultParagraphStyle()->loadOdf(appDefault, context);
- }
- d->defaultParagraphStyle = styleManager->defaultParagraphStyle();
- }
-}
-
-void KoTextSharedLoadingData::loadOdfStyles(KoShapeLoadingContext &shapeContext, KoStyleManager *styleManager)
-{
- KoOdfLoadingContext &context = shapeContext.odfLoadingContext();
-
- // only add styles of office:styles to the style manager
- addDefaultCharacterStyle(shapeContext, context.stylesReader().defaultStyle("text"), context.defaultStylesReader().defaultStyle("text"), styleManager);
-
- addCharacterStyles(shapeContext, context.stylesReader().customStyles("text").values(), ContentDotXml | StylesDotXml, styleManager);
- addCharacterStyles(shapeContext, context.stylesReader().autoStyles("text", true).values(), StylesDotXml);
- addCharacterStyles(shapeContext, context.stylesReader().autoStyles("text").values(), ContentDotXml);
-
- addListStyles(shapeContext, context.stylesReader().autoStyles("list").values(), ContentDotXml);
- addListStyles(shapeContext, context.stylesReader().autoStyles("list", true).values(), StylesDotXml);
- addListStyles(shapeContext, context.stylesReader().customStyles("list").values(), ContentDotXml | StylesDotXml, styleManager);
-
- addDefaultParagraphStyle(shapeContext, context.stylesReader().defaultStyle("paragraph"), context.defaultStylesReader().defaultStyle("paragraph"), styleManager);
- // adding all the styles in order of dependency; automatic styles can have a parent in the named styles, so load the named styles first.
-
- // add office:styles from styles.xml to paragraphContentDotXmlStyles, paragraphStylesDotXmlStyles and styleManager
- // now all styles referencable from the body in content.xml is in paragraphContentDotXmlStyles
- addParagraphStyles(shapeContext, context.stylesReader().customStyles("paragraph").values(), ContentDotXml | StylesDotXml, styleManager);
- // add office:automatic-styles in styles.xml to paragraphStylesDotXmlStyles
- addParagraphStyles(shapeContext, context.stylesReader().autoStyles("paragraph", true).values(), StylesDotXml);
- // add office:automatic-styles in content.xml to paragraphContentDotXmlStyles
- addParagraphStyles(shapeContext, context.stylesReader().autoStyles("paragraph").values(), ContentDotXml);
-
- addTableStyles(context, context.stylesReader().autoStyles("table").values(), ContentDotXml);
- addTableStyles(context, context.stylesReader().autoStyles("table", true).values(), StylesDotXml);
- addTableStyles(context, context.stylesReader().customStyles("table").values(), ContentDotXml | StylesDotXml, styleManager);
-
- addTableColumnStyles(context, context.stylesReader().autoStyles("table-column").values(), ContentDotXml);
- addTableColumnStyles(context, context.stylesReader().autoStyles("table-column", true).values(), StylesDotXml);
- addTableColumnStyles(context, context.stylesReader().customStyles("table-column").values(), ContentDotXml | StylesDotXml, styleManager);
-
- addTableRowStyles(context, context.stylesReader().autoStyles("table-row").values(), ContentDotXml);
- addTableRowStyles(context, context.stylesReader().autoStyles("table-row", true).values(), StylesDotXml);
- addTableRowStyles(context, context.stylesReader().customStyles("table-row").values(), ContentDotXml | StylesDotXml, styleManager);
-
- addTableCellStyles(shapeContext, context.stylesReader().autoStyles("table-cell").values(), ContentDotXml);
- addTableCellStyles(shapeContext, context.stylesReader().autoStyles("table-cell", true).values(), StylesDotXml);
- addTableCellStyles(shapeContext, context.stylesReader().customStyles("table-cell").values(), ContentDotXml | StylesDotXml, styleManager);
-
- addSectionStyles(context, context.stylesReader().autoStyles("section").values(), ContentDotXml);
- addSectionStyles(context, context.stylesReader().autoStyles("section", true).values(), StylesDotXml);
- addSectionStyles(context, context.stylesReader().customStyles("section").values(), ContentDotXml | StylesDotXml, styleManager);
-
- addOutlineStyle(shapeContext, styleManager);
-
- addNotesConfiguration(shapeContext, styleManager);
-
- addTableTemplate(shapeContext, styleManager);
-
- debugText << "content.xml: paragraph styles" << d->paragraphContentDotXmlStyles.count() << "character styles" << d->characterContentDotXmlStyles.count();
- debugText << "styles.xml: paragraph styles" << d->paragraphStylesDotXmlStyles.count() << "character styles" << d->characterStylesDotXmlStyles.count();
-}
-
-void KoTextSharedLoadingData::addParagraphStyles(KoShapeLoadingContext &context, const QList<KoXmlElement*> &styleElements,
- int styleTypes, KoStyleManager *styleManager)
-{
- QList<QPair<QString, KoParagraphStyle *> > paragraphStyles(loadParagraphStyles(context, styleElements, styleTypes, styleManager));
-
- QList<QPair<QString, KoParagraphStyle *> >::iterator it(paragraphStyles.begin());
- for (; it != paragraphStyles.end(); ++it) {
- if (styleTypes & ContentDotXml) {
- d->paragraphContentDotXmlStyles.insert(it->first, it->second);
- }
- if (styleTypes & StylesDotXml) {
- d->paragraphStylesDotXmlStyles.insert(it->first, it->second);
- }
- }
-}
-
-QList<QPair<QString, KoParagraphStyle *> > KoTextSharedLoadingData::loadParagraphStyles(KoShapeLoadingContext &context, const QList<KoXmlElement*> &styleElements,
- int styleTypes, KoStyleManager *styleManager)
-{
- QList<QPair<QString, KoParagraphStyle *> > paragraphStyles;
- QHash<KoParagraphStyle*,QString> nextStyles;
- QHash<KoParagraphStyle*,QString> parentStyles;
-
- Q_FOREACH (KoXmlElement *styleElem, styleElements) {
- Q_ASSERT(styleElem);
- Q_ASSERT(!styleElem->isNull());
-
- QString name = styleElem->attributeNS(KoXmlNS::style, "name", QString());
- KoParagraphStyle *parastyle = new KoParagraphStyle();
- parastyle->loadOdf(styleElem, context);
- QString listStyleName = styleElem->attributeNS(KoXmlNS::style, "list-style-name", QString());
- KoListStyle *list = listStyle(listStyleName, styleTypes & StylesDotXml);
- if (list) {
- KoListStyle *newListStyle = new KoListStyle(parastyle);
- newListStyle->copyProperties(list);
- parastyle->setListStyle(newListStyle);
- }
- paragraphStyles.append(QPair<QString, KoParagraphStyle *>(name, parastyle));
- d->namedParagraphStyles.insert(name, parastyle);
-
- if (styleElem->hasAttributeNS(KoXmlNS::style, "next-style-name"))
- nextStyles.insert(parastyle, styleElem->attributeNS(KoXmlNS::style, "next-style-name"));
- if (styleElem->hasAttributeNS(KoXmlNS::style, "parent-style-name"))
- parentStyles.insert(parastyle, styleElem->attributeNS(KoXmlNS::style, "parent-style-name"));
-
- // TODO check if it a know style set the styleid so that the custom styles are kept during copy and paste
- // in case styles are not added to the style manager they have to be deleted after loading to avoid leaking memory
- if (styleManager) {
- styleManager->add(parastyle);
- } else {
- d->paragraphStylesToDelete.append(parastyle);
- }
-
- parastyle->setDefaultStyle(d->defaultParagraphStyle);
- }
-
- // second pass; resolve all the 'next-style's and parent-style's.
- // TODO iterate via values
- foreach (KoParagraphStyle *style, nextStyles.keys()) {
- KoParagraphStyle *next = d->namedParagraphStyles.value(nextStyles.value(style));
- if (next && next->styleId() >= 0)
- style->setNextStyle(next->styleId());
- }
- foreach (KoParagraphStyle *style, parentStyles.keys()) {
- KoParagraphStyle *parent = d->namedParagraphStyles.value(parentStyles.value(style));
- if (parent)
- style->setParentStyle(parent);
- }
-
- return paragraphStyles;
-}
-
-void KoTextSharedLoadingData::addCharacterStyles(KoShapeLoadingContext &context, const QList<KoXmlElement*> &styleElements,
- int styleTypes, KoStyleManager *styleManager)
-{
- QList<OdfCharStyle> characterStyles(loadCharacterStyles(context, styleElements));
-
- foreach (const OdfCharStyle &odfStyle, characterStyles) {
- if (styleTypes & ContentDotXml) {
- d->characterContentDotXmlStyles.insert(odfStyle.odfName, odfStyle.style);
- }
- if (styleTypes & StylesDotXml) {
- d->characterStylesDotXmlStyles.insert(odfStyle.odfName, odfStyle.style);
- }
-
- if (styleManager) {
- styleManager->add(odfStyle.style);
- } else {
- d->characterStylesToDelete.append(odfStyle.style);
- }
- }
-
- // now that all name styles have been added we resolve parent relation ships
- foreach (const OdfCharStyle &odfStyle, characterStyles) {
-
- KoCharacterStyle *parent = 0;
- if (!odfStyle.parentStyle.isEmpty()) {
- parent = characterStyle(odfStyle.parentStyle, false);
- if (!parent)
- parent = characterStyle(odfStyle.parentStyle, true); // try harder
- odfStyle.style->setParentStyle(parent);
- }
- if (!styleManager) {
- if (parent) {
- // an auto style with a parent.
- // let's set the styleId of that one on the auto-style too.
- // this will have the effect that wherever the autostyle is applied, it will
- // cause the parent style-id to be applied. So we don't loose this info.
- odfStyle.style->setStyleId(parent->styleId());
- }
- }
- odfStyle.style->setDefaultStyle(d->defaultCharacterStyle);
- }
-}
-
-QList<KoTextSharedLoadingData::OdfCharStyle> KoTextSharedLoadingData::loadCharacterStyles(KoShapeLoadingContext &shapeContext, const QList<KoXmlElement*> &styleElements)
-{
- QList<OdfCharStyle> characterStyles;
-
- Q_FOREACH (KoXmlElement *styleElem, styleElements) {
- Q_ASSERT(styleElem);
- Q_ASSERT(!styleElem->isNull());
-
- OdfCharStyle answer;
- answer.odfName = styleElem->attributeNS(KoXmlNS::style, "name", QString());
- answer.parentStyle = styleElem->attributeNS(KoXmlNS::style, "parent-style-name");
- answer.style = new KoCharacterStyle();
- answer.style->loadOdf(styleElem, shapeContext);
-
- characterStyles.append(answer);
- }
- return characterStyles;
-}
-
-void KoTextSharedLoadingData::addListStyles(KoShapeLoadingContext &context, const QList<KoXmlElement*> &styleElements,
- int styleTypes, KoStyleManager *styleManager)
-{
- QList<QPair<QString, KoListStyle *> > listStyles(loadListStyles(context, styleElements));
-
- QList<QPair<QString, KoListStyle *> >::iterator it(listStyles.begin());
- for (; it != listStyles.end(); ++it) {
- if (styleTypes & ContentDotXml) {
- d->listContentDotXmlStyles.insert(it->first, it->second);
- }
- if (styleTypes & StylesDotXml) {
- d->listStylesDotXmlStyles.insert(it->first, it->second);
- }
- // TODO check if it a know style set the styleid so that the custom styles are kept during copy and paste
- // in case styles are not added to the style manager they have to be deleted after loading to avoid leaking memory
- if (styleManager) {
- styleManager->add(it->second);
- } else {
- d->listStylesToDelete.append(it->second);
- }
- }
-}
-
-QList<QPair<QString, KoListStyle *> > KoTextSharedLoadingData::loadListStyles(KoShapeLoadingContext &context, const QList<KoXmlElement*> &styleElements)
-{
- QList<QPair<QString, KoListStyle *> > listStyles;
-
- Q_FOREACH (KoXmlElement *styleElem, styleElements) {
- Q_ASSERT(styleElem);
- Q_ASSERT(!styleElem->isNull());
-
- QString name = styleElem->attributeNS(KoXmlNS::style, "name", QString());
- KoListStyle *liststyle = new KoListStyle();
- liststyle->loadOdf(context, *styleElem);
- listStyles.append(QPair<QString, KoListStyle *>(name, liststyle));
- }
- return listStyles;
-}
-
-void KoTextSharedLoadingData::addTableStyles(KoOdfLoadingContext &context, const QList<KoXmlElement*> &styleElements,
- int styleTypes, KoStyleManager *styleManager)
-{
- QList<QPair<QString, KoTableStyle *> > tableStyles(loadTableStyles(context, styleElements));
-
- QList<QPair<QString, KoTableStyle *> >::iterator it(tableStyles.begin());
- for (; it != tableStyles.end(); ++it) {
- if (styleTypes & ContentDotXml) {
- d->tableContentDotXmlStyles.insert(it->first, it->second);
- }
- if (styleTypes & StylesDotXml) {
- d->tableStylesDotXmlStyles.insert(it->first, it->second);
- }
- // TODO check if it a know style set the styleid so that the custom styles are kept during copy and paste
- // in case styles are not added to the style manager they have to be deleted after loading to avoid leaking memory
- if (styleManager) {
- styleManager->add(it->second);
- } else {
- d->tableStylesToDelete.append(it->second);
- }
- }
-}
-
-QList<QPair<QString, KoTableStyle *> > KoTextSharedLoadingData::loadTableStyles(KoOdfLoadingContext &context, const QList<KoXmlElement*> &styleElements)
-{
- QList<QPair<QString, KoTableStyle *> > tableStyles;
-
- Q_FOREACH (KoXmlElement *styleElem, styleElements) {
- Q_ASSERT(styleElem);
- Q_ASSERT(!styleElem->isNull());
-
- QString name = styleElem->attributeNS(KoXmlNS::style, "name", QString());
- // nah don't think this is it: context.fillStyleStack(*styleElem, KoXmlNS::style, "style-name", "table");
- KoTableStyle *tablestyle = new KoTableStyle();
- tablestyle->loadOdf(styleElem, context);
- tableStyles.append(QPair<QString, KoTableStyle *>(name, tablestyle));
- }
- return tableStyles;
-}
-
-void KoTextSharedLoadingData::addTableColumnStyles(KoOdfLoadingContext &context, const QList<KoXmlElement*> &styleElements,
- int styleTypes, KoStyleManager *styleManager)
-{
- QList<QPair<QString, KoTableColumnStyle *> > tableColumnStyles(loadTableColumnStyles(context, styleElements));
-
- QList<QPair<QString, KoTableColumnStyle *> >::iterator it(tableColumnStyles.begin());
- for (; it != tableColumnStyles.end(); ++it) {
- if (styleTypes & ContentDotXml) {
- d->tableColumnContentDotXmlStyles.insert(it->first, it->second);
- }
- if (styleTypes & StylesDotXml) {
- d->tableColumnStylesDotXmlStyles.insert(it->first, it->second);
- }
- // TODO check if it a know style set the styleid so that the custom styles are kept during copy and paste
- // in case styles are not added to the style manager they have to be deleted after loading to avoid leaking memory
- if (styleManager) {
- styleManager->add(it->second);
- } else {
- d->tableColumnStylesToDelete.append(it->second);
- }
- }
-}
-
-QList<QPair<QString, KoTableColumnStyle *> > KoTextSharedLoadingData::loadTableColumnStyles(KoOdfLoadingContext &context, const QList<KoXmlElement*> &styleElements)
-{
- QList<QPair<QString, KoTableColumnStyle *> > tableColumnStyles;
-
- Q_FOREACH (KoXmlElement *styleElem, styleElements) {
- Q_ASSERT(styleElem);
- Q_ASSERT(!styleElem->isNull());
-
- QString name = styleElem->attributeNS(KoXmlNS::style, "name", QString());
- // nah don't think this is it: context.fillStyleStack(*styleElem, KoXmlNS::style, "style-name", "table");
- KoTableColumnStyle *tablecolumnstyle = new KoTableColumnStyle();
- tablecolumnstyle->loadOdf(styleElem, context);
- tableColumnStyles.append(QPair<QString, KoTableColumnStyle *>(name, tablecolumnstyle));
- }
- return tableColumnStyles;
-}
-
-void KoTextSharedLoadingData::addTableRowStyles(KoOdfLoadingContext &context, const QList<KoXmlElement*> &styleElements,
- int styleTypes, KoStyleManager *styleManager)
-{
- QList<QPair<QString, KoTableRowStyle *> > tableRowStyles(loadTableRowStyles(context, styleElements));
-
- QList<QPair<QString, KoTableRowStyle *> >::iterator it(tableRowStyles.begin());
- for (; it != tableRowStyles.end(); ++it) {
- if (styleTypes & ContentDotXml) {
- d->tableRowContentDotXmlStyles.insert(it->first, it->second);
- }
- if (styleTypes & StylesDotXml) {
- d->tableRowStylesDotXmlStyles.insert(it->first, it->second);
- }
- // TODO check if it a know style set the styleid so that the custom styles are kept during copy and paste
- // in case styles are not added to the style manager they have to be deleted after loading to avoid leaking memory
- if (styleManager) {
- styleManager->add(it->second);
- } else {
- d->tableRowStylesToDelete.append(it->second);
- }
- }
-}
-
-QList<QPair<QString, KoTableRowStyle *> > KoTextSharedLoadingData::loadTableRowStyles(KoOdfLoadingContext &context, const QList<KoXmlElement*> &styleElements)
-{
- QList<QPair<QString, KoTableRowStyle *> > tableRowStyles;
-
- Q_FOREACH (KoXmlElement *styleElem, styleElements) {
- Q_ASSERT(styleElem);
- Q_ASSERT(!styleElem->isNull());
-
- QString name = styleElem->attributeNS(KoXmlNS::style, "name", QString());
- // nah don't think this is it: context.fillStyleStack(*styleElem, KoXmlNS::style, "style-name", "table");
- KoTableRowStyle *tablerowstyle = new KoTableRowStyle();
- tablerowstyle->loadOdf(styleElem, context);
- tableRowStyles.append(QPair<QString, KoTableRowStyle *>(name, tablerowstyle));
- }
- return tableRowStyles;
-}
-
-void KoTextSharedLoadingData::addTableCellStyles(KoShapeLoadingContext &context, const QList<KoXmlElement*> &styleElements,
- int styleTypes, KoStyleManager *styleManager)
-{
- QList<QPair<QString, KoTableCellStyle *> > tableCellStyles(loadTableCellStyles(context, styleElements));
-
- QList<QPair<QString, KoTableCellStyle *> >::iterator it(tableCellStyles.begin());
- for (; it != tableCellStyles.end(); ++it) {
- if (styleTypes & ContentDotXml) {
- d->tableCellContentDotXmlStyles.insert(it->first, it->second);
- }
- if (styleTypes & StylesDotXml) {
- d->tableCellStylesDotXmlStyles.insert(it->first, it->second);
- }
- // TODO check if it a know style set the styleid so that the custom styles are kept during copy and paste
- // in case styles are not added to the style manager they have to be deleted after loading to avoid leaking memory
- if (styleManager) {
- styleManager->add(it->second);
- } else {
- d->tableCellStylesToDelete.append(it->second);
- }
- }
-}
-
-QList<QPair<QString, KoTableCellStyle *> > KoTextSharedLoadingData::loadTableCellStyles(KoShapeLoadingContext &context, const QList<KoXmlElement*> &styleElements)
-{
- QList<QPair<QString, KoTableCellStyle *> > tableCellStyles;
-
- Q_FOREACH (KoXmlElement *styleElem, styleElements) {
- Q_ASSERT(styleElem);
- Q_ASSERT(!styleElem->isNull());
-
- QString name = styleElem->attributeNS(KoXmlNS::style, "name", QString());
- // nah don't think this is it: context.fillStyleStack(*styleElem, KoXmlNS::style, "style-name", "table");
- KoTableCellStyle *tablecellstyle = new KoTableCellStyle();
- tablecellstyle->loadOdf(styleElem, context);
- tableCellStyles.append(QPair<QString, KoTableCellStyle *>(name, tablecellstyle));
- }
- return tableCellStyles;
-}
-
-void KoTextSharedLoadingData::addSectionStyles(KoOdfLoadingContext &context, const QList<KoXmlElement*> &styleElements,
- int styleTypes, KoStyleManager *styleManager)
-{
- QList<QPair<QString, KoSectionStyle *> > sectionStyles(loadSectionStyles(context, styleElements));
-
- QList<QPair<QString, KoSectionStyle *> >::iterator it(sectionStyles.begin());
- for (; it != sectionStyles.end(); ++it) {
- if (styleTypes & ContentDotXml) {
- d->sectionContentDotXmlStyles.insert(it->first, it->second);
- }
- if (styleTypes & StylesDotXml) {
- d->sectionStylesDotXmlStyles.insert(it->first, it->second);
- }
- // TODO check if it a know style set the styleid so that the custom styles are kept during copy and paste
- // in case styles are not added to the style manager they have to be deleted after loading to avoid leaking memory
- if (styleManager) {
- styleManager->add(it->second);
- } else {
- d->sectionStylesToDelete.append(it->second);
- }
- }
-}
-
-QList<QPair<QString, KoSectionStyle *> > KoTextSharedLoadingData::loadSectionStyles(KoOdfLoadingContext &context, const QList<KoXmlElement*> &styleElements)
-{
- QList<QPair<QString, KoSectionStyle *> > sectionStyles;
-
- Q_FOREACH (KoXmlElement *styleElem, styleElements) {
- Q_ASSERT(styleElem);
- Q_ASSERT(!styleElem->isNull());
-
- QString name = styleElem->attributeNS(KoXmlNS::style, "name", QString());
- // nah don't think this is it: context.fillStyleStack(*styleElem, KoXmlNS::style, "style-name", "table");
- KoSectionStyle *sectionstyle = new KoSectionStyle();
- sectionstyle->loadOdf(styleElem, context);
- sectionStyles.append(QPair<QString, KoSectionStyle *>(name, sectionstyle));
- }
- return sectionStyles;
-}
-
-void KoTextSharedLoadingData::addOutlineStyle(KoShapeLoadingContext &context, KoStyleManager *styleManager)
-{
- // outline-styles used e.g. for headers
- KoXmlElement outlineStyleElem = KoXml::namedItemNS(context.odfLoadingContext().stylesReader().officeStyle(), KoXmlNS::text, "outline-style");
- if (styleManager && outlineStyleElem.isElement()) {
- KoListStyle *outlineStyle = new KoListStyle();
- outlineStyle->loadOdf(context, outlineStyleElem);
- styleManager->setOutlineStyle(outlineStyle); // style manager owns it now and will take care of deleting it.
- }
-}
-
-KoParagraphStyle *KoTextSharedLoadingData::paragraphStyle(const QString &name, bool stylesDotXml) const
-{
- return stylesDotXml ? d->paragraphStylesDotXmlStyles.value(name) : d->paragraphContentDotXmlStyles.value(name);
-}
-
-QList<KoParagraphStyle *> KoTextSharedLoadingData::paragraphStyles(bool stylesDotXml) const
-{
- return stylesDotXml ? d->paragraphStylesDotXmlStyles.values() : d->paragraphContentDotXmlStyles.values();
-}
-
-KoCharacterStyle *KoTextSharedLoadingData::characterStyle(const QString &name, bool stylesDotXml) const
-{
- return stylesDotXml ? d->characterStylesDotXmlStyles.value(name) : d->characterContentDotXmlStyles.value(name);
-}
-
-QList<KoCharacterStyle*> KoTextSharedLoadingData::characterStyles(bool stylesDotXml) const
-{
- return stylesDotXml ? d->characterStylesDotXmlStyles.values() : d->characterContentDotXmlStyles.values();
-}
-
-KoListStyle *KoTextSharedLoadingData::listStyle(const QString &name, bool stylesDotXml) const
-{
- return stylesDotXml ? d->listStylesDotXmlStyles.value(name) : d->listContentDotXmlStyles.value(name);
-}
-
-KoTableStyle *KoTextSharedLoadingData::tableStyle(const QString &name, bool stylesDotXml) const
-{
- return stylesDotXml ? d->tableStylesDotXmlStyles.value(name) : d->tableContentDotXmlStyles.value(name);
-}
-
-KoTableColumnStyle *KoTextSharedLoadingData::tableColumnStyle(const QString &name, bool stylesDotXml) const
-{
- return stylesDotXml ? d->tableColumnStylesDotXmlStyles.value(name) : d->tableColumnContentDotXmlStyles.value(name);
-}
-
-KoTableRowStyle *KoTextSharedLoadingData::tableRowStyle(const QString &name, bool stylesDotXml) const
-{
- return stylesDotXml ? d->tableRowStylesDotXmlStyles.value(name) : d->tableRowContentDotXmlStyles.value(name);
-}
-
-KoTableCellStyle *KoTextSharedLoadingData::tableCellStyle(const QString &name, bool stylesDotXml) const
-{
- return stylesDotXml ? d->tableCellStylesDotXmlStyles.value(name) : d->tableCellContentDotXmlStyles.value(name);
-}
-
-KoSectionStyle *KoTextSharedLoadingData::sectionStyle(const QString &name, bool stylesDotXml) const
-{
- return stylesDotXml ? d->sectionStylesDotXmlStyles.value(name) : d->sectionContentDotXmlStyles.value(name);
-}
-
-KoOdfBibliographyConfiguration KoTextSharedLoadingData::bibliographyConfiguration() const
-{
- return d->bibliographyConfiguration;
-}
-
-void KoTextSharedLoadingData::shapeInserted(KoShape *shape, const KoXmlElement &element, KoShapeLoadingContext &/*context*/)
-{
- d->insertedShapes.append(shape);
- Q_UNUSED(element);
-}
-
-QList<KoShape *> KoTextSharedLoadingData::insertedShapes() const
-{
- return d->insertedShapes;
-}
-
-void KoTextSharedLoadingData::addNotesConfiguration(KoShapeLoadingContext &context, KoStyleManager *styleManager)
-{
- KoOdfNotesConfiguration *footnotesConfiguration = new KoOdfNotesConfiguration(
- context.odfLoadingContext().stylesReader().globalNotesConfiguration(KoOdfNotesConfiguration::Footnote));
- KoOdfNotesConfiguration *endnotesConfiguration = new KoOdfNotesConfiguration(
- context.odfLoadingContext().stylesReader().globalNotesConfiguration(KoOdfNotesConfiguration::Endnote));
-
- footnotesConfiguration->setCitationBodyTextStyle(d->characterStylesDotXmlStyles.value(footnotesConfiguration->citationBodyTextStyleName()));
-
- footnotesConfiguration->setCitationTextStyle(d->characterStylesDotXmlStyles.value(footnotesConfiguration->citationTextStyleName()));
-
- footnotesConfiguration->setDefaultNoteParagraphStyle(d->paragraphStylesDotXmlStyles.value(footnotesConfiguration->defaultNoteParagraphStyleName()));
-
- endnotesConfiguration->setCitationBodyTextStyle(d->characterStylesDotXmlStyles.value(endnotesConfiguration->citationBodyTextStyleName()));
-
- endnotesConfiguration->setCitationTextStyle(d->characterStylesDotXmlStyles.value(endnotesConfiguration->citationTextStyleName()));
-
- endnotesConfiguration->setDefaultNoteParagraphStyle(d->paragraphStylesDotXmlStyles.value(endnotesConfiguration->defaultNoteParagraphStyleName()));
-
- styleManager->setNotesConfiguration(footnotesConfiguration);
- styleManager->setNotesConfiguration(endnotesConfiguration);
-}
-
-void KoTextSharedLoadingData::addBibliographyConfiguration(KoShapeLoadingContext &context)
-{
- d->bibliographyConfiguration =
- context.odfLoadingContext().stylesReader().globalBibliographyConfiguration();
-}
-
-void KoTextSharedLoadingData::addTableTemplate(KoShapeLoadingContext &context, KoStyleManager *styleManager)
-{
- QList<QPair<QString, KoTextTableTemplate *> > tableTemplates(loadTableTemplates(context));
-
- QList<QPair<QString, KoTextTableTemplate *> >::iterator it(tableTemplates.begin());
- for (; it != tableTemplates.end(); ++it) {
- d->tableTemplates.insert(it->first, it->second);
-
- // in case templates are not added to the style manager they have to be deleted after loading to avoid leaking memory
- if (styleManager) {
- styleManager->add(it->second);
- } else {
- d->tableTemplatesToDelete.append(it->second);
- }
- }
-}
-
-QList<QPair<QString, KoTextTableTemplate *> > KoTextSharedLoadingData::loadTableTemplates(KoShapeLoadingContext &context)
-{
- QList<QPair<QString, KoTextTableTemplate *> > tableTemplates;
-
- Q_FOREACH (KoXmlElement *styleElem, context.odfLoadingContext().stylesReader().tableTemplates()) {
- Q_ASSERT(styleElem);
- Q_ASSERT(!styleElem->isNull());
-
- KoTextTableTemplate *tableTemplate = new KoTextTableTemplate();
- tableTemplate->loadOdf(styleElem, context);
- tableTemplates.append(QPair<QString, KoTextTableTemplate *>(tableTemplate->name(), tableTemplate));
- }
- return tableTemplates;
-}
diff --git a/plugins/flake/textshape/kotext/opendocument/KoTextSharedLoadingData.h b/plugins/flake/textshape/kotext/opendocument/KoTextSharedLoadingData.h
deleted file mode 100644
index cfdf13cdbf..0000000000
--- a/plugins/flake/textshape/kotext/opendocument/KoTextSharedLoadingData.h
+++ /dev/null
@@ -1,257 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007-2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2010 Thomas Zander <zander@kde.org>
- *
- * 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 KOTEXTSHAREDLOADINGDATA_H
-#define KOTEXTSHAREDLOADINGDATA_H
-
-#include <KoSharedLoadingData.h>
-#include <KoXmlReaderForward.h>
-#include "kritatext_export.h"
-
-#include <QList>
-#include <QPair>
-#include <QString>
-
-class KoOdfLoadingContext;
-class KoParagraphStyle;
-class KoCharacterStyle;
-class KoListStyle;
-class KoTableStyle;
-class KoTableColumnStyle;
-class KoTableRowStyle;
-class KoTableCellStyle;
-class KoSectionStyle;
-class KoStyleManager;
-class KoShape;
-class KoShapeLoadingContext;
-class KoOdfNotesConfiguration;
-class KoOdfBibliographyConfiguration;
-class KoTextTableTemplate;
-
-#define KOTEXT_SHARED_LOADING_ID "KoTextSharedLoadingId"
-
-/**
- * This class is used to cache the loaded styles so that they have to be loaded only once
- * and can be used by all text shapes.
- * When a text shape is loaded it checks if the KoTextSharedLoadingData is already there.
- * If not it is created.
- */
-class KRITATEXT_EXPORT KoTextSharedLoadingData : public KoSharedLoadingData
-{
- friend class KoTextLoader;
-public:
- KoTextSharedLoadingData();
- ~KoTextSharedLoadingData() override;
-
- /**
- * Load the styles
- *
- * If your application uses a style manager call this function from you application with insertOfficeStyles = true
- * to load the custom styles into the style manager before the rest of the loading is started.
- *
- * @param scontext The shape loading context.
- * @param styleManager The style manager too use or 0 if you don't have a style manager.
- */
- void loadOdfStyles(KoShapeLoadingContext &scontext, KoStyleManager *styleManager);
-
- /**
- * Get the paragraph style for the given name
- *
- * The name is the style:name given in the file
- *
- * @param name The name of the style to get
- * @param stylesDotXml If set the styles from styles.xml are used, if unset styles from content.xml are used.
- * @return The paragraph style for the given name or 0 if not found
- */
- KoParagraphStyle *paragraphStyle(const QString &name, bool stylesDotXml) const;
-
- /**
- * Return all paragraph styles.
- *
- * @param stylesDotXml If set the styles from styles.xml are used, if unset styles from content.xml are used.
- * @return All paragraph styles from the given file
- */
- QList<KoParagraphStyle *> paragraphStyles(bool stylesDotXml) const;
-
- /**
- * Get the character style for the given name
- *
- * The name is the style:name given in the file
- *
- * @param name The name of the style to get
- * @param stylesDotXml If set the styles from styles.xml are used, if unset styles from content.xml are used.
- * @return The character style for the given name or 0 if not found
- */
- KoCharacterStyle *characterStyle(const QString &name, bool stylesDotXml) const;
-
- /**
- * Return all character styles.
- *
- * @param stylesDotXml If set the styles from styles.xml are used, if unset styles from content.xml are used.
- * @return All character styles from the given file
- */
- QList<KoCharacterStyle*> characterStyles(bool stylesDotXml) const;
-
- /**
- * Get the list style for the given name
- *
- * @param name The name of the style to get
- * @param stylesDotXml If set the styles from styles.xml are used, if unset styles from content.xml are used.
- * @return The list style for the given name or 0 if not found
- */
- KoListStyle *listStyle(const QString &name, bool stylesDotXml) const;
-
- /**
- * Get the table style for the given name
- *
- * @param name The name of the style to get
- * @param stylesDotXml If set the styles from styles.xml are used, if unset styles from content.xml are used.
- * @return The table style for the given name or 0 if not found
- */
- KoTableStyle *tableStyle(const QString &name, bool stylesDotXml) const;
-
- /**
- * Get the table column style for the given name
- *
- * @param name The name of the style to get
- * @param stylesDotXml If set the styles from styles.xml are used, if unset styles from content.xml are used.
- * @return The table column style for the given name or 0 if not found
- */
- KoTableColumnStyle *tableColumnStyle(const QString &name, bool stylesDotXml) const;
-
- /**
- * Get the table row style for the given name
- *
- * @param name The name of the style to get
- * @param stylesDotXml If set the styles from styles.xml are used, if unset styles from content.xml are used.
- * @return The table row style for the given name or 0 if not found
- */
- KoTableRowStyle *tableRowStyle(const QString &name, bool stylesDotXml) const;
-
- /**
- * Get the table cell style for the given name
- *
- * @param name The name of the style to get
- * @param stylesDotXml If set the styles from styles.xml are used, if unset styles from content.xml are used.
- * @return The table cell style for the given name or 0 if not found
- */
- KoTableCellStyle *tableCellStyle(const QString &name, bool stylesDotXml) const;
-
- /**
- * Get the section style for the given name
- *
- * @param name The name of the style to get
- * @param stylesDotXml If set the styles from styles.xml are used, if unset styles from content.xml are used.
- * @return The section style for the given name or 0 if not found
- */
- KoSectionStyle *sectionStyle(const QString &name, bool stylesDotXml) const;
-
- /**
- * Get the document-wide configuration for bibliography this contains information
- * about prefix, suffix, sort by position, sort algorithm etc.
- */
- KoOdfBibliographyConfiguration bibliographyConfiguration() const;
-
- /**
- * Returns a list of shapes that should be inserted.
- */
- QList<KoShape *> insertedShapes() const;
-
-protected:
- /**
- * This method got called by kotext once a \a KoShape got inserted and an
- * application can implement this to do additional things with shapes once
- * they got inserted.
- * @param shape a shape that has finished loading.
- * @param element the xml element that represents the shape being inserted.
- */
- virtual void shapeInserted(KoShape *shape, const KoXmlElement &element, KoShapeLoadingContext &context);
-
-private:
- enum StyleType {
- ContentDotXml = 1,
- StylesDotXml = 2
- };
- // helper functions for loading of paragraph styles
- void addParagraphStyles(KoShapeLoadingContext &context, const QList<KoXmlElement*> &styleElements, int styleTypes,
- KoStyleManager *styleManager = 0);
- QList<QPair<QString, KoParagraphStyle *> > loadParagraphStyles(KoShapeLoadingContext &context, const QList<KoXmlElement*> &styleElements,
- int styleTypes, KoStyleManager *manager = 0);
-
- void addDefaultParagraphStyle(KoShapeLoadingContext &context, const KoXmlElement *styleElem, const KoXmlElement *appDefault, KoStyleManager *styleManager);
-
- // helper functions for loading of character styles
- void addCharacterStyles(KoShapeLoadingContext &context, const QList<KoXmlElement*> &styleElements, int styleTypes,
- KoStyleManager *styleManager = 0);
- struct OdfCharStyle {
- QString odfName;
- QString parentStyle;
- KoCharacterStyle *style;
- };
- QList<OdfCharStyle> loadCharacterStyles(KoShapeLoadingContext &context, const QList<KoXmlElement*> &styleElements);
-
- void addDefaultCharacterStyle(KoShapeLoadingContext &context, const KoXmlElement *styleElem, const KoXmlElement *appDefault, KoStyleManager *styleManager);
-
- // helper functions for loading of list styles
- void addListStyles(KoShapeLoadingContext &context, const QList<KoXmlElement*> &styleElements, int styleTypes,
- KoStyleManager *styleManager = 0);
- QList<QPair<QString, KoListStyle *> > loadListStyles(KoShapeLoadingContext &context, const QList<KoXmlElement*> &styleElements);
-
- // helper functions for loading of table styles
- void addTableStyles(KoOdfLoadingContext &context, const QList<KoXmlElement*> &styleElements, int styleTypes,
- KoStyleManager *styleManager = 0);
- QList<QPair<QString, KoTableStyle *> > loadTableStyles(KoOdfLoadingContext &context, const QList<KoXmlElement*> &styleElements);
-
- // helper functions for loading of table column styles
- void addTableColumnStyles(KoOdfLoadingContext &context, const QList<KoXmlElement*> &styleElements, int styleTypes,
- KoStyleManager *styleManager = 0);
- QList<QPair<QString, KoTableColumnStyle *> > loadTableColumnStyles(KoOdfLoadingContext &context, const QList<KoXmlElement*> &styleElements);
-
- // helper functions for loading of table row styles
- void addTableRowStyles(KoOdfLoadingContext &context, const QList<KoXmlElement*> &styleElements, int styleTypes,
- KoStyleManager *styleManager = 0);
- QList<QPair<QString, KoTableRowStyle *> > loadTableRowStyles(KoOdfLoadingContext &context, const QList<KoXmlElement*> &styleElements);
-
- // helper functions for loading of table cell styles
- void addTableCellStyles(KoShapeLoadingContext &context, const QList<KoXmlElement*> &styleElements, int styleTypes,
- KoStyleManager *styleManager = 0);
- QList<QPair<QString, KoTableCellStyle *> > loadTableCellStyles(KoShapeLoadingContext &context, const QList<KoXmlElement*> &styleElements);
-
- // helper functions for loading of section styles
- void addSectionStyles(KoOdfLoadingContext &context, const QList<KoXmlElement*> &styleElements, int styleTypes,
- KoStyleManager *styleManager = 0);
- QList<QPair<QString, KoSectionStyle *> > loadSectionStyles(KoOdfLoadingContext &context, const QList<KoXmlElement*> &styleElements);
-
- void addOutlineStyle(KoShapeLoadingContext & context, KoStyleManager *styleManager);
-
- void addNotesConfiguration(KoShapeLoadingContext &context, KoStyleManager *styleManager);
-
- void addBibliographyConfiguration(KoShapeLoadingContext &context);
-
- void addTableTemplate(KoShapeLoadingContext &context, KoStyleManager *styleManager);
- QList<QPair<QString, KoTextTableTemplate *> > loadTableTemplates(KoShapeLoadingContext &context);
-
-
- class Private;
- Private * const d;
-};
-
-#endif /* KOTEXTSHAREDLOADINGDATA_H */
diff --git a/plugins/flake/textshape/kotext/opendocument/KoTextSharedSavingData.cpp b/plugins/flake/textshape/kotext/opendocument/KoTextSharedSavingData.cpp
deleted file mode 100644
index 4c5c3edef4..0000000000
--- a/plugins/flake/textshape/kotext/opendocument/KoTextSharedSavingData.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/* This file is part of the KDE project
-Copyright (C) 2008 Pierre Stirnweiss \pierre.stirnweiss_calligra@gadz.org>
-
-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 "KoTextSharedSavingData.h"
-
-#include "KoGenChanges.h"
-#include "KoDocumentRdfBase.h"
-
-#ifdef SHOULD_BUILD_RDF
-#include <Soprano/Soprano>
-#endif
-
-#include <QMap>
-
-class Q_DECL_HIDDEN KoTextSharedSavingData::Private
-{
-public:
- Private(void) : changes(0) { }
- ~Private() {}
-
- KoGenChanges *changes;
- QMap<QString, QString> m_rdfIdMapping; //< This lets the RDF system know old->new xml:id
-#ifdef SHOULD_BUILD_RDF
- QSharedPointer<Soprano::Model> m_rdfModel; //< This is so cut/paste can serialize the relevant RDF to the clipboard
-#endif
- QMap<int, QString> styleIdToName;
-};
-
-KoTextSharedSavingData::KoTextSharedSavingData()
- : d(new Private())
-{
-}
-
-KoTextSharedSavingData::~KoTextSharedSavingData()
-{
-}
-
-void KoTextSharedSavingData::setGenChanges(KoGenChanges& changes) {
- d->changes = &changes;
-}
-
-KoGenChanges& KoTextSharedSavingData::genChanges() const
-{
- return *(d->changes);
-}
-
-void KoTextSharedSavingData::addRdfIdMapping(const QString &oldid, const QString &newid)
-{
- d->m_rdfIdMapping[ oldid ] = newid;
-}
-
-QMap<QString, QString> KoTextSharedSavingData::getRdfIdMapping() const
-{
- return d->m_rdfIdMapping;
-}
-
-#ifdef SHOULD_BUILD_RDF
-void KoTextSharedSavingData::setRdfModel(QSharedPointer<Soprano::Model> m)
-{
- d->m_rdfModel = m;
-}
-
-QSharedPointer<Soprano::Model> KoTextSharedSavingData::rdfModel() const
-{
- return d->m_rdfModel;
-}
-#endif
-
-void KoTextSharedSavingData::setStyleName(int styleId, const QString &name)
-{
- d->styleIdToName.insert(styleId, name);
-}
-
-QString KoTextSharedSavingData::styleName(int styleId) const
-{
- return d->styleIdToName.value(styleId);
-}
-
-QList<QString> KoTextSharedSavingData::styleNames() const
-{
- return d->styleIdToName.values();
-}
diff --git a/plugins/flake/textshape/kotext/opendocument/KoTextSharedSavingData.h b/plugins/flake/textshape/kotext/opendocument/KoTextSharedSavingData.h
deleted file mode 100644
index fef4b29889..0000000000
--- a/plugins/flake/textshape/kotext/opendocument/KoTextSharedSavingData.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* This file is part of the KDE project
-Copyright (C) 2004-2006 David Faure <faure@kde.org>
-Copyright (C) 2007-2008 Thorsten Zachmann <zachmann@kde.org>
-
-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 KOTEXTSHAREDSAVINGDATA_H
-#define KOTEXTSHAREDSAVINGDATA_H
-
-#include <KoSharedSavingData.h>
-#include "kritatext_export.h"
-
-#include <QMap>
-#include <QSharedPointer>
-
-#define KOTEXT_SHARED_SAVING_ID "KoTextSharedSavingId"
-
-class KoGenChanges;
-
-namespace Soprano
-{
-class Model;
-}
-
-class QString;
-
-
-class KRITATEXT_EXPORT KoTextSharedSavingData : public KoSharedSavingData
-{
-public:
- KoTextSharedSavingData();
- ~KoTextSharedSavingData() override;
-
- void setGenChanges(KoGenChanges &changes);
-
- KoGenChanges& genChanges() const;
-
- void addRdfIdMapping(const QString &oldid, const QString &newid);
- QMap<QString, QString> getRdfIdMapping() const;
-
- /**
- * The Rdf Model ownership is not taken, you must still delete it,
- * and you need to ensure that it lives longer than this object
- * unless you reset the model to 0.
- */
-#ifdef SHOULD_BUILD_RDF
- void setRdfModel(QSharedPointer<Soprano::Model> m);
- QSharedPointer<Soprano::Model> rdfModel() const;
-#endif
-
- /**
- * Stores the name that written to the file for the style
- *
- * @param styleId the id of the style in KoStyleManger
- * @param savedName the name that is written to the file
- */
- void setStyleName(int styleId, const QString &name);
-
- /**
- * Style name of the style
- *
- * @param styleId the id of the style in KoStyleManager
- * @return the saved name of the style
- */
- QString styleName(int styleId) const;
-
- /**
- * @brief styleNames List of all names of the styles that are saved
- * @return All the names of styles that are saved in the style manager
- */
- QList<QString> styleNames() const;
-
-private:
-
- class Private;
- QScopedPointer<Private> d;
-};
-
-#endif // KOTEXTSHAREDSAVINGDATA_H
diff --git a/plugins/flake/textshape/kotext/opendocument/KoTextWriter.cpp b/plugins/flake/textshape/kotext/opendocument/KoTextWriter.cpp
deleted file mode 100644
index 25a8f94eed..0000000000
--- a/plugins/flake/textshape/kotext/opendocument/KoTextWriter.cpp
+++ /dev/null
@@ -1,163 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2010 Benjamin Port <port.benjamin@gmail.com>
- * Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
- * Copyright (C) 2011 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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 "KoTextWriter.h"
-
-#include <KoTextWriter_p.h>
-#include <KoStyleManager.h>
-#include <KoParagraphStyle.h>
-#include <KoTextDocument.h>
-#include <KoShapeSavingContext.h>
-#include <KoGenStyles.h>
-#include <opendocument/KoTextSharedSavingData.h>
-
-#include <QTextList>
-#include <QTextTableCell>
-
-#include "TextDebug.h"
-
-KoTextWriter::KoTextWriter(KoShapeSavingContext &context, KoDocumentRdfBase *rdfData)
- : d(new Private(context))
-{
- d->rdfData = rdfData;
- KoSharedSavingData *sharedData = context.sharedData(KOTEXT_SHARED_SAVING_ID);
- if (sharedData) {
- d->sharedData = dynamic_cast<KoTextSharedSavingData *>(sharedData);
- }
-
- if (!d->sharedData) {
- d->sharedData = new KoTextSharedSavingData();
- if (!sharedData) {
- context.addSharedData(KOTEXT_SHARED_SAVING_ID, d->sharedData);
- } else {
- warnText << "A different type of sharedData was found under the" << KOTEXT_SHARED_SAVING_ID;
- Q_ASSERT(false);
- }
- }
-}
-
-KoTextWriter::~KoTextWriter()
-{
- delete d;
-}
-
-void KoTextWriter::saveOdf(KoShapeSavingContext &context, KoDocumentRdfBase *rdfData, QTextDocument *document, int from, int to)
-{
- KoTextWriter writer(context, rdfData);
- writer.write(document, from, to);
-}
-
-QString KoTextWriter::saveParagraphStyle(const QTextBlock &block, KoStyleManager *styleManager, KoShapeSavingContext &context)
-{
- QTextBlockFormat blockFormat = block.blockFormat();
- QTextCharFormat charFormat = QTextCursor(block).blockCharFormat();
- return saveParagraphStyle(blockFormat, charFormat, styleManager, context);
-}
-
-QString KoTextWriter::saveParagraphStyle(const QTextBlockFormat &blockFormat, const QTextCharFormat &charFormat, KoStyleManager * styleManager, KoShapeSavingContext &context)
-{
- KoParagraphStyle *defaultParagraphStyle = styleManager->defaultParagraphStyle();
- KoParagraphStyle *originalParagraphStyle = styleManager->paragraphStyle(blockFormat.intProperty(KoParagraphStyle::StyleId));
- if (!originalParagraphStyle)
- originalParagraphStyle = defaultParagraphStyle;
-
- QString generatedName;
- QString displayName = originalParagraphStyle->name();
- QString internalName = QString(QUrl::toPercentEncoding(displayName, "", " ")).replace('%', '_');
-
- // we'll convert the blockFormat to a KoParagraphStyle to check for local changes.
- KoParagraphStyle paragStyle(blockFormat, charFormat);
- if (paragStyle == (*originalParagraphStyle)) { // This is the real, unmodified character style.
- // TODO zachmann: this could use the name of the saved style without saving it again
- // therefore we would need to store that information in the saving context
- if (originalParagraphStyle != defaultParagraphStyle) {
- KoGenStyle style(KoGenStyle::ParagraphStyle, "paragraph");
- originalParagraphStyle->saveOdf(style, context);
- generatedName = context.mainStyles().insert(style, internalName, KoGenStyles::DontAddNumberToName);
- }
- } else { // There are manual changes... We'll have to store them then
- KoGenStyle style(KoGenStyle::ParagraphAutoStyle, "paragraph", internalName);
- if (context.isSet(KoShapeSavingContext::AutoStyleInStyleXml))
- style.setAutoStyleInStylesDotXml(true);
- if (originalParagraphStyle) {
- paragStyle.removeDuplicates(*originalParagraphStyle);
- paragStyle.setParentStyle(originalParagraphStyle);
- }
- paragStyle.saveOdf(style, context);
- generatedName = context.mainStyles().insert(style, "P");
- }
- return generatedName;
-}
-
-void KoTextWriter::write(const QTextDocument *document, int from, int to)
-{
- d->document = const_cast<QTextDocument*>(document);
- d->styleManager = KoTextDocument(document).styleManager();
-
- QTextBlock fromblock = document->findBlock(from);
- QTextBlock toblock = document->findBlock(to);
-
- QTextCursor fromcursor(fromblock);
-
- QTextList *currentList = fromcursor.currentList();
-
- // NOTE even better would be if we create a new list out of multiple selected
- // listitems that contain only the selected items. But following
- // at least enables copying a whole list while still being able to copy/paste
- // only parts of the text within a list (see also bug 275990).
- // NOTE this has been fixed for tables now, and it looks like the list code is seriously wrong
- // not just like the table code was, but more fundamentally as lists in qt is an orthogonal concept
- if (currentList) {
- if (from == 0 && to < 0) {
- // save everything means also save current table and list
- currentList = 0;
- } else {
- QTextCursor toCursor(toblock);
- toCursor.setPosition(to, QTextCursor::KeepAnchor);
-
- if (!fromcursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor)) {
- fromcursor = QTextCursor();
- }
- if (!toCursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor)) {
- toCursor = QTextCursor();
- }
-
- // save the whole list if all list-items are selected
- int fromindex = currentList->itemNumber(fromblock);
- int toindex = currentList->itemNumber(toblock);
- if ((fromcursor.isNull() || fromcursor.currentList() != currentList) &&
- (toCursor.isNull() || toCursor.currentList() != currentList) &&
- fromindex <= 0 && (toindex < 0 || toindex == currentList->count()-1)
- ) {
- currentList = 0;
- }
- }
- }
-
- QHash<QTextList *, QString> listStyles = d->saveListStyles(fromblock, to);
- d->globalFrom = from;
- d->globalTo = to;
- d->writeBlocks(const_cast<QTextDocument *>(document), from, to, listStyles, 0, currentList);
-}
diff --git a/plugins/flake/textshape/kotext/opendocument/KoTextWriter.h b/plugins/flake/textshape/kotext/opendocument/KoTextWriter.h
deleted file mode 100644
index 5a9d668df6..0000000000
--- a/plugins/flake/textshape/kotext/opendocument/KoTextWriter.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- *
- * 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 KOTEXTWRITER_H
-#define KOTEXTWRITER_H
-
-#include "kritatext_export.h"
-
-class KoShapeSavingContext;
-class KoStyleManager;
-class QTextDocument;
-class QTextBlock;
-class QTextBlockFormat;
-class QTextCharFormat;
-class QString;
-
-class KoDocumentRdfBase;
-
-
-/**
- * KoTextWriter saves the text ODF of a shape
- */
-class KRITATEXT_EXPORT KoTextWriter
-{
-public:
- /**
- * Constructor.
- *
- * @param context The context the KoTextWriter is called in
- * @param rdfData The RDF data
- */
- explicit KoTextWriter(KoShapeSavingContext &context, KoDocumentRdfBase *rdfData = 0);
-
- /**
- * Destructor.
- */
- ~KoTextWriter();
-
- /// XXX: APIDOX!
- static void saveOdf(KoShapeSavingContext &context, KoDocumentRdfBase *rdfData, QTextDocument *document, int from, int to);
-
- /**
- * Save a paragraph style used in a text block
- *
- * This checks if the style is a document style or a automatic style
- * and saves it accordingly.
- *
- * @param block The block form which the style information are taken
- * @param styleManager The used style manager
- * @param context The saving context
- */
- static QString saveParagraphStyle(const QTextBlock &block, KoStyleManager *styleManager, KoShapeSavingContext &context);
-
- static QString saveParagraphStyle(const QTextBlockFormat &blockFormat, const QTextCharFormat &charFormat, KoStyleManager *styleManager, KoShapeSavingContext &context);
-
- /**
- * Writes the portion of document contained within 'from' and 'to'
- *
- * @param document The text document we are saving. There can be more than one
- * text document in the office document, but we don't care
- * @param from the start position in characters from which we save
- * @param to the end position in characters up to which we save. If -1, we save to the end
- */
- void write(const QTextDocument *document, int from, int to = -1);
-
-private:
- class Private;
- Private* const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/opendocument/KoTextWriter_p.cpp b/plugins/flake/textshape/kotext/opendocument/KoTextWriter_p.cpp
deleted file mode 100644
index 55c5ada0d4..0000000000
--- a/plugins/flake/textshape/kotext/opendocument/KoTextWriter_p.cpp
+++ /dev/null
@@ -1,1123 +0,0 @@
-/*
- * Copyright (c) 2010 Boudewijn Rempt <boud@valdyas.org>
- * Copyright (c) 2014 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 "KoTextWriter_p.h"
-
-#include <KoSectionUtils.h>
-#include <KoSectionEnd.h>
-#include <KoList.h>
-#include <KoElementReference.h>
-#include <KoTextRangeManager.h>
-#include <KoStyleManager.h>
-#include <KoParagraphStyle.h>
-#include <KoListLevelProperties.h>
-#include <KoTableCellStyle.h>
-#include <KoTableStyle.h>
-#include <KoTextBlockData.h>
-#include <KoTextDocument.h>
-#include <KoTextInlineRdf.h>
-#include <KoSection.h>
-#include <KoTextMeta.h>
-#include <KoShapeSavingContext.h>
-#include <KoXmlWriter.h>
-#include <KoGenStyles.h>
-#include <KoXmlNS.h>
-#include <KoTableColumnAndRowStyleManager.h>
-#include <KoTableColumnStyle.h>
-#include <opendocument/KoTextSharedSavingData.h>
-#include <KoTableOfContentsGeneratorInfo.h>
-#include <KoBibliographyInfo.h>
-#include <KoTableRowStyle.h>
-#include <KoInlineTextObjectManager.h>
-#include <KoVariable.h>
-#include "kis_assert.h"
-
-#include "TextDebug.h"
-
-#include <QTextTable>
-#include <QBuffer>
-
-// A convenience function to get a listId from a list-format
-static KoListStyle::ListIdType ListId(const QTextListFormat &format)
-{
- KoListStyle::ListIdType listId;
-
- if (sizeof(KoListStyle::ListIdType) == sizeof(uint))
- listId = format.property(KoListStyle::ListId).toUInt();
- else
- listId = format.property(KoListStyle::ListId).toULongLong();
-
- return listId;
-}
-
-typedef QPair<QString, QString> Attribute;
-
-
-KoTextWriter::Private::Private(KoShapeSavingContext &context)
- : rdfData(0)
- , sharedData(0)
- , styleManager(0)
- , document(0)
- , writer(0)
- , context(context)
-{
- currentPairedInlineObjectsStack.reset(new QStack<KoInlineObject*>());
- writer = &context.xmlWriter();
-}
-
-KoTextWriter::Private::~Private()
-{
- KIS_SAFE_ASSERT_RECOVER (pairedInlineObjectsStackStack.isEmpty()) {
- qDeleteAll(pairedInlineObjectsStackStack);
- }
-}
-
-void KoTextWriter::Private::writeBlocks(QTextDocument *doc, int from, int to, QHash<QTextList *, QString> &listStyles, QTextTable *currentTable, QTextList *currentList)
-{
- pairedInlineObjectsStackStack.push(currentPairedInlineObjectsStack.take());
- currentPairedInlineObjectsStack.reset(new QStack<KoInlineObject*>());
- QTextBlock block = doc->findBlock(from);
-
- // Here we are going to detect all sections that
- // are positioned entirely inside selection.
- // They will stay untouched, and others will be omitted.
-
- // So we are using stack to detect them, by going through
- // the selection and finding open/close pairs.
- QSet<QString> entireWithinSectionNames;
- QStack<QString> sectionNamesStack;
- QTextCursor cur(doc);
- cur.setPosition(from);
- while (to == -1 || cur.position() <= to) {
- if (cur.block().position() >= from) { // Begin of the block is inside selection.
- foreach (const KoSection *sec, KoSectionUtils::sectionStartings(cur.blockFormat())) {
- sectionNamesStack.push_back(sec->name());
- }
- }
-
- if (to == -1 || cur.block().position() + cur.block().length() - 1 <= to) { // End of the block is inside selection.
- foreach (const KoSectionEnd *sec, KoSectionUtils::sectionEndings(cur.blockFormat())) {
- if (!sectionNamesStack.empty() && sectionNamesStack.top() == sec->name()) {
- sectionNamesStack.pop();
- entireWithinSectionNames.insert(sec->name());
- }
- }
- }
-
- if (!KoSectionUtils::getNextBlock(cur)) {
- break;
- }
- }
-
- while (block.isValid() && ((to == -1) || (block.position() <= to))) {
-
- QTextCursor cursor(block);
-
- int frameType = cursor.currentFrame()->format().intProperty(KoText::SubFrameType);
- if (frameType == KoText::AuxillaryFrameType) {
- break; // we've reached the "end" (end/footnotes saved by themselves)
- // note how NoteFrameType passes through here so the notes can
- // call writeBlocks to save their contents.
- }
-
- QTextBlockFormat format = block.blockFormat();
-
- foreach (const KoSection *section, KoSectionUtils::sectionStartings(format)) {
- // We are writing in only sections, that are completely inside selection.
- if (entireWithinSectionNames.contains(section->name())) {
- section->saveOdf(context);
- }
- }
-
- if (format.hasProperty(KoParagraphStyle::HiddenByTable)) {
- block = block.next();
- continue;
- }
- if (format.hasProperty(KoParagraphStyle::TableOfContentsData)) {
- saveTableOfContents(doc, listStyles, block);
- block = block.next();
- continue;
- }
- if (format.hasProperty(KoParagraphStyle::BibliographyData)) {
- saveBibliography(doc, listStyles, block);
- block = block.next();
- continue;
- }
-
- if (cursor.currentTable() && cursor.currentTable() != currentTable) {
- // Call the code to save the table....
- saveTable(cursor.currentTable(), listStyles, from, to);
- // We skip to the end of the table.
- block = cursor.currentTable()->lastCursorPosition().block();
- block = block.next();
- continue;
- }
-
- if (cursor.currentList() && cursor.currentList() != currentList) {
- int previousBlockNumber = block.blockNumber();
- block = saveList(block, listStyles, 1, currentTable);
- int blockNumberToProcess = block.blockNumber();
- if (blockNumberToProcess != previousBlockNumber)
- continue;
- }
-
- saveParagraph(block, from, to);
-
- foreach (const KoSectionEnd *sectionEnd, KoSectionUtils::sectionEndings(format)) {
- // We are writing in only sections, that are completely inside selection.
- if (entireWithinSectionNames.contains(sectionEnd->name())) {
- sectionEnd->saveOdf(context);
- }
- }
-
- block = block.next();
- } // while
-
- Q_ASSERT(!pairedInlineObjectsStackStack.isEmpty());
- currentPairedInlineObjectsStack.reset(pairedInlineObjectsStackStack.pop());
-}
-
-
-QHash<QTextList *, QString> KoTextWriter::Private::saveListStyles(QTextBlock block, int to)
-{
- QHash<KoList *, QString> generatedLists;
- QHash<QTextList *, QString> listStyles;
-
- for (;block.isValid() && ((to == -1) || (block.position() < to)); block = block.next()) {
- QTextList *textList = block.textList();
- if (!textList)
- continue;
- KoListStyle::ListIdType listId = ListId(textList->format());
- if (KoList *list = KoTextDocument(document).list(listId)) {
- if (generatedLists.contains(list)) {
- if (!listStyles.contains(textList))
- listStyles.insert(textList, generatedLists.value(list));
- continue;
- }
- KoListStyle *listStyle = list->style();
- if (!listStyle || listStyle->isOulineStyle())
- continue;
-
- bool automatic = listStyle->styleId() == 0;
- KoGenStyle style(automatic ? KoGenStyle::ListAutoStyle : KoGenStyle::ListStyle);
- if (automatic && context.isSet(KoShapeSavingContext::AutoStyleInStyleXml))
- style.setAutoStyleInStylesDotXml(true);
- listStyle->saveOdf(style, context);
- QString generatedName = context.mainStyles().insert(style, listStyle->name(), listStyle->isNumberingStyle() ? KoGenStyles::AllowDuplicates : KoGenStyles::DontAddNumberToName);
- listStyles[textList] = generatedName;
- generatedLists.insert(list, generatedName);
- } else {
- if (listStyles.contains(textList))
- continue;
- KoListLevelProperties llp = KoListLevelProperties::fromTextList(textList);
- KoGenStyle style(KoGenStyle::ListAutoStyle);
- if (context.isSet(KoShapeSavingContext::AutoStyleInStyleXml))
- style.setAutoStyleInStylesDotXml(true);
- KoListStyle listStyle;
- listStyle.setLevelProperties(llp);
- if (listStyle.isOulineStyle()) {
- continue;
- }
- listStyle.saveOdf(style, context);
- QString generatedName = context.mainStyles().insert(style, listStyle.name());
- listStyles[textList] = generatedName;
- }
- }
- return listStyles;
-}
-
-//---------------------------- PRIVATE -----------------------------------------------------------
-
-void KoTextWriter::Private::openTagRegion(ElementType elementType, TagInformation& tagInformation)
-{
- //debugText << "tag:" << tagInformation.name() << openedTagStack.size();
- if (tagInformation.name()) {
- writer->startElement(tagInformation.name(), elementType != ParagraphOrHeader);
- foreach (const Attribute &attribute, tagInformation.attributes()) {
- writer->addAttribute(attribute.first.toLocal8Bit(), attribute.second);
- }
- }
- openedTagStack.push(tagInformation.name());
- //debugText << "stack" << openedTagStack.size();
-}
-
-void KoTextWriter::Private::closeTagRegion()
-{
- // the tag needs to be closed even if there is no change tracking
- //debugText << "stack" << openedTagStack.size();
- const char *tagName = openedTagStack.pop();
- //debugText << "tag:" << tagName << openedTagStack.size();
- if (tagName) {
- writer->endElement(); // close the tag
- }
-}
-
-QString KoTextWriter::Private::saveParagraphStyle(const QTextBlock &block)
-{
- return KoTextWriter::saveParagraphStyle(block, styleManager, context);
-}
-
-QString KoTextWriter::Private::saveParagraphStyle(const QTextBlockFormat &blockFormat, const QTextCharFormat &charFormat)
-{
- return KoTextWriter::saveParagraphStyle(blockFormat, charFormat, styleManager, context);
-}
-
-QString KoTextWriter::Private::saveCharacterStyle(const QTextCharFormat &charFormat, const QTextCharFormat &blockCharFormat)
-{
- KoCharacterStyle *defaultCharStyle = styleManager->defaultCharacterStyle();
-
- KoCharacterStyle *originalCharStyle = styleManager->characterStyle(charFormat.intProperty(KoCharacterStyle::StyleId));
- if (!originalCharStyle)
- originalCharStyle = defaultCharStyle;
-
- QString generatedName;
- QString displayName = originalCharStyle->name();
- QString internalName = QString(QUrl::toPercentEncoding(displayName, "", " ")).replace('%', '_');
-
- KoCharacterStyle *autoStyle = originalCharStyle->autoStyle(charFormat, blockCharFormat);
-
- if (autoStyle->isEmpty()) { // This is the real, unmodified character style.
- if (originalCharStyle != defaultCharStyle) {
- KoGenStyle style(KoGenStyle::TextStyle, "text");
- originalCharStyle->saveOdf(style);
- generatedName = context.mainStyles().insert(style, internalName, KoGenStyles::DontAddNumberToName);
- }
- } else { // There are manual changes... We'll have to store them then
- KoGenStyle style(KoGenStyle::TextAutoStyle, "text", originalCharStyle != defaultCharStyle ? internalName : "" /*parent*/);
- if (context.isSet(KoShapeSavingContext::AutoStyleInStyleXml))
- style.setAutoStyleInStylesDotXml(true);
-
- autoStyle->saveOdf(style);
- generatedName = context.mainStyles().insert(style, "T");
- }
-
- delete autoStyle;
- return generatedName;
-}
-
-QString KoTextWriter::Private::saveTableStyle(const QTextTable& table)
-{
- KoTableStyle *originalTableStyle = styleManager->tableStyle(table.format().intProperty(KoTableStyle::StyleId));
- QString generatedName;
- QString internalName;
- if (originalTableStyle)
- {
- internalName = QString(QUrl::toPercentEncoding(originalTableStyle->name(), "", " ")).replace('%', '_');
- }
- KoTableStyle tableStyle(table.format());
- if ((originalTableStyle) && (*originalTableStyle == tableStyle)) { // This is the real unmodified table style
- KoGenStyle style(KoGenStyle::TableStyle, "table");
- originalTableStyle->saveOdf(style);
- generatedName = context.mainStyles().insert(style, internalName, KoGenStyles::DontAddNumberToName);
- } else { // There are manual changes... We'll have to store them then
- KoGenStyle style(KoGenStyle::TableAutoStyle, "table", internalName);
- if (context.isSet(KoShapeSavingContext::AutoStyleInStyleXml))
- style.setAutoStyleInStylesDotXml(true);
- if (originalTableStyle)
- tableStyle.removeDuplicates(*originalTableStyle);
- if (!tableStyle.isEmpty()) {
- tableStyle.saveOdf(style);
- generatedName = context.mainStyles().insert(style, "Table");
- }
- }
- return generatedName;
-}
-
-QString KoTextWriter::Private::saveTableColumnStyle(const KoTableColumnStyle& tableColumnStyle, int columnNumber, const QString& tableStyleName)
-{
- // 26*26 columns should be enough for everyone
- QString columnName = QChar('A' + int(columnNumber % 26));
- if (columnNumber > 25)
- columnName.prepend(QChar('A' + int(columnNumber/26)));
- QString generatedName = tableStyleName + '.' + columnName;
-
- KoGenStyle style(KoGenStyle::TableColumnAutoStyle, "table-column");
-
- if (context.isSet(KoShapeSavingContext::AutoStyleInStyleXml))
- style.setAutoStyleInStylesDotXml(true);
-
- tableColumnStyle.saveOdf(style);
- generatedName = context.mainStyles().insert(style, generatedName, KoGenStyles::DontAddNumberToName);
- return generatedName;
-}
-
-QString KoTextWriter::Private::saveTableRowStyle(const KoTableRowStyle& tableRowStyle, int rowNumber, const QString& tableStyleName)
-{
- QString generatedName = tableStyleName + '.' + QString::number(rowNumber + 1);
-
- KoGenStyle style(KoGenStyle::TableRowAutoStyle, "table-row");
-
- if (context.isSet(KoShapeSavingContext::AutoStyleInStyleXml))
- style.setAutoStyleInStylesDotXml(true);
-
- tableRowStyle.saveOdf(style);
- generatedName = context.mainStyles().insert(style, generatedName, KoGenStyles::DontAddNumberToName);
- return generatedName;
-}
-
-QString KoTextWriter::Private::saveTableCellStyle(const QTextTableCellFormat& cellFormat, int columnNumber, const QString& tableStyleName)
-{
- // 26*26 columns should be enough for everyone
- QString columnName = QChar('A' + int(columnNumber % 26));
- if (columnNumber > 25)
- columnName.prepend(QChar('A' + int(columnNumber/26)));
- QString generatedName = tableStyleName + '.' + columnName;
-
- KoGenStyle style(KoGenStyle::TableCellAutoStyle, "table-cell");
-
- if (context.isSet(KoShapeSavingContext::AutoStyleInStyleXml))
- style.setAutoStyleInStylesDotXml(true);
-
- KoTableCellStyle cellStyle(cellFormat);
- cellStyle.saveOdf(style, context);
- generatedName = context.mainStyles().insert(style, generatedName);
- return generatedName;
-}
-
-void KoTextWriter::Private::saveInlineRdf(KoTextInlineRdf* , TagInformation* )
-{
-}
-
-/*
-Note on saving textranges:
-Start and end tags of textranges can appear on cursor positions in a text block.
-in front of the first text element, between the elements, or behind the last.
-A textblock is composed of no, one or many text fragments.
-If there is no fragment at all, the only possible cursor position is 0 (relative to the
-begin of the block).
-Example: ([] marks a block, {} a fragment)
-Three blocks, first with text fragments {AB} {C}, second empty, last with {DEF}.
-Possible positions are: [|{A|B}|{C}|] [|] [|{D|E|F}|]
-
-Start tags are ideally written in front of the content they are tagging,
-not behind the previous content. That way tags which are at the very begin
-of the complete document do not need special handling.
-End tags are ideally written directly behind the content, and not in front of
-the next content. That way end tags which are at the end of the complete document
-do not need special handling.
-Next there is the case of start tags which are at the final position of a text block:
-the content they belong to includes the block end/border, so they need to be
-written at the place of the last position.
-Then there is the case of end tags at the first position of a text block:
-the content they belong to includes the block start/border, so they need to be
-written at the place of the first position.
-Example: (< marks a start tag, > marks an end tag)
-[|>{<A><B>}|{<C>}|<] [|><] [|>{<D>|<E>|<F>}|<]
-*/
-void KoTextWriter::Private::saveParagraph(const QTextBlock &block, int from, int to)
-{
- QTextCursor cursor(block);
- QTextBlockFormat blockFormat = block.blockFormat();
- const int outlineLevel = blockFormat.intProperty(KoParagraphStyle::OutlineLevel);
-
- TagInformation blockTagInformation;
- if (outlineLevel > 0) {
- blockTagInformation.setTagName("text:h");
- blockTagInformation.addAttribute("text:outline-level", outlineLevel);
- if (blockFormat.boolProperty(KoParagraphStyle::IsListHeader) || blockFormat.boolProperty(KoParagraphStyle::UnnumberedListItem)) {
- blockTagInformation.addAttribute("text:is-list-header", "true");
- }
- } else {
- blockTagInformation.setTagName("text:p");
- }
-
- openTagRegion(KoTextWriter::Private::ParagraphOrHeader, blockTagInformation);
-
- QString styleName = saveParagraphStyle(block);
- if (!styleName.isEmpty())
- writer->addAttribute("text:style-name", styleName);
-
- KoElementReference xmlid;
- xmlid.invalidate();
-
- QTextBlock currentBlock = block;
- KoTextBlockData blockData(currentBlock);
- if (blockData.saveXmlID()) {
- xmlid = context.xmlid(&blockData);
- xmlid.saveOdf(writer, KoElementReference::TextId);
- }
- // Write the fragments and their formats
- QTextCharFormat blockCharFormat = cursor.blockCharFormat();
- QTextCharFormat previousCharFormat;
- QTextBlock::iterator it;
- if (KoTextInlineRdf* inlineRdf = KoTextInlineRdf::tryToGetInlineRdf(blockCharFormat)) {
- // Write xml:id here for Rdf
- debugText << "have inline rdf xmlid:" << inlineRdf->xmlId() << "active xml id" << xmlid.toString();
- inlineRdf->saveOdf(context, writer, xmlid);
- }
-
- const KoTextRangeManager *textRangeManager = KoTextDocument(block.document()).textRangeManager();
-
- if (textRangeManager) {
- // write tags for ranges which end at the first position of the block
- const QHash<int, KoTextRange *> endingTextRangesAtStart =
- textRangeManager->textRangesChangingWithin(block.document(), block.position(), block.position(), globalFrom, globalTo);
- foreach (const KoTextRange *range, endingTextRangesAtStart) {
- range->saveOdf(context, block.position(), KoTextRange::EndTag);
- }
- }
-
- QString previousFragmentLink;
- // stores the end position of the last fragment, is position of the block without any fragment at all
- int lastEndPosition = block.position();
- for (it = block.begin(); !(it.atEnd()); ++it) {
- QTextFragment currentFragment = it.fragment();
- const int fragmentStart = currentFragment.position();
- const int fragmentEnd = fragmentStart + currentFragment.length();
- if (to != -1 && fragmentStart >= to)
- break;
- if (currentFragment.isValid()) {
- QTextCharFormat charFormat = currentFragment.charFormat();
-
- if ((!previousFragmentLink.isEmpty()) && (charFormat.anchorHref() != previousFragmentLink || !charFormat.isAnchor())) {
- // Close the current text:a
- closeTagRegion();
- previousFragmentLink.clear();
- }
-
- if (charFormat.isAnchor() && charFormat.anchorHref() != previousFragmentLink) {
- // Open a text:a
- previousFragmentLink = charFormat.anchorHref();
- TagInformation linkTagInformation;
-
- if (charFormat.intProperty(KoCharacterStyle::AnchorType) == KoCharacterStyle::Bookmark) {
- linkTagInformation.setTagName("text:bookmark-ref");
- QString href = previousFragmentLink.right(previousFragmentLink.size()-1);
- linkTagInformation.addAttribute("text:ref-name", href);
- //linkTagInformation.addAttribute("text:ref-format", add the style of the ref here);
- } else {
- linkTagInformation.setTagName("text:a");
- linkTagInformation.addAttribute("xlink:type", "simple");
- linkTagInformation.addAttribute("xlink:href", charFormat.anchorHref());
- }
- if (KoTextInlineRdf* inlineRdf = KoTextInlineRdf::tryToGetInlineRdf(charFormat)) {
- // Write xml:id here for Rdf
- debugText << "have inline rdf xmlid:" << inlineRdf->xmlId();
- saveInlineRdf(inlineRdf, &linkTagInformation);
- }
- openTagRegion(KoTextWriter::Private::Span, linkTagInformation);
- }
-
- KoInlineTextObjectManager *textObjectManager = KoTextDocument(document).inlineTextObjectManager();
- KoInlineObject *inlineObject = textObjectManager ? textObjectManager->inlineTextObject(charFormat) : 0;
- // If we are in an inline object
- if (currentFragment.length() == 1 && inlineObject
- && currentFragment.text()[0].unicode() == QChar::ObjectReplacementCharacter) {
- bool saveInlineObject = true;
-
- if (KoTextMeta* z = dynamic_cast<KoTextMeta*>(inlineObject)) {
- if (z->position() < from) {
- //
- // This <text:meta> starts before the selection, default
- // to not saving it with special cases to allow saving
- //
- saveInlineObject = false;
- if (z->type() == KoTextMeta::StartBookmark) {
- if (z->endBookmark()->position() > from) {
- //
- // They have selected something starting after the
- // <text:meta> opening but before the </text:meta>
- //
- saveInlineObject = true;
- }
- }
- }
- }
-
- // get all text ranges which start before this inline object
- // or end directly after it (+1 to last position for that)
- const QHash<int, KoTextRange *> textRanges = textRangeManager ?
- textRangeManager->textRangesChangingWithin(block.document(), currentFragment.position(), currentFragment.position()+1,
- globalFrom, (globalTo==-1)?-1:globalTo+1) : QHash<int, KoTextRange *>();
- // get all text ranges which start before this
- const QList<KoTextRange *> textRangesBefore = textRanges.values(currentFragment.position());
- // write tags for ranges which start before this content or at positioned at it
- foreach (const KoTextRange *range, textRangesBefore) {
- range->saveOdf(context, currentFragment.position(), KoTextRange::StartTag);
- }
-
- bool saveSpan = dynamic_cast<KoVariable*>(inlineObject) != 0;
-
- if (saveSpan) {
- QString styleName = saveCharacterStyle(charFormat, blockCharFormat);
- if (!styleName.isEmpty()) {
- writer->startElement("text:span", false);
- writer->addAttribute("text:style-name", styleName);
- }
- else {
- saveSpan = false;
- }
- }
-
- if (saveInlineObject) {
- inlineObject->saveOdf(context);
- }
-
- if (saveSpan) {
- writer->endElement();
- }
-
- // write tags for ranges which end after this inline object
- const QList<KoTextRange *> textRangesAfter = textRanges.values(currentFragment.position()+1);
- foreach (const KoTextRange *range, textRangesAfter) {
- range->saveOdf(context, currentFragment.position()+1, KoTextRange::EndTag);
- }
-
- //
- // Track the end marker for matched pairs so we produce valid
- // ODF
- //
- if (KoTextMeta* z = dynamic_cast<KoTextMeta*>(inlineObject)) {
- debugText << "found kometa, type:" << z->type();
- if (z->type() == KoTextMeta::StartBookmark)
- currentPairedInlineObjectsStack->push(z->endBookmark());
- if (z->type() == KoTextMeta::EndBookmark
- && !currentPairedInlineObjectsStack->isEmpty())
- currentPairedInlineObjectsStack->pop();
- }/* else if (KoBookmark* z = dynamic_cast<KoBookmark*>(inlineObject)) {
- if (z->type() == KoBookmark::StartBookmark)
- currentPairedInlineObjectsStack->push(z->endBookmark());
- if (z->type() == KoBookmark::EndBookmark
- && !currentPairedInlineObjectsStack->isEmpty())
- currentPairedInlineObjectsStack->pop();
- }*/
- } else {
- // Normal block, easier to handle
- QString styleName = saveCharacterStyle(charFormat, blockCharFormat);
-
- TagInformation fragmentTagInformation;
- if (!styleName.isEmpty() /*&& !identical*/) {
- fragmentTagInformation.setTagName("text:span");
- fragmentTagInformation.addAttribute("text:style-name", styleName);
- }
-
- openTagRegion(KoTextWriter::Private::Span, fragmentTagInformation);
-
- QString text = currentFragment.text();
- int spanFrom = fragmentStart >= from ? fragmentStart : from;
- int spanTo = to == -1 ? fragmentEnd : (fragmentEnd > to ? to : fragmentEnd);
- // get all text ranges which change within this span
- // or end directly after it (+1 to last position to include those)
- const QHash<int, KoTextRange *> textRanges = textRangeManager ?
- textRangeManager->textRangesChangingWithin(block.document(), spanFrom, spanTo, globalFrom, (globalTo==-1)?-1:globalTo+1) :
- QHash<int, KoTextRange *>();
- // avoid mid, if possible
- if (spanFrom != fragmentStart || spanTo != fragmentEnd || !textRanges.isEmpty()) {
- if (textRanges.isEmpty()) {
- writer->addTextSpan(text.mid(spanFrom - fragmentStart, spanTo - spanFrom));
- } else {
- // split the fragment into subspans at the points of range starts/ends
- QList<int> subSpanTos = textRanges.uniqueKeys();
- std::sort(subSpanTos.begin(), subSpanTos.end());
- // ensure last subSpanTo to be at the end
- if (subSpanTos.last() != spanTo) {
- subSpanTos.append(spanTo);
- }
- // spanFrom should not need to be included
- if (subSpanTos.first() == spanFrom) {
- subSpanTos.removeOne(spanFrom);
- }
- int subSpanFrom = spanFrom;
- // for all subspans
- foreach (int subSpanTo, subSpanTos) {
- // write tags for text ranges which start before this subspan or are positioned at it
- const QList<KoTextRange *> textRangesStartingBefore = textRanges.values(subSpanFrom);
- foreach (const KoTextRange *range, textRangesStartingBefore) {
- range->saveOdf(context, subSpanFrom, KoTextRange::StartTag);
- }
-
- // write subspan content
- writer->addTextSpan(text.mid(subSpanFrom - fragmentStart, subSpanTo - subSpanFrom));
-
- // write tags for text ranges which end behind this subspan
- const QList<KoTextRange *> textRangesEndingBehind = textRanges.values(subSpanTo);
- foreach (const KoTextRange *range, textRangesEndingBehind) {
- range->saveOdf(context, subSpanTo, KoTextRange::EndTag);
- }
-
- subSpanFrom = subSpanTo;
- }
- }
- } else {
- writer->addTextSpan(text);
- }
-
- closeTagRegion();
- } // if (inlineObject)
-
- previousCharFormat = charFormat;
- lastEndPosition = fragmentEnd;
- }
- }
-
- if (!previousFragmentLink.isEmpty()) {
- writer->endElement();
- }
-
- if (it.atEnd() && textRangeManager && ((to == -1) || (lastEndPosition <= to))) {
- // write tags for ranges which start at the last position of the block,
- // i.e. at the position after the last (text) fragment
- const QHash<int, KoTextRange *> startingTextRangesAtEnd =
- textRangeManager->textRangesChangingWithin(block.document(), lastEndPosition, lastEndPosition, globalFrom, globalTo);
- foreach (const KoTextRange *range, startingTextRangesAtEnd) {
- range->saveOdf(context, lastEndPosition, KoTextRange::StartTag);
- }
- }
-
- QString text = block.text();
- if (text.length() == 0 || text.at(text.length()-1) == QChar(0x2028)) {
- if (block.blockFormat().hasProperty(KoParagraphStyle::EndCharStyle)) {
- QVariant v = block.blockFormat().property(KoParagraphStyle::EndCharStyle);
- QSharedPointer<KoCharacterStyle> endCharStyle = v.value< QSharedPointer<KoCharacterStyle> >();
- if (!endCharStyle.isNull()) {
- QTextCharFormat charFormat;
- endCharStyle->applyStyle(charFormat);
-
- QString styleName = saveCharacterStyle(charFormat, blockCharFormat);
-
- if (!styleName.isEmpty()) {
- writer->startElement("text:span", false);
- writer->addAttribute("text:style-name", styleName);
- writer->endElement();
- }
- }
- }
- }
-
- if (to !=-1 && to < block.position() + block.length()) {
- foreach (KoInlineObject* inlineObject, *currentPairedInlineObjectsStack) {
- inlineObject->saveOdf(context);
- }
- }
-
- closeTagRegion();
-}
-
-void KoTextWriter::Private::saveTable(QTextTable *table, QHash<QTextList *, QString> &listStyles, int from, int to)
-{
- KoTableColumnAndRowStyleManager tcarManager = KoTableColumnAndRowStyleManager::getManager(table);
- int numberHeadingRows = table->format().property(KoTableStyle::NumberHeadingRows).toInt();
- TagInformation tableTagInformation;
- QString tableStyleName = saveTableStyle(*table);
- tableTagInformation.setTagName("table:table");
- tableTagInformation.addAttribute("table:style-name", tableStyleName);
- if (table->format().boolProperty(KoTableStyle::TableIsProtected))
- {
- tableTagInformation.addAttribute("table:protected", "true");
- }
-
- if (table->format().hasProperty(KoTableStyle::TableTemplate))
- {
- tableTagInformation.addAttribute("table:template-name",
- sharedData->styleName(table->format().intProperty(KoTableStyle::TableTemplate)));
- }
-
- if (table->format().boolProperty(KoTableStyle::UseBandingColumnStyles))
- {
- tableTagInformation.addAttribute("table:use-banding-columns-styles", "true");
- }
-
- if (table->format().boolProperty(KoTableStyle::UseBandingRowStyles))
- {
- tableTagInformation.addAttribute("table:use-banding-rows-styles", "true");
- }
-
- if (table->format().boolProperty(KoTableStyle::UseFirstColumnStyles))
- {
- tableTagInformation.addAttribute("table:use-first-column-styles", "true");
- }
-
- if (table->format().boolProperty(KoTableStyle::UseFirstRowStyles))
- {
- tableTagInformation.addAttribute("table:use-first-row-styles", "true");
- }
-
- if (table->format().boolProperty(KoTableStyle::UseLastColumnStyles))
- {
- tableTagInformation.addAttribute("table:use-last-column-styles", "true");
- }
-
- if (table->format().boolProperty(KoTableStyle::UseLastRowStyles))
- {
- tableTagInformation.addAttribute("table:use-last-row-styles", "true");
- }
-
-
-
- int firstColumn = 0;
- int lastColumn = table->columns() -1;
- int firstRow = 0;
- int lastRow = table->rows() -1;
- if (to != -1 && from >= table->firstPosition() && to <= table->lastPosition()) {
- firstColumn = table->cellAt(from).column();
- firstRow = table->cellAt(from).row();
- lastColumn = table->cellAt(to).column();
- lastRow = table->cellAt(to).row();
-
- if (firstColumn == lastColumn && firstRow == lastRow && from >= table->firstPosition()) {
- // we only selected something inside a single cell so don't save a table
- writeBlocks(table->document(), from, to, listStyles, table);
- return;
- }
- }
-
-
- openTagRegion(KoTextWriter::Private::Table, tableTagInformation);
-
- for (int c = firstColumn ; c <= lastColumn; c++) {
- KoTableColumnStyle columnStyle = tcarManager.columnStyle(c);
- int repetition = 0;
-
- for (; repetition <= (lastColumn - c) ; repetition++)
- {
- if (columnStyle != tcarManager.columnStyle(c + repetition + 1))
- break;
- }
-
- TagInformation tableColumnInformation;
- tableColumnInformation.setTagName("table:table-column");
- QString columnStyleName = saveTableColumnStyle(columnStyle, c, tableStyleName);
- tableColumnInformation.addAttribute("table:style-name", columnStyleName);
-
- if (repetition > 0)
- tableColumnInformation.addAttribute("table:number-columns-repeated", repetition + 1);
-
- openTagRegion(KoTextWriter::Private::TableColumn, tableColumnInformation);
- closeTagRegion();
- c += repetition;
- }
-
- if (numberHeadingRows)
- writer->startElement("table:table-header-rows");
-
- // TODO make work for copying part of table that has header rows - copy header rows additionally or not ?
- for (int r = firstRow; r <= lastRow; r++) {
- TagInformation tableRowInformation;
- tableRowInformation.setTagName("table:table-row");
- KoTableRowStyle rowStyle = tcarManager.rowStyle(r);
- if (!rowStyle.isEmpty())
- {
- QString rowStyleName = saveTableRowStyle(rowStyle, r, tableStyleName);
- tableRowInformation.addAttribute("table:style-name", rowStyleName);
- }
- openTagRegion(KoTextWriter::Private::TableRow, tableRowInformation);
-
- for (int c = firstColumn; c <= lastColumn; c++) {
- QTextTableCell cell = table->cellAt(r, c);
-
- TagInformation tableCellInformation;
- if ((cell.row() == r) && (cell.column() == c)) {
- tableCellInformation.setTagName("table:table-cell");
- if (cell.rowSpan() > 1)
- tableCellInformation.addAttribute("table:number-rows-spanned", cell.rowSpan());
- if (cell.columnSpan() > 1)
- tableCellInformation.addAttribute("table:number-columns-spanned", cell.columnSpan());
- if (cell.format().boolProperty(KoTableCellStyle::CellIsProtected))
- {
- tableCellInformation.addAttribute("table:protected", "true");
- }
-
- // Save the Rdf for the table cell
- QTextTableCellFormat cellFormat = cell.format().toTableCellFormat();
- QVariant v = cellFormat.property(KoTableCellStyle::InlineRdf);
- if (KoTextInlineRdf* inlineRdf = v.value<KoTextInlineRdf*>()) {
- inlineRdf->saveOdf(context, writer);
- }
-
- QString cellStyleName = saveTableCellStyle(cellFormat, c, tableStyleName);
- tableCellInformation.addAttribute("table:style-name", cellStyleName);
- openTagRegion(KoTextWriter::Private::TableCell, tableCellInformation);
- writeBlocks(table->document(), cell.firstPosition(), cell.lastPosition(), listStyles, table);
- } else {
- tableCellInformation.setTagName("table:covered-table-cell");
- if (cell.format().boolProperty(KoTableCellStyle::CellIsProtected))
- {
- tableCellInformation.addAttribute("table:protected", "true");
- }
- openTagRegion(KoTextWriter::Private::TableCell, tableCellInformation);
- }
- closeTagRegion();
- }
- closeTagRegion();
-
- if (r + 1 == numberHeadingRows) {
- writer->endElement(); // table:table-header-rows
- writer->startElement("table:table-rows");
- }
- }
-
- if (numberHeadingRows)
- writer->endElement(); // table:table-rows
- closeTagRegion();
-
-}
-
-void KoTextWriter::Private::saveTableOfContents(QTextDocument *document, QHash<QTextList *, QString> &listStyles, QTextBlock toc)
-{
- Q_UNUSED(document);
-
- writer->startElement("text:table-of-content");
-
- KoTableOfContentsGeneratorInfo *info = toc.blockFormat().property(KoParagraphStyle::TableOfContentsData).value<KoTableOfContentsGeneratorInfo*>();
- QTextDocument *tocDocument = toc.blockFormat().property(KoParagraphStyle::GeneratedDocument).value<QTextDocument*>();
- if (!info->m_styleName.isNull()) {
- writer->addAttribute("text:style-name",info->m_styleName);
- }
- writer->addAttribute("text:name",info->m_name);
-
- info->saveOdf(writer);
-
- writer->startElement("text:index-body");
- // write the title (one p block)
- QTextCursor localBlock = tocDocument->rootFrame()->firstCursorPosition();
- localBlock.movePosition(QTextCursor::NextBlock);
- int endTitle = localBlock.position();
- writer->startElement("text:index-title");
- writer->addAttribute("text:name", QString("%1_Head").arg(info->m_name));
- writeBlocks(tocDocument, 0, endTitle, listStyles);
- writer->endElement(); // text:index-title
-
- writeBlocks(tocDocument, endTitle, -1, listStyles);
-
- writer->endElement(); // table:index-body
- writer->endElement(); // table:table-of-content
-}
-
-void KoTextWriter::Private::saveBibliography(QTextDocument *document, QHash<QTextList *, QString> &listStyles, QTextBlock bib)
-{
- Q_UNUSED(document);
-
- writer->startElement("text:bibliography");
-
- KoBibliographyInfo *info = bib.blockFormat().property(KoParagraphStyle::BibliographyData).value<KoBibliographyInfo*>();
- QTextDocument *bibDocument = bib.blockFormat().property(KoParagraphStyle::GeneratedDocument).value<QTextDocument*>();
- if (!info->m_styleName.isNull()) {
- writer->addAttribute("text:style-name",info->m_styleName);
- }
- writer->addAttribute("text:name",info->m_name);
-
- info->saveOdf(writer);
-
- writer->startElement("text:index-body");
- // write the title (one p block)
- QTextCursor localBlock = bibDocument->rootFrame()->firstCursorPosition();
- localBlock.movePosition(QTextCursor::NextBlock);
- int endTitle = localBlock.position();
- writer->startElement("text:index-title");
- writeBlocks(bibDocument, 0, endTitle, listStyles);
- writer->endElement(); // text:index-title
-
- writeBlocks(bibDocument, endTitle, -1, listStyles);
-
- writer->endElement(); // table:index-body
- writer->endElement(); // table:bibliography
-}
-
-QTextBlock& KoTextWriter::Private::saveList(QTextBlock &block, QHash<QTextList *, QString> &listStyles, int level, QTextTable *currentTable)
-{
- QTextList *textList, *topLevelTextList;
- topLevelTextList = textList = block.textList();
-
- int headingLevel = 0, numberedParagraphLevel = 0;
- QTextBlockFormat blockFormat = block.blockFormat();
- headingLevel = blockFormat.intProperty(KoParagraphStyle::OutlineLevel);
- numberedParagraphLevel = blockFormat.intProperty(KoParagraphStyle::ListLevel);
-
- KoTextDocument textDocument(block.document());
- KoList *list = textDocument.list(block);
- int topListLevel = KoList::level(block);
-
- bool listStarted = false;
- if (!headingLevel && !numberedParagraphLevel) {
- listStarted = true;
-
- TagInformation listTagInformation;
- listTagInformation.setTagName("text:list");
- listTagInformation.addAttribute("text:style-name", listStyles[textList]);
-
- if (list && listXmlIds.contains(list->listContinuedFrom())) {
- listTagInformation.addAttribute("text:continue-list", listXmlIds.value(list->listContinuedFrom()));
- }
-
- QString listXmlId = QString("list-%1").arg(createXmlId());
- listTagInformation.addAttribute("xml:id", listXmlId);
- if (! listXmlIds.contains(list)) {
- listXmlIds.insert(list, listXmlId);
- }
-
- openTagRegion(KoTextWriter::Private::List, listTagInformation);
- }
-
- if (!headingLevel) {
- do {
- if (numberedParagraphLevel) {
- TagInformation paraTagInformation;
- paraTagInformation.setTagName("text:numbered-paragraph");
- paraTagInformation.addAttribute("text:level", numberedParagraphLevel);
- paraTagInformation.addAttribute("text:style-name", listStyles.value(textList));
-
- QString listId = numberedParagraphListIds.value(list, QString("list-%1").arg(createXmlId()));
- numberedParagraphListIds.insert(list, listId);
- paraTagInformation.addAttribute("text:list-id", listId);
-
- openTagRegion(KoTextWriter::Private::NumberedParagraph, paraTagInformation);
- writeBlocks(textDocument.document(), block.position(), block.position() + block.length() - 1, listStyles, currentTable, textList);
- closeTagRegion();
- } else {
-
- const bool listHeader = blockFormat.boolProperty(KoParagraphStyle::IsListHeader)|| blockFormat.boolProperty(KoParagraphStyle::UnnumberedListItem);
- TagInformation listItemTagInformation;
- listItemTagInformation.setTagName(listHeader ? "text:list-header" : "text:list-item");
- if (block.blockFormat().hasProperty(KoParagraphStyle::ListStartValue)) {
- int startValue = block.blockFormat().intProperty(KoParagraphStyle::ListStartValue);
- listItemTagInformation.addAttribute("text:start-value", startValue);
- }
- if (textList == topLevelTextList) {
- openTagRegion(KoTextWriter::Private::ListItem, listItemTagInformation);
- } else {
- // This is a sub-list. So check for a list-change
- openTagRegion(KoTextWriter::Private::List, listItemTagInformation);
- }
-
- if (KoListStyle::isNumberingStyle(textList->format().style())) {
- KoTextBlockData blockData(block);
- writer->startElement("text:number", false);
- writer->addTextSpan(blockData.counterText());
- writer->endElement();
- }
-
- if (topListLevel == level && textList == topLevelTextList) {
- writeBlocks(textDocument.document(), block.position(), block.position() + block.length() - 1, listStyles, currentTable, textList);
- // we are generating a text:list-item. Look forward and generate unnumbered list items.
- while (true) {
- QTextBlock nextBlock = block.next();
- if (!nextBlock.textList() || !nextBlock.blockFormat().boolProperty(KoParagraphStyle::UnnumberedListItem))
- break;
- block = nextBlock;
- saveParagraph(block, block.position(), block.position() + block.length() - 1);
- }
- } else {
- //This is a sub-list
- while (KoList::level(block) >= (level + 1) && !(headingLevel || numberedParagraphLevel)) {
- block = saveList(block, listStyles, level + 1, currentTable);
-
- blockFormat = block.blockFormat();
- headingLevel = blockFormat.intProperty(KoParagraphStyle::OutlineLevel);
- numberedParagraphLevel = blockFormat.intProperty(KoParagraphStyle::ListLevel);
- }
- //saveList will return a block one-past the last block of the list.
- //Since we are doing a block.next() below, we need to go one back.
- block = block.previous();
- }
-
- closeTagRegion();
-
- }
- block = block.next();
- blockFormat = block.blockFormat();
- headingLevel = blockFormat.intProperty(KoParagraphStyle::OutlineLevel);
- numberedParagraphLevel = blockFormat.intProperty(KoParagraphStyle::ListLevel);
- textList = block.textList();
- } while ((textDocument.list(block) == list) && (KoList::level(block) >= topListLevel));
- }
-
- if (listStarted) {
- closeTagRegion();
- }
-
- return block;
-}
-
-void KoTextWriter::Private::addNameSpaceDefinitions(QString &generatedXmlString)
-{
- //Generate the name-space definitions so that it can be parsed. Like what is office:text, office:delta etc
- QString nameSpaceDefinitions;
- QTextStream nameSpacesStream(&nameSpaceDefinitions);
- nameSpacesStream.setCodec("UTF-8");
-
- nameSpacesStream << "<generated-xml ";
- nameSpacesStream << "xmlns:office=\"" << KoXmlNS::office << "\" ";
- nameSpacesStream << "xmlns:meta=\"" << KoXmlNS::meta << "\" ";
- nameSpacesStream << "xmlns:config=\"" << KoXmlNS::config << "\" ";
- nameSpacesStream << "xmlns:text=\"" << KoXmlNS::text << "\" ";
- nameSpacesStream << "xmlns:table=\"" << KoXmlNS::table << "\" ";
- nameSpacesStream << "xmlns:draw=\"" << KoXmlNS::draw << "\" ";
- nameSpacesStream << "xmlns:presentation=\"" << KoXmlNS::presentation << "\" ";
- nameSpacesStream << "xmlns:dr3d=\"" << KoXmlNS::dr3d << "\" ";
- nameSpacesStream << "xmlns:chart=\"" << KoXmlNS::chart << "\" ";
- nameSpacesStream << "xmlns:form=\"" << KoXmlNS::form << "\" ";
- nameSpacesStream << "xmlns:script=\"" << KoXmlNS::script << "\" ";
- nameSpacesStream << "xmlns:style=\"" << KoXmlNS::style << "\" ";
- nameSpacesStream << "xmlns:number=\"" << KoXmlNS::number << "\" ";
- nameSpacesStream << "xmlns:math=\"" << KoXmlNS::math << "\" ";
- nameSpacesStream << "xmlns:svg=\"" << KoXmlNS::svg << "\" ";
- nameSpacesStream << "xmlns:fo=\"" << KoXmlNS::fo << "\" ";
- nameSpacesStream << "xmlns:anim=\"" << KoXmlNS::anim << "\" ";
- nameSpacesStream << "xmlns:smil=\"" << KoXmlNS::smil << "\" ";
- nameSpacesStream << "xmlns:calligra=\"" << KoXmlNS::calligra << "\" ";
- nameSpacesStream << "xmlns:officeooo=\"" << KoXmlNS::officeooo << "\" ";
- nameSpacesStream << "xmlns:split=\"" << KoXmlNS::split << "\" ";
- nameSpacesStream << "xmlns:ac=\"" << KoXmlNS::ac << "\" ";
- nameSpacesStream << ">";
-
- generatedXmlString.prepend(nameSpaceDefinitions);
- generatedXmlString.append("</generated-xml>");
-}
-
-
-void KoTextWriter::Private::writeAttributes(QTextStream &, KoXmlElement &)
-{
-
-}
-
-void KoTextWriter::Private::writeNode(QTextStream &outputXmlStream, const KoXmlNode &node, bool writeOnlyChildren)
-{
- if (node.isText()) {
- outputXmlStream << node.toText().data();
- } else if (node.isElement()) {
- KoXmlElement element = node.toElement();
- if ((element.localName() == "removed-content") && !KoXml::childNodesCount(element)) {
- return;
- }
-
- if (!writeOnlyChildren) {
- outputXmlStream << "<" << element.prefix() << ":" << element.localName();
- writeAttributes(outputXmlStream,element);
- outputXmlStream << ">";
- }
-
- for (KoXmlNode node = element.firstChild(); !node.isNull(); node = node.nextSibling()) {
- writeNode(outputXmlStream, node);
- }
-
- if (!writeOnlyChildren) {
- outputXmlStream << "</" << element.prefix() << ":" << element.localName() << ">";
- }
- }
-}
-
-QString KoTextWriter::Private::createXmlId()
-{
- QString uuid = QUuid::createUuid().toString();
- uuid.remove('{');
- uuid.remove('}');
- return uuid;
-}
-
diff --git a/plugins/flake/textshape/kotext/opendocument/KoTextWriter_p.h b/plugins/flake/textshape/kotext/opendocument/KoTextWriter_p.h
deleted file mode 100644
index 77fcb64bf4..0000000000
--- a/plugins/flake/textshape/kotext/opendocument/KoTextWriter_p.h
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (c) 2010 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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.
- */
-
-#ifndef KOTEXTWRITER_P_H
-#define KOTEXTWRITER_P_H
-
-#include <QMap>
-#include <QHash>
-#include <QStack>
-#include <QPair>
-#include <QString>
-#include <QScopedPointer>
-
-#include <KoTextWriter.h>
-#include <KoXmlReaderForward.h>
-
-class KoInlineObject;
-class KoTextInlineRdf;
-class KoList;
-class KoShapeSavingContext;
-class KoXmlWriter;
-class KoTableColumnStyle;
-class KoTextSharedSavingData;
-class KoTableRowStyle;
-class KoDocumentRdfBase;
-
-class QTextDocument;
-class QTextTable;
-class QTextTableCellFormat;
-class QTextList;
-class QTextStream;
-
-/**
- * XXX: Apidox!
- */
-class TagInformation
-{
- public:
- TagInformation():tagName(0), attributeList()
- {
- }
-
- void setTagName(const char *tagName)
- {
- this->tagName = tagName;
- }
-
- void addAttribute(const QString& attributeName, const QString& attributeValue)
- {
- attributeList.push_back(QPair<QString,QString>(attributeName, attributeValue));
- }
-
- void addAttribute(const QString& attributeName, int value)
- {
- addAttribute(attributeName, QString::number(value));
- }
-
- void clear()
- {
- tagName = 0;
- attributeList.clear();
- }
-
- const char *name() const
- {
- return tagName;
- }
-
- const QVector<QPair<QString, QString> >& attributes() const
- {
- return attributeList;
- }
-
- private:
- const char *tagName;
- QVector<QPair<QString, QString> > attributeList;
-};
-
-
-/**
- * XXX: Apidox!
- */
-class Q_DECL_HIDDEN KoTextWriter::Private
-{
-public:
-
- explicit Private(KoShapeSavingContext &context);
-
- ~Private();
-
- void writeBlocks(QTextDocument *document, int from, int to,
- QHash<QTextList *, QString> &listStyles,
- QTextTable *currentTable = 0,
- QTextList *currentList = 0);
- QHash<QTextList *, QString> saveListStyles(QTextBlock block, int to);
-
-private:
-
- enum ElementType {
- Span,
- ParagraphOrHeader,
- ListItem,
- List,
- NumberedParagraph,
- Table,
- TableRow,
- TableColumn,
- TableCell
- };
-
- void openTagRegion(KoTextWriter::Private::ElementType elementType, TagInformation &tagInformation);
- void closeTagRegion();
-
- QString saveParagraphStyle(const QTextBlock &block);
- QString saveParagraphStyle(const QTextBlockFormat &blockFormat, const QTextCharFormat &charFormat);
- QString saveCharacterStyle(const QTextCharFormat &charFormat, const QTextCharFormat &blockCharFormat);
- QString saveTableStyle(const QTextTable &table);
- QString saveTableColumnStyle(const KoTableColumnStyle &columnStyle, int columnNumber, const QString &tableStyleName);
- QString saveTableRowStyle(const KoTableRowStyle &rowStyle, int rowNumber, const QString &tableStyleName);
- QString saveTableCellStyle(const QTextTableCellFormat &cellFormat, int columnNumber, const QString &tableStyleName);
-
- void saveParagraph(const QTextBlock &block, int from, int to);
- void saveTable(QTextTable *table, QHash<QTextList *, QString> &listStyles, int from, int to);
- QTextBlock& saveList(QTextBlock &block, QHash<QTextList *, QString> &listStyles, int level, QTextTable *currentTable);
- void saveTableOfContents(QTextDocument *document, QHash<QTextList *, QString> &listStyles, QTextBlock toc);
- void saveBibliography(QTextDocument *document, QHash<QTextList *, QString> &listStyles, QTextBlock bib);
- void saveInlineRdf(KoTextInlineRdf *rdf, TagInformation *tagInfos);
-
- void addNameSpaceDefinitions(QString &generatedXmlString);
-
- // Common methods
- void writeAttributes(QTextStream &outputXmlStream, KoXmlElement &element);
- void writeNode(QTextStream &outputXmlStream, const KoXmlNode &node, bool writeOnlyChildren = false);
-
- QString createXmlId();
-
-public:
-
- KoDocumentRdfBase *rdfData;
- KoTextSharedSavingData *sharedData;
- KoStyleManager *styleManager;
- QTextDocument *document;
- int globalFrom; // to and from positions, relevant for finding matching bookmarks etc
- int globalTo;
-
-private:
-
- KoXmlWriter *writer;
-
- QStack<const char *> openedTagStack;
-
- KoShapeSavingContext &context;
-
- // Things like bookmarks need to be properly turn down during a cut and paste operation
- // when their end markeris not included in the selection. However, when recursing into
- // e.g. the QTextDocument of a table, we need have a clean slate. Hence, a stack of stacks.
- QStack< QStack<KoInlineObject*> *> pairedInlineObjectsStackStack;
- QScopedPointer<QStack<KoInlineObject*>> currentPairedInlineObjectsStack;
-
- QMap<KoList *, QString> listXmlIds;
-
- QMap<KoList *, QString> numberedParagraphListIds;
-};
-
-#endif // KOTEXTWRITER_P_H
diff --git a/plugins/flake/textshape/kotext/styles/KoCharacterStyle.cpp b/plugins/flake/textshape/kotext/styles/KoCharacterStyle.cpp
deleted file mode 100644
index bac90fbecd..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoCharacterStyle.cpp
+++ /dev/null
@@ -1,2268 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2007 Sebastian Sauer <mail@dipe.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2011 Stuart Dickson <stuart@furkinfantasic.net>
- *
- * 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 "KoCharacterStyle.h"
-
-#include "Styles_p.h"
-
-#include <QTextBlock>
-#include <QTextCursor>
-#include <QFontDatabase>
-
-#include <KoOdfLoadingContext.h>
-#include <KoOdfStylesReader.h>
-#include <KoXmlNS.h>
-#include <KoXmlReader.h>
-#include <KoUnit.h>
-#include <KoStore.h>
-#include <KoStoreDevice.h>
-#include <KoGenStyle.h>
-#include <KoShadowStyle.h>
-#include <KoShapeLoadingContext.h>
-#include <KoStyleStack.h>
-#include "KoTextDocument.h"
-
-#ifdef SHOULD_BUILD_FONT_CONVERSION
-#include <string.h>
-#include <fontconfig/fontconfig.h>
-#include <fontconfig/fcfreetype.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_GLYPH_H
-#include FT_TYPES_H
-#include FT_OUTLINE_H
-#include FT_RENDER_H
-#include FT_TRUETYPE_TABLES_H
-#include FT_SFNT_NAMES_H
-#endif
-
-#include "TextDebug.h"
-#include "KoTextDebug.h"
-
-#ifdef SHOULD_BUILD_FONT_CONVERSION
- QMap<QString,qreal> textScaleMap;
-#endif //SHOULD_BUILD_FONT_CONVERSION
-
-class Q_DECL_HIDDEN KoCharacterStyle::Private
-{
-public:
- Private();
- ~Private() { }
-
- void setProperty(int key, const QVariant &value) {
- stylesPrivate.add(key, value);
- }
- qreal propertyDouble(int key) const {
- QVariant variant = stylesPrivate.value(key);
- if (variant.isNull()) {
- if (parentStyle)
- return parentStyle->d->propertyDouble(key);
- else if (defaultStyle)
- return defaultStyle->d->propertyDouble(key);
- return 0.0;
- }
- return variant.toDouble();
- }
- int propertyInt(int key) const {
- QVariant variant = stylesPrivate.value(key);
- if (variant.isNull()) {
- if (parentStyle)
- return parentStyle->d->propertyInt(key);
- else if (defaultStyle)
- return defaultStyle->d->propertyInt(key);
- return 0;
- }
- return variant.toInt();
- }
- QString propertyString(int key) const {
- QVariant variant = stylesPrivate.value(key);
- if (variant.isNull()) {
- if (parentStyle)
- return parentStyle->d->propertyString(key);
- else if (defaultStyle)
- return defaultStyle->d->propertyString(key);
- return QString();
- }
- return qvariant_cast<QString>(variant);
- }
- bool propertyBoolean(int key) const {
- QVariant variant = stylesPrivate.value(key);
- if (variant.isNull()) {
- if (parentStyle)
- return parentStyle->d->propertyBoolean(key);
- else if (defaultStyle)
- return defaultStyle->d->propertyBoolean(key);
- return false;
- }
- return variant.toBool();
- }
- QColor propertyColor(int key) const {
- QVariant variant = stylesPrivate.value(key);
- if (variant.isNull()) {
- if (parentStyle)
- return parentStyle->d->propertyColor(key);
- else if (defaultStyle)
- return defaultStyle->d->propertyColor(key);
- return QColor();
- }
- return variant.value<QColor>();
- }
-
- // problem with fonts in linux and windows is that true type fonts have more than one metric
- // they have normal metric placed in font header table
- // microsoft metric placed in os2 table
- // apple metric placed in os2 table
- // ms-word is probably using CreateFontIndirect and GetOutlineTextMetric function to calculate line height
- // and this functions are using windows gdi environment which is using microsoft font metric placed in os2 table
- // qt on linux is using normal font metric
- // this two metrics are different and change from font to font
- // this font stretch is needed if we want to have exact line height as in ms-word and oo
- //
- // font_size * font_stretch = windows_font_height
- qreal calculateFontYStretch(const QString &fontFamily);
-
-
- StylePrivate hardCodedDefaultStyle;
-
- QString name;
- StylePrivate stylesPrivate;
- KoCharacterStyle *parentStyle;
- KoCharacterStyle *defaultStyle;
- bool m_inUse;
-};
-
-KoCharacterStyle::Private::Private()
- : parentStyle(0), defaultStyle(0), m_inUse(false)
-{
- //set the minimal default properties
- hardCodedDefaultStyle.add(QTextFormat::FontFamily, QString("Sans Serif"));
- hardCodedDefaultStyle.add(QTextFormat::FontPointSize, 12.0);
- hardCodedDefaultStyle.add(QTextFormat::ForegroundBrush, QBrush(Qt::black));
- hardCodedDefaultStyle.add(KoCharacterStyle::FontYStretch, 1);
- hardCodedDefaultStyle.add(QTextFormat::FontHintingPreference, QFont::PreferNoHinting);
-}
-
-
-void KoCharacterStyle::ensureMinimalProperties(QTextCharFormat &format) const
-{
- if (d->defaultStyle) {
- QMap<int, QVariant> props = d->defaultStyle->d->stylesPrivate.properties();
- QMap<int, QVariant>::const_iterator it = props.constBegin();
- while (it != props.constEnd()) {
- // in case there is already a foreground color don't apply the use window font color as then the foreground color
- // should be used.
- if (it.key() == KoCharacterStyle::UseWindowFontColor && format.hasProperty(QTextFormat::ForegroundBrush)) {
- ++it;
- continue;
- }
- // in case there is already a use window font color don't apply the foreground brush as this overwrite the foreground color
- if (it.key() == QTextFormat::ForegroundBrush && format.hasProperty(KoCharacterStyle::UseWindowFontColor)) {
- ++it;
- continue;
- }
-
- if (!it.value().isNull() && !format.hasProperty(it.key())) {
- format.setProperty(it.key(), it.value());
- }
- ++it;
- }
- }
- QMap<int, QVariant> props = d->hardCodedDefaultStyle.properties();
- QMap<int, QVariant>::const_iterator it = props.constBegin();
- while (it != props.constEnd()) {
- if (!it.value().isNull() && !format.hasProperty(it.key())) {
- if (it.key() == QTextFormat::ForegroundBrush && format.hasProperty(KoCharacterStyle::UseWindowFontColor)) {
- ++it;
- continue;
- }
-
- format.setProperty(it.key(), it.value());
- }
- ++it;
- }
-}
-
-qreal KoCharacterStyle::Private::calculateFontYStretch(const QString &fontFamily)
-{
- qreal stretch = 1;
-#ifdef SHOULD_BUILD_FONT_CONVERSION
-
- if (textScaleMap.contains(fontFamily)) {
- return textScaleMap.value(fontFamily);
- }
-
- FcResult result = FcResultMatch;
- FT_Library library;
- FT_Face face;
- int id = 0;
- int error = 0;
- QByteArray fontName = fontFamily.toLatin1();
-
- //TODO https://freedesktop.org/software/fontconfig/fontconfig-devel/x19.html
- // we should specify slant and weight too
- FcPattern *font = FcPatternBuild (0, FC_FAMILY, FcTypeString,fontName.data(), FC_SIZE, FcTypeDouble, (qreal)11, 0);
- if (font == 0) {
- return 1;
- }
-
- // find font
- FcPattern *matched = 0;
- matched = FcFontMatch (0, font, &result);
- if (matched == 0) {
- FcPatternDestroy (font);
- return 1;
- }
-
- // get font family name
- char * str = 0;
- result = FcPatternGetString (matched, FC_FAMILY, 0,(FcChar8**) &str);
- if (result != FcResultMatch || str == 0) {
- FcPatternDestroy (font);
- FcPatternDestroy (matched);
- return 1;
- }
-
- // check if right font was found
- QByteArray foundFontFamily = QByteArray::fromRawData(str, strlen(str));
- if (foundFontFamily != fontName) {
- FcPatternDestroy (font);
- FcPatternDestroy (matched);
- return 1;
- }
-
- // get path to font
- str = 0;
- result = FcPatternGetString (matched, FC_FILE, 0,(FcChar8**) &str);
- if (result != FcResultMatch) {
- FcPatternDestroy (font);
- FcPatternDestroy (matched);
- return 1;
- }
-
- // get index of font inside the font file
- result = FcPatternGetInteger (matched, FC_INDEX, 0, &id);
- if (result != FcResultMatch) {
- FcPatternDestroy (font);
- FcPatternDestroy (matched);
- return 1;
- }
-
- // initialize freetype
- error = FT_Init_FreeType( &library );
- if (error) {
- FcPatternDestroy (font);
- FcPatternDestroy (matched);
- return 1;
- }
-
- // get font metric
- error = FT_New_Face (library,(char *) str, id, &face);
- if (error) {
- FT_Done_FreeType(library);
- FcPatternDestroy (font);
- FcPatternDestroy (matched);
- return 1;
- }
-
- // get font metric os2 table
- TT_OS2 *os2;
- os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
- if(os2 == 0) {
- FT_Done_Face(face);
- FT_Done_FreeType(library);
- FcPatternDestroy (font);
- FcPatternDestroy (matched);
- return 1;
- }
-
- // get font metric header table
- TT_Header *header;
- header = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
- if(header == 0) {
- FT_Done_Face(face);
- FT_Done_FreeType(library);
- FcPatternDestroy (font);
- FcPatternDestroy (matched);
- return 1;
- }
-
- // check if the data is valid
- if (header->Units_Per_EM == 0 || (os2->usWinAscent + os2->usWinDescent) == 0) {
- FT_Done_Face(face);
- FT_Done_FreeType(library);
- FcPatternDestroy (font);
- FcPatternDestroy (matched);
- return 1;
- }
-
- // compute font height stretch
- // font_size * font_stretch = windows_font_height
- qreal height = os2->usWinAscent + os2->usWinDescent;
- height = height * (2048 / header->Units_Per_EM);
- stretch = (1.215 * height)/2500;
- stretch = (1.15 * height)/2500; // seems a better guess but probably not right
-
- FT_Done_Face(face);
- FT_Done_FreeType(library);
- FcPatternDestroy (font);
- FcPatternDestroy (matched);
-
- textScaleMap.insert(fontFamily, stretch);
-#else
- Q_UNUSED(fontFamily);
-#endif //SHOULD_BUILD_FONT_CONVERSION
-
- return stretch;
-}
-KoCharacterStyle::KoCharacterStyle(QObject *parent)
- : QObject(parent), d(new Private())
-{
-}
-
-KoCharacterStyle::KoCharacterStyle(const QTextCharFormat &format, QObject *parent)
- : QObject(parent), d(new Private())
-{
- copyProperties(format);
-}
-
-KoCharacterStyle::Type KoCharacterStyle::styleType() const
-{
- return KoCharacterStyle::CharacterStyle;
-}
-
-void KoCharacterStyle::copyProperties(const KoCharacterStyle *style)
-{
- d->stylesPrivate = style->d->stylesPrivate;
- setName(style->name()); // make sure we emit property change
- d->parentStyle = style->d->parentStyle;
- d->defaultStyle = style->d->defaultStyle;
-}
-
-void KoCharacterStyle::copyProperties(const QTextCharFormat &format)
-{
- d->stylesPrivate = format.properties();
-}
-
-KoCharacterStyle *KoCharacterStyle::clone(QObject *parent) const
-{
- KoCharacterStyle *newStyle = new KoCharacterStyle(parent);
- newStyle->copyProperties(this);
- return newStyle;
-}
-
-KoCharacterStyle::~KoCharacterStyle()
-{
- delete d;
-}
-
-void KoCharacterStyle::setDefaultStyle(KoCharacterStyle *defaultStyle)
-{
- d->defaultStyle = defaultStyle;
-}
-
-void KoCharacterStyle::setParentStyle(KoCharacterStyle *parent)
-{
- d->parentStyle = parent;
-}
-
-KoCharacterStyle *KoCharacterStyle::parentStyle() const
-{
- return d->parentStyle;
-}
-
-QPen KoCharacterStyle::textOutline() const
-{
- QVariant variant = value(QTextFormat::TextOutline);
- if (variant.isNull()) {
- return QPen(Qt::NoPen);
- }
- return qvariant_cast<QPen>(variant);
-}
-
-QBrush KoCharacterStyle::background() const
-{
- QVariant variant = value(QTextFormat::BackgroundBrush);
-
- if (variant.isNull()) {
- return QBrush();
- }
- return qvariant_cast<QBrush>(variant);
-}
-
-void KoCharacterStyle::clearBackground()
-{
- d->stylesPrivate.remove(QTextCharFormat::BackgroundBrush);
-}
-
-QBrush KoCharacterStyle::foreground() const
-{
- QVariant variant = value(QTextFormat::ForegroundBrush);
- if (variant.isNull()) {
- return QBrush();
- }
- return qvariant_cast<QBrush>(variant);
-}
-
-void KoCharacterStyle::clearForeground()
-{
- d->stylesPrivate.remove(QTextCharFormat::ForegroundBrush);
-}
-
-void KoCharacterStyle::applyStyle(QTextCharFormat &format, bool emitSignal) const
-{
- if (d->parentStyle) {
- d->parentStyle->applyStyle(format);
- }
-
- bool fontSizeSet = false; // if this style has already set size don't apply the relatives
- const QMap<int, QVariant> props = d->stylesPrivate.properties();
- QMap<int, QVariant>::const_iterator it = props.begin();
- QList<int> clearProperty;
- while (it != props.end()) {
- if (!it.value().isNull()) {
- if (it.key() == KoCharacterStyle::PercentageFontSize && !fontSizeSet) {
- qreal size = it.value().toDouble() / 100.0;
- if (format.hasProperty(QTextFormat::FontPointSize)) {
- size *= format.doubleProperty(QTextFormat::FontPointSize);
- } else {
- size *= 12.0;
- }
- format.setProperty(QTextFormat::FontPointSize, size);
- }
- else if (it.key() == KoCharacterStyle::AdditionalFontSize && !fontSizeSet) {
- qreal size = it.value().toDouble() / 100.0;
- if (format.hasProperty(QTextFormat::FontPointSize)) {
- size += format.doubleProperty(QTextFormat::FontPointSize);
- } else {
- size += 12.0;
- }
- format.setProperty(QTextFormat::FontPointSize, size);
- }
- else if (it.key() == QTextFormat::FontFamily) {
- if (!props.contains(QTextFormat::FontStyleHint)) {
- clearProperty.append(QTextFormat::FontStyleHint);
- }
- if (!props.contains(QTextFormat::FontFixedPitch)) {
- clearProperty.append(QTextFormat::FontFixedPitch);
- }
- if (!props.contains(KoCharacterStyle::FontCharset)) {
- clearProperty.append(KoCharacterStyle::FontCharset);
- }
- format.setProperty(it.key(), it.value());
- }
- else {
- debugText << "setProperty" << it.key() << it.value();
- format.setProperty(it.key(), it.value());
- }
-
- if (it.key() == QTextFormat::FontPointSize) {
- fontSizeSet = true;
- }
-
- if (it.key() == QTextFormat::ForegroundBrush) {
- clearProperty.append(KoCharacterStyle::UseWindowFontColor);
- }
- else if (it.key() == KoCharacterStyle::UseWindowFontColor) {
- clearProperty.append(QTextFormat::ForegroundBrush);
- }
- }
- ++it;
- }
-
- foreach (int property, clearProperty) {
- debugText << "clearProperty" << property;
- format.clearProperty(property);
- }
- if (emitSignal) {
- emit styleApplied(this);
- d->m_inUse = true;
- }
-}
-
-KoCharacterStyle *KoCharacterStyle::autoStyle(const QTextCharFormat &format, QTextCharFormat blockCharFormat) const
-{
- KoCharacterStyle *autoStyle = new KoCharacterStyle(format);
- applyStyle(blockCharFormat, false);
- ensureMinimalProperties(blockCharFormat);
- autoStyle->removeDuplicates(blockCharFormat);
- autoStyle->setParentStyle(const_cast<KoCharacterStyle*>(this));
- // remove StyleId if it is there as it is not a property of the style itself and will not be written out
- // so it should not be part of the autostyle. As otherwise it can happen that the StyleId is the only
- // property left and then we write out an empty style which is unneeded.
- // we also need to remove the properties of links as they are saved differently
- autoStyle->d->stylesPrivate.remove(StyleId);
- autoStyle->d->stylesPrivate.remove(QTextFormat::IsAnchor);
- autoStyle->d->stylesPrivate.remove(QTextFormat::AnchorHref);
- autoStyle->d->stylesPrivate.remove(QTextFormat::AnchorName);
- return autoStyle;
-}
-
-struct FragmentData
-{
- FragmentData(const QTextCharFormat &format, int position, int length)
- : format(format)
- , position(position)
- , length(length)
- {}
-
- QTextCharFormat format;
- int position;
- int length;
-};
-
-void KoCharacterStyle::applyStyle(QTextBlock &block) const
-{
- QTextCursor cursor(block);
- QTextCharFormat cf = block.charFormat();
-
- if (!cf.isTableCellFormat()) {
- cf = KoTextDocument(block.document()).frameCharFormat();
- }
-
- applyStyle(cf);
- ensureMinimalProperties(cf);
- cursor.setBlockCharFormat(cf);
-
- // be sure that we keep the InlineInstanceId, anchor information and ChangeTrackerId when applying a style
-
- QList<FragmentData> fragments;
- for (QTextBlock::iterator it = block.begin(); it != block.end(); ++it) {
- QTextFragment currentFragment = it.fragment();
- if (currentFragment.isValid()) {
- QTextCharFormat format(cf);
- QVariant v = currentFragment.charFormat().property(InlineInstanceId);
- if (!v.isNull()) {
- format.setProperty(InlineInstanceId, v);
- }
-
- v = currentFragment.charFormat().property(ChangeTrackerId);
- if (!v.isNull()) {
- format.setProperty(ChangeTrackerId, v);
- }
-
- if (currentFragment.charFormat().isAnchor()) {
- format.setAnchor(true);
- format.setAnchorHref(currentFragment.charFormat().anchorHref());
- }
- fragments.append(FragmentData(format, currentFragment.position(), currentFragment.length()));
- }
- }
-
- foreach (const FragmentData &fragment, fragments) {
- cursor.setPosition(fragment.position);
- cursor.setPosition(fragment.position + fragment.length, QTextCursor::KeepAnchor);
- cursor.setCharFormat(fragment.format);
- }
-}
-
-void KoCharacterStyle::applyStyle(QTextCursor *selection) const
-{
-// FIXME below should be done for each frament in the selection
- QTextCharFormat cf = selection->charFormat();
- applyStyle(cf);
- ensureMinimalProperties(cf);
- selection->setCharFormat(cf);
-}
-
-void KoCharacterStyle::unapplyStyle(QTextCharFormat &format) const
-{
- if (d->parentStyle)
- d->parentStyle->unapplyStyle(format);
-
- QMap<int, QVariant> props = d->stylesPrivate.properties();
- QMap<int, QVariant>::const_iterator it = props.constBegin();
- while (it != props.constEnd()) {
- if (!it.value().isNull() && it.value() == format.property(it.key())) {
- format.clearProperty(it.key());
- }
- ++it;
- }
-
- props = d->hardCodedDefaultStyle.properties();
- it = props.constBegin();
- while (it != props.constEnd()) {
- if (!it.value().isNull() && !format.hasProperty(it.key())) {
- format.setProperty(it.key(), it.value());
- }
- ++it;
- }
-}
-
-bool KoCharacterStyle::isApplied() const
-{
- return d->m_inUse;
-}
-
-void KoCharacterStyle::unapplyStyle(QTextBlock &block) const
-{
- QTextCursor cursor(block);
- QTextCharFormat cf = cursor.blockCharFormat();
- unapplyStyle(cf);
- cursor.setBlockCharFormat(cf);
-
- if (block.length() == 1) // only the linefeed
- return;
- QTextBlock::iterator iter = block.end();
- do {
- --iter;
- QTextFragment fragment = iter.fragment();
- cursor.setPosition(fragment.position() + 1);
- cf = cursor.charFormat();
- unapplyStyle(cf);
- cursor.setPosition(fragment.position());
- cursor.setPosition(fragment.position() + fragment.length(), QTextCursor::KeepAnchor);
- cursor.setCharFormat(cf);
- } while (iter != block.begin());
-}
-
-// OASIS 14.2.29
-static void parseOdfLineWidth(const QString &width, KoCharacterStyle::LineWeight &lineWeight, qreal &lineWidth)
-{
- lineWidth = 0;
- lineWeight = KoCharacterStyle::AutoLineWeight;
- if (width.isEmpty() || width == "auto")
- lineWeight = KoCharacterStyle::AutoLineWeight;
- else if (width == "normal")
- lineWeight = KoCharacterStyle::NormalLineWeight;
- else if (width == "bold")
- lineWeight = KoCharacterStyle::BoldLineWeight;
- else if (width == "thin")
- lineWeight = KoCharacterStyle::ThinLineWeight;
- else if (width == "dash")
- lineWeight = KoCharacterStyle::DashLineWeight;
- else if (width == "medium")
- lineWeight = KoCharacterStyle::MediumLineWeight;
- else if (width == "thick")
- lineWeight = KoCharacterStyle::ThickLineWeight;
- else if (width.endsWith('%')) {
- lineWeight = KoCharacterStyle::PercentLineWeight;
- lineWidth = width.mid(0, width.length() - 1).toDouble();
- } else if (width[width.length()-1].isNumber()) {
- lineWeight = KoCharacterStyle::LengthLineWeight;
- lineWidth = width.toDouble();
- } else {
- lineWeight = KoCharacterStyle::LengthLineWeight;
- lineWidth = KoUnit::parseValue(width);
- }
-}
-
-// OASIS 14.2.29
-static void importOdfLine(const QString &type, const QString &style, KoCharacterStyle::LineStyle &lineStyle, KoCharacterStyle::LineType &lineType)
-{
- lineStyle = KoCharacterStyle::NoLineStyle;
- lineType = KoCharacterStyle::NoLineType;
-
- QString fixedType = type;
- QString fixedStyle = style;
- if (fixedStyle == "none")
- fixedType.clear();
- else if (fixedType.isEmpty() && !fixedStyle.isEmpty())
- fixedType = "single";
- else if (!fixedType.isEmpty() && fixedType != "none" && fixedStyle.isEmpty()) {
- // don't set a style when the type is none
- fixedStyle = "solid";
- }
-
- if (fixedType == "single")
- lineType = KoCharacterStyle::SingleLine;
- else if (fixedType == "double")
- lineType = KoCharacterStyle::DoubleLine;
-
- if (fixedStyle == "solid")
- lineStyle = KoCharacterStyle::SolidLine;
- else if (fixedStyle == "dotted")
- lineStyle = KoCharacterStyle::DottedLine;
- else if (fixedStyle == "dash")
- lineStyle = KoCharacterStyle::DashLine;
- else if (fixedStyle == "long-dash")
- lineStyle = KoCharacterStyle::LongDashLine;
- else if (fixedStyle == "dot-dash")
- lineStyle = KoCharacterStyle::DotDashLine;
- else if (fixedStyle == "dot-dot-dash")
- lineStyle = KoCharacterStyle::DotDotDashLine;
- else if (fixedStyle == "wave")
- lineStyle = KoCharacterStyle::WaveLine;
-}
-
-static QString exportOdfLineType(KoCharacterStyle::LineType lineType)
-{
- switch (lineType) {
- case KoCharacterStyle::NoLineType:
- return "none";
- case KoCharacterStyle::SingleLine:
- return "single";
- case KoCharacterStyle::DoubleLine:
- return "double";
- default:
- return "";
- }
-}
-
-static QString exportOdfLineStyle(KoCharacterStyle::LineStyle lineStyle)
-{
- switch (lineStyle) {
- case KoCharacterStyle::NoLineStyle:
- return "none";
- case KoCharacterStyle::SolidLine:
- return "solid";
- case KoCharacterStyle::DottedLine:
- return "dotted";
- case KoCharacterStyle::DashLine:
- return "dash";
- case KoCharacterStyle::LongDashLine:
- return "long-dash";
- case KoCharacterStyle::DotDashLine:
- return "dot-dash";
- case KoCharacterStyle::DotDotDashLine:
- return "dot-dot-dash";
- case KoCharacterStyle::WaveLine:
- return "wave";
- default:
- return "";
- }
-}
-static QString exportOdfLineMode(KoCharacterStyle::LineMode lineMode)
-{
- switch (lineMode) {
- case KoCharacterStyle::ContinuousLineMode:
- return "continuous";
- case KoCharacterStyle::SkipWhiteSpaceLineMode:
- return "skip-white-space";
- default:
- return "";
- }
-}
-
-static QString exportOdfLineWidth(KoCharacterStyle::LineWeight lineWeight, qreal lineWidth)
-{
- switch (lineWeight) {
- case KoCharacterStyle::AutoLineWeight:
- return "auto";
- case KoCharacterStyle::NormalLineWeight:
- return "normal";
- case KoCharacterStyle::BoldLineWeight:
- return "bold";
- case KoCharacterStyle::ThinLineWeight:
- return "thin";
- case KoCharacterStyle::DashLineWeight:
- return "dash";
- case KoCharacterStyle::MediumLineWeight:
- return "medium";
- case KoCharacterStyle::ThickLineWeight:
- return "thick";
- case KoCharacterStyle::PercentLineWeight:
- return QString("%1%").arg(lineWidth);
- case KoCharacterStyle::LengthLineWeight:
- return QString("%1pt").arg(lineWidth);
- default:
- return QString();
- }
-}
-
-static QString exportOdfFontStyleHint(QFont::StyleHint hint)
-{
- switch (hint) {
- case QFont::Serif:
- return "roman";
- case QFont::SansSerif:
- return "swiss";
- case QFont::TypeWriter:
- return "modern";
- case QFont::Decorative:
- return "decorative";
- case QFont::System:
- return "system";
- /*case QFont::Script */
- default:
- return "";
- }
-}
-
-void KoCharacterStyle::setFontFamily(const QString &family)
-{
- d->setProperty(QTextFormat::FontFamily, family);
- setFontYStretch(d->calculateFontYStretch(family));
-}
-QString KoCharacterStyle::fontFamily() const
-{
- return d->propertyString(QTextFormat::FontFamily);
-}
-void KoCharacterStyle::setFontPointSize(qreal size)
-{
- d->setProperty(QTextFormat::FontPointSize, size);
-}
-void KoCharacterStyle::clearFontPointSize() {
- d->stylesPrivate.remove(QTextFormat::FontPointSize);
-}
-qreal KoCharacterStyle::fontPointSize() const
-{
- return d->propertyDouble(QTextFormat::FontPointSize);
-}
-void KoCharacterStyle::setFontWeight(int weight)
-{
- d->setProperty(QTextFormat::FontWeight, weight);
-}
-int KoCharacterStyle::fontWeight() const
-{
- return d->propertyInt(QTextFormat::FontWeight);
-}
-void KoCharacterStyle::setFontItalic(bool italic)
-{
- d->setProperty(QTextFormat::FontItalic, italic);
-}
-bool KoCharacterStyle::fontItalic() const
-{
- return d->propertyBoolean(QTextFormat::FontItalic);
-}
-///TODO Review legacy fontOverline functions and testing (consider removal)
-/*
-void KoCharacterStyle::setFontOverline(bool overline)
-{
- d->setProperty(QTextFormat::FontOverline, overline);
-}
-bool KoCharacterStyle::fontOverline() const
-{
- return d->propertyBoolean(QTextFormat::FontOverline);
-}
-*/
-void KoCharacterStyle::setFontFixedPitch(bool fixedPitch)
-{
- d->setProperty(QTextFormat::FontFixedPitch, fixedPitch);
-}
-bool KoCharacterStyle::fontFixedPitch() const
-{
- return d->propertyBoolean(QTextFormat::FontFixedPitch);
-}
-void KoCharacterStyle::setFontStyleHint(QFont::StyleHint styleHint)
-{
- d->setProperty(QTextFormat::FontStyleHint, styleHint);
-}
-QFont::StyleHint KoCharacterStyle::fontStyleHint() const
-{
- return static_cast<QFont::StyleHint>(d->propertyInt(QTextFormat::FontStyleHint));
-}
-void KoCharacterStyle::setFontKerning(bool enable)
-{
- d->setProperty(QTextFormat::FontKerning, enable);
-}
-bool KoCharacterStyle::fontKerning() const
-{
- return d->propertyBoolean(QTextFormat::FontKerning);
-}
-void KoCharacterStyle::setVerticalAlignment(QTextCharFormat::VerticalAlignment alignment)
-{
- d->setProperty(QTextFormat::TextVerticalAlignment, alignment);
-}
-QTextCharFormat::VerticalAlignment KoCharacterStyle::verticalAlignment() const
-{
- return static_cast<QTextCharFormat::VerticalAlignment>(d->propertyInt(QTextFormat::TextVerticalAlignment));
-}
-void KoCharacterStyle::setTextOutline(const QPen &pen)
-{
- d->setProperty(QTextFormat::TextOutline, pen);
-}
-void KoCharacterStyle::setBackground(const QBrush &brush)
-{
- d->setProperty(QTextFormat::BackgroundBrush, brush);
-}
-void KoCharacterStyle::setForeground(const QBrush &brush)
-{
- d->setProperty(QTextFormat::ForegroundBrush, brush);
-}
-void KoCharacterStyle::setFontAutoColor(bool use)
-{
- d->setProperty(KoCharacterStyle::UseWindowFontColor, use);
-}
-
-QString KoCharacterStyle::name() const
-{
- return d->name;
-}
-void KoCharacterStyle::setName(const QString &name)
-{
- if (name == d->name)
- return;
- d->name = name;
- emit nameChanged(name);
-}
-int KoCharacterStyle::styleId() const
-{
- return d->propertyInt(StyleId);
-}
-void KoCharacterStyle::setStyleId(int id)
-{
- d->setProperty(StyleId, id);
-}
-QFont KoCharacterStyle::font() const
-{
- QFont font;
- if (d->stylesPrivate.contains(QTextFormat::FontFamily))
- font.setFamily(fontFamily());
- if (d->stylesPrivate.contains(QTextFormat::FontPointSize))
- font.setPointSizeF(fontPointSize());
- if (d->stylesPrivate.contains(QTextFormat::FontWeight))
- font.setWeight(fontWeight());
- if (d->stylesPrivate.contains(QTextFormat::FontItalic))
- font.setItalic(fontItalic());
- return font;
-}
-void KoCharacterStyle::setHasHyphenation(bool on)
-{
- d->setProperty(HasHyphenation, on);
-}
-bool KoCharacterStyle::hasHyphenation() const
-{
- return d->propertyBoolean(HasHyphenation);
-}
-
-void KoCharacterStyle::setHyphenationPushCharCount(int count)
-{
- if (count > 0)
- d->setProperty(HyphenationPushCharCount, count);
- else
- d->stylesPrivate.remove(HyphenationPushCharCount);
-}
-
-int KoCharacterStyle::hyphenationPushCharCount() const
-{
- if (hasProperty(HyphenationPushCharCount))
- return d->propertyInt(HyphenationPushCharCount);
- return 0;
-}
-
-void KoCharacterStyle::setHyphenationRemainCharCount(int count)
-{
- if (count > 0)
- d->setProperty(HyphenationRemainCharCount, count);
- else
- d->stylesPrivate.remove(HyphenationRemainCharCount);
-}
-
-int KoCharacterStyle::hyphenationRemainCharCount() const
-{
- if (hasProperty(HyphenationRemainCharCount))
- return d->propertyInt(HyphenationRemainCharCount);
- return 0;
-}
-
-void KoCharacterStyle::setStrikeOutStyle(KoCharacterStyle::LineStyle strikeOut)
-{
- d->setProperty(StrikeOutStyle, strikeOut);
-}
-
-KoCharacterStyle::LineStyle KoCharacterStyle::strikeOutStyle() const
-{
- return (KoCharacterStyle::LineStyle) d->propertyInt(StrikeOutStyle);
-}
-
-void KoCharacterStyle::setStrikeOutType(LineType lineType)
-{
- d->setProperty(StrikeOutType, lineType);
-}
-
-KoCharacterStyle::LineType KoCharacterStyle::strikeOutType() const
-{
- return (KoCharacterStyle::LineType) d->propertyInt(StrikeOutType);
-}
-
-void KoCharacterStyle::setStrikeOutColor(const QColor &color)
-{
- d->setProperty(StrikeOutColor, color);
-}
-
-QColor KoCharacterStyle::strikeOutColor() const
-{
- return d->propertyColor(StrikeOutColor);
-}
-
-void KoCharacterStyle::setStrikeOutWidth(LineWeight weight, qreal width)
-{
- d->setProperty(KoCharacterStyle::StrikeOutWeight, weight);
- d->setProperty(KoCharacterStyle::StrikeOutWidth, width);
-}
-
-void KoCharacterStyle::strikeOutWidth(LineWeight &weight, qreal &width) const
-{
- weight = (KoCharacterStyle::LineWeight) d->propertyInt(KoCharacterStyle::StrikeOutWeight);
- width = d->propertyDouble(KoCharacterStyle::StrikeOutWidth);
-}
-void KoCharacterStyle::setStrikeOutMode(LineMode lineMode)
-{
- d->setProperty(StrikeOutMode, lineMode);
-}
-
-void KoCharacterStyle::setStrikeOutText(const QString &text)
-{
- d->setProperty(StrikeOutText, text);
-}
-QString KoCharacterStyle::strikeOutText() const
-{
- return d->propertyString(StrikeOutText);
-}
-KoCharacterStyle::LineMode KoCharacterStyle::strikeOutMode() const
-{
- return (KoCharacterStyle::LineMode) d->propertyInt(StrikeOutMode);
-}
-
-void KoCharacterStyle::setOverlineStyle(KoCharacterStyle::LineStyle overline)
-{
- d->setProperty(OverlineStyle, overline);
-}
-
-KoCharacterStyle::LineStyle KoCharacterStyle::overlineStyle() const
-{
- return (KoCharacterStyle::LineStyle) d->propertyInt(OverlineStyle);
-}
-
-void KoCharacterStyle::setOverlineType(LineType lineType)
-{
- d->setProperty(OverlineType, lineType);
-}
-
-KoCharacterStyle::LineType KoCharacterStyle::overlineType() const
-{
- return (KoCharacterStyle::LineType) d->propertyInt(OverlineType);
-}
-
-void KoCharacterStyle::setOverlineColor(const QColor &color)
-{
- d->setProperty(KoCharacterStyle::OverlineColor, color);
-}
-
-QColor KoCharacterStyle::overlineColor() const
-{
- return d->propertyColor(KoCharacterStyle::OverlineColor);
-}
-
-void KoCharacterStyle::setOverlineWidth(LineWeight weight, qreal width)
-{
- d->setProperty(KoCharacterStyle::OverlineWeight, weight);
- d->setProperty(KoCharacterStyle::OverlineWidth, width);
-}
-
-void KoCharacterStyle::overlineWidth(LineWeight &weight, qreal &width) const
-{
- weight = (KoCharacterStyle::LineWeight) d->propertyInt(KoCharacterStyle::OverlineWeight);
- width = d->propertyDouble(KoCharacterStyle::OverlineWidth);
-}
-
-void KoCharacterStyle::setOverlineMode(LineMode mode)
-{
- d->setProperty(KoCharacterStyle::OverlineMode, mode);
-}
-
-KoCharacterStyle::LineMode KoCharacterStyle::overlineMode() const
-{
- return static_cast<KoCharacterStyle::LineMode>(d->propertyInt(KoCharacterStyle::OverlineMode));
-}
-
-void KoCharacterStyle::setUnderlineStyle(KoCharacterStyle::LineStyle underline)
-{
- d->setProperty(UnderlineStyle, underline);
-}
-
-KoCharacterStyle::LineStyle KoCharacterStyle::underlineStyle() const
-{
- return (KoCharacterStyle::LineStyle) d->propertyInt(UnderlineStyle);
-}
-
-void KoCharacterStyle::setUnderlineType(LineType lineType)
-{
- d->setProperty(UnderlineType, lineType);
-}
-
-KoCharacterStyle::LineType KoCharacterStyle::underlineType() const
-{
- return (KoCharacterStyle::LineType) d->propertyInt(UnderlineType);
-}
-
-void KoCharacterStyle::setUnderlineColor(const QColor &color)
-{
- d->setProperty(QTextFormat::TextUnderlineColor, color);
-}
-
-QColor KoCharacterStyle::underlineColor() const
-{
- return d->propertyColor(QTextFormat::TextUnderlineColor);
-}
-
-void KoCharacterStyle::setUnderlineWidth(LineWeight weight, qreal width)
-{
- d->setProperty(KoCharacterStyle::UnderlineWeight, weight);
- d->setProperty(KoCharacterStyle::UnderlineWidth, width);
-}
-
-void KoCharacterStyle::underlineWidth(LineWeight &weight, qreal &width) const
-{
- weight = (KoCharacterStyle::LineWeight) d->propertyInt(KoCharacterStyle::UnderlineWeight);
- width = d->propertyDouble(KoCharacterStyle::UnderlineWidth);
-}
-
-void KoCharacterStyle::setUnderlineMode(LineMode mode)
-{
- d->setProperty(KoCharacterStyle::UnderlineMode, mode);
-}
-
-KoCharacterStyle::LineMode KoCharacterStyle::underlineMode() const
-{
- return static_cast<KoCharacterStyle::LineMode>(d->propertyInt(KoCharacterStyle::UnderlineMode));
-}
-
-void KoCharacterStyle::setFontLetterSpacing(qreal spacing)
-{
- d->setProperty(KoCharacterStyle::FontLetterSpacing, spacing);
-}
-
-qreal KoCharacterStyle::fontLetterSpacing() const
-{
- return d->propertyDouble(KoCharacterStyle::FontLetterSpacing);
-}
-
-void KoCharacterStyle::setFontWordSpacing(qreal spacing)
-{
- d->setProperty(QTextCharFormat::FontWordSpacing, spacing);
-}
-
-qreal KoCharacterStyle::fontWordSpacing() const
-{
- return d->propertyDouble(QTextCharFormat::FontWordSpacing);
-}
-
-
-void KoCharacterStyle::setFontCapitalization(QFont::Capitalization capitalization)
-{
- d->setProperty(QTextFormat::FontCapitalization, capitalization);
-}
-
-QFont::Capitalization KoCharacterStyle::fontCapitalization() const
-{
- return (QFont::Capitalization) d->propertyInt(QTextFormat::FontCapitalization);
-}
-
-
-void KoCharacterStyle::setFontYStretch(qreal stretch)
-{
- d->setProperty(KoCharacterStyle::FontYStretch, stretch);
-}
-
-qreal KoCharacterStyle::fontYStretch() const
-{
- return d->propertyDouble(KoCharacterStyle::FontYStretch);
-}
-
-void KoCharacterStyle::setCountry(const QString &country)
-{
- if (country.isEmpty())
- d->stylesPrivate.remove(KoCharacterStyle::Country);
- else
- d->setProperty(KoCharacterStyle::Country, country);
-}
-
-void KoCharacterStyle::setLanguage(const QString &language)
-{
- if (language.isEmpty())
- d->stylesPrivate.remove(KoCharacterStyle::Language);
- else
- d->setProperty(KoCharacterStyle::Language, language);
-}
-
-QString KoCharacterStyle::country() const
-{
- return value(KoCharacterStyle::Country).toString();
-}
-
-QString KoCharacterStyle::language() const
-{
- return d->propertyString(KoCharacterStyle::Language);
-}
-
-bool KoCharacterStyle::blinking() const
-{
- return d->propertyBoolean(Blink);
-}
-
-void KoCharacterStyle::setBlinking(bool blink)
-{
- d->setProperty(KoCharacterStyle::Blink, blink);
-}
-
-bool KoCharacterStyle::hasProperty(int key) const
-{
- return d->stylesPrivate.contains(key);
-}
-
-static QString rotationScaleToString(KoCharacterStyle::RotationScale rotationScale)
-{
- QString scale = "line-height";
- if (rotationScale == KoCharacterStyle::Fixed) {
- scale = "fixed";
- }
- return scale;
-}
-
-static KoCharacterStyle::RotationScale stringToRotationScale(const QString &scale)
-{
- KoCharacterStyle::RotationScale rotationScale = KoCharacterStyle::LineHeight;
- if (scale == "fixed") {
- rotationScale = KoCharacterStyle::Fixed;
- }
- return rotationScale;
-}
-
-void KoCharacterStyle::setTextRotationAngle(qreal angle)
-{
- d->setProperty(TextRotationAngle, angle);
-}
-
-qreal KoCharacterStyle::textRotationAngle() const
-{
- return d->propertyDouble(TextRotationAngle);
-}
-
-void KoCharacterStyle::setTextRotationScale(RotationScale scale)
-{
- d->setProperty(TextRotationScale, rotationScaleToString(scale));
-}
-
-KoCharacterStyle::RotationScale KoCharacterStyle::textRotationScale() const
-{
- return stringToRotationScale(d->propertyString(TextRotationScale));
-}
-
-void KoCharacterStyle::setTextScale(int scale)
-{
- d->setProperty(TextScale, scale);
-}
-
-int KoCharacterStyle::textScale() const
-{
- return d->propertyInt(TextScale);
-}
-
-void KoCharacterStyle::setTextShadow(const KoShadowStyle& shadow)
-{
- d->setProperty(TextShadow, qVariantFromValue<KoShadowStyle>(shadow));
-}
-
-KoShadowStyle KoCharacterStyle::textShadow() const
-{
- if (hasProperty(TextShadow)) {
- QVariant shadow = value(TextShadow);
- if (shadow.canConvert<KoShadowStyle>())
- return shadow.value<KoShadowStyle>();
- }
- return KoShadowStyle();
-}
-
-void KoCharacterStyle::setTextCombine(KoCharacterStyle::TextCombineType type)
-{
- d->setProperty(TextCombine, type);
-}
-
-KoCharacterStyle::TextCombineType KoCharacterStyle::textCombine() const
-{
- if (hasProperty(TextCombine)) {
- return (KoCharacterStyle::TextCombineType) d->propertyInt(TextCombine);
- }
- return NoTextCombine;
-}
-
-QChar KoCharacterStyle::textCombineEndChar() const
-{
- if (hasProperty(TextCombineEndChar)) {
- QString val = d->propertyString(TextCombineEndChar);
- if (val.length() > 0)
- return val.at(0);
- }
- return QChar();
-}
-
-void KoCharacterStyle::setTextCombineEndChar(const QChar& character)
-{
- d->setProperty(TextCombineEndChar, character);
-}
-
-QChar KoCharacterStyle::textCombineStartChar() const
-{
- if (hasProperty(TextCombineStartChar)) {
- QString val = d->propertyString(TextCombineStartChar);
- if (val.length() > 0)
- return val.at(0);
- }
- return QChar();
-}
-
-void KoCharacterStyle::setTextCombineStartChar(const QChar& character)
-{
- d->setProperty(TextCombineStartChar, character);
-}
-
-void KoCharacterStyle::setFontRelief(KoCharacterStyle::ReliefType relief)
-{
- d->setProperty(FontRelief, relief);
-}
-
-KoCharacterStyle::ReliefType KoCharacterStyle::fontRelief() const
-{
- if (hasProperty(FontRelief))
- return (KoCharacterStyle::ReliefType) d->propertyInt(FontRelief);
- return KoCharacterStyle::NoRelief;
-}
-
-
-KoCharacterStyle::EmphasisPosition KoCharacterStyle::textEmphasizePosition() const
-{
- if (hasProperty(TextEmphasizePosition))
- return (KoCharacterStyle::EmphasisPosition) d->propertyInt(TextEmphasizePosition);
- return KoCharacterStyle::EmphasisAbove;
-}
-
-void KoCharacterStyle::setTextEmphasizePosition(KoCharacterStyle::EmphasisPosition position)
-{
- d->setProperty(TextEmphasizePosition, position);
-}
-
-KoCharacterStyle::EmphasisStyle KoCharacterStyle::textEmphasizeStyle() const
-{
- if (hasProperty(TextEmphasizeStyle))
- return (KoCharacterStyle::EmphasisStyle) d->propertyInt(TextEmphasizeStyle);
- return KoCharacterStyle::NoEmphasis;
-}
-
-void KoCharacterStyle::setTextEmphasizeStyle(KoCharacterStyle::EmphasisStyle emphasis)
-{
- d->setProperty(TextEmphasizeStyle, emphasis);
-}
-
-void KoCharacterStyle::setPercentageFontSize(qreal percent)
-{
- d->setProperty(KoCharacterStyle::PercentageFontSize, percent);
-}
-
-qreal KoCharacterStyle::percentageFontSize() const
-{
- return d->propertyDouble(KoCharacterStyle::PercentageFontSize);
-}
-
-void KoCharacterStyle::setAdditionalFontSize(qreal percent)
-{
- d->setProperty(KoCharacterStyle::AdditionalFontSize, percent);
-}
-
-qreal KoCharacterStyle::additionalFontSize() const
-{
- return d->propertyDouble(KoCharacterStyle::AdditionalFontSize);
-}
-
-void KoCharacterStyle::loadOdf(const KoXmlElement *element, KoShapeLoadingContext &scontext,
- bool loadParents)
-{
- KoOdfLoadingContext &context = scontext.odfLoadingContext();
- const QString name(element->attributeNS(KoXmlNS::style, "display-name", QString()));
- if (!name.isEmpty()) {
- d->name = name;
- }
- else {
- d->name = element->attributeNS(KoXmlNS::style, "name", QString());
- }
-
- QString family = element->attributeNS(KoXmlNS::style, "family", "text");
-
- context.styleStack().save();
- if (loadParents) {
- context.addStyles(element, family.toLocal8Bit().constData()); // Load all parent
- } else {
- context.styleStack().push(*element);
- }
- context.styleStack().setTypeProperties("text"); // load the style:text-properties
- loadOdfProperties(scontext);
- context.styleStack().restore();
-}
-
-void KoCharacterStyle::loadOdfProperties(KoShapeLoadingContext &scontext)
-{
- KoStyleStack &styleStack = scontext.odfLoadingContext().styleStack();
-
- d->stylesPrivate = StylePrivate();
-
- // The fo:color attribute specifies the foreground color of text.
- const QString color(styleStack.property(KoXmlNS::fo, "color"));
- if (!color.isEmpty()) {
- QColor c(color);
- if (c.isValid()) { // 3.10.3
- setForeground(QBrush(c));
- }
- }
-
- QString fontName(styleStack.property(KoXmlNS::fo, "font-family"));
- if (!fontName.isEmpty()) {
- // Specify whether a font has a fixed or variable width.
- // These attributes are ignored if there is no corresponding fo:font-family attribute attached to the same formatting properties element.
- const QString fontPitch(styleStack.property(KoXmlNS::style, "font-pitch"));
- if (!fontPitch.isEmpty()) {
- setFontFixedPitch(fontPitch == "fixed");
- }
-
- const QString genericFamily(styleStack.property(KoXmlNS::style, "font-family-generic"));
- if (!genericFamily.isEmpty()) {
- if (genericFamily == "roman")
- setFontStyleHint(QFont::Serif);
- else if (genericFamily == "swiss")
- setFontStyleHint(QFont::SansSerif);
- else if (genericFamily == "modern")
- setFontStyleHint(QFont::TypeWriter);
- else if (genericFamily == "decorative")
- setFontStyleHint(QFont::Decorative);
- else if (genericFamily == "system")
- setFontStyleHint(QFont::System);
- else if (genericFamily == "script") {
- ; // TODO: no hint available in Qt yet, we should at least store it as a property internally!
- }
- }
-
- const QString fontCharset(styleStack.property(KoXmlNS::style, "font-charset"));
- if (!fontCharset.isEmpty()) {
- // this property is not required by Qt, since Qt auto selects the right font based on the text
- // The only charset of interest to us is x-symbol - this should disable spell checking
- d->setProperty(KoCharacterStyle::FontCharset, fontCharset);
- }
- }
-
- const QString fontFamily(styleStack.property(KoXmlNS::style, "font-family"));
- if (!fontFamily.isEmpty())
- fontName = fontFamily;
-
- if (styleStack.hasProperty(KoXmlNS::style, "font-name")) {
- // This font name is a reference to a font face declaration.
- KoOdfStylesReader &stylesReader = scontext.odfLoadingContext().stylesReader();
- const KoXmlElement *fontFace = stylesReader.findStyle(styleStack.property(KoXmlNS::style, "font-name"));
- if (fontFace != 0) {
- fontName = fontFace->attributeNS(KoXmlNS::svg, "font-family", "");
-
- KoXmlElement fontFaceElem;
- forEachElement(fontFaceElem, (*fontFace)) {
- if (fontFaceElem.tagName() == "font-face-src") {
- KoXmlElement fontUriElem;
- forEachElement(fontUriElem, fontFaceElem) {
- if (fontUriElem.tagName() == "font-face-uri") {
- QString filename = fontUriElem.attributeNS(KoXmlNS::xlink, "href");
- KoStore *store = scontext.odfLoadingContext().store();
- if (store->open(filename)) {
- KoStoreDevice device(store);
- QByteArray data = device.readAll();
- if (device.open(QIODevice::ReadOnly)) {
- QFontDatabase::addApplicationFontFromData(data);
- }
- }
- }
- }
- }
- }
- }
- }
-
- if (!fontName.isEmpty()) {
- // Hmm, the remove "'" could break it's in the middle of the fontname...
- fontName = fontName.remove('\'');
-
- // 'Thorndale' is not known outside OpenOffice so we substitute it
- // with 'Times New Roman' that looks nearly the same.
- if (fontName == "Thorndale")
- fontName = "Times New Roman";
-
- // 'StarSymbol' is written by OpenOffice but they actually mean
- // 'OpenSymbol'.
- if (fontName == "StarSymbol")
- fontName = "OpenSymbol";
-
- fontName.remove(QRegExp("\\sCE$")); // Arial CE -> Arial
- setFontFamily(fontName);
- }
-
- // Specify the size of a font. The value of these attribute is either an absolute length or a percentage
- if (styleStack.hasProperty(KoXmlNS::fo, "font-size")) {
- const QString fontSize(styleStack.property(KoXmlNS::fo, "font-size"));
- if (!fontSize.isEmpty()) {
- if (fontSize.endsWith('%')) {
- setPercentageFontSize(fontSize.left(fontSize.length() - 1).toDouble());
- } else {
- setFontPointSize(KoUnit::parseValue(fontSize));
- }
- }
- }
- else {
- const QString fontSizeRel(styleStack.property(KoXmlNS::style, "font-size-rel"));
- if (!fontSizeRel.isEmpty()) {
- setAdditionalFontSize(KoUnit::parseValue(fontSizeRel));
- }
- }
-
- // Specify the weight of a font. The permitted values are normal, bold, and numeric values 100-900, in steps of 100. Unsupported numerical values are rounded off to the next supported value.
- const QString fontWeight(styleStack.property(KoXmlNS::fo, "font-weight"));
- if (!fontWeight.isEmpty()) { // 3.10.24
- int boldness;
- if (fontWeight == "normal")
- boldness = 50;
- else if (fontWeight == "bold")
- boldness = 75;
- else
- // XSL/CSS has 100,200,300...900. Not the same scale as Qt!
- // See http://www.w3.org/TR/2001/REC-xsl-20011015/slice7.html#font-weight
- boldness = fontWeight.toInt() / 10;
- setFontWeight(boldness);
- }
-
- // Specify whether to use normal or italic font face.
- const QString fontStyle(styleStack.property(KoXmlNS::fo, "font-style" ));
- if (!fontStyle.isEmpty()) { // 3.10.19
- if (fontStyle == "italic" || fontStyle == "oblique") { // no difference in kotext
- setFontItalic(true);
- } else {
- setFontItalic(false);
- }
- }
-
-//TODO
-#if 0
- d->m_bWordByWord = styleStack.property(KoXmlNS::style, "text-underline-mode") == "skip-white-space";
- // TODO style:text-line-through-mode
-
- /*
- // OO compat code, to move to OO import filter
- d->m_bWordByWord = (styleStack.hasProperty( KoXmlNS::fo, "score-spaces")) // 3.10.25
- && (styleStack.property( KoXmlNS::fo, "score-spaces") == "false");
- if( styleStack.hasProperty( KoXmlNS::style, "text-crossing-out" )) { // 3.10.6
- QString strikeOutType = styleStack.property( KoXmlNS::style, "text-crossing-out" );
- if( strikeOutType =="double-line")
- m_strikeOutType = S_DOUBLE;
- else if( strikeOutType =="single-line")
- m_strikeOutType = S_SIMPLE;
- else if( strikeOutType =="thick-line")
- m_strikeOutType = S_SIMPLE_BOLD;
- // not supported by Words: "slash" and "X"
- // not supported by OO: stylelines (solid, dash, dot, dashdot, dashdotdot)
- }
- */
-#endif
-
- // overline modes
- const QString textOverlineMode(styleStack.property( KoXmlNS::style, "text-overline-mode"));
- if (!textOverlineMode.isEmpty()) {
- if (textOverlineMode == "skip-white-space") {
- setOverlineMode(SkipWhiteSpaceLineMode);
- } else if (textOverlineMode == "continuous") {
- setOverlineMode(ContinuousLineMode);
- }
- }
-
- // Specifies whether text is overlined, and if so, whether a single or qreal line will be used for overlining.
- const QString textOverlineType(styleStack.property(KoXmlNS::style, "text-overline-type"));
- const QString textOverlineStyle(styleStack.property(KoXmlNS::style, "text-overline-style"));
- if (!textOverlineType.isEmpty() || !textOverlineStyle.isEmpty()) { // OASIS 14.4.28
- LineStyle overlineStyle;
- LineType overlineType;
-
- importOdfLine(textOverlineType, textOverlineStyle,
- overlineStyle, overlineType);
- setOverlineStyle(overlineStyle);
- setOverlineType(overlineType);
- }
-
- const QString textOverlineWidth(styleStack.property(KoXmlNS::style, "text-overline-width"));
- if (!textOverlineWidth.isEmpty()) {
- qreal overlineWidth;
- LineWeight overlineWeight;
- parseOdfLineWidth(textOverlineWidth, overlineWeight, overlineWidth);
- setOverlineWidth(overlineWeight, overlineWidth);
- }
-
- // Specifies the color that is used to overline text. The value of this attribute is either font-color or a color. If the value is font-color, the current text color is used for overlining.
- QString overLineColor = styleStack.property(KoXmlNS::style, "text-overline-color"); // OO 3.10.23, OASIS 14.4.31
- if (!overLineColor.isEmpty() && overLineColor != "font-color") {
- setOverlineColor(QColor(overLineColor));
- } else if (overLineColor == "font-color") {
- setOverlineColor(QColor());
- }
-
- // underline modes
- const QString textUndelineMode(styleStack.property( KoXmlNS::style, "text-underline-mode"));
- if (!textUndelineMode.isEmpty()) {
- if (textUndelineMode == "skip-white-space") {
- setUnderlineMode(SkipWhiteSpaceLineMode);
- } else if (textUndelineMode == "continuous") {
- setUnderlineMode(ContinuousLineMode);
- }
- }
-
- // Specifies whether text is underlined, and if so, whether a single or qreal line will be used for underlining.
- const QString textUnderlineType(styleStack.property(KoXmlNS::style, "text-underline-type"));
- const QString textUnderlineStyle(styleStack.property(KoXmlNS::style, "text-underline-style"));
- if (!textUnderlineType.isEmpty() || !textUnderlineStyle.isEmpty()) { // OASIS 14.4.28
- LineStyle underlineStyle;
- LineType underlineType;
-
- importOdfLine(textUnderlineType, textUnderlineStyle,
- underlineStyle, underlineType);
- setUnderlineStyle(underlineStyle);
- setUnderlineType(underlineType);
- }
-
- const QString textUnderlineWidth(styleStack.property(KoXmlNS::style, "text-underline-width"));
- if (!textUnderlineWidth.isEmpty()) {
- qreal underlineWidth;
- LineWeight underlineWeight;
- parseOdfLineWidth(textUnderlineWidth, underlineWeight, underlineWidth);
- setUnderlineWidth(underlineWeight, underlineWidth);
- }
-
- // Specifies the color that is used to underline text. The value of this attribute is either font-color or a color. If the value is font-color, the current text color is used for underlining.
- QString underLineColor = styleStack.property(KoXmlNS::style, "text-underline-color"); // OO 3.10.23, OASIS 14.4.31
- if (!underLineColor.isEmpty() && underLineColor != "font-color") {
- setUnderlineColor(QColor(underLineColor));
- } else if (underLineColor == "font-color") {
- setUnderlineColor(QColor());
- }
-
-
- const QString textLineThroughType(styleStack.property(KoXmlNS::style, "text-line-through-type"));
- const QString textLineThroughStyle(styleStack.property(KoXmlNS::style, "text-line-through-style"));
- if (!textLineThroughType.isEmpty() || !textLineThroughStyle.isEmpty()) { // OASIS 14.4.7
- KoCharacterStyle::LineStyle throughStyle;
- LineType throughType;
-
- importOdfLine(textLineThroughType,textLineThroughStyle,
- throughStyle, throughType);
-
- setStrikeOutStyle(throughStyle);
- setStrikeOutType(throughType);
- const QString textLineThroughText(styleStack.property(KoXmlNS::style, "text-line-through-text"));
- if (!textLineThroughText.isEmpty()) {
- setStrikeOutText(textLineThroughText);
- }
- }
-
- const QString textLineThroughWidth(styleStack.property(KoXmlNS::style, "text-line-through-width"));
- if (!textLineThroughWidth.isEmpty()) {
- qreal throughWidth;
- LineWeight throughWeight;
- parseOdfLineWidth(textLineThroughWidth, throughWeight, throughWidth);
- setStrikeOutWidth(throughWeight, throughWidth);
- }
-
- const QString lineThroughColor(styleStack.property(KoXmlNS::style, "text-line-through-color")); // OO 3.10.23, OASIS 14.4.31
- if (!lineThroughColor.isEmpty() && lineThroughColor != "font-color") {
- setStrikeOutColor(QColor(lineThroughColor));
- }
-
- const QString lineThroughMode(styleStack.property(KoXmlNS::style, "text-line-through-mode"));
- if (lineThroughMode == "continuous") {
- setStrikeOutMode(ContinuousLineMode);
- }
- else if (lineThroughMode == "skip-white-space") {
- setStrikeOutMode(SkipWhiteSpaceLineMode);
- }
-
- const QString textPosition(styleStack.property(KoXmlNS::style, "text-position"));
- if (!textPosition.isEmpty()) { // OO 3.10.7
- if (textPosition.startsWith("super"))
- setVerticalAlignment(QTextCharFormat::AlignSuperScript);
- else if (textPosition.startsWith("sub"))
- setVerticalAlignment(QTextCharFormat::AlignSubScript);
- else {
- QRegExp re("(-?[\\d.]+)%.*");
- if (re.exactMatch(textPosition)) {
- int percent = re.capturedTexts()[1].toInt();
- if (percent > 0)
- setVerticalAlignment(QTextCharFormat::AlignSuperScript);
- else if (percent < 0)
- setVerticalAlignment(QTextCharFormat::AlignSubScript);
- else // set explicit to overwrite inherited text-position's
- setVerticalAlignment(QTextCharFormat::AlignNormal);
- }
- }
- }
-
- // The fo:font-variant attribute provides the option to display text as small capitalized letters.
- const QString textVariant(styleStack.property(KoXmlNS::fo, "font-variant"));
- if (!textVariant.isEmpty()) {
- if (textVariant == "small-caps")
- setFontCapitalization(QFont::SmallCaps);
- else if (textVariant == "normal")
- setFontCapitalization(QFont::MixedCase);
- }
- // The fo:text-transform attribute specifies text transformations to uppercase, lowercase, and capitalization.
- else {
- const QString textTransform(styleStack.property(KoXmlNS::fo, "text-transform"));
- if (!textTransform.isEmpty()) {
- if (textTransform == "uppercase")
- setFontCapitalization(QFont::AllUppercase);
- else if (textTransform == "lowercase")
- setFontCapitalization(QFont::AllLowercase);
- else if (textTransform == "capitalize")
- setFontCapitalization(QFont::Capitalize);
- else if (textTransform == "none")
- setFontCapitalization(QFont::MixedCase);
- }
- }
-
- const QString foLanguage(styleStack.property(KoXmlNS::fo, "language"));
- if (!foLanguage.isEmpty()) {
- setLanguage(foLanguage);
- }
-
- const QString foCountry(styleStack.property(KoXmlNS::fo, "country"));
- if (!foCountry.isEmpty()) {
- setCountry(foCountry);
- }
-
- // The fo:background-color attribute specifies the background color of a paragraph.
- const QString bgcolor(styleStack.property(KoXmlNS::fo, "background-color"));
- if (!bgcolor.isEmpty()) {
- QBrush brush = background();
- if (bgcolor == "transparent")
- brush.setStyle(Qt::NoBrush);
- else {
- if (brush.style() == Qt::NoBrush)
- brush.setStyle(Qt::SolidPattern);
- brush.setColor(bgcolor); // #rrggbb format
- }
- setBackground(brush);
- }
-
- // The style:use-window-font-color attribute specifies whether or not the window foreground color should be as used as the foreground color for a light background color and white for a dark background color.
- const QString useWindowFont(styleStack.property(KoXmlNS::style, "use-window-font-color"));
- if (!useWindowFont.isEmpty()) {
- setFontAutoColor(useWindowFont == "true");
- }
-
- const QString letterKerning(styleStack.property( KoXmlNS::style, "letter-kerning"));
- if (!letterKerning.isEmpty()) {
- setFontKerning(letterKerning == "true");
- }
-
- const QString letterSpacing(styleStack.property(KoXmlNS::fo, "letter-spacing"));
- if ((!letterSpacing.isEmpty()) && (letterSpacing != "normal")) {
- qreal space = KoUnit::parseValue(letterSpacing);
- setFontLetterSpacing(space);
- }
-
- const QString textOutline(styleStack.property(KoXmlNS::style, "text-outline"));
- if (!textOutline.isEmpty()) {
- if (textOutline == "true") {
- setTextOutline(QPen((foreground().style() != Qt::NoBrush)?foreground():QBrush(Qt::black) , 0));
- setForeground(Qt::transparent);
- } else {
- setTextOutline(QPen(Qt::NoPen));
- }
- }
-
- const QString textRotationAngle(styleStack.property(KoXmlNS::style, "text-rotation-angle"));
- if (!textRotationAngle.isEmpty()) {
- setTextRotationAngle(KoUnit::parseAngle(textRotationAngle));
- }
-
- const QString textRotationScale(styleStack.property(KoXmlNS::style, "text-rotation-scale"));
- if (!textRotationScale.isEmpty()) {
- setTextRotationScale(stringToRotationScale(textRotationScale));
- }
-
- const QString textScale(styleStack.property(KoXmlNS::style, "text-scale"));
- if (!textScale.isEmpty()) {
- const int scale = (textScale.endsWith('%') ? textScale.left(textScale.length()-1) : textScale).toInt();
- setTextScale(scale);
- }
-
- const QString textShadow(styleStack.property(KoXmlNS::fo, "text-shadow"));
- if (!textShadow.isEmpty()) {
- KoShadowStyle shadow;
- if (shadow.loadOdf(textShadow))
- setTextShadow(shadow);
- }
-
- const QString textCombine(styleStack.property(KoXmlNS::style, "text-combine"));
- if (!textCombine.isEmpty()) {
- if (textCombine == "letters")
- setTextCombine(TextCombineLetters);
- else if (textCombine == "lines")
- setTextCombine(TextCombineLines);
- else if (textCombine == "none")
- setTextCombine(NoTextCombine);
- }
-
- const QString textCombineEndChar(styleStack.property(KoXmlNS::style, "text-combine-end-char"));
- if (!textCombineEndChar.isEmpty()) {
- setTextCombineEndChar(textCombineEndChar.at(0));
- }
- const QString textCombineStartChar(styleStack.property(KoXmlNS::style, "text-combine-start-char"));
- if (!textCombineStartChar.isEmpty()) {
- setTextCombineStartChar(textCombineStartChar.at(0));
- }
-
-
- const QString fontRelief(styleStack.property(KoXmlNS::style, "font-relief"));
- if (!fontRelief.isEmpty()) {
- if (fontRelief == "none")
- setFontRelief(KoCharacterStyle::NoRelief);
- else if (fontRelief == "embossed")
- setFontRelief(KoCharacterStyle::Embossed);
- else if (fontRelief == "engraved")
- setFontRelief(KoCharacterStyle::Engraved);
- }
-
- const QString fontEmphasize(styleStack.property(KoXmlNS::style, "text-emphasize"));
- if (!fontEmphasize.isEmpty()) {
- QString style, position;
- QStringList parts = fontEmphasize.split(' ');
- style = parts[0];
- if (parts.length() > 1)
- position = parts[1];
-
- if (style == "none") {
- setTextEmphasizeStyle(NoEmphasis);
- } else if (style == "accent") {
- setTextEmphasizeStyle(AccentEmphasis);
- } else if (style == "circle") {
- setTextEmphasizeStyle(CircleEmphasis);
- } else if (style == "disc") {
- setTextEmphasizeStyle(DiscEmphasis);
- } else if (style == "dot") {
- setTextEmphasizeStyle(DotEmphasis);
- }
-
- if (position == "below") {
- setTextEmphasizePosition(EmphasisBelow);
- } else if (position == "above") {
- setTextEmphasizePosition(EmphasisAbove);
- }
- }
-
- if (styleStack.hasProperty(KoXmlNS::fo, "hyphenate"))
- setHasHyphenation(styleStack.property(KoXmlNS::fo, "hyphenate") == "true");
-
- if (styleStack.hasProperty(KoXmlNS::fo, "hyphenation-remain-char-count")) {
- bool ok = false;
- int count = styleStack.property(KoXmlNS::fo, "hyphenation-remain-char-count").toInt(&ok);
- if (ok)
- setHyphenationRemainCharCount(count);
- }
- if (styleStack.hasProperty(KoXmlNS::fo, "hyphenation-push-char-count")) {
- bool ok = false;
- int count = styleStack.property(KoXmlNS::fo, "hyphenation-push-char-count").toInt(&ok);
- if (ok)
- setHyphenationPushCharCount(count);
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "text-blinking")) {
- setBlinking(styleStack.property(KoXmlNS::style, "text-blinking") == "true");
- }
-
-
-//TODO
-#if 0
- /*
- Missing properties:
- style:font-style-name, 3.10.11 - can be ignored, says DV, the other ways to specify a font are more precise
- fo:letter-spacing, 3.10.16 - not implemented in kotext
- style:text-relief, 3.10.20 - not implemented in kotext
- style:text-blinking, 3.10.27 - not implemented in kotext IIRC
- style:text-combine, 3.10.29/30 - not implemented, see http://www.w3.org/TR/WD-i18n-format/
- style:text-emphasis, 3.10.31 - not implemented in kotext
- style:text-scale, 3.10.33 - not implemented in kotext
- style:text-rotation-angle, 3.10.34 - not implemented in kotext (kpr rotates whole objects)
- style:text-rotation-scale, 3.10.35 - not implemented in kotext (kpr rotates whole objects)
- style:punctuation-wrap, 3.10.36 - not implemented in kotext
- */
-
- d->m_underLineWidth = 1.0;
-
- generateKey();
- addRef();
-#endif
-}
-
-bool KoCharacterStyle::operator==(const KoCharacterStyle &other) const
-{
- return compareCharacterProperties(other);
-}
-
-bool KoCharacterStyle::operator!=(const KoCharacterStyle &other) const
-{
- return !compareCharacterProperties(other);
-}
-
-bool KoCharacterStyle::compareCharacterProperties(const KoCharacterStyle &other) const
-{
- return other.d->stylesPrivate == d->stylesPrivate;
-}
-
-void KoCharacterStyle::removeDuplicates(const KoCharacterStyle &other)
-{
- // In case the current style doesn't have the flag UseWindowFontColor set but the other has it set and they use the same color
- // remove duplicates will remove the color. However to make it work correctly we need to store the color with the style so it
- // will be loaded again. We don't store a use-window-font-color="false" as that is not compatible to the way OO/LO does work.
- // So save the color and restore it after the remove duplicates
- QBrush brush;
- if (other.d->propertyBoolean(KoCharacterStyle::UseWindowFontColor) && !d->propertyBoolean(KoCharacterStyle::UseWindowFontColor)) {
- brush = foreground();
- }
-
- // this properties should need to be kept if there is a font family defined as these are only evaluated if there is also a font family
- int keepProperties[] = { QTextFormat::FontStyleHint, QTextFormat::FontFixedPitch, KoCharacterStyle::FontCharset };
-
- QMap<int, QVariant> keep;
- for (unsigned int i = 0; i < sizeof(keepProperties)/sizeof(*keepProperties); ++i) {
- if (hasProperty(keepProperties[i])) {
- keep.insert(keepProperties[i], value(keepProperties[i]));
- }
- }
- this->d->stylesPrivate.removeDuplicates(other.d->stylesPrivate);
- if (brush.style() != Qt::NoBrush) {
- setForeground(brush);
- }
-
- // in case the char style has any of the following properties it also needs to have the fontFamily as otherwise
- // these values will be ignored when loading according to the odf spec
- if (!hasProperty(QTextFormat::FontFamily)) {
- if (hasProperty(QTextFormat::FontStyleHint) || hasProperty(QTextFormat::FontFixedPitch) || hasProperty(KoCharacterStyle::FontCharset)) {
- QString fontFamily = other.fontFamily();
- if (!fontFamily.isEmpty()) {
- setFontFamily(fontFamily);
- }
- }
- }
- else {
- for (QMap<int, QVariant>::const_iterator it(keep.constBegin()); it != keep.constEnd(); ++it) {
- this->d->stylesPrivate.add(it.key(), it.value());
- }
- }
-}
-
-void KoCharacterStyle::removeDuplicates(const QTextCharFormat &otherFormat)
-{
- KoCharacterStyle other(otherFormat);
- removeDuplicates(other);
-}
-
-void KoCharacterStyle::remove(int key)
-{
- d->stylesPrivate.remove(key);
-}
-
-bool KoCharacterStyle::isEmpty() const
-{
- return d->stylesPrivate.isEmpty();
-}
-
-void KoCharacterStyle::saveOdf(KoGenStyle &style) const
-{
- if (!d->name.isEmpty() && !style.isDefaultStyle()) {
- style.addAttribute("style:display-name", d->name);
- }
- QList<int> keys = d->stylesPrivate.keys();
- Q_FOREACH (int key, keys) {
- if (key == QTextFormat::FontWeight) {
- bool ok = false;
- int boldness = d->stylesPrivate.value(key).toInt(&ok);
- if (ok) {
- if (boldness == QFont::Normal) {
- style.addProperty("fo:font-weight", "normal", KoGenStyle::TextType);
- } else if (boldness == QFont::Bold) {
- style.addProperty("fo:font-weight", "bold", KoGenStyle::TextType);
- } else {
- // Remember : Qt and CSS/XSL doesn't have the same scale. Its 100-900 instead of Qts 0-100
- style.addProperty("fo:font-weight", qBound(10, boldness, 90) * 10, KoGenStyle::TextType);
- }
- }
- } else if (key == QTextFormat::FontItalic) {
- if (d->stylesPrivate.value(key).toBool()) {
- style.addProperty("fo:font-style", "italic", KoGenStyle::TextType);
- } else {
- style.addProperty("fo:font-style", "normal", KoGenStyle::TextType);
- }
- } else if (key == QTextFormat::FontFamily) {
- QString fontFamily = d->stylesPrivate.value(key).toString();
- style.addProperty("fo:font-family", fontFamily, KoGenStyle::TextType);
- } else if (key == QTextFormat::FontFixedPitch) {
- bool fixedPitch = d->stylesPrivate.value(key).toBool();
- style.addProperty("style:font-pitch", fixedPitch ? "fixed" : "variable", KoGenStyle::TextType);
- // if this property is saved we also need to save the fo:font-family attribute as otherwise it will be ignored on loading as defined in the spec
- style.addProperty("fo:font-family", fontFamily(), KoGenStyle::TextType);
- } else if (key == QTextFormat::FontStyleHint) {
- bool ok = false;
- int styleHint = d->stylesPrivate.value(key).toInt(&ok);
- if (ok) {
- QString generic = exportOdfFontStyleHint((QFont::StyleHint) styleHint);
- if (!generic.isEmpty()) {
- style.addProperty("style:font-family-generic", generic, KoGenStyle::TextType);
- }
- // if this property is saved we also need to save the fo:font-family attribute as otherwise it will be ignored on loading as defined in the spec
- style.addProperty("fo:font-family", fontFamily(), KoGenStyle::TextType);
- }
- } else if (key == QTextFormat::FontKerning) {
- style.addProperty("style:letter-kerning", fontKerning() ? "true" : "false", KoGenStyle::TextType);
- } else if (key == QTextFormat::FontCapitalization) {
- switch (fontCapitalization()) {
- case QFont::SmallCaps:
- style.addProperty("fo:font-variant", "small-caps", KoGenStyle::TextType);
- break;
- case QFont::MixedCase:
- style.addProperty("fo:font-variant", "normal", KoGenStyle::TextType);
- style.addProperty("fo:text-transform", "none", KoGenStyle::TextType);
- break;
- case QFont::AllUppercase:
- style.addProperty("fo:text-transform", "uppercase", KoGenStyle::TextType);
- break;
- case QFont::AllLowercase:
- style.addProperty("fo:text-transform", "lowercase", KoGenStyle::TextType);
- break;
- case QFont::Capitalize:
- style.addProperty("fo:text-transform", "capitalize", KoGenStyle::TextType);
- break;
- }
- } else if (key == OverlineStyle) {
- bool ok = false;
- int styleId = d->stylesPrivate.value(key).toInt(&ok);
- if (ok) {
- style.addProperty("style:text-overline-style", exportOdfLineStyle((KoCharacterStyle::LineStyle) styleId), KoGenStyle::TextType);
- }
- } else if (key == OverlineType) {
- bool ok = false;
- int type = d->stylesPrivate.value(key).toInt(&ok);
- if (ok) {
- style.addProperty("style:text-overline-type", exportOdfLineType((KoCharacterStyle::LineType) type), KoGenStyle::TextType);
- }
- } else if (key == OverlineColor) {
- QColor color = d->stylesPrivate.value(key).value<QColor>();
- if (color.isValid())
- style.addProperty("style:text-overline-color", color.name(), KoGenStyle::TextType);
- else
- style.addProperty("style:text-overline-color", "font-color", KoGenStyle::TextType);
- } else if (key == OverlineMode) {
- bool ok = false;
- int mode = d->stylesPrivate.value(key).toInt(&ok);
- if (ok) {
- style.addProperty("style:text-overline-mode", exportOdfLineMode((KoCharacterStyle::LineMode) mode), KoGenStyle::TextType);
- }
- } else if (key == OverlineWidth) {
- KoCharacterStyle::LineWeight weight;
- qreal width;
- overlineWidth(weight, width);
- style.addProperty("style:text-overline-width", exportOdfLineWidth(weight, width), KoGenStyle::TextType);
- } else if (key == UnderlineStyle) {
- bool ok = false;
- int styleId = d->stylesPrivate.value(key).toInt(&ok);
- if (ok)
- style.addProperty("style:text-underline-style", exportOdfLineStyle((KoCharacterStyle::LineStyle) styleId), KoGenStyle::TextType);
- } else if (key == UnderlineType) {
- bool ok = false;
- int type = d->stylesPrivate.value(key).toInt(&ok);
- if (ok)
- style.addProperty("style:text-underline-type", exportOdfLineType((KoCharacterStyle::LineType) type), KoGenStyle::TextType);
- } else if (key == QTextFormat::TextUnderlineColor) {
- QColor color = d->stylesPrivate.value(key).value<QColor>();
- if (color.isValid())
- style.addProperty("style:text-underline-color", color.name(), KoGenStyle::TextType);
- else
- style.addProperty("style:text-underline-color", "font-color", KoGenStyle::TextType);
- } else if (key == UnderlineMode) {
- bool ok = false;
- int mode = d->stylesPrivate.value(key).toInt(&ok);
- if (ok)
- style.addProperty("style:text-underline-mode", exportOdfLineMode((KoCharacterStyle::LineMode) mode), KoGenStyle::TextType);
- } else if (key == UnderlineWidth) {
- KoCharacterStyle::LineWeight weight;
- qreal width;
- underlineWidth(weight, width);
- style.addProperty("style:text-underline-width", exportOdfLineWidth(weight, width), KoGenStyle::TextType);
- } else if (key == StrikeOutStyle) {
- bool ok = false;
- int styleId = d->stylesPrivate.value(key).toInt(&ok);
- if (ok)
- style.addProperty("style:text-line-through-style", exportOdfLineStyle((KoCharacterStyle::LineStyle) styleId), KoGenStyle::TextType);
- } else if (key == StrikeOutType) {
- bool ok = false;
- int type = d->stylesPrivate.value(key).toInt(&ok);
- if (ok)
- style.addProperty("style:text-line-through-type", exportOdfLineType((KoCharacterStyle::LineType) type), KoGenStyle::TextType);
- } else if (key == StrikeOutText) {
- style.addProperty("style:text-line-through-text", d->stylesPrivate.value(key).toString(), KoGenStyle::TextType);
- } else if (key == StrikeOutColor) {
- QColor color = d->stylesPrivate.value(key).value<QColor>();
- if (color.isValid())
- style.addProperty("style:text-line-through-color", color.name(), KoGenStyle::TextType);
- } else if (key == StrikeOutMode) {
- bool ok = false;
- int mode = d->stylesPrivate.value(key).toInt(&ok);
- if (ok)
- style.addProperty("style:text-line-through-mode", exportOdfLineMode((KoCharacterStyle::LineMode) mode), KoGenStyle::TextType);
- } else if (key == StrikeOutWidth) {
- KoCharacterStyle::LineWeight weight;
- qreal width;
- strikeOutWidth(weight, width);
- style.addProperty("style:text-line-through-width", exportOdfLineWidth(weight, width), KoGenStyle::TextType);
- } else if (key == QTextFormat::BackgroundBrush) {
- QBrush brush = d->stylesPrivate.value(key).value<QBrush>();
- if (brush.style() == Qt::NoBrush)
- style.addProperty("fo:background-color", "transparent", KoGenStyle::TextType);
- else
- style.addProperty("fo:background-color", brush.color().name(), KoGenStyle::TextType);
- } else if (key == QTextFormat::ForegroundBrush) {
- QBrush brush = d->stylesPrivate.value(key).value<QBrush>();
- if (brush.style() != Qt::NoBrush) {
- style.addProperty("fo:color", brush.color().name(), KoGenStyle::TextType);
- }
- } else if (key == KoCharacterStyle::UseWindowFontColor) {
- bool use = d->stylesPrivate.value(key).toBool();
- style.addProperty("style:use-window-font-color", use ? "true" : "false", KoGenStyle::TextType);
- } else if (key == QTextFormat::TextVerticalAlignment) {
- if (verticalAlignment() == QTextCharFormat::AlignSuperScript)
- style.addProperty("style:text-position", "super", KoGenStyle::TextType);
- else if (verticalAlignment() == QTextCharFormat::AlignSubScript)
- style.addProperty("style:text-position", "sub", KoGenStyle::TextType);
- else if (d->stylesPrivate.contains(QTextFormat::TextVerticalAlignment)) // no superscript or subscript
- style.addProperty("style:text-position", "0% 100%", KoGenStyle::TextType);
- } else if (key == QTextFormat::FontPointSize) {
- // when there is percentageFontSize!=100% property ignore the fontSize property and store the percentage property
- if ( (!hasProperty(KoCharacterStyle::PercentageFontSize)) || (percentageFontSize()==100))
- style.addPropertyPt("fo:font-size", fontPointSize(), KoGenStyle::TextType);
- } else if (key == KoCharacterStyle::PercentageFontSize) {
- if(percentageFontSize()!=100) {
- style.addProperty("fo:font-size", QString::number(percentageFontSize()) + '%', KoGenStyle::TextType);
- }
- } else if (key == KoCharacterStyle::Country) {
- style.addProperty("fo:country", d->stylesPrivate.value(KoCharacterStyle::Country).toString(), KoGenStyle::TextType);
- } else if (key == KoCharacterStyle::Language) {
- style.addProperty("fo:language", d->stylesPrivate.value(KoCharacterStyle::Language).toString(), KoGenStyle::TextType);
- } else if (key == KoCharacterStyle::FontLetterSpacing) {
- qreal space = fontLetterSpacing();
- style.addPropertyPt("fo:letter-spacing", space, KoGenStyle::TextType);
- } else if (key == QTextFormat::TextOutline) {
- QPen outline = textOutline();
- style.addProperty("style:text-outline", outline.style() == Qt::NoPen ? "false" : "true", KoGenStyle::TextType);
- } else if (key == KoCharacterStyle::FontCharset) {
- style.addProperty("style:font-charset", d->stylesPrivate.value(KoCharacterStyle::FontCharset).toString(), KoGenStyle::TextType);
- // if this property is saved we also need to save the fo:font-family attribute as otherwise it will be ignored on loading as defined in the spec
- style.addProperty("fo:font-family", fontFamily(), KoGenStyle::TextType);
- } else if (key == KoCharacterStyle::TextRotationAngle) {
- style.addProperty("style:text-rotation-angle", QString::number(textRotationAngle()), KoGenStyle::TextType);
- } else if (key == KoCharacterStyle::TextRotationScale) {
- RotationScale scale = textRotationScale();
- style.addProperty("style:text-rotation-scale", rotationScaleToString(scale), KoGenStyle::TextType);
- } else if (key == KoCharacterStyle::TextScale) {
- int scale = textScale();
- style.addProperty("style:text-scale", QString::number(scale) + '%', KoGenStyle::TextType);
- } else if (key == KoCharacterStyle::TextShadow) {
- KoShadowStyle shadow = textShadow();
- style.addProperty("fo:text-shadow", shadow.saveOdf(), KoGenStyle::TextType);
- } else if (key == KoCharacterStyle::TextCombine) {
- KoCharacterStyle::TextCombineType textCombineType = textCombine();
- switch (textCombineType)
- {
- case KoCharacterStyle::NoTextCombine:
- style.addProperty("style:text-combine", "none", KoGenStyle::TextType);
- break;
- case KoCharacterStyle::TextCombineLetters:
- style.addProperty("style:text-combine", "letters", KoGenStyle::TextType);
- break;
- case KoCharacterStyle::TextCombineLines:
- style.addProperty("style:text-combine", "lines", KoGenStyle::TextType);
- break;
- }
- } else if (key == KoCharacterStyle::TextCombineEndChar) {
- style.addProperty("style:text-combine-end-char", textCombineEndChar(), KoGenStyle::TextType);
- } else if (key == KoCharacterStyle::TextCombineStartChar) {
- style.addProperty("style:text-combine-start-char", textCombineStartChar(), KoGenStyle::TextType);
- } else if (key == KoCharacterStyle::FontRelief) {
- KoCharacterStyle::ReliefType relief = fontRelief();
- switch (relief)
- {
- case KoCharacterStyle::NoRelief:
- style.addProperty("style:font-relief", "none", KoGenStyle::TextType);
- break;
- case KoCharacterStyle::Embossed:
- style.addProperty("style:font-relief", "embossed", KoGenStyle::TextType);
- break;
- case KoCharacterStyle::Engraved:
- style.addProperty("style:font-relief", "engraved", KoGenStyle::TextType);
- break;
- }
- } else if (key == KoCharacterStyle::TextEmphasizeStyle) {
- KoCharacterStyle::EmphasisStyle emphasisStyle = textEmphasizeStyle();
- KoCharacterStyle::EmphasisPosition position = textEmphasizePosition();
- QString odfEmphasis;
- switch (emphasisStyle)
- {
- case KoCharacterStyle::NoEmphasis:
- odfEmphasis = "none";
- break;
- case KoCharacterStyle::AccentEmphasis:
- odfEmphasis = "accent";
- break;
- case KoCharacterStyle::CircleEmphasis:
- odfEmphasis = "circle";
- break;
- case KoCharacterStyle::DiscEmphasis:
- odfEmphasis = "disc";
- break;
- case KoCharacterStyle::DotEmphasis:
- odfEmphasis = "dot";
- break;
- }
- if (hasProperty(KoCharacterStyle::TextEmphasizePosition)) {
- if (position == KoCharacterStyle::EmphasisAbove)
- odfEmphasis += " above";
- else
- odfEmphasis += " below";
- }
- style.addProperty("style:text-emphasize", odfEmphasis, KoGenStyle::TextType);
- } else if (key == KoCharacterStyle::HasHyphenation) {
- if (hasHyphenation())
- style.addProperty("fo:hyphenate", "true", KoGenStyle::TextType);
- else
- style.addProperty("fo:hyphenate", "false", KoGenStyle::TextType);
- } else if (key == KoCharacterStyle::HyphenationPushCharCount) {
- style.addProperty("fo:hyphenation-push-char-count", hyphenationPushCharCount(), KoGenStyle::TextType);
- } else if (key == KoCharacterStyle::HyphenationRemainCharCount) {
- style.addProperty("fo:hyphenation-remain-char-count", hyphenationRemainCharCount(), KoGenStyle::TextType);
- } else if (key == KoCharacterStyle::Blink) {
- style.addProperty("style:text-blinking", blinking(), KoGenStyle::TextType);
- }
- }
- //TODO: font name and family
-}
-
-QVariant KoCharacterStyle::value(int key) const
-{
- QVariant variant = d->stylesPrivate.value(key);
- if (variant.isNull()) {
- if (d->parentStyle)
- variant = d->parentStyle->value(key);
- else if (d->defaultStyle)
- variant = d->defaultStyle->value(key);
- }
- return variant;
-}
-
-void KoCharacterStyle::removeHardCodedDefaults()
-{
- d->hardCodedDefaultStyle.clearAll();
-}
diff --git a/plugins/flake/textshape/kotext/styles/KoCharacterStyle.h b/plugins/flake/textshape/kotext/styles/KoCharacterStyle.h
deleted file mode 100644
index 4bf95beff0..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoCharacterStyle.h
+++ /dev/null
@@ -1,556 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2007 Sebastian Sauer <mail@dipe.org>
- * Copyright (C) 2007 Pierre Ducroquet <pinaraf@gmail.com>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2008 Pierre Stirnweiss <pierre.stirnweiss_calligra@gadz.org>
- * Copyright (C) 2011 Stuart Dickson <stuart@furkinfantasic.net>
- *
- * 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 KOCHARACTERSTYLE_H
-#define KOCHARACTERSTYLE_H
-
-#include <KoXmlReaderForward.h>
-
-#include <QObject>
-#include <QTextCharFormat>
-#include "kritatext_export.h"
-
-class QTextBlock;
-class KoShapeLoadingContext;
-class KoShadowStyle;
-class KoGenStyle;
-class QString;
-class QChar;
-class QVariant;
-
-/**
- * A container for all properties for a character style.
- * A character style represents all character properties for a set of characters.
- * Each character in the document will have a character style, most of the time
- * shared with all the characters next to it that have the same style (see
- * QTextFragment).
- * In a document the instances of QTextCharFormat which are based on a
- * KoCharacterStyle have a property StyleId with an integer as value which
- * equals styleId() of that style.
- * @see KoStyleManager
- */
-class KRITATEXT_EXPORT KoCharacterStyle : public QObject
-{
- Q_OBJECT
-public:
- /// types of style
- enum Type {
- CharacterStyle,
- ParagraphStyle
- };
-
- /// list of character style properties we can store in a QTextCharFormat
- enum Property {
- StyleId = QTextFormat::UserProperty + 1, ///< The id stored in the charFormat to link the text to this style.
- HasHyphenation,
- StrikeOutStyle,
- StrikeOutType,
- StrikeOutColor,
- StrikeOutWidth,
- StrikeOutWeight,
- StrikeOutMode,
- StrikeOutText,
- OverlineStyle,
- OverlineType,
- OverlineColor,
- OverlineWidth,
- OverlineWeight,
- OverlineMode,
- UnderlineStyle,
- UnderlineType,
- UnderlineWidth,
- UnderlineWeight,
- UnderlineMode,
- Language,
- Country,
- FontCharset,
- TextRotationAngle,
- TextRotationScale,
- TextScale,
- InlineRdf, ///< KoTextInlineRdf pointer
- TextShadow,
- FontRelief,
- TextEmphasizeStyle,
- TextEmphasizePosition,
- TextCombine, ///< TextCombineType
- TextCombineStartChar, ///< QChar
- TextCombineEndChar, ///< QChar
- HyphenationPushCharCount, ///< int
- HyphenationRemainCharCount, ///< int
- FontLetterSpacing, ///< qreal, not the same format as the FontLetterSpacing in QTextFormat
- PercentageFontSize, //font-size can be in % and this stores that value
- AdditionalFontSize, //font-size-rel can specify an addition to the parent value
- UseWindowFontColor, //boolean, same as odf
- Blink,
- AnchorType, //valid only if QTextCharFormat::isAnchor() is true
- InlineInstanceId = 577297549, // Internal: Reserved for KoInlineTextObjectManager
- ChangeTrackerId = 577297550, // Internal: Reserved for ChangeTracker
- FontYStretch = 577297551 // Internal: Ratio between Linux font pt size and Windows font height
- };
-
- /// List of possible combine mode
- enum TextCombineType {
- NoTextCombine,
- TextCombineLetters,
- TextCombineLines
- };
-
- /// list of possible line type : no line, single line, double line
- enum LineType {
- NoLineType,
- SingleLine,
- DoubleLine
- };
-
- /// List of possible font relief : none, embossed, engraved
- enum ReliefType {
- NoRelief,
- Embossed,
- Engraved
- };
-
- enum EmphasisStyle {
- NoEmphasis,
- AccentEmphasis,
- CircleEmphasis,
- DiscEmphasis,
- DotEmphasis
- };
-
- enum EmphasisPosition {
- EmphasisAbove,
- EmphasisBelow
- };
-
-
- /// list of possible line style.
- enum LineStyle {
- NoLineStyle = Qt::NoPen,
- SolidLine = Qt::SolidLine,
- DottedLine = Qt::DotLine,
- DashLine = Qt::DashLine,
- DotDashLine = Qt::DashDotLine,
- DotDotDashLine = Qt::DashDotDotLine,
- LongDashLine,
- WaveLine
- };
-
- enum LineWeight {
- AutoLineWeight,
- NormalLineWeight,
- BoldLineWeight,
- ThinLineWeight,
- DashLineWeight, // ## ??what the heck does this mean??
- MediumLineWeight,
- ThickLineWeight,
- PercentLineWeight,
- LengthLineWeight
- };
-
- /// list of possible line modes.
- enum LineMode {
- NoLineMode,
- ContinuousLineMode,
- SkipWhiteSpaceLineMode
- };
-
- enum RotationScale {
- Fixed,
- LineHeight
- };
-
- enum AnchorTypes {
- Bookmark,
- Anchor // corresponds to text:a ODF element
- };
-
- /**
- * Constructor. Initializes with standard size/font properties.
- * @param parent the parent object for memory management purposes.
- */
- explicit KoCharacterStyle(QObject *parent = 0);
- /// Copy constructor
- explicit KoCharacterStyle(const QTextCharFormat &format, QObject *parent = 0);
- /// Destructor
- ~KoCharacterStyle() override;
-
- /// returns the type of style
- virtual Type styleType() const;
-
- /// set the default style this one inherits its unset properties from if no parent style.
- void setDefaultStyle(KoCharacterStyle *parent);
-
- /// set the parent style this one inherits its unset properties from.
- void setParentStyle(KoCharacterStyle *parent);
-
- /// return the parent style
- KoCharacterStyle *parentStyle() const;
-
- /// return the effective font for this style
- QFont font() const;
-
- /// See similar named method on QTextCharFormat
- void setFontFamily(const QString &family);
- /// See similar named method on QTextCharFormat
- QString fontFamily() const;
- /// See similar named method on QTextCharFormat
- void setFontPointSize(qreal size);
- /// remove the font point size attribute
- void clearFontPointSize();
- /// See similar named method on QTextCharFormat
- qreal fontPointSize() const;
- /// See similar named method on QTextCharFormat
- void setFontWeight(int weight);
- /// See similar named method on QTextCharFormat
- int fontWeight() const;
- /// See similar named method on QTextCharFormat
- void setFontItalic(bool italic);
- /// See similar named method on QTextCharFormat
- bool fontItalic() const;
- /*
- /// See similar named method on QTextCharFormat
- void setFontOverline(bool overline);
- /// See similar named method on QTextCharFormat
- bool fontOverline() const;
- */
- /// See similar named method on QTextCharFormat
- void setFontFixedPitch(bool fixedPitch);
- /// See similar named method on QTextCharFormat
- bool fontFixedPitch() const;
- /// See similar named method on QTextCharFormat
- void setVerticalAlignment(QTextCharFormat::VerticalAlignment alignment);
- /// See similar named method on QTextCharFormat
- QTextCharFormat::VerticalAlignment verticalAlignment() const;
- /// See similar named method on QTextCharFormat
- void setTextOutline(const QPen &pen);
- /// See similar named method on QTextCharFormat
- QPen textOutline() const;
- /// See similar named method on QTextCharFormat
- void setFontLetterSpacing(qreal spacing);
- /// See similar named method on QTextCharFormat
- qreal fontLetterSpacing() const;
- /// See similar named method on QTextCharFormat
- void setFontWordSpacing(qreal spacing);
- /// See similar named method on QTextCharFormat
- qreal fontWordSpacing() const;
- /// Set the text capitalization
- void setFontCapitalization(QFont::Capitalization capitalization);
- /// Return how the text should be capitalized
- QFont::Capitalization fontCapitalization() const;
- /// Set font Y stretch
- void setFontYStretch(qreal stretch);
- /// Return font Y stretch (value relevant for MS compatibility)
- qreal fontYStretch() const;
-
-
- /// See similar named method on QTextCharFormat
- void setFontStyleHint(QFont::StyleHint styleHint);
- /// See similar named method on QTextCharFormat
- QFont::StyleHint fontStyleHint() const;
- /// See similar named method on QTextCharFormat
- void setFontKerning(bool enable);
- /// See similar named method on QTextCharFormat
- bool fontKerning() const;
-
- /// See similar named method on QTextCharFormat
- void setBackground(const QBrush &brush);
- /// See similar named method on QTextCharFormat
- QBrush background() const;
- /// See similar named method on QTextCharFormat
- void clearBackground();
-
- /// See similar named method on QTextCharFormat
- void setForeground(const QBrush &brush);
- /// See similar named method on QTextCharFormat
- QBrush foreground() const;
- /// See similar named method on QTextCharFormat
- void clearForeground();
-
- /// Set the boolean of using window font color (see odf spec)
- void setFontAutoColor(bool use);
-
- /// Apply a font strike out style to this KoCharacterStyle
- void setStrikeOutStyle(LineStyle style);
- /// Get the current font strike out style of this KoCharacterStyle
- LineStyle strikeOutStyle() const;
- /// Apply a font strike out width to this KoCharacterStyle
- void setStrikeOutWidth(LineWeight weight, qreal width);
- /// Get the current font strike out width of this KoCharacterStyle
- void strikeOutWidth(LineWeight &weight, qreal &width) const;
- /// Apply a font strike out color to this KoCharacterStyle
- void setStrikeOutColor(const QColor &color);
- /// Get the current font strike out color of this KoCharacterStyle
- QColor strikeOutColor() const;
- /// Apply a font strike out color to this KoCharacterStyle
- void setStrikeOutType(LineType lineType);
- /// Get the current font strike out color of this KoCharacterStyle
- LineType strikeOutType() const;
- /// Apply a strike out mode of this KoCharacterStyle
- void setStrikeOutMode(LineMode lineMode);
- /// Get the current strike out mode of this KoCharacterStyle
- LineMode strikeOutMode() const;
- /// Apply a strike out text of this KoCharacterStyle
- void setStrikeOutText(const QString &text);
- /// Get the current strike out text of this KoCharacterStyle
- QString strikeOutText() const;
-
- /// Apply a font overline style to this KoCharacterStyle
- void setOverlineStyle(LineStyle style);
- /// Get the current font overline style of this KoCharacterStyle
- LineStyle overlineStyle() const;
- /// Apply a font overline width to this KoCharacterStyle
- void setOverlineWidth(LineWeight weight, qreal width);
- /// Get the current font overline width of this KoCharacterStyle
- void overlineWidth(LineWeight &weight, qreal &width) const;
- /// Apply a font overline color to this KoCharacterStyle
- void setOverlineColor(const QColor &color);
- /// Get the current font overline color of this KoCharacterStyle
- QColor overlineColor() const;
- /// Apply a font overline color to this KoCharacterStyle
- void setOverlineType(LineType lineType);
- /// Get the current font overline color of this KoCharacterStyle
- LineType overlineType() const;
- /// Apply a overline mode to this KoCharacterStyle
- void setOverlineMode(LineMode mode);
- /// Get the current overline mode of this KoCharacterStyle
- LineMode overlineMode() const;
-
- /// Apply a font underline style to this KoCharacterStyle
- void setUnderlineStyle(LineStyle style);
- /// Get the current font underline style of this KoCharacterStyle
- LineStyle underlineStyle() const;
- /// Apply a font underline width to this KoCharacterStyle
- void setUnderlineWidth(LineWeight weight, qreal width);
- /// Get the current font underline width of this KoCharacterStyle
- void underlineWidth(LineWeight &weight, qreal &width) const;
- /// Apply a font underline color to this KoCharacterStyle
- void setUnderlineColor(const QColor &color);
- /// Get the current font underline color of this KoCharacterStyle
- QColor underlineColor() const;
- /// Apply a font underline color to this KoCharacterStyle
- void setUnderlineType(LineType lineType);
- /// Get the current font underline color of this KoCharacterStyle
- LineType underlineType() const;
- /// Apply a underline mode to this KoCharacterStyle
- void setUnderlineMode(LineMode mode);
- /// Get the current underline mode of this KoCharacterStyle
- LineMode underlineMode() const;
-
- /// Apply text rotation angle to this KoCharacterStyle
- void setTextRotationAngle(qreal angle);
- /// Get the current text rotation angle of this KoCharacterStyle
- qreal textRotationAngle() const;
- /**
- * RotationScale pecifies whether for rotated text the width of the text
- * should be scaled to fit into the current line height or the width of the text
- * should remain fixed, therefore changing the current line height
- */
- void setTextRotationScale(RotationScale scale);
- /// Get the current text rotation scale of this KoCharacterStyle
- RotationScale textRotationScale() const;
- /// Apply text scale to this KoCharacterStyle
- void setTextScale(int scale);
- /// Get the current text scale of this KoCharacterStyle
- int textScale() const;
-
- KoShadowStyle textShadow() const;
- void setTextShadow(const KoShadowStyle &shadow);
-
- TextCombineType textCombine() const;
- void setTextCombine(TextCombineType type);
-
- QChar textCombineStartChar() const;
- void setTextCombineStartChar(const QChar &character);
-
- QChar textCombineEndChar() const;
- void setTextCombineEndChar(const QChar &character);
-
-
- ReliefType fontRelief() const;
- void setFontRelief(ReliefType relief);
-
- EmphasisStyle textEmphasizeStyle() const;
- void setTextEmphasizeStyle(EmphasisStyle emphasis);
-
- EmphasisPosition textEmphasizePosition() const;
- void setTextEmphasizePosition(EmphasisPosition position);
-
- /// Set the country
- void setCountry(const QString &country);
- /// Set the language
- void setLanguage(const QString &language);
- /// Get the country
- QString country() const;
- /// Get the language
- QString language() const;
-
- bool blinking() const;
- void setBlinking(bool blink);
-
- void setHasHyphenation(bool on);
- bool hasHyphenation() const;
-
- void setHyphenationPushCharCount(int count);
- int hyphenationPushCharCount() const;
-
- void setHyphenationRemainCharCount(int count);
- int hyphenationRemainCharCount() const;
-
- void setPercentageFontSize(qreal percent);
- qreal percentageFontSize() const;
-
- void setAdditionalFontSize(qreal percent);
- qreal additionalFontSize() const;
-
- /// set the anchor type, valid only if QTextCharFormat::isAnchor() is true
- void setAnchorType(AnchorTypes anchorType);
- /// returns the anchor type, valid only if QTextCharFormat::isAnchor() is true
- AnchorTypes anchorType() const;
-
- void copyProperties(const KoCharacterStyle *style);
- void copyProperties(const QTextCharFormat &format);
-
- KoCharacterStyle *clone(QObject *parent = 0) const;
-
- /// return the name of the style.
- QString name() const;
-
- /// set a user-visible name on the style.
- void setName(const QString &name);
-
- /// each style has a unique ID (non persistent) given out by the styleManager
- int styleId() const;
-
- /// each style has a unique ID (non persistent) given out by the styleManager
- void setStyleId(int id);
-
- void unapplyStyle(QTextBlock &block) const;
- void unapplyStyle(QTextCharFormat &format) const;
-
- /**
- * Apply this style to a blockFormat by copying all properties from this
- * style to the target char format.
- */
- void applyStyle(QTextCharFormat &format, bool emitSignal = true) const;
- /**
- * Apply this style to the textBlock by copying all properties from this
- * style to the target block formats.
- */
- void applyStyle(QTextBlock &block) const;
- /**
- * Reset any styles and apply this style on the whole selection.
- */
- void applyStyle(QTextCursor *selection) const;
-
- /// This should be called after all charFormat properties are merged.
- void ensureMinimalProperties(QTextCharFormat &format) const;
-
- /**
- * Load the style form the element
- *
- * @param context the odf loading context
- * @param element the element containing the
- * @param loadParents true = use the stylestack, false = use just the element
- */
- void loadOdf(const KoXmlElement *element, KoShapeLoadingContext &context,
- bool loadParents = false);
-
- /// return true if this style has a non-default value set for the Property
- bool hasProperty(int key) const;
-
- bool compareCharacterProperties(const KoCharacterStyle &other) const;
-
- bool operator==(const KoCharacterStyle &other) const;
-
- bool operator!=(const KoCharacterStyle &other) const;
-
- /**
- * Removes properties from this style that have the same value in other style.
- */
- void removeDuplicates(const KoCharacterStyle &other);
-
- /**
- * Removes properties from this style that have the same value in other format.
- */
- void removeDuplicates(const QTextCharFormat &other_format);
-
- /**
- * Create an autostyle out of the format and baseFormat
- * @param format the format that is converted to an autostyle.
- * @param baseFormat the format (typically a blockCharFormat) that is the basis of the format,
- * but not itself part of the character style inheritance.
- * @return pointer to autostyle that has this as parent style
- */
- KoCharacterStyle *autoStyle(const QTextCharFormat &format, QTextCharFormat blockCharFormat) const;
-
- void saveOdf(KoGenStyle &style) const;
-
- /**
- * Returns true if this style has no properties set. Else, returns false.
- */
- bool isEmpty() const;
-
- /** Returns true if the style is in use.
- */
- bool isApplied() const;
-
- /**
- * Return the value of key as represented on this style.
- * You should consider using the direct accessors for individual properties instead.
- * @param key the Property to request.
- * @returns a QVariant which holds the property value.
- */
- QVariant value(int key) const;
-
- /**
- * Remove the hardcoded defaults from this style (SansSerif, 12 points, black).
- * @internal - this method is a bit of an ugly workaround to make it easier to
- * use KoTextLoader for loading richtext in kspread, normally styles with
- * no font etc. set are not something you should want.
- */
- void removeHardCodedDefaults();
-
- void remove(int key);
-
-Q_SIGNALS:
- void nameChanged(const QString &newName);
- void styleApplied(const KoCharacterStyle*) const;
-
-protected:
- /**
- * Load the text properties from the \a KoStyleStack style stack using the
- * OpenDocument format.
- */
- void loadOdfProperties(KoShapeLoadingContext &context);
-
-private:
- class Private;
- Private * const d;
-};
-
-Q_DECLARE_METATYPE(KoCharacterStyle *)
-Q_DECLARE_METATYPE(const KoCharacterStyle *)
-Q_DECLARE_METATYPE(QSharedPointer<KoCharacterStyle>)
-
-#endif
diff --git a/plugins/flake/textshape/kotext/styles/KoListLevelProperties.cpp b/plugins/flake/textshape/kotext/styles/KoListLevelProperties.cpp
deleted file mode 100644
index 992e41ee05..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoListLevelProperties.cpp
+++ /dev/null
@@ -1,938 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2007 Sebastian Sauer <mail@dipe.org>
- * Copyright (C) 2008 Pierre Ducroquet <pinaraf@pinaraf.info>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2010 Nandita Suri <suri.nandita@gmail.com>
- * Copyright (C) 2011 Lukáš Tvrdý <lukas.tvrdy@ixonos.com>
- * Copyright (C) 2011-2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- * Copyright (C) 2011 Mojtaba Shahi Senobari <mojtaba.shahi3000@gmail.com>
- *
- * 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 "KoListLevelProperties.h"
-
-#include "KoTextSharedLoadingData.h"
-#include "Styles_p.h"
-
-#include <float.h>
-
-#include "TextDebug.h"
-
-#include <KoXmlNS.h>
-#include <KoOdfLoadingContext.h>
-#include <KoShapeLoadingContext.h>
-#include <KoShapeSavingContext.h>
-#include <KoXmlWriter.h>
-#include <KoUnit.h>
-#include <KoText.h>
-#include <KoImageCollection.h>
-#include <KoImageData.h>
-#include <KoImageData_p.h>
-#include <KoOdfNumberDefinition.h>
-#include <KoGenStyle.h>
-#include <KoTextSharedSavingData.h>
-
-#include <QTextList>
-
-class Q_DECL_HIDDEN KoListLevelProperties::Private
-{
-public:
- StylePrivate stylesPrivate;
-
- void copy(Private *other) {
- stylesPrivate = other->stylesPrivate;
- }
-};
-
-KoListLevelProperties::KoListLevelProperties()
- : QObject()
- , d(new Private())
-{
- QSharedPointer<KoCharacterStyle> charStyle(new KoCharacterStyle);
- setCharacterProperties(charStyle);
-
- setRelativeBulletSize(100);
- setAlignmentMode(false);
- setDisplayLevel(1);
- connect(this,SIGNAL(styleChanged(int)),SLOT(onStyleChanged(int)));
-}
-
-KoListLevelProperties::KoListLevelProperties(const KoListLevelProperties &other)
- : QObject()
- , d(new Private())
-{
- d->copy(other.d);
- connect(this,SIGNAL(styleChanged(int)),SLOT(onStyleChanged(int)));
-}
-
-KoListLevelProperties::~KoListLevelProperties()
-{
- delete d;
-}
-
-int KoListLevelProperties::styleId() const
-{
- return propertyInt(KoListStyle::StyleId);
-}
-
-void KoListLevelProperties::setStyleId(int id)
-{
- setProperty(KoListStyle::StyleId, id);
-}
-
-void KoListLevelProperties::setProperty(int key, const QVariant &value)
-{
- d->stylesPrivate.add(key, value);
-}
-
-int KoListLevelProperties::propertyInt(int key) const
-{
- QVariant variant = d->stylesPrivate.value(key);
- if (variant.isNull())
- return 0;
- return variant.toInt();
-}
-
-uint KoListLevelProperties::propertyUInt(int key) const
-{
- QVariant variant = d->stylesPrivate.value(key);
- if (variant.isNull())
- return 0;
- return variant.toUInt();
-}
-
-qulonglong KoListLevelProperties::propertyULongLong(int key) const
-{
- QVariant variant = d->stylesPrivate.value(key);
- if (variant.isNull())
- return 0;
- return variant.toULongLong();
-}
-
-qreal KoListLevelProperties::propertyDouble(int key) const
-{
- QVariant variant = d->stylesPrivate.value(key);
- if (variant.isNull())
- return 0.;
- return variant.toDouble();
-}
-
-bool KoListLevelProperties::propertyBoolean(int key) const
-{
- QVariant variant = d->stylesPrivate.value(key);
- if (variant.isNull())
- return false;
- return variant.toBool();
-}
-
-QString KoListLevelProperties::propertyString(int key) const
-{
- QVariant variant = d->stylesPrivate.value(key);
- if (variant.isNull())
- return QString();
- return qvariant_cast<QString>(variant);
-}
-
-QColor KoListLevelProperties::propertyColor(int key) const
-{
- QVariant variant = d->stylesPrivate.value(key);
- if (variant.isNull())
- return QColor(Qt::black);
- return qvariant_cast<QColor>(variant);
-}
-
-QVariant KoListLevelProperties::property(int key) const
-{
- QVariant variant = d->stylesPrivate.value(key);
- if (!variant.isNull()) {
- return variant;
- } else {
- return QVariant();
- }
-}
-
-void KoListLevelProperties::applyStyle(QTextListFormat &format) const
-{
- QList<int> keys = d->stylesPrivate.keys();
- for (int i = 0; i < keys.count(); i++) {
- QVariant variant = d->stylesPrivate.value(keys[i]);
- format.setProperty(keys[i], variant);
- }
-}
-
-bool KoListLevelProperties::operator==(const KoListLevelProperties &other) const
-{
- return d->stylesPrivate == other.d->stylesPrivate;
-}
-
-bool KoListLevelProperties::operator!=(const KoListLevelProperties &other) const
-{
- return d->stylesPrivate != other.d->stylesPrivate;
-}
-
-void KoListLevelProperties::setListItemPrefix(const QString &prefix)
-{
- setProperty(KoListStyle::ListItemPrefix, prefix);
-}
-
-QString KoListLevelProperties::listItemPrefix() const
-{
- return propertyString(KoListStyle::ListItemPrefix);
-}
-
-void KoListLevelProperties::setStyle(KoListStyle::Style style)
-{
- setProperty(QTextListFormat::ListStyle, (int) style);
- emit styleChanged(style);
-}
-
-KoListStyle::Style KoListLevelProperties::style() const
-{
- return static_cast<KoListStyle::Style>(propertyInt(QTextListFormat::ListStyle));
-}
-
-void KoListLevelProperties::setListItemSuffix(const QString &suffix)
-{
- setProperty(KoListStyle::ListItemSuffix, suffix);
-}
-
-QString KoListLevelProperties::listItemSuffix() const
-{
- return propertyString(KoListStyle::ListItemSuffix);
-}
-
-void KoListLevelProperties::setStartValue(int value)
-{
- setProperty(KoListStyle::StartValue, value);
-}
-
-int KoListLevelProperties::startValue() const
-{
- return propertyInt(KoListStyle::StartValue);
-}
-
-void KoListLevelProperties::setLevel(int value)
-{
- setProperty(KoListStyle::Level, value);
-}
-
-int KoListLevelProperties::level() const
-{
- return propertyInt(KoListStyle::Level);
-}
-
-void KoListLevelProperties::setDisplayLevel(int level)
-{
- setProperty(KoListStyle::DisplayLevel, level);
-}
-
-int KoListLevelProperties::displayLevel() const
-{
- return propertyInt(KoListStyle::DisplayLevel);
-}
-
-void KoListLevelProperties::setCharacterStyleId(int id)
-{
- setProperty(KoListStyle::CharacterStyleId, id);
-}
-
-int KoListLevelProperties::characterStyleId() const
-{
- return propertyInt(KoListStyle::CharacterStyleId);
-}
-
-void KoListLevelProperties::setCharacterProperties(QSharedPointer< KoCharacterStyle > style)
-{
- setProperty(KoListStyle::CharacterProperties, QVariant::fromValue< QSharedPointer<KoCharacterStyle> >(style));
-}
-
-QSharedPointer<KoCharacterStyle> KoListLevelProperties::characterProperties() const
-{
- const QVariant v = d->stylesPrivate.value(KoListStyle::CharacterProperties);
- if (v.isNull()) {
- return QSharedPointer<KoCharacterStyle>(0);
- }
- return v.value< QSharedPointer<KoCharacterStyle> >();
-}
-
-void KoListLevelProperties::setBulletCharacter(QChar character)
-{
- setProperty(KoListStyle::BulletCharacter, (int) character.unicode());
-}
-
-QChar KoListLevelProperties::bulletCharacter() const
-{
- return propertyInt(KoListStyle::BulletCharacter);
-}
-
-void KoListLevelProperties::setRelativeBulletSize(int percent)
-{
- setProperty(KoListStyle::RelativeBulletSize, percent);
-}
-
-int KoListLevelProperties::relativeBulletSize() const
-{
- return propertyInt(KoListStyle::RelativeBulletSize);
-}
-
-void KoListLevelProperties::setAlignment(Qt::Alignment align)
-{
- setProperty(KoListStyle::Alignment, static_cast<int>(align));
-}
-
-Qt::Alignment KoListLevelProperties::alignment() const
-{
- return static_cast<Qt::Alignment>(propertyInt(KoListStyle::Alignment));
-}
-
-void KoListLevelProperties::setMinimumWidth(qreal width)
-{
- setProperty(KoListStyle::MinimumWidth, width);
-}
-
-qreal KoListLevelProperties::minimumWidth() const
-{
- return propertyDouble(KoListStyle::MinimumWidth);
-}
-
-void KoListLevelProperties::setWidth(qreal width)
-{
- setProperty(KoListStyle::Width, width);
-}
-
-qreal KoListLevelProperties::width() const
-{
- return propertyDouble(KoListStyle::Width);
-}
-
-void KoListLevelProperties::setHeight(qreal height)
-{
- setProperty(KoListStyle::Height, height);
-}
-
-qreal KoListLevelProperties::height() const
-{
- return propertyDouble(KoListStyle::Height);
-}
-
-void KoListLevelProperties::setBulletImage(KoImageData *imageData)
-{
- setProperty(KoListStyle::BulletImage, QVariant::fromValue(imageData));
-}
-
-KoImageData *KoListLevelProperties::bulletImage() const
-{
- return property(KoListStyle::BulletImage).value< KoImageData * >();
-}
-
-KoListLevelProperties & KoListLevelProperties::operator=(const KoListLevelProperties & other)
-{
- d->copy(other.d);
- return *this;
-}
-
-void KoListLevelProperties::setListId(KoListStyle::ListIdType listId)
-{
- setProperty(KoListStyle::ListId, listId);
-}
-
-KoListStyle::ListIdType KoListLevelProperties::listId() const
-{
- if (sizeof(KoListStyle::ListIdType) == sizeof(uint))
- return propertyUInt(KoListStyle::ListId);
- else
- return propertyULongLong(KoListStyle::ListId);
-}
-
-bool KoListLevelProperties::letterSynchronization() const
-{
- return propertyBoolean(KoListStyle::LetterSynchronization);
-}
-
-void KoListLevelProperties::setLetterSynchronization(bool on)
-{
- setProperty(KoListStyle::LetterSynchronization, on);
-}
-
-void KoListLevelProperties::setIndent(qreal value)
-{
- setProperty(KoListStyle::Indent, value);
-}
-
-qreal KoListLevelProperties::indent() const
-{
- return propertyDouble(KoListStyle::Indent);
-}
-
-void KoListLevelProperties::setMinimumDistance(qreal value)
-{
- setProperty(KoListStyle::MinimumDistance, value);
-}
-
-qreal KoListLevelProperties::minimumDistance() const
-{
- return propertyDouble(KoListStyle::MinimumDistance);
-}
-
-void KoListLevelProperties::setMargin(qreal value)
-{
- setProperty(KoListStyle::Margin, value);
-}
-
-qreal KoListLevelProperties::margin() const
-{
- return propertyDouble(KoListStyle::Margin);
-}
-
-void KoListLevelProperties::setTextIndent(qreal value)
-{
- setProperty(KoListStyle::TextIndent, value);
-}
-
-qreal KoListLevelProperties::textIndent() const
-{
- return propertyDouble(KoListStyle::TextIndent);
-}
-
-void KoListLevelProperties::setAlignmentMode(bool isLabelAlignmentMode)
-{
- setProperty(KoListStyle::AlignmentMode, isLabelAlignmentMode);
-}
-
-bool KoListLevelProperties::alignmentMode() const
-{
- return propertyBoolean(KoListStyle::AlignmentMode);
-}
-
-void KoListLevelProperties::setTabStopPosition(qreal value)
-{
- setProperty(KoListStyle::TabStopPosition,value);
-}
-
-qreal KoListLevelProperties::tabStopPosition() const
-{
- return propertyDouble(KoListStyle::TabStopPosition);
-}
-
-void KoListLevelProperties::setLabelFollowedBy(KoListStyle::ListLabelFollowedBy value)
-{
- setProperty(KoListStyle::LabelFollowedBy, value);
-}
-
-KoListStyle::ListLabelFollowedBy KoListLevelProperties::labelFollowedBy() const
-{
- return (KoListStyle::ListLabelFollowedBy)propertyInt(KoListStyle::LabelFollowedBy);
-}
-
-void KoListLevelProperties::setOutlineList(bool isOutline)
-{
- setProperty(KoListStyle::IsOutline, isOutline);
-}
-
-bool KoListLevelProperties::isOutlineList() const
-{
- return propertyBoolean(KoListStyle::IsOutline);
-}
-
-// static
-KoListLevelProperties KoListLevelProperties::fromTextList(QTextList *list)
-{
- KoListLevelProperties llp;
- if (!list) {
- llp.setStyle(KoListStyle::None);
- return llp;
- }
- llp.d->stylesPrivate = list->format().properties();
- return llp;
-}
-
-void KoListLevelProperties::onStyleChanged(int key)
-{
- int bullet=KoListStyle::bulletCharacter(key);
- if (bullet != 0)
- setBulletCharacter(QChar(bullet));
-
- //for numbered list the relative bullet size is made 100
- if (KoListStyle::isNumberingStyle(key)) {
- setRelativeBulletSize(100);
- }
-}
-
-void KoListLevelProperties::loadOdf(KoShapeLoadingContext& scontext, const KoXmlElement& style)
-{
- KoOdfLoadingContext &context = scontext.odfLoadingContext();
-
- // The text:level attribute specifies the level of the number list
- // style. It can be used on all list-level styles.
- const int level = qMax(1, style.attributeNS(KoXmlNS::text, "level", QString()).toInt());
- // The text:display-levels attribute specifies the number of
- // levels whose numbers are displayed at the current level.
- const QString displayLevel = style.attributeNS(KoXmlNS::text,
- "display-levels", QString());
-
- const QString styleName = style.attributeNS(KoXmlNS::text, "style-name", QString());
- KoCharacterStyle *cs = 0;
- if (!styleName.isEmpty()) {
-// debugText << "Should use the style =>" << styleName << "<=";
-
- KoSharedLoadingData *sharedData = scontext.sharedData(KOTEXT_SHARED_LOADING_ID);
- KoTextSharedLoadingData *textSharedData = 0;
- if (sharedData) {
- textSharedData = dynamic_cast<KoTextSharedLoadingData *>(sharedData);
- }
- if (textSharedData) {
- cs = textSharedData->characterStyle(styleName, context.useStylesAutoStyles());
- if (!cs) {
- warnText << "Missing KoCharacterStyle!";
- }
- else {
-// debugText << "==> cs.name:" << cs->name();
-// debugText << "==> cs.styleId:" << cs->styleId();
- setCharacterStyleId(cs->styleId());
- }
- }
- }
-
- if (style.localName() == "list-level-style-bullet") { // list with bullets
- // special case bullets:
- //debugText << QChar(0x2202) << QChar(0x25CF) << QChar(0xF0B7) << QChar(0xE00C)
- //<< QChar(0xE00A) << QChar(0x27A2)<< QChar(0x2794) << QChar(0x2714) << QChar(0x2d) << QChar(0x2717);
-
- //1.6: KoParagCounter::loadOasisListStyle
- QString bulletChar = style.attributeNS(KoXmlNS::text, "bullet-char", QString());
-// debugText << "style.localName()=" << style.localName() << "level=" << level << "displayLevel=" << displayLevel << "bulletChar=" << bulletChar;
- if (bulletChar.isEmpty()) { // list without any visible bullets
- setStyle(KoListStyle::CustomCharItem);
- setBulletCharacter(QChar());
- } else { // try to determinate the bullet we should use
- switch (bulletChar[0].unicode()) {
- case 0x2022: // bullet, a small disc -> circle
- setStyle(KoListStyle::Bullet);
- break;
- case 0x25CF: // black circle, large disc -> disc
- setStyle(KoListStyle::BlackCircle);
- break;
- case 0x25CB: //white circle, no fill
- setStyle(KoListStyle::CircleItem);
- break;
- case 0x25C6: // losange => rhombus
- setStyle(KoListStyle::RhombusItem);
- break;
- case 0x25A0: // square. Not in OASIS (reserved Unicode area!), but used in both OOo and kotext.
- setStyle(KoListStyle::SquareItem);
- break;
- case 0x27A2: // two-colors right-pointing triangle
- setStyle(KoListStyle::RightArrowHeadItem);
- break;
- case 0x2794: // arrow to right
- setStyle(KoListStyle::RightArrowItem);
- break;
- case 0x2714: // checkmark
- setStyle(KoListStyle::HeavyCheckMarkItem);
- break;
- case 0x2d: // minus
- setStyle(KoListStyle::CustomCharItem);
- break;
- case 0x2717: // cross
- setStyle(KoListStyle::BallotXItem);
- break;
- default:
- QChar customBulletChar = bulletChar[0];
- debugText << "Unhandled bullet code 0x" << QString::number((uint)customBulletChar.unicode(), 16) << bulletChar;
- debugText << "Should use the style =>" << style.attributeNS(KoXmlNS::text, "style-name", QString()) << "<=";
- setStyle(KoListStyle::CustomCharItem);
- /*
- QString customBulletFont;
- // often StarSymbol when it comes from OO; doesn't matter, Qt finds it in another font if needed.
- if ( listStyleProperties.hasAttributeNS( KoXmlNS::style, "font-name" ) )
- {
- customBulletFont = listStyleProperties.attributeNS( KoXmlNS::style, "font-name", QString() );
- debugText <<"customBulletFont style:font-name =" << listStyleProperties.attributeNS( KoXmlNS::style,"font-name", QString() );
- }
- else if ( listStyleTextProperties.hasAttributeNS( KoXmlNS::fo, "font-family" ) )
- {
- customBulletFont = listStyleTextProperties.attributeNS( KoXmlNS::fo, "font-family", QString() );
- debugText <<"customBulletFont fo:font-family =" << listStyleTextProperties.attributeNS( KoXmlNS::fo,"font-family", QString() );
- }
- // ## TODO in fact we're supposed to read it from the style pointed to by text:style-name
- */
-// setStyle(KoListStyle::BoxItem); //fallback
- break;
- } // switch
- setBulletCharacter(bulletChar[0]);
- }
- QString size = style.attributeNS(KoXmlNS::text, "bullet-relative-size", QString());
- if (!size.isEmpty()) {
- setRelativeBulletSize(size.remove('%').toInt());
- }
-
- } else if (style.localName() == "list-level-style-number" || style.localName() == "outline-level-style") { // it's a numbered list
-
- if (style.localName() == "outline-level-style") {
- setOutlineList(true);
- }
- setRelativeBulletSize(100); //arbitrary value for numbered list
-
- KoOdfNumberDefinition numberDefinition;
- numberDefinition.loadOdf(style);
-
- switch(numberDefinition.formatSpecification()) {
- case KoOdfNumberDefinition::Empty:
- setStyle(KoListStyle::None);
- break;
- case KoOdfNumberDefinition::AlphabeticLowerCase:
- setStyle(KoListStyle::AlphaLowerItem);
- break;
- case KoOdfNumberDefinition::AlphabeticUpperCase:
- setStyle(KoListStyle::UpperAlphaItem);
- break;
- case KoOdfNumberDefinition::RomanLowerCase:
- setStyle(KoListStyle::RomanLowerItem);
- break;
- case KoOdfNumberDefinition::RomanUpperCase:
- setStyle(KoListStyle::UpperRomanItem);
- break;
- case KoOdfNumberDefinition::ArabicAlphabet:
- setStyle(KoListStyle::ArabicAlphabet);
- break;
- case KoOdfNumberDefinition::Thai:
- setStyle(KoListStyle::Thai);
- break;
- case KoOdfNumberDefinition::Abjad:
- setStyle(KoListStyle::Abjad);
- break;
- case KoOdfNumberDefinition::AbjadMinor:
- setStyle(KoListStyle::AbjadMinor);
- break;
- case KoOdfNumberDefinition::Tibetan:
- setStyle(KoListStyle::Tibetan);
- break;
- case KoOdfNumberDefinition::Telugu:
- setStyle(KoListStyle::Telugu);
- break;
- case KoOdfNumberDefinition::Tamil:
- setStyle(KoListStyle::Tamil);
- break;
- case KoOdfNumberDefinition::Oriya:
- setStyle(KoListStyle::Oriya);
- break;
- case KoOdfNumberDefinition::Malayalam:
- setStyle(KoListStyle::Malayalam);
- break;
- case KoOdfNumberDefinition::Kannada:
- setStyle(KoListStyle::Kannada);
- break;
- case KoOdfNumberDefinition::Gurumukhi:
- setStyle(KoListStyle::Gurumukhi);
- break;
- case KoOdfNumberDefinition::Gujarati:
- setStyle(KoListStyle::Gujarati);
- break;
- case KoOdfNumberDefinition::Bengali:
- setStyle(KoListStyle::Bengali);
- break;
- case KoOdfNumberDefinition::Numeric:
- default:
- setStyle(KoListStyle::DecimalItem);
- }
-
- if (!numberDefinition.prefix().isNull()) {
- setListItemPrefix(numberDefinition.prefix());
- }
-
- if (!numberDefinition.suffix().isNull()) {
- setListItemSuffix(numberDefinition.suffix());
- }
- const QString startValue = style.attributeNS(KoXmlNS::text, "start-value", QString("1"));
- setStartValue(startValue.toInt());
- }
- else if (style.localName() == "list-level-style-image") { // list with image
- setStyle(KoListStyle::ImageItem);
- KoImageCollection *imageCollection = scontext.imageCollection();
- const QString href = style.attribute("href");
- if(imageCollection) {
- if (!href.isEmpty()) {
- KoStore *store = context.store();
- setBulletImage(imageCollection->createImageData(href, store));
- } else {
- // check if we have an office:binary data element containing the image data
- const KoXmlElement &binaryData(KoXml::namedItemNS(style, KoXmlNS::office, "binary-data"));
- if (!binaryData.isNull()) {
- QImage image;
- if (image.loadFromData(QByteArray::fromBase64(binaryData.text().toLatin1()))) {
- setBulletImage(imageCollection->createImageData(image));
- }
- }
- }
- }
- }
- else { // if not defined, we have do nothing
-// debugText << "stylename else:" << style.localName() << "level=" << level << "displayLevel=" << displayLevel;
- setStyle(KoListStyle::DecimalItem);
- setListItemSuffix(".");
- }
-
- setLevel(level);
- if (!displayLevel.isEmpty())
- setDisplayLevel(displayLevel.toInt());
-
- KoXmlElement property;
- forEachElement(property, style) {
- if (property.namespaceURI() != KoXmlNS::style)
- continue;
- const QString localName = property.localName();
- if (localName == "list-level-properties") {
- QString mode(property.attributeNS(KoXmlNS::text, "list-level-position-and-space-mode"));
- if (mode == "label-alignment") {
- QString textAlign(property.attributeNS(KoXmlNS::fo, "text-align"));
- setAlignment(textAlign.isEmpty() ? Qt::AlignLeft : KoText::alignmentFromString(textAlign));
-
- KoXmlElement p;
- forEachElement(p, property) {
- if (p.namespaceURI() == KoXmlNS::style && p.localName() == "list-level-label-alignment") {
- // The <style:list-level-label-alignment> element and the fo:text-align attribute are used to define
- // the position and spacing of the list label and the list item. The values of the attributes for
- // text:space-before, text:min-label-width and text:min-label-distance are assumed to be 0.
- setAlignmentMode(true);
-
- QString textindent(p.attributeNS(KoXmlNS::fo, "text-indent"));
- QString marginleft(p.attributeNS(KoXmlNS::fo, "margin-left"));
- qreal ti = textindent.isEmpty() ? 0 : KoUnit::parseValue(textindent);
- qreal ml = marginleft.isEmpty() ? 0 : KoUnit::parseValue(marginleft);
- setTextIndent(ti);
- setMargin(ml);
-
- QString labelFollowedBy(p.attributeNS(KoXmlNS::text, "label-followed-by","space"));
- if(labelFollowedBy.compare("listtab",Qt::CaseInsensitive)==0) {
-
- setLabelFollowedBy(KoListStyle::ListTab);
-
- // list tab position is evaluated only if label is followed by listtab
- // the it is only evaluated if there is a list-tab-stop-position specified
- // if not specified use the fo:margin-left:
- QString tabStop(p.attributeNS(KoXmlNS::text, "list-tab-stop-position"));
- if (!tabStop.isEmpty()) {
- qreal tabStopPos = KoUnit::parseValue(tabStop);
- setTabStopPosition(qMax<qreal>(0.0, tabStopPos));
- }
-
- }else if(labelFollowedBy.compare("nothing",Qt::CaseInsensitive)==0) {
-
- setLabelFollowedBy(KoListStyle::Nothing);
-
- }else {
-
- setLabelFollowedBy(KoListStyle::Space);
-
- }
-
- setMinimumWidth(0);
- setMinimumDistance(0);
-
- //TODO support ODF 18.829 text:label-followed-by and 18.832 text:list-tab-stop-position
- }
- }
- }
-
- if(alignmentMode()!=true ){ // default is mode == "label-width-and-position"
- // The text:space-before, text:min-label-width, text:minimum-label-distance and fo:text-align attributes
- // are used to define the position and spacing of the list label and the list item.
-
- setAlignmentMode(false);
-
- QString spaceBefore(property.attributeNS(KoXmlNS::text, "space-before"));
- if (!spaceBefore.isEmpty())
- setIndent(KoUnit::parseValue(spaceBefore));
-
- QString minLableWidth(property.attributeNS(KoXmlNS::text, "min-label-width"));
- if (!minLableWidth.isEmpty())
- setMinimumWidth(KoUnit::parseValue(minLableWidth));
-
- QString textAlign(property.attributeNS(KoXmlNS::fo, "text-align"));
- if (!textAlign.isEmpty())
- setAlignment(KoText::alignmentFromString(textAlign));
-
- QString minLableDistance(property.attributeNS(KoXmlNS::text, "min-label-distance"));
- if (!minLableDistance.isEmpty())
- setMinimumDistance(KoUnit::parseValue(minLableDistance));
- }
-
- QString width(property.attributeNS(KoXmlNS::fo, "width"));
- if (!width.isEmpty())
- setWidth(KoUnit::parseValue(width));
-
- QString height(property.attributeNS(KoXmlNS::fo, "height"));
- if (!height.isEmpty())
- setHeight(KoUnit::parseValue(height));
-
- } else if (localName == "text-properties") {
- QSharedPointer<KoCharacterStyle> charStyle(new KoCharacterStyle);
- charStyle->loadOdf(&style, scontext);
- setCharacterProperties(charStyle);
- }
- }
-}
-
-void KoListLevelProperties::saveOdf(KoXmlWriter *writer, KoShapeSavingContext &context) const
-{
- bool isNumber = KoListStyle::isNumberingStyle(d->stylesPrivate.value(QTextListFormat::ListStyle).toInt());
-
- if (isNumber || isOutlineList()) {
- if (isOutlineList()) {
- writer->startElement("text:outline-level-style"); } else {
- writer->startElement("text:list-level-style-number");
- }
-
- if (d->stylesPrivate.contains(KoListStyle::StartValue))
- writer->addAttribute("text:start-value", d->stylesPrivate.value(KoListStyle::StartValue).toInt());
- if (d->stylesPrivate.contains(KoListStyle::DisplayLevel))
- writer->addAttribute("text:display-levels", d->stylesPrivate.value(KoListStyle::DisplayLevel).toInt());
-
- QByteArray format;
- switch (style()) {
- case KoListStyle::DecimalItem: format = "1"; break;
- case KoListStyle::AlphaLowerItem: format = "a"; break;
- case KoListStyle::UpperAlphaItem: format = "A"; break;
- case KoListStyle::RomanLowerItem: format = "i"; break;
- case KoListStyle::UpperRomanItem: format = "I"; break;
- case KoListStyle::ArabicAlphabet: format = "أ, ب, ت, ..."; break;
- case KoListStyle::Thai: format = "ก, ข, ค, ..."; break;
- case KoListStyle::Abjad: format = "أ, ب, ج, ..."; break;
- case KoListStyle::AbjadMinor: format = "ﺃ,ﺏ, ﺝ, ... "; break;
- case KoListStyle::Telugu: format = "౧, ౨, ౩, ..."; break;
- case KoListStyle::Tamil: format = "௧, ௨, ௪, ..."; break;
- case KoListStyle::Oriya: format = "୧, ୨, ୩, ..."; break;
- case KoListStyle::Malayalam: format = "൧, ൨, ൩, ..."; break;
- case KoListStyle::Kannada: format = "೧, ೨, ೩, ..."; break;
- case KoListStyle::Gurumukhi: format = "੧, ੨, ੩, ..."; break;
- case KoListStyle::Gujarati: format = "૧, ૨, ૩, ..."; break;
- case KoListStyle::Bengali: format = "১, ২, ৩, ..."; break;
- default: format = ""; break;
- }
- writer->addAttribute("style:num-format", format);
- }
- else if (style() == KoListStyle::ImageItem) {
- KoImageData *imageData = d->stylesPrivate.value(KoListStyle::BulletImage).value<KoImageData *>();
- if (imageData && imageData->priv()->collection) {
- writer->startElement("text:list-level-style-image");
- writer->addAttribute("xlink:show", "embed");
- writer->addAttribute("xlink:actuate", "onLoad");
- writer->addAttribute("xlink:type", "simple");
- writer->addAttribute("xlink:href", context.imageHref(imageData));
- context.addDataCenter(imageData->priv()->collection);
- }
- }
- else {
- writer->startElement("text:list-level-style-bullet");
-
- int bullet;
- if (d->stylesPrivate.contains(KoListStyle::BulletCharacter)) {
- bullet = d->stylesPrivate.value(KoListStyle::BulletCharacter).toInt();
- } else { // try to determine the bullet character from the style
- bullet = KoListStyle::bulletCharacter(style());
- }
- writer->addAttribute("text:bullet-char", QChar(bullet));
- }
-
- KoTextSharedSavingData *sharedSavingData = 0;
- if (d->stylesPrivate.contains(KoListStyle::CharacterStyleId) && (characterStyleId() != 0) &&
- (sharedSavingData = static_cast<KoTextSharedSavingData *>(context.sharedData(KOTEXT_SHARED_SAVING_ID)))) {
- QString styleName = sharedSavingData->styleName(characterStyleId());
- // dynamic_cast<KoTextSharedSavingData *>(context.sharedData(KOTEXT_SHARED_SAVING_ID))->styleName(characterStyleId());
- if (!styleName.isEmpty()) {
- writer->addAttribute("text:style-name", styleName);
- }
- }
-
- // These apply to bulleted and numbered lists
- if (d->stylesPrivate.contains(KoListStyle::Level))
- writer->addAttribute("text:level", d->stylesPrivate.value(KoListStyle::Level).toInt());
- if (d->stylesPrivate.contains(KoListStyle::ListItemPrefix))
- writer->addAttribute("style:num-prefix", d->stylesPrivate.value(KoListStyle::ListItemPrefix).toString());
- if (d->stylesPrivate.contains(KoListStyle::ListItemSuffix))
- writer->addAttribute("style:num-suffix", d->stylesPrivate.value(KoListStyle::ListItemSuffix).toString());
-
- writer->startElement("style:list-level-properties", false);
-
- if (d->stylesPrivate.contains(KoListStyle::Width)) {
- writer->addAttribute("fo:width", width());
- }
- if (d->stylesPrivate.contains(KoListStyle::Height)) {
- writer->addAttribute("fo:height", height());
- }
-
- if(d->stylesPrivate.contains(KoListStyle::AlignmentMode) && alignmentMode()==false) {
-
- writer->addAttribute("text:list-level-position-and-space-mode","label-width-and-position");
-
- if (d->stylesPrivate.contains(KoListStyle::Indent))
- writer->addAttribute("text:space-before", indent());
-
- if (d->stylesPrivate.contains(KoListStyle::MinimumWidth))
- writer->addAttribute("text:min-label-width", minimumWidth());
-
- if (d->stylesPrivate.contains(KoListStyle::Alignment))
- writer->addAttribute("fo:text-align", KoText::alignmentToString(alignment()));
-
- if (d->stylesPrivate.contains(KoListStyle::MinimumDistance))
- writer->addAttribute("text:min-label-distance", minimumDistance());
- } else {
- writer->addAttribute("text:list-level-position-and-space-mode","label-alignment");
-
- if (d->stylesPrivate.contains(KoListStyle::Alignment))
- writer->addAttribute("fo:text-align", KoText::alignmentToString(alignment()));
-
- writer->startElement("style:list-level-label-alignment");
-
- if(labelFollowedBy()==KoListStyle::ListTab) {
- writer->addAttribute("text:label-followed-by","listtab");
- writer->addAttribute("text:list-tab-stop-position", tabStopPosition());
- } else if (labelFollowedBy()==KoListStyle::Nothing){
- writer->addAttribute("text:label-followed-by","nothing");
- }else{
- writer->addAttribute("text:label-followed-by","space");
- }
-
- writer->addAttribute("fo:text-indent", textIndent());
- writer->addAttribute("fo:margin-left", margin());
-
- writer->endElement();
- }
-
- writer->endElement(); // list-level-properties
-
- // text properties
-
- if (d->stylesPrivate.contains(KoListStyle::CharacterProperties)) {
- KoGenStyle liststyle(KoGenStyle::ListStyle);
-
- QSharedPointer<KoCharacterStyle> cs = characterProperties();
- cs->saveOdf(liststyle);
-
- liststyle.writeStyleProperties(writer, KoGenStyle::TextType);
- }
-
-// debugText << "Key KoListStyle::ListItemPrefix :" << d->stylesPrivate.value(KoListStyle::ListItemPrefix);
-// debugText << "Key KoListStyle::ListItemSuffix :" << d->stylesPrivate.value(KoListStyle::ListItemSuffix);
-// debugText << "Key KoListStyle::CharacterStyleId :" << d->stylesPrivate.value(KoListStyle::CharacterStyleId);
-// debugText << "Key KoListStyle::RelativeBulletSize :" << d->stylesPrivate.value(KoListStyle::RelativeBulletSize);
-// debugText << "Key KoListStyle::Alignment :" << d->stylesPrivate.value(KoListStyle::Alignment);
-// debugText << "Key KoListStyle::LetterSynchronization :" << d->stylesPrivate.value(KoListStyle::LetterSynchronization);
-
- writer->endElement();
-}
diff --git a/plugins/flake/textshape/kotext/styles/KoListLevelProperties.h b/plugins/flake/textshape/kotext/styles/KoListLevelProperties.h
deleted file mode 100644
index d333bbee96..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoListLevelProperties.h
+++ /dev/null
@@ -1,217 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2010 Nandita Suri <suri.nandita@gmail.com>
- * Copyright (C) 2011-2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 KOLISTLEVELPROPERTIES_H
-#define KOLISTLEVELPROPERTIES_H
-
-#include "KoListStyle.h"
-
-#include <KoXmlReader.h>
-
-class KoCharacterStyle;
-class KoShapeLoadingContext;
-class KoShapeSavingContext;
-class KoXmlWriter;
-class KoImageData;
-
-class QTextList;
-
-/**
- * Properties per list level.
- */
-class KRITATEXT_EXPORT KoListLevelProperties : public QObject
-{
- Q_OBJECT
-public:
- /// Constructor
- explicit KoListLevelProperties();
- /// Copy constructor
- KoListLevelProperties(const KoListLevelProperties &other);
- /// Destructor
- ~KoListLevelProperties() override;
-
- /// each style has a unique ID (non persistent) given out by the styleManager
- int styleId() const;
- /// each style has a unique ID (non persistent) given out by the styleManager
- void setStyleId(int id);
-
- /// set the style to be used for this list-level.
- void setStyle(KoListStyle::Style style);
- /// return the used style
- KoListStyle::Style style() const;
- /// set the string that will be shown before the counter in the list label
- void setListItemPrefix(const QString &prefix);
- /// return the string that will be shown before the counter in the list label
- QString listItemPrefix() const;
- /// set the string that will be shown after the counter in the list label
- void setListItemSuffix(const QString &suffix);
- /// return the string that will be shown after the counter in the list label
- QString listItemSuffix() const;
- /// set the index of the first value of this whole list.
- void setStartValue(int value);
- /// return the index of the first value of this whole list.
- int startValue() const;
- /// set the list level which is how deep the counter is nested below other lists (should be >=1)
- void setLevel(int level);
- /// return the list level which is how deep the counter is nested below other lists
- int level() const;
- /// set the amount of levels that will be shown in list items of this list.
- void setDisplayLevel(int level);
- /// return the amount of levels that will be shown in list items of this list.
- int displayLevel() const;
- /// set the styleId of the KoCharacterStyle to be used to layout the listitem
- void setCharacterStyleId(int id);
- /// return the styleId of the KoCharacterStyle to be used to layout the listitem
- int characterStyleId() const;
- /// set the style for the bullet or the number of the list
- void setCharacterProperties(QSharedPointer<KoCharacterStyle> style);
- /// return the KoCharacterStyle for the bullet or the number of the list
- QSharedPointer<KoCharacterStyle> characterProperties() const;
- /// set the character to be used as the counter of the listitem
- void setBulletCharacter(QChar character);
- /// return the character to be used as the counter of the listitem
- QChar bulletCharacter() const;
- /// set the size, in percent, of the bullet counter relative to the fontsize of the counter
- void setRelativeBulletSize(int percent);
- /// return the size, in percent, of the bullet counter relative to the fontsize of the counter
- int relativeBulletSize() const;
- /// set how the list label should be aligned in the width this list reserves for the listitems
- void setAlignment(Qt::Alignment align);
- /// return how the list label should be aligned in the width this list reserves for the listitems
- Qt::Alignment alignment() const;
- /// set the minimum width (in pt) of the list label for all items in this list
- void setMinimumWidth(qreal width);
- /// return the minimum width (in pt) of the list label for all items in this list
- qreal minimumWidth() const;
- /// set the width (in pt) of the image bullet
- void setWidth(qreal width);
- /// return the width (in pt) of the image bullet
- qreal width() const;
- /// set the height (in pt) of the image bullet
- void setHeight(qreal height);
- /// return the height (in pt) of the image bullet
- qreal height() const;
- /// set the bullet image key (as from the KoImageData)
- void setBulletImage(KoImageData *imageData);
- /// return the bullet image that is used in the list(as KoImageData)
- KoImageData *bulletImage() const;
-
- /// set the listId used by all list-styles that together make 1 user defined list in an ODF file.
- void setListId(KoListStyle::ListIdType listId);
- /// return the listId used by all list-styles that together make 1 user defined list in an ODF file.
- KoListStyle::ListIdType listId() const;
- /**
- * For alpha-based lists numbers above the 'z' will increase the value of all characters at the same time.
- * If true; we get the sequence 'aa', 'bb', 'cc'. If false; 'aa', 'ab', 'ac'.
- * @return if letterSynchronization should be applied.
- */
- bool letterSynchronization() const;
- /**
- * For alpha-based lists numbers above the 'z' will increase the value of all characters at the same time.
- * If true; we get the sequence 'aa', 'bb', 'cc'. If false; 'aa', 'ab', 'ac'.
- * @param on if letterSynchronization should be applied.
- */
- void setLetterSynchronization(bool on);
-
- /// sets the indentation of paragraph
- void setIndent(qreal value);
- /// returns the indentation of paragraphs
- qreal indent() const;
-
- /// sets the minimum distance between the counter and the text
- void setMinimumDistance(qreal value);
- /// returns the minimum distance between the counter and text
- qreal minimumDistance() const;
-
- /// sets the margin of the list
- void setMargin(qreal value);
- /// returns the margin of the list
- qreal margin() const;
-
- /// sets the text indent of the list item
- void setTextIndent(qreal value);
- /// returns the text indent of the list item
- qreal textIndent() const;
-
- /// set the item that follows the label; this is used if alignmentMode() is true
- void setLabelFollowedBy(KoListStyle::ListLabelFollowedBy value);
- /// returns the item that follows the label; this is used if alignmentMode() is true
- KoListStyle::ListLabelFollowedBy labelFollowedBy() const;
-
- /// sets the value of tab stop that follows the label, it is used only if ListLabelFollowedBy is ListTab
- void setTabStopPosition(qreal value);
- /// returns the value of tab stop that follows the label, it is used only if ListLabelFollowedBy is ListTab
- qreal tabStopPosition() const;
-
- /// sets the alignment mode of the list isLabelAlignmentMode=true if ist-level-position-and-space-mode=label-alignment
- void setAlignmentMode(bool isLabelAlignmentMode);
- /// return the alignment mode of the list isLabelAlignmentMode=true if ist-level-position-and-space-mode=label-alignment
- bool alignmentMode() const;
-
- void setOutlineList(bool isOutline);
- bool isOutlineList() const;
-
- bool operator==(const KoListLevelProperties &other) const;
- bool operator!=(const KoListLevelProperties &other) const;
- KoListLevelProperties & operator=(const KoListLevelProperties &other);
-
- /**
- * Create a KoListLevelProperties object from a QTextList instance.
- */
- static KoListLevelProperties fromTextList(QTextList *list);
-
- /**
- * Apply this style to a QTextListFormat by copying all properties from this style
- * to the target list format.
- */
- void applyStyle(QTextListFormat &format) const;
-
- /**
- * Load the properties from the \p style using the OpenDocument format.
- */
- void loadOdf(KoShapeLoadingContext& scontext, const KoXmlElement& style);
-
- /**
- * Save the properties of the style using the OpenDocument format
- */
- void saveOdf(KoXmlWriter *writer, KoShapeSavingContext &context) const;
-
-public Q_SLOTS:
- void onStyleChanged(int key);
-
-Q_SIGNALS:
- void styleChanged(int key);
-
-private:
- void setProperty(int key, const QVariant &value);
- int propertyInt(int key) const;
- uint propertyUInt(int key) const;
- qulonglong propertyULongLong(int key) const;
- bool propertyBoolean(int key) const;
- qreal propertyDouble(int key) const;
- QString propertyString(int key) const;
- QColor propertyColor(int key) const;
- QVariant property(int key) const;
-
- class Private;
- Private * const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/styles/KoListStyle.cpp b/plugins/flake/textshape/kotext/styles/KoListStyle.cpp
deleted file mode 100644
index 256a76663a..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoListStyle.cpp
+++ /dev/null
@@ -1,289 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2007-2010 Sebastian Sauer <mail@dipe.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2011-2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 "KoListStyle.h"
-
-#include "KoListLevelProperties.h"
-#include "KoList.h"
-
-#include <KoXmlNS.h>
-#include <KoXmlWriter.h>
-#include <KoGenStyle.h>
-#include "TextDebug.h"
-#include <QBuffer>
-
-class Q_DECL_HIDDEN KoListStyle::Private
-{
-public:
- Private() : styleId(0) { }
-
- QString name;
- int styleId;
- QMap<int, KoListLevelProperties> levels;
-};
-
-KoListStyle::KoListStyle(QObject *parent)
- : QObject(parent), d(new Private())
-{
-}
-
-KoListStyle::~KoListStyle()
-{
- delete d;
-}
-
-bool KoListStyle::operator==(const KoListStyle &other) const
-{
- Q_FOREACH (int level, d->levels.keys()) {
- if (! other.hasLevelProperties(level))
- return false;
- if (!(other.levelProperties(level) == d->levels[level]))
- return false;
- }
- Q_FOREACH (int level, other.d->levels.keys()) {
- if (! hasLevelProperties(level))
- return false;
- }
- return true;
-}
-
-bool KoListStyle::operator!=(const KoListStyle &other) const
-{
- return !KoListStyle::operator==(other);
-}
-
-void KoListStyle::copyProperties(KoListStyle *other)
-{
- d->styleId = other->d->styleId;
- d->levels = other->d->levels;
- setName(other->name());
-}
-
-KoListStyle *KoListStyle::clone(QObject *parent)
-{
- KoListStyle *newStyle = new KoListStyle(parent);
- newStyle->copyProperties(this);
- return newStyle;
-}
-
-QString KoListStyle::name() const
-{
- return d->name;
-}
-
-void KoListStyle::setName(const QString &name)
-{
- if (d->name == name)
- return;
- d->name = name;
- emit nameChanged(d->name);
-}
-
-int KoListStyle::styleId() const
-{
- return d->styleId;
-}
-
-void KoListStyle::setStyleId(int id)
-{
- d->styleId = id;
- Q_FOREACH (int level, d->levels.keys()) {
- d->levels[level].setStyleId(id);
- }
-}
-
-KoListLevelProperties KoListStyle::levelProperties(int level) const
-{
- if (d->levels.contains(level))
- return d->levels.value(level);
-
- level = qMax(1, level);
- if (d->levels.count()) {
- KoListLevelProperties llp = d->levels.begin().value();
- llp.setLevel(level);
- return llp;
- }
- KoListLevelProperties llp;
- llp.setLevel(level);
- if (d->styleId)
- llp.setStyleId(d->styleId);
- return llp;
-}
-
-QTextListFormat KoListStyle::listFormat(int level) const
-{
- KoListLevelProperties llp = levelProperties(level);
- QTextListFormat format;
- llp.applyStyle(format);
- return format;
-}
-
-void KoListStyle::setLevelProperties(const KoListLevelProperties &properties)
-{
- int level = qMax(1, properties.level());
- refreshLevelProperties(properties);
- emit styleChanged(level);
-}
-
-void KoListStyle::refreshLevelProperties(const KoListLevelProperties &properties)
-{
- int level = qMax(1, properties.level());
- KoListLevelProperties llp = properties;
- if (isOulineStyle()) {
- llp.setOutlineList(true);
- }
- llp.setLevel(level);
- d->levels.insert(level, llp);
-}
-
-bool KoListStyle::hasLevelProperties(int level) const
-{
- return d->levels.contains(level);
-}
-
-void KoListStyle::removeLevelProperties(int level)
-{
- d->levels.remove(level);
-}
-
-void KoListStyle::applyStyle(const QTextBlock &block, int level)
-{
- KoList::applyStyle(block, this, level);
-}
-
-void KoListStyle::loadOdf(KoShapeLoadingContext& scontext, const KoXmlElement& style)
-{
- d->name = style.attributeNS(KoXmlNS::style, "display-name", QString());
- // if no style:display-name is given us the style:name
- if (d->name.isEmpty()) {
- d->name = style.attributeNS(KoXmlNS::style, "name", QString());
- }
- d->name = style.attributeNS(KoXmlNS::style, "name", QString());
-
- KoXmlElement styleElem;
- forEachElement(styleElem, style) {
- KoListLevelProperties properties;
- properties.loadOdf(scontext, styleElem);
- if (d->styleId)
- properties.setStyleId(d->styleId);
- setLevelProperties(properties);
- }
-
- if (d->levels.isEmpty()) {
- KoListLevelProperties llp;
- llp.setLevel(1);
- llp.setStartValue(1);
- llp.setStyle(KoListStyle::DecimalItem);
- llp.setListItemSuffix(".");
- setLevelProperties(llp);
- }
-}
-
-void KoListStyle::saveOdf(KoGenStyle &style, KoShapeSavingContext &context) const
-{
- // style:display-name can be used in list styles but not in outline styles
- if (!d->name.isEmpty() && !style.isDefaultStyle() && !isOulineStyle()) {
- style.addAttribute("style:display-name", d->name);
- }
- QBuffer buffer;
- buffer.open(QIODevice::WriteOnly);
- KoXmlWriter elementWriter(&buffer); // TODO pass indentation level
- QMapIterator<int, KoListLevelProperties> it(d->levels);
- while (it.hasNext()) {
- it.next();
- it.value().saveOdf(&elementWriter, context);
- }
- QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
- style.addChildElement("text-list-level-style-content", elementContents);
-}
-
-bool KoListStyle::isNumberingStyle() const
-{
- QMap<int, KoListLevelProperties>::const_iterator it(d->levels.constBegin());
- for (; it != d->levels.constEnd(); ++it) {
- if (isNumberingStyle(it.value().style())) {
- return true;
- }
- }
- return false;
-}
-
-bool KoListStyle::isNumberingStyle(int style)
-{
- bool retval = true;
- switch (style) {
- case KoListStyle::SquareItem:
- case KoListStyle::DiscItem:
- case KoListStyle::CircleItem:
- case KoListStyle::None:
- case KoListStyle::Bullet:
- case KoListStyle::BlackCircle:
- case KoListStyle::BoxItem:
- case KoListStyle::RhombusItem:
- case KoListStyle::HeavyCheckMarkItem:
- case KoListStyle::BallotXItem:
- case KoListStyle::RightArrowItem:
- case KoListStyle::RightArrowHeadItem:
- case KoListStyle::CustomCharItem:
- case KoListStyle::ImageItem:
- retval = false;
- break;
- default:
- retval = true;
- }
- return retval;
-}
-
-bool KoListStyle::isOulineStyle() const
-{
- QMap<int, KoListLevelProperties>::const_iterator it(d->levels.constBegin());
- for (; it != d->levels.constEnd(); ++it) {
- if (it.value().isOutlineList()) {
- return true;
- }
- }
- return false;
-}
-
-QList<int> KoListStyle::listLevels() const
-{
- return d->levels.keys();
-}
-
-int KoListStyle::bulletCharacter(int style)
-{
- int bullet;
- switch (style) {
- case KoListStyle::Bullet: bullet = 0x2022; break;
- case KoListStyle::CircleItem: bullet = 0x25CB; break;
- case KoListStyle::RhombusItem: bullet = 0x25C6; break;
- case KoListStyle::SquareItem: bullet = 0x25A0; break;
- case KoListStyle::RightArrowHeadItem: bullet = 0x27A2; break;
- case KoListStyle::RightArrowItem: bullet = 0x2794; break;
- case KoListStyle::HeavyCheckMarkItem: bullet = 0x2714; break;
- case KoListStyle::BallotXItem: bullet = 0x2717; break;
- case KoListStyle::BlackCircle:
- case KoListStyle::DiscItem: bullet = 0x25CF; break;
- default: bullet = 0; break; //empty character
- }
- return bullet;
-}
diff --git a/plugins/flake/textshape/kotext/styles/KoListStyle.h b/plugins/flake/textshape/kotext/styles/KoListStyle.h
deleted file mode 100644
index 4c50de5c01..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoListStyle.h
+++ /dev/null
@@ -1,281 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2010 Nandita Suri <suri.nandita@gmail.com>
- * Copyright (C) 2011 Lukáš Tvrdý <lukas.tvrdy@ixonos.com>
- * Copyright (C) 2011-2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 KOLISTSTYLE_H
-#define KOLISTSTYLE_H
-
-#include "kritatext_export.h"
-
-#include <QTextFormat>
-#include <QTextListFormat>
-
-#include <KoXmlReader.h>
-
-class KoListLevelProperties;
-class KoShapeLoadingContext;
-class KoShapeSavingContext;
-class KoGenStyle;
-
-class QTextBlock;
-
-/**
- * This class groups all styling-options for lists.
- * See KoParagraphStyle::setListStyle()
- * The list-style represents several list-levels, where each level is represented by the
- * KoListLevelProperties class. The top most list level is 1.
- *
- * list level1
- * list level2
- * list level2
- * list level3
- * list level1
- *
- * A list-style as such represents cross paragraph relations. The most obvious evidence of this
- * is with a numbered list where a counter is automatically increased from one paragraph to the next.
- *
- * If the list is interrupted by a praragraph with another list-style the counting will start from
- * fresh when the list resumes. However you can set the list to continue if you like.
- *
- * Following from the above you can use the same paragraph style for several paragraphs and the
- * the counter will increase. If you want a paragraph to be on a sub level you do however need to
- * create a new paragraph-style when another listLevel set.
- */
-class KRITATEXT_EXPORT KoListStyle : public QObject
-{
- Q_OBJECT
- Q_ENUMS(Style Property)
-public:
- // ListIdType will be 32-bit in 32 bit machines and 64 bit in 64 bit machines
- typedef quintptr ListIdType;
-
- /// This list is used to specify what kind of list-style to use
- /// If you add a style to that list you also need to check if you need to update
- /// KoListStyle::isNumberingStyle(int)
- enum Style {
- /// Draw a square
- SquareItem = QTextListFormat::ListSquare,
- /// Draw a disc (filled circle) (aka bullet)
- DiscItem = QTextListFormat::ListDisc,
- /// Draw a disc (non-filled disk)
- CircleItem = QTextListFormat::ListCircle,
- /// use arabic numbering (1, 2, 3, ...)
- DecimalItem = QTextListFormat::ListDecimal,
- /// use alpha numbering (a, b, c, ... aa, ab, ...)
- AlphaLowerItem = QTextListFormat::ListLowerAlpha,
- /// use alpha numbering (A, B, C, ... AA, AB, ...)
- UpperAlphaItem = QTextListFormat::ListUpperAlpha,
- /// List style with no numbering
- None = 1,
- /// use lower roman counting. (i, ii, iii, iv, ...)
- RomanLowerItem,
- /// use upper roman counting. (I, II, III, IV, ...)
- UpperRomanItem,
- /// bullet, a small circle Unicode char U+2022
- Bullet,
- /// black circle, a large circle Unicode char U+25CF
- BlackCircle,
- /// draw a box
- BoxItem,
- /// rhombus, like a SquareItem but rotated by 45 degree
- RhombusItem,
- /// a check mark
- HeavyCheckMarkItem,
- /// a ballot x
- BallotXItem,
- /// heavy wide-headed rightwards arrow
- RightArrowItem,
- /// three-d top-lighted rightwards arrowhead
- RightArrowHeadItem,
- /// use an unicode char for the bullet
- CustomCharItem,
- Bengali, ///< Bengali characters for normal 10-base counting
- Gujarati, ///< Gujarati characters for normal 10-base counting
- Gurumukhi, ///< Gurumukhi characters for normal 10-base counting
- Kannada, ///< Kannada characters for normal 10-base counting
- Malayalam, ///< Malayalam characters for normal 10-base counting
- Oriya, ///< Oriya characters for normal 10-base counting
- Tamil, ///< Tamil characters for normal 10-base counting
- Telugu, ///< Telugu characters for normal 10-base counting
- Tibetan, ///< Tibetan characters for normal 10-base counting
- Thai, ///< Thai characters for normal 10-base counting
- Abjad, ///< Abjad sequence.
- AbjadMinor, ///< A lesser known version of the Abjad sequence.
- ArabicAlphabet, ///< Arabic alphabet.
- /// an image for the bullet
- ImageItem
-
- // TODO look at css 3 for things like hebrew counters
- };
-
- /// further properties
- enum Property {
- ListItemPrefix = QTextFormat::UserProperty + 1000, ///< The text to be printed before the listItem
- ListItemSuffix, ///< The text to be printed after the listItem
- StartValue, ///< First value to use
- Level, ///< list nesting level, is 1 or higher, or zero when implied
- DisplayLevel, ///< show this many levels. Is always lower than the (implied) level.
- CharacterStyleId,///< CharacterStyle used for markup of the counter
- CharacterProperties, ///< This stores the character properties of the list style
- BulletCharacter,///< an int with the unicode value of the character (for CustomCharItem)
- RelativeBulletSize, ///< size in percent relative to the height of the text
- Alignment, ///< Alignment of the counter
- MinimumWidth, ///< The minimum width, in pt, of the listItem including the prefix/suffix.
- ListId, ///< A group of lists together are called 1 (user intended) list in ODF. Store the listId here
- IsOutline, ///< If true then this list is an outline list (for header paragraphs)
- LetterSynchronization, ///< If letters are used for numbering, when true increment all at the same time. (aa, bb)
- StyleId, ///< The id stored in the listFormat to link the list to this style.
- Indent, ///< The space (margin) to include for all paragraphs
- MinimumDistance, ///< The minimum distance, in pt, between the counter and the text
- Width, ///< The width, in pt, of a picture bullet.
- Height, ///< The height, in pt, of a picture bullet.
- BulletImage, ///< Bullet image stored as a key for lookup in the imageCollection
- Margin, ///< Stores the margin of the list
- TextIndent, ///< Stores the text indent of list item
- AlignmentMode, ///< Is true if list-level-position-and-space-mode=label-alignment
- LabelFollowedBy, ///< Label followed by one of the enums ListLabelFollowedBy
- TabStopPosition ///< Specifies the additional tab stops
- };
-
- enum ListLabelFollowedBy
- {
- ListTab, ///< Label is followed by a list tab
- Space, ///< Label followed by a Space
- Nothing ///< Nothing is present between label and the text
- };
-
- /**
- * Constructor
- * Create a new list style which uses numbered (KoListStyle::ListDecimal) listitems.
- */
- explicit KoListStyle(QObject *parent = 0);
-
- /// Destructor
- ~KoListStyle() override;
-
- /// creates a clone of this style with the specified parent
- KoListStyle *clone(QObject *parent = 0);
-
- /// each style has a unique ID (non persistent) given out by the styleManager
- int styleId() const;
-
- /// each style has a unique ID (non persistent) given out by the styleManager
- void setStyleId(int id);
-
- /**
- * Return the properties for the specified list level.
- * A list style can contain properties for more than one level, when a paragraph is added to this list
- * it will be added at a certain level and it will then be using the properties of that level.
- * The gain from using one list style for multiple levels is in allowing a way to format the list label.
- * A list item which is of level '4' will be able to have a display level of up to 4, which means that not
- * only is the counter of the current level displayed, the counters of the higher levels can be displayed as
- * well.
- * Adding level properties for lower levels will have the effect that the counter of that level will be displayed
- * in the specified format instead of being inherited from the list style at the higher level.
- */
- KoListLevelProperties levelProperties(int level) const;
-
- /**
- * Set the properties for a level.
- * @param properties the new properties for the level, including the level number.
- * @see level()
- */
- void setLevelProperties(const KoListLevelProperties &properties);
-
- /**
- * @return if there are the properties for a level set.
- * @param level the level for which to check
- * @see level()
- */
- bool hasLevelProperties(int level) const;
-
- /**
- * Remove any properties that were set for a level.
- * @param level the level for which to remove
- * @see level()
- */
- void removeLevelProperties(int level);
-
- /// return a QTextListFormat that contains formatting information for the level.
- QTextListFormat listFormat(int level) const;
-
- /// return the configured list levels that hasLevelProperties would return true to.
- QList<int> listLevels() const;
-
- /// return the name of the style.
- QString name() const;
-
- /// set a user-visible name on the style.
- void setName(const QString &name);
-
- /**
- * Apply this style to a block by adding the block to the proper list.
- */
- void applyStyle(const QTextBlock &block, int level = 0);
-
- bool operator==(const KoListStyle &other) const;
- bool operator!=(const KoListStyle &other) const;
-
- /**
- * Load the style from the \a KoStyleStack style stack using the
- * OpenDocument format.
- */
- void loadOdf(KoShapeLoadingContext& context, const KoXmlElement& style = KoXmlElement());
-
- /**
- * Save the style to a KoGenStyle object using the OpenDocument format
- */
- void saveOdf(KoGenStyle &style, KoShapeSavingContext &context) const;
-
- /// copy all the properties from the other style to this style, effectively duplicating it.
- void copyProperties(KoListStyle *other);
-
- /**
- * Check if list has numbering in one of it's list levels
- */
- bool isNumberingStyle() const;
-
- /**
- * Returns true if this list style is a outline style
- */
- bool isOulineStyle() const;
-
- /// returns true if style is a numbering style
- static bool isNumberingStyle(int style);
-
- static int bulletCharacter(int style);
-Q_SIGNALS:
- void nameChanged(const QString &newName);
- void styleChanged(int level);
-
-private:
- friend class ChangeListCommand;
- friend class ChangeListLevelCommand;
-
- void refreshLevelProperties(const KoListLevelProperties &properties);
-
- class Private;
- Private * const d;
-};
-
-Q_DECLARE_METATYPE(KoListStyle *)
-
-#endif
diff --git a/plugins/flake/textshape/kotext/styles/KoParagraphStyle.cpp b/plugins/flake/textshape/kotext/styles/KoParagraphStyle.cpp
deleted file mode 100644
index bede0385b6..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoParagraphStyle.cpp
+++ /dev/null
@@ -1,2367 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2007,2008 Sebastian Sauer <mail@dipe.org>
- * Copyright (C) 2007-2011 Pierre Ducroquet <pinaraf@pinaraf.info>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Roopesh Chander <roop@forwardbias.in>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 "KoParagraphStyle.h"
-
-#include "KoList.h"
-#include "KoListStyle.h"
-#include "KoTextBlockData.h"
-#include "KoStyleManager.h"
-#include "KoListLevelProperties.h"
-#include "KoTextSharedLoadingData.h"
-#include <KoShapeLoadingContext.h>
-#include <KoShapeSavingContext.h>
-#include <KoGenStyle.h>
-#include <KoGenStyles.h>
-#include "Styles_p.h"
-#include "KoTextDocument.h"
-
-#include "TextDebug.h"
-
-#include <QTextBlock>
-#include <QTextBlockFormat>
-#include <QTextCursor>
-#include <QBuffer>
-
-#include <KoUnit.h>
-#include <KoStyleStack.h>
-#include <KoOdfLoadingContext.h>
-#include <KoXmlNS.h>
-#include <KoXmlWriter.h>
-#include <KoBorder.h>
-#include <KoShadowStyle.h>
-
-//already defined in KoRulerController.cpp
-#ifndef KDE_USE_FINAL
-struct {
- bool operator()(KoText::Tab tab1, KoText::Tab tab2) const
- {
- return tab1.position < tab2.position;
- }
-} compareTabs;
-#endif
-class Q_DECL_HIDDEN KoParagraphStyle::Private
-{
-public:
- Private() : parentStyle(0), defaultStyle(0), list(0), m_inUse(false) {}
-
- ~Private()
- {
- }
-
- void setProperty(int key, const QVariant &value)
- {
- stylesPrivate.add(key, value);
- }
-
- void ensureDefaults(QTextBlockFormat &format)
- {
- if (defaultStyle) {
- QMap<int, QVariant> props = defaultStyle->d->stylesPrivate.properties();
- QMap<int, QVariant>::const_iterator it = props.constBegin();
- while (it != props.constEnd()) {
- if (!it.value().isNull() && !format.hasProperty(it.key())) {
- format.setProperty(it.key(), it.value());
- }
- ++it;
- }
- }
- }
-
- QString name;
- KoParagraphStyle *parentStyle;
- KoParagraphStyle *defaultStyle;
- KoList *list;
- StylePrivate stylesPrivate;
- bool m_inUse;
-};
-
-KoParagraphStyle::KoParagraphStyle(QObject *parent)
- : KoCharacterStyle(parent), d(new Private())
-{
-}
-
-KoParagraphStyle::KoParagraphStyle(const QTextBlockFormat &blockFormat, const QTextCharFormat &blockCharFormat, QObject *parent)
- : KoCharacterStyle(blockCharFormat, parent),
- d(new Private())
-{
- d->stylesPrivate = blockFormat.properties();
-}
-
-KoParagraphStyle *KoParagraphStyle::fromBlock(const QTextBlock &block, QObject *parent)
-{
- QTextBlockFormat blockFormat = block.blockFormat();
- QTextCursor cursor(block);
- KoParagraphStyle *answer = new KoParagraphStyle(blockFormat, cursor.blockCharFormat(), parent);
-
- int listStyleId = blockFormat.intProperty(ListStyleId);
- KoStyleManager *sm = KoTextDocument(block.document()).styleManager();
- if (KoListStyle *listStyle = sm->listStyle(listStyleId)) {
- answer->setListStyle(listStyle->clone(answer));
- } else if (block.textList()) {
- KoListLevelProperties llp = KoListLevelProperties::fromTextList(block.textList());
- KoListStyle *listStyle = new KoListStyle(answer);
- listStyle->setLevelProperties(llp);
- answer->setListStyle(listStyle);
- }
- return answer;
-}
-
-KoParagraphStyle::~KoParagraphStyle()
-{
- delete d;
-}
-
-KoCharacterStyle::Type KoParagraphStyle::styleType() const
-{
- return KoCharacterStyle::ParagraphStyle;
-}
-
-void KoParagraphStyle::setDefaultStyle(KoParagraphStyle *defaultStyle)
-{
- d->defaultStyle = defaultStyle;
- KoCharacterStyle::setDefaultStyle(defaultStyle);
-}
-
-void KoParagraphStyle::setParentStyle(KoParagraphStyle *parent)
-{
- d->parentStyle = parent;
- KoCharacterStyle::setParentStyle(parent);
-}
-
-void KoParagraphStyle::setProperty(int key, const QVariant &value)
-{
- if (d->parentStyle) {
- QVariant var = d->parentStyle->value(key);
- if (!var.isNull() && var == value) { // same as parent, so its actually a reset.
- d->stylesPrivate.remove(key);
- return;
- }
- }
- d->stylesPrivate.add(key, value);
-}
-
-void KoParagraphStyle::remove(int key)
-{
- d->stylesPrivate.remove(key);
-}
-
-QVariant KoParagraphStyle::value(int key) const
-{
- QVariant var = d->stylesPrivate.value(key);
- if (var.isNull()) {
- if (d->parentStyle)
- return d->parentStyle->value(key);
- else if (d->defaultStyle)
- return d->defaultStyle->value(key);
- }
- return var;
-}
-
-bool KoParagraphStyle::hasProperty(int key) const
-{
- return d->stylesPrivate.contains(key);
-}
-
-qreal KoParagraphStyle::propertyDouble(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull())
- return 0.0;
- return variant.toDouble();
-}
-
-QTextLength KoParagraphStyle::propertyLength(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull())
- return QTextLength(QTextLength::FixedLength, 0.0);
- if (!variant.canConvert<QTextLength>())
- {
- // Fake support, for compatibility sake
- if (variant.canConvert<qreal>())
- {
- return QTextLength(QTextLength::FixedLength, variant.toReal());
- }
-
- warnText << "This should never happen : requested property can't be converted to QTextLength";
- return QTextLength(QTextLength::FixedLength, 0.0);
- }
- return variant.value<QTextLength>();
-}
-
-int KoParagraphStyle::propertyInt(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull())
- return 0;
- return variant.toInt();
-}
-
-bool KoParagraphStyle::propertyBoolean(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull())
- return false;
- return variant.toBool();
-}
-
-QColor KoParagraphStyle::propertyColor(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull()) {
- return QColor();
- }
- return qvariant_cast<QColor>(variant);
-}
-
-void KoParagraphStyle::applyStyle(QTextBlockFormat &format) const
-{
- if (d->parentStyle) {
- d->parentStyle->applyStyle(format);
- }
-
- const QMap<int, QVariant> props = d->stylesPrivate.properties();
- QMap<int, QVariant>::const_iterator it = props.begin();
- while (it != props.end()) {
- if (it.key() == QTextBlockFormat::BlockLeftMargin) {
- format.setLeftMargin(leftMargin());
- } else if (it.key() == QTextBlockFormat::BlockRightMargin) {
- format.setRightMargin(rightMargin());
- } else if (it.key() == QTextBlockFormat::TextIndent) {
- format.setTextIndent(textIndent());
- } else {
- format.setProperty(it.key(), it.value());
- }
- ++it;
- }
- if ((hasProperty(DefaultOutlineLevel)) && (!format.hasProperty(OutlineLevel))) {
- format.setProperty(OutlineLevel, defaultOutlineLevel());
- }
- emit styleApplied(this);
- d->m_inUse = true;
-}
-
-void KoParagraphStyle::applyStyle(QTextBlock &block, bool applyListStyle) const
-{
- QTextCursor cursor(block);
- QTextBlockFormat format = cursor.blockFormat();
- applyStyle(format);
- d->ensureDefaults(format);
- cursor.setBlockFormat(format);
-
- KoCharacterStyle::applyStyle(block);
-
- if (applyListStyle) {
- applyParagraphListStyle(block, format);
- }
-}
-
-bool KoParagraphStyle::isApplied() const
-{
- return d->m_inUse;
-}
-
-void KoParagraphStyle::applyParagraphListStyle(QTextBlock &block, const QTextBlockFormat &blockFormat) const
-{
- //gopalakbhat: We need to differentiate between normal styles and styles with outline(part of heading)
- //Styles part of outline: We ignore the listStyle()( even if this is a valid in ODF; even LibreOffice does the same)
- // since we can specify all info required in text:outline-style
- //Normal styles: we use the listStyle()
- if (blockFormat.hasProperty(OutlineLevel)) {
- if (! d->list) {
- if (! KoTextDocument(block.document()).headingList()) {
- if (KoTextDocument(block.document()).styleManager() && KoTextDocument(block.document()).styleManager()->outlineStyle()) {
- d->list = new KoList(block.document(), KoTextDocument(block.document()).styleManager()->outlineStyle());
- KoTextDocument(block.document()).setHeadingList(d->list);
- }
- } else {
- d->list = KoTextDocument(block.document()).headingList();
- }
- }
- if (d->list) {
- d->list->applyStyle(block, KoTextDocument(block.document()).styleManager()->outlineStyle(), blockFormat.intProperty(OutlineLevel));
- }
- } else {
- if (listStyle()) {
- if (!d->list) {
- d->list = new KoList(block.document(), listStyle());
- }
- //FIXME: Gopalakrishna Bhat A: This condition should never happen.
- // i.e. d->list->style() should always be in sync with the listStyle()
- if (d->list->style() != listStyle()) {
- d->list->setStyle(listStyle());
- }
- d->list->add(block, listLevel());
- } else {
- if (block.textList())
- block.textList()->remove(block);
- KoTextBlockData data(block);
- data.setCounterWidth(-1);
- }
- }
-}
-
-void KoParagraphStyle::unapplyStyle(QTextBlock &block) const
-{
- if (d->parentStyle)
- d->parentStyle->unapplyStyle(block);
-
- QTextCursor cursor(block);
- QTextBlockFormat format = cursor.blockFormat();
-
- QList<int> keys = d->stylesPrivate.keys();
- for (int i = 0; i < keys.count(); i++) {
- QVariant variant = d->stylesPrivate.value(keys[i]);
- if (keys[i] == QTextBlockFormat::BlockLeftMargin) {
- if (leftMargin() == format.property(keys[i]))
- format.clearProperty(keys[i]);
- } else if (keys[i] == QTextBlockFormat::BlockRightMargin) {
- if (rightMargin() == format.property(keys[i]))
- format.clearProperty(keys[i]);
- } else if (keys[i] == QTextBlockFormat::TextIndent) {
- if (textIndent() == format.property(keys[i]))
- format.clearProperty(keys[i]);
- } else {
- if (variant == format.property(keys[i]))
- format.clearProperty(keys[i]);
- }
- }
-
- format.clearProperty(KoParagraphStyle::OutlineLevel);
-
- cursor.setBlockFormat(format);
- KoCharacterStyle::unapplyStyle(block);
- if (listStyle() && block.textList()) { // TODO check its the same one?
- KoList::remove(block);
- }
- if (d->list && block.textList()) { // TODO check its the same one?
- KoList::remove(block);
- }
-}
-
-void KoParagraphStyle::setLineHeightPercent(qreal lineHeight)
-{
- setProperty(PercentLineHeight, lineHeight);
- setProperty(FixedLineHeight, 0.0);
- setProperty(MinimumLineHeight, QTextLength(QTextLength::FixedLength, 0.0));
- remove(NormalLineHeight);
-}
-
-qreal KoParagraphStyle::lineHeightPercent() const
-{
- return propertyInt(PercentLineHeight);
-}
-
-void KoParagraphStyle::setLineHeightAbsolute(qreal height)
-{
- setProperty(FixedLineHeight, height);
- setProperty(PercentLineHeight, 0);
- setProperty(MinimumLineHeight, QTextLength(QTextLength::FixedLength, 0.0));
- remove(NormalLineHeight);
-}
-
-qreal KoParagraphStyle::lineHeightAbsolute() const
-{
- return propertyDouble(FixedLineHeight);
-}
-
-void KoParagraphStyle::setMinimumLineHeight(const QTextLength &height)
-{
- setProperty(FixedLineHeight, 0.0);
- setProperty(PercentLineHeight, 0);
- setProperty(MinimumLineHeight, height);
- remove(NormalLineHeight);
-}
-
-qreal KoParagraphStyle::minimumLineHeight() const
-{
- if (parentStyle())
- return propertyLength(MinimumLineHeight).value(parentStyle()->minimumLineHeight());
- else
- return propertyLength(MinimumLineHeight).value(0);
-}
-
-void KoParagraphStyle::setLineSpacing(qreal spacing)
-{
- setProperty(LineSpacing, spacing);
- remove(NormalLineHeight);
-}
-
-qreal KoParagraphStyle::lineSpacing() const
-{
- return propertyDouble(LineSpacing);
-}
-
-void KoParagraphStyle::setLineSpacingFromFont(bool on)
-{
- setProperty(LineSpacingFromFont, on);
- remove(NormalLineHeight);
-}
-
-bool KoParagraphStyle::lineSpacingFromFont() const
-{
- return propertyBoolean(LineSpacingFromFont);
-}
-
-void KoParagraphStyle::setNormalLineHeight()
-{
- setProperty(NormalLineHeight, true);
- setProperty(PercentLineHeight, 0);
- setProperty(FixedLineHeight, 0.0);
- setProperty(MinimumLineHeight, QTextLength(QTextLength::FixedLength, 0.0));
- setProperty(LineSpacing, 0.0);
-}
-
-bool KoParagraphStyle::hasNormalLineHeight() const
-{
- return propertyBoolean(NormalLineHeight);
-}
-
-void KoParagraphStyle::setAlignLastLine(Qt::Alignment alignment)
-{
- setProperty(AlignLastLine, (int) alignment);
-}
-
-Qt::Alignment KoParagraphStyle::alignLastLine() const
-{
- if (hasProperty(AlignLastLine))
- return static_cast<Qt::Alignment>(propertyInt(AlignLastLine));
- // Hum, that doesn't sound right !
- return alignment();
-}
-
-void KoParagraphStyle::setWidowThreshold(int lines)
-{
- setProperty(WidowThreshold, lines);
-}
-
-int KoParagraphStyle::widowThreshold() const
-{
- return propertyInt(WidowThreshold);
-}
-
-void KoParagraphStyle::setOrphanThreshold(int lines)
-{
- setProperty(OrphanThreshold, lines);
-}
-
-int KoParagraphStyle::orphanThreshold() const
-{
- return propertyInt(OrphanThreshold);
-}
-
-void KoParagraphStyle::setDropCaps(bool on)
-{
- setProperty(DropCaps, on);
-}
-
-bool KoParagraphStyle::dropCaps() const
-{
- return propertyBoolean(DropCaps);
-}
-
-void KoParagraphStyle::setDropCapsLength(int characters)
-{
- setProperty(DropCapsLength, characters);
-}
-
-int KoParagraphStyle::dropCapsLength() const
-{
- return propertyInt(DropCapsLength);
-}
-
-void KoParagraphStyle::setDropCapsLines(int lines)
-{
- setProperty(DropCapsLines, lines);
-}
-
-int KoParagraphStyle::dropCapsLines() const
-{
- return propertyInt(DropCapsLines);
-}
-
-void KoParagraphStyle::setDropCapsDistance(qreal distance)
-{
- setProperty(DropCapsDistance, distance);
-}
-
-qreal KoParagraphStyle::dropCapsDistance() const
-{
- return propertyDouble(DropCapsDistance);
-}
-
-void KoParagraphStyle::setDropCapsTextStyleId(int id)
-{
- setProperty(KoParagraphStyle::DropCapsTextStyle, id);
-}
-
-int KoParagraphStyle::dropCapsTextStyleId() const
-{
- return propertyInt(KoParagraphStyle::DropCapsTextStyle);
-}
-
-void KoParagraphStyle::setFollowDocBaseline(bool on)
-{
- setProperty(FollowDocBaseline, on);
-}
-
-bool KoParagraphStyle::followDocBaseline() const
-{
- return propertyBoolean(FollowDocBaseline);
-}
-
-void KoParagraphStyle::setBreakBefore(KoText::KoTextBreakProperty value)
-{
- setProperty(BreakBefore, value);
-}
-
-KoText::KoTextBreakProperty KoParagraphStyle::breakBefore() const
-{
- return static_cast<KoText::KoTextBreakProperty>(propertyInt(BreakBefore));
-}
-
-void KoParagraphStyle::setBreakAfter(KoText::KoTextBreakProperty value)
-{
- setProperty(BreakAfter, value);
-}
-
-KoText::KoTextBreakProperty KoParagraphStyle::breakAfter() const
-{
- return static_cast<KoText::KoTextBreakProperty>(propertyInt(BreakAfter));
-}
-
-void KoParagraphStyle::setLeftPadding(qreal padding)
-{
- setProperty(LeftPadding, padding);
-}
-
-qreal KoParagraphStyle::leftPadding() const
-{
- return propertyDouble(LeftPadding);
-}
-
-void KoParagraphStyle::setTopPadding(qreal padding)
-{
- setProperty(TopPadding, padding);
-}
-
-qreal KoParagraphStyle::topPadding() const
-{
- return propertyDouble(TopPadding);
-}
-
-void KoParagraphStyle::setRightPadding(qreal padding)
-{
- setProperty(RightPadding, padding);
-}
-
-qreal KoParagraphStyle::rightPadding() const
-{
- return propertyDouble(RightPadding);
-}
-
-void KoParagraphStyle::setBottomPadding(qreal padding)
-{
- setProperty(BottomPadding, padding);
-}
-
-qreal KoParagraphStyle::bottomPadding() const
-{
- return propertyDouble(BottomPadding);
-}
-
-void KoParagraphStyle::setPadding(qreal padding)
-{
- setBottomPadding(padding);
- setTopPadding(padding);
- setRightPadding(padding);
- setLeftPadding(padding);
-}
-
-void KoParagraphStyle::setLeftBorderWidth(qreal width)
-{
- setProperty(LeftBorderWidth, width);
-}
-
-qreal KoParagraphStyle::leftBorderWidth() const
-{
- return propertyDouble(LeftBorderWidth);
-}
-
-void KoParagraphStyle::setLeftInnerBorderWidth(qreal width)
-{
- setProperty(LeftInnerBorderWidth, width);
-}
-
-qreal KoParagraphStyle::leftInnerBorderWidth() const
-{
- return propertyDouble(LeftInnerBorderWidth);
-}
-
-void KoParagraphStyle::setLeftBorderSpacing(qreal width)
-{
- setProperty(LeftBorderSpacing, width);
-}
-
-qreal KoParagraphStyle::leftBorderSpacing() const
-{
- return propertyDouble(LeftBorderSpacing);
-}
-
-void KoParagraphStyle::setLeftBorderStyle(KoBorder::BorderStyle style)
-{
- setProperty(LeftBorderStyle, style);
-}
-
-KoBorder::BorderStyle KoParagraphStyle::leftBorderStyle() const
-{
- return static_cast<KoBorder::BorderStyle>(propertyInt(LeftBorderStyle));
-}
-
-void KoParagraphStyle::setLeftBorderColor(const QColor &color)
-{
- setProperty(LeftBorderColor, color);
-}
-
-QColor KoParagraphStyle::leftBorderColor() const
-{
- return propertyColor(LeftBorderColor);
-}
-
-void KoParagraphStyle::setTopBorderWidth(qreal width)
-{
- setProperty(TopBorderWidth, width);
-}
-
-qreal KoParagraphStyle::topBorderWidth() const
-{
- return propertyDouble(TopBorderWidth);
-}
-
-void KoParagraphStyle::setTopInnerBorderWidth(qreal width)
-{
- setProperty(TopInnerBorderWidth, width);
-}
-
-qreal KoParagraphStyle::topInnerBorderWidth() const
-{
- return propertyDouble(TopInnerBorderWidth);
-}
-
-void KoParagraphStyle::setTopBorderSpacing(qreal width)
-{
- setProperty(TopBorderSpacing, width);
-}
-
-qreal KoParagraphStyle::topBorderSpacing() const
-{
- return propertyDouble(TopBorderSpacing);
-}
-
-void KoParagraphStyle::setTopBorderStyle(KoBorder::BorderStyle style)
-{
- setProperty(TopBorderStyle, style);
-}
-
-KoBorder::BorderStyle KoParagraphStyle::topBorderStyle() const
-{
- return static_cast<KoBorder::BorderStyle>(propertyInt(TopBorderStyle));
-}
-
-void KoParagraphStyle::setTopBorderColor(const QColor &color)
-{
- setProperty(TopBorderColor, color);
-}
-
-QColor KoParagraphStyle::topBorderColor() const
-{
- return propertyColor(TopBorderColor);
-}
-
-void KoParagraphStyle::setRightBorderWidth(qreal width)
-{
- setProperty(RightBorderWidth, width);
-}
-
-qreal KoParagraphStyle::rightBorderWidth() const
-{
- return propertyDouble(RightBorderWidth);
-}
-
-void KoParagraphStyle::setRightInnerBorderWidth(qreal width)
-{
- setProperty(RightInnerBorderWidth, width);
-}
-
-qreal KoParagraphStyle::rightInnerBorderWidth() const
-{
- return propertyDouble(RightInnerBorderWidth);
-}
-
-void KoParagraphStyle::setRightBorderSpacing(qreal width)
-{
- setProperty(RightBorderSpacing, width);
-}
-
-qreal KoParagraphStyle::rightBorderSpacing() const
-{
- return propertyDouble(RightBorderSpacing);
-}
-
-void KoParagraphStyle::setRightBorderStyle(KoBorder::BorderStyle style)
-{
- setProperty(RightBorderStyle, style);
-}
-
-KoBorder::BorderStyle KoParagraphStyle::rightBorderStyle() const
-{
- return static_cast<KoBorder::BorderStyle>(propertyInt(RightBorderStyle));
-}
-
-void KoParagraphStyle::setRightBorderColor(const QColor &color)
-{
- setProperty(RightBorderColor, color);
-}
-
-QColor KoParagraphStyle::rightBorderColor() const
-{
- return propertyColor(RightBorderColor);
-}
-
-void KoParagraphStyle::setBottomBorderWidth(qreal width)
-{
- setProperty(BottomBorderWidth, width);
-}
-
-qreal KoParagraphStyle::bottomBorderWidth() const
-{
- return propertyDouble(BottomBorderWidth);
-}
-
-void KoParagraphStyle::setBottomInnerBorderWidth(qreal width)
-{
- setProperty(BottomInnerBorderWidth, width);
-}
-
-qreal KoParagraphStyle::bottomInnerBorderWidth() const
-{
- return propertyDouble(BottomInnerBorderWidth);
-}
-
-void KoParagraphStyle::setBottomBorderSpacing(qreal width)
-{
- setProperty(BottomBorderSpacing, width);
-}
-
-qreal KoParagraphStyle::bottomBorderSpacing() const
-{
- return propertyDouble(BottomBorderSpacing);
-}
-
-void KoParagraphStyle::setBottomBorderStyle(KoBorder::BorderStyle style)
-{
- setProperty(BottomBorderStyle, style);
-}
-
-KoBorder::BorderStyle KoParagraphStyle::bottomBorderStyle() const
-{
- return static_cast<KoBorder::BorderStyle>(propertyInt(BottomBorderStyle));
-}
-
-void KoParagraphStyle::setBottomBorderColor(const QColor &color)
-{
- setProperty(BottomBorderColor, color);
-}
-
-QColor KoParagraphStyle::bottomBorderColor() const
-{
- return propertyColor(BottomBorderColor);
-}
-
-void KoParagraphStyle::setTopMargin(QTextLength topMargin)
-{
- setProperty(QTextFormat::BlockTopMargin, topMargin);
-}
-
-qreal KoParagraphStyle::topMargin() const
-{
- if (parentStyle())
- return propertyLength(QTextFormat::BlockTopMargin).value(parentStyle()->topMargin());
- else
- return propertyLength(QTextFormat::BlockTopMargin).value(0);
-}
-
-void KoParagraphStyle::setBottomMargin(QTextLength margin)
-{
- setProperty(QTextFormat::BlockBottomMargin, margin);
-}
-
-qreal KoParagraphStyle::bottomMargin() const
-{
- if (parentStyle())
- return propertyLength(QTextFormat::BlockBottomMargin).value(parentStyle()->bottomMargin());
- else
- return propertyLength(QTextFormat::BlockBottomMargin).value(0);
-}
-
-void KoParagraphStyle::setLeftMargin(QTextLength margin)
-{
- setProperty(QTextFormat::BlockLeftMargin, margin);
-}
-
-qreal KoParagraphStyle::leftMargin() const
-{
- if (parentStyle())
- return propertyLength(QTextFormat::BlockLeftMargin).value(parentStyle()->leftMargin());
- else
- return propertyLength(QTextFormat::BlockLeftMargin).value(0);
-}
-
-void KoParagraphStyle::setRightMargin(QTextLength margin)
-{
- setProperty(QTextFormat::BlockRightMargin, margin);
-}
-
-qreal KoParagraphStyle::rightMargin() const
-{
- if (parentStyle())
- return propertyLength(QTextFormat::BlockRightMargin).value(parentStyle()->rightMargin());
- else
- return propertyLength(QTextFormat::BlockRightMargin).value(0);
-}
-
-void KoParagraphStyle::setMargin(QTextLength margin)
-{
- setTopMargin(margin);
- setBottomMargin(margin);
- setLeftMargin(margin);
- setRightMargin(margin);
-}
-
-void KoParagraphStyle::setAlignment(Qt::Alignment alignment)
-{
- setProperty(QTextFormat::BlockAlignment, (int) alignment);
-}
-
-Qt::Alignment KoParagraphStyle::alignment() const
-{
- return static_cast<Qt::Alignment>(propertyInt(QTextFormat::BlockAlignment));
-}
-
-void KoParagraphStyle::setTextIndent(QTextLength margin)
-{
- setProperty(QTextFormat::TextIndent, margin);
-}
-
-qreal KoParagraphStyle::textIndent() const
-{
- if (parentStyle())
- return propertyLength(QTextFormat::TextIndent).value(parentStyle()->textIndent());
- else
- return propertyLength(QTextFormat::TextIndent).value(0);
-}
-
-void KoParagraphStyle::setAutoTextIndent(bool on)
-{
- setProperty(KoParagraphStyle::AutoTextIndent, on);
-}
-
-bool KoParagraphStyle::autoTextIndent() const
-{
- return propertyBoolean(KoParagraphStyle::AutoTextIndent);
-}
-
-void KoParagraphStyle::setNonBreakableLines(bool on)
-{
- setProperty(QTextFormat::BlockNonBreakableLines, on);
-}
-
-bool KoParagraphStyle::nonBreakableLines() const
-{
- return propertyBoolean(QTextFormat::BlockNonBreakableLines);
-}
-
-void KoParagraphStyle::setKeepWithNext(bool value)
-{
- setProperty(KeepWithNext, value);
-}
-
-bool KoParagraphStyle::keepWithNext() const
-{
- if (hasProperty(KeepWithNext))
- return propertyBoolean(KeepWithNext);
- return false;
-}
-
-bool KoParagraphStyle::punctuationWrap() const
-{
- if (hasProperty(PunctuationWrap))
- return propertyBoolean(PunctuationWrap);
- return false;
-}
-
-void KoParagraphStyle::setPunctuationWrap(bool value)
-{
- setProperty(PunctuationWrap, value);
-}
-
-KoParagraphStyle *KoParagraphStyle::parentStyle() const
-{
- return d->parentStyle;
-}
-
-void KoParagraphStyle::setNextStyle(int next)
-{
- setProperty(NextStyle, next);
-}
-
-int KoParagraphStyle::nextStyle() const
-{
- return propertyInt(NextStyle);
-}
-
-QString KoParagraphStyle::name() const
-{
- return d->name;
-}
-
-void KoParagraphStyle::setName(const QString &name)
-{
- if (name == d->name)
- return;
- d->name = name;
- KoCharacterStyle::setName(name);
- emit nameChanged(name);
-}
-
-int KoParagraphStyle::styleId() const
-{
- // duplicate some code to avoid getting the parents style id
- QVariant variant = d->stylesPrivate.value(StyleId);
- if (variant.isNull())
- return 0;
- return variant.toInt();
-}
-
-void KoParagraphStyle::setStyleId(int id)
-{
- setProperty(StyleId, id); if (nextStyle() == 0) setNextStyle(id);
- KoCharacterStyle::setStyleId(id);
-}
-
-QString KoParagraphStyle::masterPageName() const
-{
- return value(MasterPageName).toString();
-}
-
-void KoParagraphStyle::setMasterPageName(const QString &name)
-{
- setProperty(MasterPageName, name);
-}
-
-void KoParagraphStyle::setListStartValue(int value)
-{
- setProperty(ListStartValue, value);
-}
-
-int KoParagraphStyle::listStartValue() const
-{
- return propertyInt(ListStartValue);
-}
-
-void KoParagraphStyle::setRestartListNumbering(bool on)
-{
- setProperty(RestartListNumbering, on);
-}
-
-bool KoParagraphStyle::restartListNumbering()
-{
- return propertyBoolean(RestartListNumbering);
-}
-
-void KoParagraphStyle::setListLevel(int value)
-{
- setProperty(ListLevel, value);
-}
-
-int KoParagraphStyle::listLevel() const
-{
- return propertyInt(ListLevel);
-}
-
-void KoParagraphStyle::setOutlineLevel(int outline)
-{
- setProperty(OutlineLevel, outline);
-}
-
-int KoParagraphStyle::outlineLevel() const
-{
- return propertyInt(OutlineLevel);
-}
-
-void KoParagraphStyle::setDefaultOutlineLevel(int outline)
-{
- setProperty(DefaultOutlineLevel, outline);
-}
-
-int KoParagraphStyle::defaultOutlineLevel() const
-{
- return propertyInt(DefaultOutlineLevel);
-}
-
-bool KoParagraphStyle::lineNumbering() const
-{
- return propertyBoolean(LineNumbering);
-}
-
-void KoParagraphStyle::setLineNumbering(bool lineNumbering)
-{
- setProperty(LineNumbering, lineNumbering);
-}
-
-int KoParagraphStyle::lineNumberStartValue() const
-{
- return propertyInt(LineNumberStartValue);
-}
-
-void KoParagraphStyle::setLineNumberStartValue(int lineNumberStartValue)
-{
- setProperty(LineNumberStartValue, lineNumberStartValue);
-}
-
-void KoParagraphStyle::setIsListHeader(bool on)
-{
- setProperty(IsListHeader, on);
-}
-
-bool KoParagraphStyle::isListHeader() const
-{
- return propertyBoolean(IsListHeader);
-}
-
-KoListStyle *KoParagraphStyle::listStyle() const
-{
- QVariant variant = value(ParagraphListStyleId);
- if (variant.isNull())
- return 0;
- return variant.value<KoListStyle *>();
-}
-
-void KoParagraphStyle::setListStyle(KoListStyle *style)
-{
- if (listStyle() == style)
- return;
- if (listStyle() && listStyle()->parent() == this)
- delete listStyle();
- QVariant variant;
- KoListStyle *cloneStyle = 0;
- if (style) {
- cloneStyle = style->clone();
- variant.setValue(cloneStyle);
-
- setProperty(ParagraphListStyleId, variant);
- } else {
- d->stylesPrivate.remove(ParagraphListStyleId);
- }
-}
-
-KoText::Direction KoParagraphStyle::textProgressionDirection() const
-{
- return static_cast<KoText::Direction>(propertyInt(TextProgressionDirection));
-}
-
-void KoParagraphStyle::setTextProgressionDirection(KoText::Direction dir)
-{
- setProperty(TextProgressionDirection, dir);
-}
-
-bool KoParagraphStyle::keepHyphenation() const
-{
- if (hasProperty(KeepHyphenation))
- return propertyBoolean(KeepHyphenation);
- return false;
-}
-
-void KoParagraphStyle::setKeepHyphenation(bool value)
-{
- setProperty(KeepHyphenation, value);
-}
-
-int KoParagraphStyle::hyphenationLadderCount() const
-{
- if (hasProperty(HyphenationLadderCount))
- return propertyInt(HyphenationLadderCount);
- return 0;
-}
-
-void KoParagraphStyle::setHyphenationLadderCount(int value)
-{
- setProperty(HyphenationLadderCount, value);
-}
-
-void KoParagraphStyle::setBackground(const QBrush &brush)
-{
- d->setProperty(QTextFormat::BackgroundBrush, brush);
-}
-
-void KoParagraphStyle::clearBackground()
-{
- d->stylesPrivate.remove(QTextCharFormat::BackgroundBrush);
-}
-
-QBrush KoParagraphStyle::background() const
-{
- QVariant variant = d->stylesPrivate.value(QTextFormat::BackgroundBrush);
-
- if (variant.isNull()) {
- return QBrush();
- }
- return qvariant_cast<QBrush>(variant);
-}
-
-qreal KoParagraphStyle::backgroundTransparency() const
-{
- if (hasProperty(BackgroundTransparency))
- return propertyDouble(BackgroundTransparency);
- return 0.0;
-}
-
-void KoParagraphStyle::setBackgroundTransparency(qreal transparency)
-{
- setProperty(BackgroundTransparency, transparency);
-}
-
-void KoParagraphStyle::setSnapToLayoutGrid(bool value)
-{
- setProperty(SnapToLayoutGrid, value);
-}
-
-bool KoParagraphStyle::snapToLayoutGrid() const
-{
- if (hasProperty(SnapToLayoutGrid))
- return propertyBoolean(SnapToLayoutGrid);
- return false;
-}
-
-bool KoParagraphStyle::joinBorder() const
-{
- if (hasProperty(JoinBorder))
- return propertyBoolean(JoinBorder);
- return true; //default is true
-}
-
-void KoParagraphStyle::setJoinBorder(bool value)
-{
- setProperty(JoinBorder, value);
-}
-
-int KoParagraphStyle::pageNumber() const
-{
- return propertyInt(PageNumber);
-}
-
-void KoParagraphStyle::setPageNumber(int pageNumber)
-{
- if (pageNumber >= 0)
- setProperty(PageNumber, pageNumber);
-}
-
-bool KoParagraphStyle::automaticWritingMode() const
-{
- if (hasProperty(AutomaticWritingMode))
- return propertyBoolean(AutomaticWritingMode);
- return true;
-}
-
-void KoParagraphStyle::setAutomaticWritingMode(bool value)
-{
- setProperty(AutomaticWritingMode, value);
-}
-
-void KoParagraphStyle::setVerticalAlignment(KoParagraphStyle::VerticalAlign value)
-{
- setProperty(VerticalAlignment, value);
-}
-
-KoParagraphStyle::VerticalAlign KoParagraphStyle::verticalAlignment() const
-{
- if (hasProperty(VerticalAlignment))
- return (VerticalAlign) propertyInt(VerticalAlignment);
- return VAlignAuto;
-}
-
-void KoParagraphStyle::setShadow(const KoShadowStyle &shadow)
-{
- d->setProperty(Shadow, QVariant::fromValue<KoShadowStyle>(shadow));
-}
-
-KoShadowStyle KoParagraphStyle::shadow() const
-{
- if (hasProperty(Shadow))
- return value(Shadow).value<KoShadowStyle>();
- return KoShadowStyle();
-}
-
-void KoParagraphStyle::loadOdf(const KoXmlElement *element, KoShapeLoadingContext &scontext,
- bool loadParents)
-{
- KoOdfLoadingContext &context = scontext.odfLoadingContext();
- const QString name(element->attributeNS(KoXmlNS::style, "display-name", QString()));
- if (!name.isEmpty()) {
- setName(name);
- }
- else {
- setName(element->attributeNS(KoXmlNS::style, "name", QString()));
- }
-
- QString family = element->attributeNS(KoXmlNS::style, "family", "paragraph");
-
- context.styleStack().save();
- if (loadParents) {
- context.addStyles(element, family.toLocal8Bit().constData()); // Load all parent
- } else {
- context.styleStack().push(*element);
- }
- context.styleStack().setTypeProperties("text"); // load the style:text-properties
- KoCharacterStyle::loadOdfProperties(scontext);
-
- QString masterPage = element->attributeNS(KoXmlNS::style, "master-page-name", QString());
- if (! masterPage.isEmpty()) {
- setMasterPageName(masterPage);
- }
-
- if (element->hasAttributeNS(KoXmlNS::style, "default-outline-level")) {
- bool ok = false;
- int level = element->attributeNS(KoXmlNS::style, "default-outline-level").toInt(&ok);
- if (ok)
- setDefaultOutlineLevel(level);
- }
-
- context.styleStack().setTypeProperties("paragraph"); // load all style attributes from "style:paragraph-properties"
-
- loadOdfProperties(scontext); // load the KoParagraphStyle from the stylestack
-
- context.styleStack().restore();
-}
-
-struct ParagraphBorderData {
- enum Values {Style = 1, Color = 2, Width = 4};
-
- ParagraphBorderData()
- : values(0) {}
-
- ParagraphBorderData(const ParagraphBorderData &other)
- : values(other.values), style(other.style), color(other.color), width(other.width) {}
-
- // flag defining which data is set
- int values;
-
- KoBorder::BorderStyle style;
- QColor color;
- qreal width; ///< in pt
-};
-
-
-/// Parses the @p dataString as value defined by CSS2 §7.29.3 "border"
-/// Adds parsed data to the data as set for @p defaultParagraphBorderData.
-/// Returns the enriched border data on success, the original @p defaultParagraphBorderData on a parsing error
-static ParagraphBorderData parseParagraphBorderData(const QString &dataString, const ParagraphBorderData &defaultParagraphBorderData)
-{
- const QStringList bv = dataString.split(QLatin1Char(' '), QString::SkipEmptyParts);
- // too many items? ignore complete value
- if (bv.count() > 3) {
- return defaultParagraphBorderData;
- }
-
- ParagraphBorderData borderData = defaultParagraphBorderData;
- int parsedValues = 0; ///< used to track what is read from the given string
-
- Q_FOREACH (const QString &v, bv) {
- // try style
- if (! (parsedValues & ParagraphBorderData::Style)) {
- bool success = false;
- KoBorder::BorderStyle style = KoBorder::odfBorderStyle(v, &success);
- // workaround for not yet supported "hidden"
- if (! success && (v == QLatin1String("hidden"))) {
- // map to "none" for now TODO: KoBorder needs to support "hidden"
- style = KoBorder::BorderNone;
- success = true;
- }
- if (success) {
- borderData.style = style;
- borderData.values |= ParagraphBorderData::Style;
- parsedValues |= ParagraphBorderData::Style;
- continue;
- }
- }
- // try color
- if (! (parsedValues & ParagraphBorderData::Color)) {
- const QColor color(v);
- if (color.isValid()) {
- borderData.color = color;
- borderData.values |= ParagraphBorderData::Color;
- parsedValues |= ParagraphBorderData::Color;
- continue;
- }
- }
- // try width
- if (! (parsedValues & ParagraphBorderData::Width)) {
- const qreal width = KoUnit::parseValue(v);
- if (width >= 0.0) {
- borderData.width = width;
- borderData.values |= ParagraphBorderData::Width;
- parsedValues |= ParagraphBorderData::Width;
- continue;
- }
- }
- // still here? found a value which cannot be parsed
- return defaultParagraphBorderData;
- }
- return borderData;
-}
-
-void KoParagraphStyle::loadOdfProperties(KoShapeLoadingContext &scontext)
-{
- KoStyleStack &styleStack = scontext.odfLoadingContext().styleStack();
-
- // in 1.6 this was defined at KoParagLayout::loadOasisParagLayout(KoParagLayout&, KoOasisContext&)
- const QString writingMode(styleStack.property(KoXmlNS::style, "writing-mode"));
- if (!writingMode.isEmpty()) {
- setTextProgressionDirection(KoText::directionFromString(writingMode));
- }
-
- // Alignment
- const QString textAlign(styleStack.property(KoXmlNS::fo, "text-align"));
- if (!textAlign.isEmpty()) {
- setAlignment(KoText::alignmentFromString(textAlign));
- }
-
- // Spacing (padding)
- const QString padding(styleStack.property(KoXmlNS::fo, "padding"));
- if (!padding.isEmpty()) {
- setPadding(KoUnit::parseValue(padding));
- }
- const QString paddingLeft(styleStack.property(KoXmlNS::fo, "padding-left" ));
- if (!paddingLeft.isEmpty()) {
- setLeftPadding(KoUnit::parseValue(paddingLeft));
- }
- const QString paddingRight(styleStack.property(KoXmlNS::fo, "padding-right" ));
- if (!paddingRight.isEmpty()) {
- setRightPadding(KoUnit::parseValue(paddingRight));
- }
- const QString paddingTop(styleStack.property(KoXmlNS::fo, "padding-top" ));
- if (!paddingTop.isEmpty()) {
- setTopPadding(KoUnit::parseValue(paddingTop));
- }
- const QString paddingBottom(styleStack.property(KoXmlNS::fo, "padding-bottom" ));
- if (!paddingBottom.isEmpty()) {
- setBottomPadding(KoUnit::parseValue(paddingBottom));
- }
-
- // Indentation (margin)
- const QString margin(styleStack.property(KoXmlNS::fo, "margin"));
- if (!margin.isEmpty()) {
- setMargin(KoText::parseLength(margin));
- }
- const QString marginLeft(styleStack.property(KoXmlNS::fo, "margin-left" ));
- if (!marginLeft.isEmpty()) {
- setLeftMargin(KoText::parseLength(marginLeft));
- }
- const QString marginRight(styleStack.property(KoXmlNS::fo, "margin-right" ));
- if (!marginRight.isEmpty()) {
- setRightMargin(KoText::parseLength(marginRight));
- }
- const QString marginTop(styleStack.property(KoXmlNS::fo, "margin-top"));
- if (!marginTop.isEmpty()) {
- setTopMargin(KoText::parseLength(marginTop));
- }
- const QString marginBottom(styleStack.property(KoXmlNS::fo, "margin-bottom"));
- if (!marginBottom.isEmpty()) {
- setBottomMargin(KoText::parseLength(marginBottom));
- }
-
- // Automatic Text indent
- // OOo is not assuming this. Commenting this line thus allow more OpenDocuments to be supported, including a
- // testcase from the ODF test suite. See §15.5.18 in the spec.
- //if ( hasMarginLeft || hasMarginRight ) {
- // style:auto-text-indent takes precedence
- const QString autoTextIndent(styleStack.property(KoXmlNS::style, "auto-text-indent"));
- if (!autoTextIndent.isEmpty()) {
- setAutoTextIndent(autoTextIndent == "true");
- }
-
- if (autoTextIndent != "true" || autoTextIndent.isEmpty()) {
- const QString textIndent(styleStack.property(KoXmlNS::fo, "text-indent"));
- if (!textIndent.isEmpty()) {
- setTextIndent(KoText::parseLength(textIndent));
- }
- }
-
- //}
-
- // Line spacing
- QString lineHeight(styleStack.property(KoXmlNS::fo, "line-height"));
- if (!lineHeight.isEmpty()) {
- if (lineHeight != "normal") {
- if (lineHeight.indexOf('%') > -1) {
- bool ok;
- const qreal percent = lineHeight.remove('%').toDouble(&ok);
- if (ok) {
- setLineHeightPercent(percent);
- }
- }
- else { // fixed value is between 0.0201in and 3.9402in
- const qreal value = KoUnit::parseValue(lineHeight, -1.0);
- if (value >= 0.0) {
- setLineHeightAbsolute(value);
- }
- }
- }
- else {
- setNormalLineHeight();
- }
- }
- else {
- const QString lineSpacing(styleStack.property(KoXmlNS::style, "line-spacing"));
- if (!lineSpacing.isEmpty()) { // 3.11.3
- setLineSpacing(KoUnit::parseValue(lineSpacing));
- }
- }
-
- // 15.5.30 - 31
- if (styleStack.hasProperty(KoXmlNS::text, "number-lines")) {
- setLineNumbering(styleStack.property(KoXmlNS::text, "number-lines", "false") == "true");
- }
- if (styleStack.hasProperty(KoXmlNS::text, "line-number")) {
- bool ok;
- int startValue = styleStack.property(KoXmlNS::text, "line-number").toInt(&ok);
- if (ok) {
- setLineNumberStartValue(startValue);
- }
- }
-
- const QString lineHeightAtLeast(styleStack.property(KoXmlNS::style, "line-height-at-least"));
- if (!lineHeightAtLeast.isEmpty() && !propertyBoolean(NormalLineHeight) && lineHeightAbsolute() == 0) { // 3.11.2
- setMinimumLineHeight(KoText::parseLength(lineHeightAtLeast));
- } // Line-height-at-least is mutually exclusive with absolute line-height
- const QString fontIndependentLineSpacing(styleStack.property(KoXmlNS::style, "font-independent-line-spacing"));
- if (!fontIndependentLineSpacing.isEmpty() && !propertyBoolean(NormalLineHeight) && lineHeightAbsolute() == 0) {
- setLineSpacingFromFont(fontIndependentLineSpacing == "true");
- }
-
- // Tabulators
- const QString tabStopDistance(styleStack.property(KoXmlNS::style, "tab-stop-distance"));
- if (!tabStopDistance.isEmpty()) {
- qreal stopDistance = KoUnit::parseValue(tabStopDistance);
- if (stopDistance >= 0)
- setTabStopDistance(stopDistance);
- }
- KoXmlElement tabStops(styleStack.childNode(KoXmlNS::style, "tab-stops"));
- if (!tabStops.isNull()) { // 3.11.10
- QList<KoText::Tab> tabList;
- KoXmlElement tabStop;
- forEachElement(tabStop, tabStops) {
- if(tabStop.localName() != "tab-stop")
- continue;
-
- // Tab position
- KoText::Tab tab;
- tab.position = KoUnit::parseValue(tabStop.attributeNS(KoXmlNS::style, "position", QString()));
- //debugText << "tab position " << tab.position;
-
- // Tab stop positions in the XML are relative to the left-margin
- // Equivalently, relative to the left end of our textshape
- // Tab type (left/right/center/char)
- const QString type = tabStop.attributeNS(KoXmlNS::style, "type", QString());
- if (type == "center")
- tab.type = QTextOption::CenterTab;
- else if (type == "right")
- tab.type = QTextOption::RightTab;
- else if (type == "char") {
- tab.type = QTextOption::DelimiterTab;
- tab.delimiter = QChar('.');
- } else //if ( type == "left" )
- tab.type = QTextOption::LeftTab;
-
- // Tab delimiter char
- if (tab.type == QTextOption::DelimiterTab) {
- QString delimiterChar = tabStop.attributeNS(KoXmlNS::style, "char", QString()); // single character
- if (!delimiterChar.isEmpty()) {
- tab.delimiter = delimiterChar[0];
- } else {
- // this is invalid. fallback to left-tabbing.
- tab.type = QTextOption::LeftTab;
- }
- }
-
- QString leaderType = tabStop.attributeNS(KoXmlNS::style, "leader-type", QString());
- if (leaderType.isEmpty() || leaderType == "none") {
- tab.leaderType = KoCharacterStyle::NoLineType;
- } else {
- if (leaderType == "single")
- tab.leaderType = KoCharacterStyle::SingleLine;
- else if (leaderType == "double")
- tab.leaderType = KoCharacterStyle::DoubleLine;
- // change default leaderStyle
- tab.leaderStyle = KoCharacterStyle::SolidLine;
- }
-
- QString leaderStyle = tabStop.attributeNS(KoXmlNS::style, "leader-style", QString());
- if (leaderStyle == "none")
- tab.leaderStyle = KoCharacterStyle::NoLineStyle;
- else if (leaderStyle == "solid")
- tab.leaderStyle = KoCharacterStyle::SolidLine;
- else if (leaderStyle == "dotted")
- tab.leaderStyle = KoCharacterStyle::DottedLine;
- else if (leaderStyle == "dash")
- tab.leaderStyle = KoCharacterStyle::DashLine;
- else if (leaderStyle == "long-dash")
- tab.leaderStyle = KoCharacterStyle::LongDashLine;
- else if (leaderStyle == "dot-dash")
- tab.leaderStyle = KoCharacterStyle::DotDashLine;
- else if (leaderStyle == "dot-dot-dash")
- tab.leaderStyle = KoCharacterStyle::DotDotDashLine;
- else if (leaderStyle == "wave")
- tab.leaderStyle = KoCharacterStyle::WaveLine;
-
- if (tab.leaderType == KoCharacterStyle::NoLineType && tab.leaderStyle != KoCharacterStyle::NoLineStyle) {
- if (leaderType == "none")
- // if leaderType was explicitly specified as none, but style was not none,
- // make leaderType override (ODF1.1 §15.5.11)
- tab.leaderStyle = KoCharacterStyle::NoLineStyle;
- else
- // if leaderType was implicitly assumed none, but style was not none,
- // make leaderStyle override
- tab.leaderType = KoCharacterStyle::SingleLine;
- }
-
- QString leaderColor = tabStop.attributeNS(KoXmlNS::style, "leader-color", QString());
- if (leaderColor != "font-color")
- tab.leaderColor = QColor(leaderColor); // if invalid color (the default), will use text color
-
- QString width = tabStop.attributeNS(KoXmlNS::style, "leader-width", QString());
- if (width.isEmpty() || width == "auto")
- tab.leaderWeight = KoCharacterStyle::AutoLineWeight;
- else if (width == "normal")
- tab.leaderWeight = KoCharacterStyle::NormalLineWeight;
- else if (width == "bold")
- tab.leaderWeight = KoCharacterStyle::BoldLineWeight;
- else if (width == "thin")
- tab.leaderWeight = KoCharacterStyle::ThinLineWeight;
- else if (width == "dash")
- tab.leaderWeight = KoCharacterStyle::DashLineWeight;
- else if (width == "medium")
- tab.leaderWeight = KoCharacterStyle::MediumLineWeight;
- else if (width == "thick")
- tab.leaderWeight = KoCharacterStyle::ThickLineWeight;
- else if (width.endsWith('%')) {
- tab.leaderWeight = KoCharacterStyle::PercentLineWeight;
- tab.leaderWidth = width.mid(0, width.length() - 1).toDouble();
- } else if (width[width.length()-1].isNumber()) {
- tab.leaderWeight = KoCharacterStyle::PercentLineWeight;
- tab.leaderWidth = 100 * width.toDouble();
- } else {
- tab.leaderWeight = KoCharacterStyle::LengthLineWeight;
- tab.leaderWidth = KoUnit::parseValue(width);
- }
-
- tab.leaderText = tabStop.attributeNS(KoXmlNS::style, "leader-text", QString());
-
-#if 0
- else {
- // Fallback: convert leaderChar's unicode value
- QString leaderChar = tabStop.attributeNS(KoXmlNS::style, "leader-text", QString());
- if (!leaderChar.isEmpty()) {
- QChar ch = leaderChar[0];
- switch (ch.latin1()) {
- case '.':
- tab.filling = TF_DOTS; break;
- case '-':
- case '_': // TODO in Words: differentiate --- and ___
- tab.filling = TF_LINE; break;
- default:
- // Words doesn't have support for "any char" as filling.
- break;
- }
- }
- }
-#endif
- tabList.append(tab);
- } //for
- setTabPositions(tabList);
- }
-
-#if 0
- layout.joinBorder = !(styleStack.property(KoXmlNS::style, "join-border") == "false");
-#endif
-
- // Borders
- // The border attribute is actually three attributes in one string, all optional
- // and with no given order. Also there is a hierarchy, first the common for all
- // sides and then overwrites per side, while in the code only the sides are stored.
- // So first the common data border is fetched, then this is overwritten per
- // side and the result stored.
- const QString border(styleStack.property(KoXmlNS::fo, "border"));
- const ParagraphBorderData borderData = parseParagraphBorderData(border, ParagraphBorderData());
-
- const QString borderLeft(styleStack.property(KoXmlNS::fo, "border-left"));
- const ParagraphBorderData leftParagraphBorderData = parseParagraphBorderData(borderLeft, borderData);
- if (leftParagraphBorderData.values & ParagraphBorderData::Width) {
- setLeftBorderWidth(leftParagraphBorderData.width);
- }
- if (leftParagraphBorderData.values & ParagraphBorderData::Style) {
- setLeftBorderStyle(leftParagraphBorderData.style);
- }
- if (leftParagraphBorderData.values & ParagraphBorderData::Color) {
- setLeftBorderColor(leftParagraphBorderData.color);
- }
-
- const QString borderTop(styleStack.property(KoXmlNS::fo, "border-top"));
- const ParagraphBorderData topParagraphBorderData = parseParagraphBorderData(borderTop, borderData);
- if (topParagraphBorderData.values & ParagraphBorderData::Width) {
- setTopBorderWidth(topParagraphBorderData.width);
- }
- if (topParagraphBorderData.values & ParagraphBorderData::Style) {
- setTopBorderStyle(topParagraphBorderData.style);
- }
- if (topParagraphBorderData.values & ParagraphBorderData::Color) {
- setTopBorderColor(topParagraphBorderData.color);
- }
-
- const QString borderRight(styleStack.property(KoXmlNS::fo, "border-right"));
- const ParagraphBorderData rightParagraphBorderData = parseParagraphBorderData(borderRight, borderData);
- if (rightParagraphBorderData.values & ParagraphBorderData::Width) {
- setRightBorderWidth(rightParagraphBorderData.width);
- }
- if (rightParagraphBorderData.values & ParagraphBorderData::Style) {
- setRightBorderStyle(rightParagraphBorderData.style);
- }
- if (rightParagraphBorderData.values & ParagraphBorderData::Color) {
- setRightBorderColor(rightParagraphBorderData.color);
- }
-
- const QString borderBottom(styleStack.property(KoXmlNS::fo, "border-bottom"));
- const ParagraphBorderData bottomParagraphBorderData = parseParagraphBorderData(borderBottom, borderData);
- if (bottomParagraphBorderData.values & ParagraphBorderData::Width) {
- setBottomBorderWidth(bottomParagraphBorderData.width);
- }
- if (bottomParagraphBorderData.values & ParagraphBorderData::Style) {
- setBottomBorderStyle(bottomParagraphBorderData.style);
- }
- if (bottomParagraphBorderData.values & ParagraphBorderData::Color) {
- setBottomBorderColor(bottomParagraphBorderData.color);
- }
-
- const QString borderLineWidthLeft(styleStack.property(KoXmlNS::style, "border-line-width", "left"));
- if (!borderLineWidthLeft.isEmpty()) {
- QStringList blw = borderLineWidthLeft.split(' ', QString::SkipEmptyParts);
- setLeftInnerBorderWidth(KoUnit::parseValue(blw.value(0), 0.1));
- setLeftBorderSpacing(KoUnit::parseValue(blw.value(1), 1.0));
- setLeftBorderWidth(KoUnit::parseValue(blw.value(2), 0.1));
- }
- const QString borderLineWidthTop(styleStack.property(KoXmlNS::style, "border-line-width", "top"));
- if (!borderLineWidthTop.isEmpty()) {
- QStringList blw = borderLineWidthTop.split(' ', QString::SkipEmptyParts);
- setTopInnerBorderWidth(KoUnit::parseValue(blw.value(0), 0.1));
- setTopBorderSpacing(KoUnit::parseValue(blw.value(1), 1.0));
- setTopBorderWidth(KoUnit::parseValue(blw.value(2), 0.1));
- }
- const QString borderLineWidthRight(styleStack.property(KoXmlNS::style, "border-line-width", "right"));
- if (!borderLineWidthRight.isEmpty()) {
- QStringList blw = borderLineWidthRight.split(' ', QString::SkipEmptyParts);
- setRightInnerBorderWidth(KoUnit::parseValue(blw.value(0), 0.1));
- setRightBorderSpacing(KoUnit::parseValue(blw.value(1), 1.0));
- setRightBorderWidth(KoUnit::parseValue(blw.value(2), 0.1));
- }
- const QString borderLineWidthBottom(styleStack.property(KoXmlNS::style, "border-line-width", "bottom"));
- if (!borderLineWidthBottom.isEmpty()) {
- QStringList blw = borderLineWidthBottom.split(' ', QString::SkipEmptyParts);
- setBottomInnerBorderWidth(KoUnit::parseValue(blw.value(0), 0.1));
- setBottomBorderSpacing(KoUnit::parseValue(blw.value(1), 1.0));
- setBottomBorderWidth(KoUnit::parseValue(blw.value(2), 0.1));
- }
-
- // drop caps
- KoXmlElement dropCap(styleStack.childNode(KoXmlNS::style, "drop-cap"));
- if (!dropCap.isNull()) {
- setDropCaps(true);
- const QString length = dropCap.attributeNS(KoXmlNS::style, "length", QString("1"));
- if (length.toLower() == "word") {
- setDropCapsLength(0); // 0 indicates drop caps of the whole first word
- } else {
- int l = length.toInt();
- if (l > 0) // somefiles may use this to turn dropcaps off
- setDropCapsLength(length.toInt());
- else
- setDropCaps(false);
- }
- const QString lines = dropCap.attributeNS(KoXmlNS::style, "lines", QString("1"));
- setDropCapsLines(lines.toInt());
- const qreal distance = KoUnit::parseValue(dropCap.attributeNS(KoXmlNS::style, "distance", QString()));
- setDropCapsDistance(distance);
-
- const QString dropstyle = dropCap.attributeNS(KoXmlNS::style, "style-name");
- if (! dropstyle.isEmpty()) {
- KoSharedLoadingData *sharedData = scontext.sharedData(KOTEXT_SHARED_LOADING_ID);
- KoTextSharedLoadingData *textSharedData = 0;
- textSharedData = dynamic_cast<KoTextSharedLoadingData *>(sharedData);
- if (textSharedData) {
- KoCharacterStyle *cs = textSharedData->characterStyle(dropstyle, true);
- if (cs)
- setDropCapsTextStyleId(cs->styleId());
- }
- }
- }
-
- // The fo:break-before and fo:break-after attributes insert a page or column break before or after a paragraph.
- const QString breakBefore(styleStack.property(KoXmlNS::fo, "break-before"));
- if (!breakBefore.isEmpty()) {
- setBreakBefore(KoText::textBreakFromString(breakBefore));
- }
- const QString breakAfter(styleStack.property(KoXmlNS::fo, "break-after"));
- if (!breakAfter.isEmpty()) {
- setBreakAfter(KoText::textBreakFromString(breakAfter));
- }
- const QString keepTogether(styleStack.property(KoXmlNS::fo, "keep-together"));
- if (!keepTogether.isEmpty()) {
- setNonBreakableLines(keepTogether == "always");
- }
-
- const QString rawPageNumber(styleStack.property(KoXmlNS::style, "page-number"));
- if (!rawPageNumber.isEmpty()) {
- if (rawPageNumber == "auto") {
- setPageNumber(0);
- } else {
- bool ok;
- int number = rawPageNumber.toInt(&ok);
- if (ok)
- setPageNumber(number);
- }
- }
- // The fo:background-color attribute specifies the background color of a paragraph.
- const QString bgcolor(styleStack.property(KoXmlNS::fo, "background-color"));
- if (!bgcolor.isEmpty()) {
- const QString bgcolor = styleStack.property(KoXmlNS::fo, "background-color");
- QBrush brush = background();
- if (bgcolor == "transparent")
- brush.setStyle(Qt::NoBrush);
- else {
- if (brush.style() == Qt::NoBrush)
- brush.setStyle(Qt::SolidPattern);
- brush.setColor(bgcolor); // #rrggbb format
- }
- setBackground(brush);
- }
- if (styleStack.hasProperty(KoXmlNS::style, "background-transparency"))
- {
- QString transparency = styleStack.property(KoXmlNS::style, "background-transparency");
- bool ok = false;
- qreal transparencyValue = transparency.remove('%').toDouble(&ok);
- if (ok) {
- setBackgroundTransparency(transparencyValue/100);
- }
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "snap-to-layout-grid"))
- {
- setSnapToLayoutGrid(styleStack.property(KoXmlNS::style, "snap-to-layout-grid") == "true");
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "register-true"))
- {
- setRegisterTrue(styleStack.property(KoXmlNS::style, "register-true") == "true");
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "join-border"))
- {
- setJoinBorder(styleStack.property(KoXmlNS::style, "join-border") == "true");
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "line-break"))
- {
- setStrictLineBreak(styleStack.property(KoXmlNS::style, "line-break") == "strict");
- }
-
- // Support for an old non-standard OpenOffice attribute that we still find in too many documents...
- if (styleStack.hasProperty(KoXmlNS::text, "enable-numbering")) {
- setProperty(ForceDisablingList, styleStack.property(KoXmlNS::text, "enable-numbering") == "false");
- }
-
- if (styleStack.hasProperty(KoXmlNS::fo, "orphans")) {
- bool ok = false;
- int orphans = styleStack.property(KoXmlNS::fo, "orphans").toInt(&ok);
- if (ok)
- setOrphanThreshold(orphans);
- }
-
- if (styleStack.hasProperty(KoXmlNS::fo, "widows")) {
- bool ok = false;
- int widows = styleStack.property(KoXmlNS::fo, "widows").toInt(&ok);
- if (ok)
- setWidowThreshold(widows);
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "justify-single-word")) {
- setJustifySingleWord(styleStack.property(KoXmlNS::style, "justify-single-word") == "true");
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "writing-mode-automatic")) {
- setAutomaticWritingMode(styleStack.property(KoXmlNS::style, "writing-mode-automatic") == "true");
- }
-
- if (styleStack.hasProperty(KoXmlNS::fo, "text-align-last")) {
- setAlignLastLine(KoText::alignmentFromString(styleStack.property(KoXmlNS::fo, "text-align-last")));
- }
-
- if (styleStack.hasProperty(KoXmlNS::fo, "keep-with-next")) {
- setKeepWithNext(styleStack.property(KoXmlNS::fo, "keep-with-next") == "always");
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "text-autospace")) {
- const QString autoSpace = styleStack.property(KoXmlNS::style, "text-autospace");
- if (autoSpace == "none")
- setTextAutoSpace(NoAutoSpace);
- else if (autoSpace == "ideograph-alpha")
- setTextAutoSpace(IdeographAlpha);
- }
-
- if (styleStack.hasProperty(KoXmlNS::fo, "hyphenation-keep")) {
- setKeepHyphenation(styleStack.property(KoXmlNS::fo, "hyphenation-keep") == "page");
- }
-
- if (styleStack.hasProperty(KoXmlNS::fo, "hyphenation-ladder-count")) {
- QString ladderCount = styleStack.property(KoXmlNS::fo, "hyphenation-ladder-count");
- if (ladderCount == "no-limit")
- setHyphenationLadderCount(0);
- else {
- bool ok;
- int value = ladderCount.toInt(&ok);
- if ((ok) && (value > 0))
- setHyphenationLadderCount(value);
- }
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "punctuation-wrap")) {
- setPunctuationWrap(styleStack.property(KoXmlNS::style, "punctuation-wrap") == "simple");
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "vertical-align")) {
- const QString valign = styleStack.property(KoXmlNS::style, "vertical-align");
- if (valign == "auto")
- setVerticalAlignment(VAlignAuto);
- else if (valign == "baseline")
- setVerticalAlignment(VAlignBaseline);
- else if (valign == "bottom")
- setVerticalAlignment(VAlignBottom);
- else if (valign == "middle")
- setVerticalAlignment(VAlignMiddle);
- else if (valign == "top")
- setVerticalAlignment(VAlignTop);
- }
-
-
- if (styleStack.hasProperty(KoXmlNS::style, "shadow")) {
- KoShadowStyle shadow;
- if (shadow.loadOdf(styleStack.property(KoXmlNS::style, "shadow")))
- setShadow(shadow);
- }
-
- //following properties KoParagraphStyle provides us are not handled now;
- // LineSpacingFromFont,
- // FollowDocBaseline,
-
-}
-
-void KoParagraphStyle::setTabPositions(const QList<KoText::Tab> &tabs)
-{
- QList<KoText::Tab> newTabs = tabs;
- std::sort(newTabs.begin(), newTabs.end(), compareTabs);
- QList<QVariant> list;
- Q_FOREACH (const KoText::Tab &tab, tabs) {
- QVariant v;
- v.setValue(tab);
- list.append(v);
- }
- setProperty(TabPositions, list);
-}
-
-QList<KoText::Tab> KoParagraphStyle::tabPositions() const
-{
- QVariant variant = value(TabPositions);
- if (variant.isNull())
- return QList<KoText::Tab>();
- QList<KoText::Tab> answer;
- Q_FOREACH (const QVariant &tab, qvariant_cast<QList<QVariant> >(variant)) {
- answer.append(tab.value<KoText::Tab>());
- }
- return answer;
-}
-
-void KoParagraphStyle::setTabStopDistance(qreal value)
-{
- setProperty(TabStopDistance, value);
-}
-
-qreal KoParagraphStyle::tabStopDistance() const
-{
- return propertyDouble(TabStopDistance);
-}
-
-bool KoParagraphStyle::registerTrue() const
-{
- if (hasProperty(RegisterTrue))
- return propertyBoolean(RegisterTrue);
- return false;
-}
-
-void KoParagraphStyle::setRegisterTrue(bool value)
-{
- setProperty(RegisterTrue, value);
-}
-
-bool KoParagraphStyle::strictLineBreak() const
-{
- if (hasProperty(StrictLineBreak))
- return propertyBoolean(StrictLineBreak);
- return false;
-}
-
-void KoParagraphStyle::setStrictLineBreak(bool value)
-{
- setProperty(StrictLineBreak, value);
-}
-
-bool KoParagraphStyle::justifySingleWord() const
-{
- if (hasProperty(JustifySingleWord))
- return propertyBoolean(JustifySingleWord);
- return false;
-}
-
-void KoParagraphStyle::setJustifySingleWord(bool value)
-{
- setProperty(JustifySingleWord, value);
-}
-
-void KoParagraphStyle::setTextAutoSpace(KoParagraphStyle::AutoSpace value)
-{
- setProperty(TextAutoSpace, value);
-}
-
-KoParagraphStyle::AutoSpace KoParagraphStyle::textAutoSpace() const
-{
- if (hasProperty(TextAutoSpace))
- return static_cast<AutoSpace>(propertyInt(TextAutoSpace));
- return NoAutoSpace;
-}
-
-void KoParagraphStyle::copyProperties(const KoParagraphStyle *style)
-{
- d->stylesPrivate = style->d->stylesPrivate;
- setName(style->name()); // make sure we emit property change
- KoCharacterStyle::copyProperties(style);
- d->parentStyle = style->d->parentStyle;
- d->defaultStyle = style->d->defaultStyle;
-}
-
-KoParagraphStyle *KoParagraphStyle::clone(QObject *parent) const
-{
- KoParagraphStyle *newStyle = new KoParagraphStyle(parent);
- newStyle->copyProperties(this);
- return newStyle;
-}
-
-bool KoParagraphStyle::compareParagraphProperties(const KoParagraphStyle &other) const
-{
- return other.d->stylesPrivate == d->stylesPrivate;
-}
-
-bool KoParagraphStyle::operator==(const KoParagraphStyle &other) const
-{
- if (!compareParagraphProperties(other))
- return false;
- if (!compareCharacterProperties(other))
- return false;
- return true;
-}
-
-void KoParagraphStyle::removeDuplicates(const KoParagraphStyle &other)
-{
- d->stylesPrivate.removeDuplicates(other.d->stylesPrivate);
- KoCharacterStyle::removeDuplicates(other);
-}
-
-void KoParagraphStyle::saveOdf(KoGenStyle &style, KoShapeSavingContext &context) const
-{
- bool writtenLineSpacing = false;
- KoCharacterStyle::saveOdf(style);
-
- if (listStyle()) {
- KoGenStyle liststyle(KoGenStyle::ListStyle);
- listStyle()->saveOdf(liststyle, context);
- QString name(QString(QUrl::toPercentEncoding(listStyle()->name(), "", " ")).replace('%', '_'));
- if (name.isEmpty())
- name = 'L';
- style.addAttribute("style:list-style-name", context.mainStyles().insert(liststyle, name, KoGenStyles::DontAddNumberToName));
- }
- // only custom style have a displayname. automatic styles don't have a name set.
- if (!d->name.isEmpty() && !style.isDefaultStyle()) {
- style.addAttribute("style:display-name", d->name);
- }
-
- QList<int> keys = d->stylesPrivate.keys();
- if (keys.contains(KoParagraphStyle::LeftPadding) && keys.contains(KoParagraphStyle::RightPadding)
- && keys.contains(KoParagraphStyle::TopPadding) && keys.contains(KoParagraphStyle::BottomPadding))
- {
- if ((leftPadding() == rightPadding()) && (topPadding() == bottomPadding()) && (rightPadding() == topPadding())) {
- style.addPropertyPt("fo:padding", leftPadding(), KoGenStyle::ParagraphType);
- keys.removeOne(KoParagraphStyle::LeftPadding);
- keys.removeOne(KoParagraphStyle::RightPadding);
- keys.removeOne(KoParagraphStyle::TopPadding);
- keys.removeOne(KoParagraphStyle::BottomPadding);
- }
- }
-
- if (keys.contains(QTextFormat::BlockLeftMargin) && keys.contains(QTextFormat::BlockRightMargin)
- && keys.contains(QTextFormat::BlockBottomMargin) && keys.contains(QTextFormat::BlockTopMargin))
- {
- if ((leftMargin() == rightMargin()) && (topMargin() == bottomMargin()) && (rightMargin() == topMargin())) {
- style.addPropertyLength("fo:margin", propertyLength(QTextFormat::BlockLeftMargin), KoGenStyle::ParagraphType);
- keys.removeOne(QTextFormat::BlockLeftMargin);
- keys.removeOne(QTextFormat::BlockRightMargin);
- keys.removeOne(QTextFormat::BlockTopMargin);
- keys.removeOne(QTextFormat::BlockBottomMargin);
- }
- }
-
-
- foreach (int key, keys) {
- if (key == QTextFormat::BlockAlignment) {
- int alignValue = 0;
- bool ok = false;
- alignValue = d->stylesPrivate.value(key).toInt(&ok);
- if (ok) {
- Qt::Alignment alignment = (Qt::Alignment) alignValue;
- QString align = KoText::alignmentToString(alignment);
- if (!align.isEmpty())
- style.addProperty("fo:text-align", align, KoGenStyle::ParagraphType);
- }
- } else if (key == KoParagraphStyle::AlignLastLine) {
- QString align = KoText::alignmentToString(alignLastLine());
- if (!align.isEmpty())
- style.addProperty("fo:text-align-last", align, KoGenStyle::ParagraphType);
- } else if (key == KoParagraphStyle::TextProgressionDirection) {
- style.addProperty("style:writing-mode", KoText::directionToString(textProgressionDirection()), KoGenStyle::ParagraphType);
- } else if (key == LineNumbering) {
- style.addProperty("text:number-lines", lineNumbering());
- } else if (key == PageNumber) {
- if (pageNumber() == 0)
- style.addProperty("style:page-number", "auto", KoGenStyle::ParagraphType);
- else
- style.addProperty("style:page-number", pageNumber(), KoGenStyle::ParagraphType);
- } else if (key == LineNumberStartValue) {
- style.addProperty("text:line-number", lineNumberStartValue());
- } else if (key == BreakAfter) {
- style.addProperty("fo:break-after", KoText::textBreakToString(breakAfter()), KoGenStyle::ParagraphType);
- } else if (key == BreakBefore) {
- style.addProperty("fo:break-before", KoText::textBreakToString(breakBefore()), KoGenStyle::ParagraphType);
- } else if (key == QTextFormat::BlockNonBreakableLines) {
- if (nonBreakableLines()) {
- style.addProperty("fo:keep-together", "always", KoGenStyle::ParagraphType);
- } else {
- style.addProperty("fo:keep-together", "auto", KoGenStyle::ParagraphType);
- }
- } else if (key == QTextFormat::BackgroundBrush) {
- QBrush backBrush = background();
- if (backBrush.style() != Qt::NoBrush)
- style.addProperty("fo:background-color", backBrush.color().name(), KoGenStyle::ParagraphType);
- else
- style.addProperty("fo:background-color", "transparent", KoGenStyle::ParagraphType);
- } else if (key == KoParagraphStyle::BackgroundTransparency) {
- style.addProperty("style:background-transparency", QString("%1%").arg(backgroundTransparency() * 100), KoGenStyle::ParagraphType);
- } else if (key == KoParagraphStyle::SnapToLayoutGrid) {
- style.addProperty("style:snap-to-layout-grid", snapToLayoutGrid(), KoGenStyle::ParagraphType);
- } else if (key == KoParagraphStyle::JustifySingleWord) {
- style.addProperty("style:justify-single-word", justifySingleWord(), KoGenStyle::ParagraphType);
- } else if (key == RegisterTrue) {
- style.addProperty("style:register-true", registerTrue(), KoGenStyle::ParagraphType);
- } else if (key == StrictLineBreak) {
- if (strictLineBreak())
- style.addProperty("style:line-break", "strict", KoGenStyle::ParagraphType);
- else
- style.addProperty("style:line-break", "normal", KoGenStyle::ParagraphType);
- } else if (key == JoinBorder) {
- style.addProperty("style:join-border", joinBorder(), KoGenStyle::ParagraphType);
- } else if (key == OrphanThreshold) {
- style.addProperty("fo:orphans", orphanThreshold(), KoGenStyle::ParagraphType);
- } else if (key == WidowThreshold) {
- style.addProperty("fo:widows", widowThreshold(), KoGenStyle::ParagraphType);
-
- // Padding
- } else if (key == KoParagraphStyle::LeftPadding) {
- style.addPropertyPt("fo:padding-left", leftPadding(), KoGenStyle::ParagraphType);
- } else if (key == KoParagraphStyle::RightPadding) {
- style.addPropertyPt("fo:padding-right", rightPadding(), KoGenStyle::ParagraphType);
- } else if (key == KoParagraphStyle::TopPadding) {
- style.addPropertyPt("fo:padding-top", topPadding(), KoGenStyle::ParagraphType);
- } else if (key == KoParagraphStyle::BottomPadding) {
- style.addPropertyPt("fo:padding-bottom", bottomPadding(), KoGenStyle::ParagraphType);
-
- // Margin
- } else if (key == QTextFormat::BlockLeftMargin) {
- style.addPropertyLength("fo:margin-left", propertyLength(QTextFormat::BlockLeftMargin), KoGenStyle::ParagraphType);
- } else if (key == QTextFormat::BlockRightMargin) {
- style.addPropertyLength("fo:margin-right", propertyLength(QTextFormat::BlockRightMargin), KoGenStyle::ParagraphType);
- } else if (key == QTextFormat::BlockTopMargin) {
- style.addPropertyLength("fo:margin-top", propertyLength(QTextFormat::BlockTopMargin), KoGenStyle::ParagraphType);
- } else if (key == QTextFormat::BlockBottomMargin) {
- style.addPropertyLength("fo:margin-bottom", propertyLength(QTextFormat::BlockBottomMargin), KoGenStyle::ParagraphType);
-
- // Line spacing
- } else if ( key == KoParagraphStyle::MinimumLineHeight ||
- key == KoParagraphStyle::LineSpacing ||
- key == KoParagraphStyle::PercentLineHeight ||
- key == KoParagraphStyle::FixedLineHeight ||
- key == KoParagraphStyle::LineSpacingFromFont) {
-
- if (key == KoParagraphStyle::MinimumLineHeight && propertyLength(MinimumLineHeight).rawValue() != 0) {
- style.addPropertyLength("style:line-height-at-least", propertyLength(MinimumLineHeight), KoGenStyle::ParagraphType);
- writtenLineSpacing = true;
- } else if (key == KoParagraphStyle::LineSpacing && lineSpacing() != 0) {
- style.addPropertyPt("style:line-spacing", lineSpacing(), KoGenStyle::ParagraphType);
- writtenLineSpacing = true;
- } else if (key == KoParagraphStyle::PercentLineHeight && lineHeightPercent() != 0) {
- style.addProperty("fo:line-height", QString("%1%").arg(lineHeightPercent()), KoGenStyle::ParagraphType);
- writtenLineSpacing = true;
- } else if (key == KoParagraphStyle::FixedLineHeight && lineHeightAbsolute() != 0) {
- style.addPropertyPt("fo:line-height", lineHeightAbsolute(), KoGenStyle::ParagraphType);
- writtenLineSpacing = true;
- } else if (key == KoParagraphStyle::LineSpacingFromFont && lineHeightAbsolute() == 0) {
- style.addProperty("style:font-independent-line-spacing", lineSpacingFromFont(), KoGenStyle::ParagraphType);
- writtenLineSpacing = true;
- }
- //
- } else if (key == QTextFormat::TextIndent) {
- style.addPropertyLength("fo:text-indent", propertyLength(QTextFormat::TextIndent), KoGenStyle::ParagraphType);
- } else if (key == KoParagraphStyle::AutoTextIndent) {
- style.addProperty("style:auto-text-indent", autoTextIndent(), KoGenStyle::ParagraphType);
- } else if (key == KoParagraphStyle::TabStopDistance) {
- style.addPropertyPt("style:tab-stop-distance", tabStopDistance(), KoGenStyle::ParagraphType);
- } else if (key == KoParagraphStyle::MasterPageName) {
- style.addAttribute("style:master-page-name", masterPageName());
- } else if (key == KoParagraphStyle::DefaultOutlineLevel) {
- style.addAttribute("style:default-outline-level", defaultOutlineLevel());
- } else if (key == KoParagraphStyle::AutomaticWritingMode) {
- style.addProperty("style:writing-mode-automatic", automaticWritingMode(), KoGenStyle::ParagraphType);
- } else if (key == KoParagraphStyle::TextAutoSpace) {
- if (textAutoSpace() == NoAutoSpace)
- style.addProperty("style:text-autospace", "none", KoGenStyle::ParagraphType);
- else if (textAutoSpace() == IdeographAlpha)
- style.addProperty("style:text-autospace", "ideograph-alpha", KoGenStyle::ParagraphType);
- } else if (key == KoParagraphStyle::KeepWithNext) {
- if (keepWithNext())
- style.addProperty("fo:keep-with-next", "always", KoGenStyle::ParagraphType);
- else
- style.addProperty("fo:keep-with-next", "auto", KoGenStyle::ParagraphType);
- } else if (key == KoParagraphStyle::KeepHyphenation) {
- if (keepHyphenation())
- style.addProperty("fo:hyphenation-keep", "page", KoGenStyle::ParagraphType);
- else
- style.addProperty("fo:hyphenation-keep", "auto", KoGenStyle::ParagraphType);
- } else if (key == KoParagraphStyle::HyphenationLadderCount) {
- int value = hyphenationLadderCount();
- if (value == 0)
- style.addProperty("fo:hyphenation-ladder-count", "no-limit", KoGenStyle::ParagraphType);
- else
- style.addProperty("fo:hyphenation-ladder-count", value, KoGenStyle::ParagraphType);
- } else if (key == PunctuationWrap) {
- if (punctuationWrap())
- style.addProperty("style:punctuation-wrap", "simple", KoGenStyle::ParagraphType);
- else
- style.addProperty("style:punctuation-wrap", "hanging", KoGenStyle::ParagraphType);
- } else if (key == VerticalAlignment) {
- VerticalAlign valign = verticalAlignment();
- if (valign == VAlignAuto)
- style.addProperty("style:vertical-align", "auto", KoGenStyle::ParagraphType);
- else if (valign == VAlignBaseline)
- style.addProperty("style:vertical-align", "baseline", KoGenStyle::ParagraphType);
- else if (valign == VAlignBottom)
- style.addProperty("style:vertical-align", "bottom", KoGenStyle::ParagraphType);
- else if (valign == VAlignMiddle)
- style.addProperty("style:vertical-align", "middle", KoGenStyle::ParagraphType);
- else if (valign == VAlignTop)
- style.addProperty("style:vertical-align", "top", KoGenStyle::ParagraphType);
- } else if (key == Shadow) {
- style.addProperty("style:shadow", shadow().saveOdf());
- }
- }
- if (!writtenLineSpacing && propertyBoolean(NormalLineHeight))
- style.addProperty("fo:line-height", QString("normal"), KoGenStyle::ParagraphType);
- // save border stuff
- QString leftBorder = QString("%1pt %2 %3").arg(QString::number(leftBorderWidth()),
- KoBorder::odfBorderStyleString(leftBorderStyle()),
- leftBorderColor().name());
- QString rightBorder = QString("%1pt %2 %3").arg(QString::number(rightBorderWidth()),
- KoBorder::odfBorderStyleString(rightBorderStyle()),
- rightBorderColor().name());
- QString topBorder = QString("%1pt %2 %3").arg(QString::number(topBorderWidth()),
- KoBorder::odfBorderStyleString(topBorderStyle()),
- topBorderColor().name());
- QString bottomBorder = QString("%1pt %2 %3").arg(QString::number(bottomBorderWidth()),
- KoBorder::odfBorderStyleString(bottomBorderStyle()),
- bottomBorderColor().name());
- if (leftBorder == rightBorder && leftBorder == topBorder && leftBorder == bottomBorder) {
- if (leftBorderWidth() > 0 && leftBorderStyle() != KoBorder::BorderNone)
- style.addProperty("fo:border", leftBorder, KoGenStyle::ParagraphType);
- } else {
- if (leftBorderWidth() > 0 && leftBorderStyle() != KoBorder::BorderNone)
- style.addProperty("fo:border-left", leftBorder, KoGenStyle::ParagraphType);
- if (rightBorderWidth() > 0 && rightBorderStyle() != KoBorder::BorderNone)
- style.addProperty("fo:border-right", rightBorder, KoGenStyle::ParagraphType);
- if (topBorderWidth() > 0 && topBorderStyle() != KoBorder::BorderNone)
- style.addProperty("fo:border-top", topBorder, KoGenStyle::ParagraphType);
- if (bottomBorderWidth() > 0 && bottomBorderStyle() != KoBorder::BorderNone)
- style.addProperty("fo:border-bottom", bottomBorder, KoGenStyle::ParagraphType);
- }
- QString leftBorderLineWidth, rightBorderLineWidth, topBorderLineWidth, bottomBorderLineWidth;
- if (leftBorderStyle() == KoBorder::BorderDouble)
- leftBorderLineWidth = QString("%1pt %2pt %3pt").arg(QString::number(leftInnerBorderWidth()),
- QString::number(leftBorderSpacing()),
- QString::number(leftBorderWidth()));
- if (rightBorderStyle() == KoBorder::BorderDouble)
- rightBorderLineWidth = QString("%1pt %2pt %3pt").arg(QString::number(rightInnerBorderWidth()),
- QString::number(rightBorderSpacing()),
- QString::number(rightBorderWidth()));
- if (topBorderStyle() == KoBorder::BorderDouble)
- topBorderLineWidth = QString("%1pt %2pt %3pt").arg(QString::number(topInnerBorderWidth()),
- QString::number(topBorderSpacing()),
- QString::number(topBorderWidth()));
- if (bottomBorderStyle() == KoBorder::BorderDouble)
- bottomBorderLineWidth = QString("%1pt %2pt %3pt").arg(QString::number(bottomInnerBorderWidth()),
- QString::number(bottomBorderSpacing()),
- QString::number(bottomBorderWidth()));
- if (leftBorderLineWidth == rightBorderLineWidth &&
- leftBorderLineWidth == topBorderLineWidth &&
- leftBorderLineWidth == bottomBorderLineWidth && !leftBorderLineWidth.isEmpty()) {
- style.addProperty("style:border-line-width", leftBorderLineWidth, KoGenStyle::ParagraphType);
- } else {
- if (!leftBorderLineWidth.isEmpty())
- style.addProperty("style:border-line-width-left", leftBorderLineWidth, KoGenStyle::ParagraphType);
- if (!rightBorderLineWidth.isEmpty())
- style.addProperty("style:border-line-width-right", rightBorderLineWidth, KoGenStyle::ParagraphType);
- if (!topBorderLineWidth.isEmpty())
- style.addProperty("style:border-line-width-top", topBorderLineWidth, KoGenStyle::ParagraphType);
- if (!bottomBorderLineWidth.isEmpty())
- style.addProperty("style:border-line-width-bottom", bottomBorderLineWidth, KoGenStyle::ParagraphType);
- }
- const int indentation = 4; // indentation for children of office:styles/style:style/style:paragraph-properties
- // drop-caps
- if (dropCaps()) {
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- KoXmlWriter elementWriter(&buf, indentation);
- elementWriter.startElement("style:drop-cap");
- elementWriter.addAttribute("style:lines", QString::number(dropCapsLines()));
- elementWriter.addAttribute("style:length", dropCapsLength() == 0 ? "word" : QString::number(dropCapsLength()));
- if (dropCapsDistance())
- elementWriter.addAttribute("style:distance", dropCapsDistance());
- elementWriter.endElement();
- QString elementContents = QString::fromUtf8(buf.buffer(), buf.buffer().size());
- style.addChildElement("style:drop-cap", elementContents, KoGenStyle::ParagraphType);
- }
- if (tabPositions().count() > 0) {
- QMap<int, QString> tabTypeMap, leaderTypeMap, leaderStyleMap, leaderWeightMap;
- tabTypeMap[QTextOption::LeftTab] = "left";
- tabTypeMap[QTextOption::RightTab] = "right";
- tabTypeMap[QTextOption::CenterTab] = "center";
- tabTypeMap[QTextOption::DelimiterTab] = "char";
- leaderTypeMap[KoCharacterStyle::NoLineType] = "none";
- leaderTypeMap[KoCharacterStyle::SingleLine] = "single";
- leaderTypeMap[KoCharacterStyle::DoubleLine] = "double";
- leaderStyleMap[KoCharacterStyle::NoLineStyle] = "none";
- leaderStyleMap[KoCharacterStyle::SolidLine] = "solid";
- leaderStyleMap[KoCharacterStyle::DottedLine] = "dotted";
- leaderStyleMap[KoCharacterStyle::DashLine] = "dash";
- leaderStyleMap[KoCharacterStyle::LongDashLine] = "long-dash";
- leaderStyleMap[KoCharacterStyle::DotDashLine] = "dot-dash";
- leaderStyleMap[KoCharacterStyle::DotDotDashLine] = "dot-dot-dash";
- leaderStyleMap[KoCharacterStyle::WaveLine] = "wave";
- leaderWeightMap[KoCharacterStyle::AutoLineWeight] = "auto";
- leaderWeightMap[KoCharacterStyle::NormalLineWeight] = "normal";
- leaderWeightMap[KoCharacterStyle::BoldLineWeight] = "bold";
- leaderWeightMap[KoCharacterStyle::ThinLineWeight] = "thin";
- leaderWeightMap[KoCharacterStyle::DashLineWeight] = "dash";
- leaderWeightMap[KoCharacterStyle::MediumLineWeight] = "medium";
- leaderWeightMap[KoCharacterStyle::ThickLineWeight] = "thick";
-
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- KoXmlWriter elementWriter(&buf, indentation);
- elementWriter.startElement("style:tab-stops");
- Q_FOREACH (const KoText::Tab &tab, tabPositions()) {
- elementWriter.startElement("style:tab-stop");
- elementWriter.addAttribute("style:position", tab.position);
- if (!tabTypeMap[tab.type].isEmpty())
- elementWriter.addAttribute("style:type", tabTypeMap[tab.type]);
- if (tab.type == QTextOption::DelimiterTab && !tab.delimiter.isNull())
- elementWriter.addAttribute("style:char", tab.delimiter);
- if (!leaderTypeMap[tab.leaderType].isEmpty())
- elementWriter.addAttribute("style:leader-type", leaderTypeMap[tab.leaderType]);
- if (!leaderStyleMap[tab.leaderStyle].isEmpty())
- elementWriter.addAttribute("style:leader-style", leaderStyleMap[tab.leaderStyle]);
- if (!leaderWeightMap[tab.leaderWeight].isEmpty())
- elementWriter.addAttribute("style:leader-width", leaderWeightMap[tab.leaderWeight]);
- else if (tab.leaderWeight == KoCharacterStyle::PercentLineWeight)
- elementWriter.addAttribute("style:leader-width", QString("%1%").arg(QString::number(tab.leaderWidth)));
- else if (tab.leaderWeight == KoCharacterStyle::LengthLineWeight)
- elementWriter.addAttribute("style:leader-width", tab.leaderWidth);
- if (tab.leaderColor.isValid())
- elementWriter.addAttribute("style:leader-color", tab.leaderColor.name());
- else
- elementWriter.addAttribute("style:leader-color", "font-color");
- if (!tab.leaderText.isEmpty())
- elementWriter.addAttribute("style:leader-text", tab.leaderText);
- elementWriter.endElement();
- }
- elementWriter.endElement();
- buf.close();
- QString elementContents = QString::fromUtf8(buf.buffer(), buf.buffer().size());
- style.addChildElement("style:tab-stops", elementContents, KoGenStyle::ParagraphType);
- }
-}
-
-bool KoParagraphStyle::hasDefaults() const
-{
- int size=d->stylesPrivate.properties().size();
- if ((size == 0) || (size==1 && d->stylesPrivate.properties().contains(StyleId))) {
- return true;
- }
- return false;
-}
-
-KoList *KoParagraphStyle::list() const
-{
- return d->list;
-}
diff --git a/plugins/flake/textshape/kotext/styles/KoParagraphStyle.h b/plugins/flake/textshape/kotext/styles/KoParagraphStyle.h
deleted file mode 100644
index 73ef52656f..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoParagraphStyle.h
+++ /dev/null
@@ -1,745 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2007,2008 Sebastian Sauer <mail@dipe.org>
- * Copyright (C) 2007-2011 Pierre Ducroquet <pinaraf@gmail.com>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- *
- * 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 KOPARAGRAPHSTYLE_H
-#define KOPARAGRAPHSTYLE_H
-
-#include "KoCharacterStyle.h"
-#include "KoText.h"
-#include "kritatext_export.h"
-
-#include <KoXmlReaderForward.h>
-#include <KoBorder.h>
-
-#include <QVariant>
-#include <QTextFormat>
-
-extern QVariant val;
-class KoShadowStyle;
-class KoListStyle;
-class QTextBlock;
-class KoGenStyle;
-class KoShapeLoadingContext;
-class KoShapeSavingContext;
-class KoList;
-
-/**
- * A container for all properties for the paragraph wide style.
- * Each paragraph in the main text either is based on a parag style, or its not. Where
- * it is based on a paragraph style this is indecated that it has a property 'StyleId'
- * with an integer as value. The integer value corresponds to the styleId() output of
- * a specific KoParagraphStyle.
- * @see KoStyleManager
- */
-class KRITATEXT_EXPORT KoParagraphStyle : public KoCharacterStyle
-{
- Q_OBJECT
-public:
- enum Property {
- // Every 10 properties, the decimal number shown indicates the decimal offset over the QTextFormat::UserProperty enum value
- StyleId = QTextFormat::UserProperty + 1,
- // Linespacing properties
- PercentLineHeight, ///< this property is used for a percentage of the highest character on that line
- FixedLineHeight, ///< this property is used to use a non-default line height
- MinimumLineHeight, ///< this property is used to have a minimum line spacing
- LineSpacing, ///< Hard leader height.
- LineSpacingFromFont, ///< if false, use fontsize (in pt) solely, otherwise respect font settings
- AlignLastLine, ///< When the paragraph is justified, what to do with the last word line
- WidowThreshold, ///< If 'keep together'=false, amount of lines to keep it anyway.
- OrphanThreshold, ///< If 'keep together'=false, amount of lines to keep it anyway.
- DropCaps, /*10*/ ///< defines if a paragraph renders its first char(s) with drop-caps
- DropCapsLength, ///< Number of glyphs to show as drop-caps
- DropCapsLines, ///< Number of lines that the drop-caps span
- DropCapsDistance, ///< Distance between drop caps and text
- DropCapsTextStyle, ///< Text style of dropped chars.
- FollowDocBaseline, ///< If true the baselines will be aligned with the doc-wide grid
-
- // border stuff
- HasLeftBorder, ///< If true, paint a border on the left
- HasTopBorder, ///< If true, paint a border on the top
- HasRightBorder, ///< If true, paint a border on the right
- HasBottomBorder,///< If true, paint a border on the bottom
- BorderLineWidth, /*20*/ ///< Thickness of inner-border
- SecondBorderLineWidth, ///< Thickness of outer-border
- DistanceToSecondBorder, ///< Distance between inner and outer border
- LeftPadding, ///< distance between text and border
- TopPadding, ///< distance between text and border
- RightPadding, ///< distance between text and border
- BottomPadding, ///< distance between text and border
- LeftBorderWidth, ///< The thickness of the border, or 0 if there is no border
- LeftInnerBorderWidth, ///< In case of style being 'double' the thickness of the inner border line
- LeftBorderSpacing, ///< In case of style being 'double' the space between the inner and outer border lines
- LeftBorderStyle, /*30*/ ///< The border style. (see BorderStyle)
- LeftBorderColor, ///< The border Color
- TopBorderWidth, ///< The thickness of the border, or 0 if there is no border
- TopInnerBorderWidth, ///< In case of style being 'double' the thickness of the inner border line
- TopBorderSpacing, ///< In case of style being 'double' the space between the inner and outer border lines
- TopBorderStyle, ///< The border style. (see BorderStyle)
- TopBorderColor, ///< The border Color
- RightBorderWidth, ///< The thickness of the border, or 0 if there is no border
- RightInnerBorderWidth, ///< In case of style being 'double' the thickness of the inner border line
- RightBorderSpacing, ///< In case of style being 'double' the space between the inner and outer border lines
- RightBorderStyle, /*40*/ ///< The border style. (see BorderStyle)
- RightBorderColor, ///< The border Color
- BottomBorderWidth, ///< The thickness of the border, or 0 if there is no border
- BottomInnerBorderWidth, ///< In case of style being 'double' the thickness of the inner border line
- BottomBorderSpacing, ///< In case of style being 'double' the space between the inner and outer border lines
- BottomBorderStyle, ///< The border style. (see BorderStyle)
- BottomBorderColor, ///< The border Color
-
- // lists
- ListStyleId, ///< Style Id of associated list style
- ListStartValue, ///< Int with the list-value that parag will have. Ignored if this is not a list.
- RestartListNumbering, ///< boolean to indicate that this paragraph will have numbering restart at the list-start. Ignored if this is not a list.
- ListLevel, /*50*/ ///< int with the list-level that the paragraph will get when this is a list (numbered paragraphs)
- IsListHeader, ///< bool, if true the paragraph shows up as a list item, but w/o a list label.
- UnnumberedListItem, ///< bool. if true this paragraph is part of a list but is not numbered
-
- AutoTextIndent, ///< bool, says whether the paragraph is auto-indented or not
-
- TabStopDistance, ///< Double, Length. specifies that there's a tab stop every n inches
- ///< (after the last of the TabPositions, if any)
- TabPositions, ///< A list of tab positions
- TextProgressionDirection,
-
- MasterPageName, ///< Optional name of the master-page
-
- OutlineLevel, ///< Outline level for headings
- DefaultOutlineLevel,
-
- // numbering
- LineNumbering, /*60*/ ///< bool, specifies whether lines should be numbered in this paragraph
- LineNumberStartValue, ///< integer value that specifies the number for the first line in the paragraph
- SectionStartings, ///< list of section definitions
- SectionEndings, ///< list <end of a named section>
-// do 15.5.24
-// continue at 15.5.28
- ForceDisablingList, ///< bool, for compatibility with the weird text:enable-numbering attribute not used anymore by OpenOffice.org
-
- // other properties
- BackgroundTransparency, ///< qreal between 0 and 1, background transparency
- SnapToLayoutGrid, ///< bool, snap the paragraph to the layout grid of the page
- JoinBorder, ///< bool, whether a border for one paragraph is to be extended around the following paragraph
- RegisterTrue, ///< bool, align lines on both sides of a printed text
- StrictLineBreak, ///< bool, if true, line breaks are forbidden between some characters
- JustifySingleWord, ///< bool, if true, a single word will be justified
- BreakBefore, ///< KoText::TextBreakProperty, whether there is a page/column break before the paragraphs
- BreakAfter, ///< KoText::TextBreakProperty, whether there is a page/column break after the paragraphs
- AutomaticWritingMode, ///< bool
- PageNumber, ///< int, 0 means auto (ie. previous page number + 1), N sets up a new page number
- TextAutoSpace, ///< AutoSpace, indicating whether to add space between portions of Asian, Western and complex texts
- KeepWithNext, ///< Try to keep this block with its following block on the same page
- KeepHyphenation, ///< bool, whether both parts of a hyphenated word shall lie within a single page
- HyphenationLadderCount, ///< int, 0 means no limit, else limit the number of successive hyphenated line areas in a block
- PunctuationWrap, ///< bool, whether a punctuation mark can be at the end of a full line (false) or not (true)
- VerticalAlignment, ///< KoParagraphStyle::VerticalAlign, the alignment of this paragraph text
- HiddenByTable, ///< don't let this paragraph have any height
-
- NormalLineHeight, ///< bool, internal property for reserved usage
- BibliographyData,
-
- TableOfContentsData, // set when block is instead a TableOfContents
- GeneratedDocument, // set when block is instead a generated document
- Shadow, //< KoShadowStyle, the shadow of this paragraph
- NextStyle, ///< holds the styleId of the style to be used on a new paragraph
- ParagraphListStyleId, ///< this holds the listStyleId of the list got from style:list-style-name property from ODF 1.2
- EndCharStyle // QSharedPointer<KoCharacterStyle> used when final line is empty
- };
-
- enum AutoSpace {
- NoAutoSpace, ///< space should not be added between portions of Asian, Western and complex texts
- IdeographAlpha ///< space should be added between portions of Asian, Western and complex texts
- };
-
- enum VerticalAlign {
- VAlignAuto,
- VAlignBaseline,
- VAlignBottom,
- VAlignMiddle,
- VAlignTop
- };
-
- /// Constructor
- KoParagraphStyle(QObject *parent = 0);
- /// Creates a KoParagrahStyle with the given block format, the block character format and \a parent
- KoParagraphStyle(const QTextBlockFormat &blockFormat, const QTextCharFormat &blockCharFormat, QObject *parent = 0);
- /// Destructor
- ~KoParagraphStyle() override;
-
- KoCharacterStyle::Type styleType() const override;
-
- /// Creates a KoParagraphStyle that represents the formatting of \a block.
- static KoParagraphStyle *fromBlock(const QTextBlock &block, QObject *parent = 0);
-
- /// creates a clone of this style with the specified parent
- KoParagraphStyle *clone(QObject *parent = 0) const;
-
- // ***** Linespacing
- /**
- * Sets the line height as a percentage of the highest character on that line.
- * A good typographically correct value would be 120%
- * Note that lineSpacing() is added to this.
- * You should consider doing a remove(KoParagraphStyle::LineSpacing); because if set, it will
- * be used instead of this value.
- * @see setLineSpacingFromFont
- */
- void setLineHeightPercent(qreal lineHeight);
- /// @see setLineHeightPercent
- qreal lineHeightPercent() const;
-
- /**
- * Sets the line height to a specific pt-based height, ignoring the font size.
- * Setting this will ignore the lineHeightPercent() and lineSpacing() values.
- */
- void setLineHeightAbsolute(qreal height);
- /// @see setLineHeightAbsolute
- qreal lineHeightAbsolute() const;
-
- /**
- * Sets the line height to have a minimum height in pt.
- * You should consider doing a remove(KoParagraphStyle::FixedLineHeight); because if set, it will
- * be used instead of this value.
- */
- void setMinimumLineHeight(const QTextLength &height);
- /// @see setMinimumLineHeight
- qreal minimumLineHeight() const;
-
- /**
- * Sets the space between two lines to be a specific height. The total linespacing will become
- * the line height + this height. Where the line height is dependent on the font.
- * You should consider doing a remove(KoParagraphStyle::FixedLineHeight) and a
- * remove(KoParagraphStyle::PercentLineHeight); because if set, they will be used instead of this value.
- */
- void setLineSpacing(qreal spacing);
- /// @see setLineSpacing
- qreal lineSpacing() const;
-
- /**
- * Set the line-height to "normal". This overwrites a line-height set before either
- * with \a setLineHeightAbsolute or \a setMinimumLineHeight . If set then a value
- * set with \a setLineSpacing will be ignored.
- */
- void setNormalLineHeight();
- /// @see setNormalLineHeight
- bool hasNormalLineHeight() const;
-
- /**
- * If set to true the font-encoded height will be used instead of the font-size property
- * This property influences setLineHeightPercent() behavior.
- * When off (default) a font of 12pt will always have a linespacing of 12pt times the
- * current linespacing percentage. When on the linespacing embedded in the font
- * is used which can differ for various fonts, even if they are the same pt-size.
- */
- void setLineSpacingFromFont(bool on);
- /**
- * @see setLineSpacingFromFont
- */
- bool lineSpacingFromFont() const;
-
-
- /**
- * For paragraphs that are justified the last line alignment is specified here.
- * There are only 3 valid options, Left, Center and Justified. (where Left will
- * be right aligned for RTL text).
- */
- void setAlignLastLine(Qt::Alignment alignment);
- /**
- * @see setAlignLastLine
- */
- Qt::Alignment alignLastLine() const;
- /**
- * Paragraphs that are broken across two frames are normally broken at the bottom
- * of the frame. Using this property we can set the minimum number of lines that should
- * appear in the second frame to avoid really short paragraphs standing alone (also called
- * widows). So, if a 10 line parag is broken in a way that only one line is in the second
- * frame, setting a widowThreshold of 4 will break at 6 lines instead to leave the
- * requested 4 lines.
- */
-
- void setWidowThreshold(int lines);
- /**
- * @see setWidowThreshold
- */
- int widowThreshold() const;
- /**
- * Paragraphs that are broken across two frames are normally broken at the bottom
- * of the frame. Using this property we can set the minimum number of lines that should
- * appear in the first frame to avoid really short paragraphs standing alone (also called
- * orphans). So, if a paragraph is broken so only 2 line is left in the first frame
- * setting the orphanThreshold to something greater than 2 will move the whole paragraph
- * to the second frame.
- */
-
- void setOrphanThreshold(int lines);
- /**
- * @see setOrphanThreshold
- */
- int orphanThreshold() const;
- /**
- * If true, make the first character span multiple lines.
- * @see setDropCapsLength
- * @see setDropCapsLines
- * @see dropCapsDistance
- */
-
- void setDropCaps(bool on);
- /**
- * @see setDropCaps
- */
- bool dropCaps() const;
- /**
- * Set the number of glyphs to show as drop-caps
- * @see setDropCaps
- * @see setDropCapsLines
- * @see dropCapsDistance
- */
-
- void setDropCapsLength(int characters);
- /**
- * set dropCaps Length in characters
- * @see setDropCapsLength
- */
- int dropCapsLength() const;
- /**
- * Set the number of lines that the drop-caps span
- * @see setDropCapsLength
- * @see setDropCaps
- * @see dropCapsDistance
- */
-
- void setDropCapsLines(int lines);
- /**
- * The dropCapsLines
- * @see setDropCapsLines
- */
- int dropCapsLines() const;
- /**
- * set the distance between drop caps and text in pt
- * @see setDropCapsLength
- * @see setDropCaps
- * @see setDropCapsLines
- */
-
- void setDropCapsDistance(qreal distance);
- /**
- * The dropCaps distance
- * @see setDropCapsDistance
- */
- qreal dropCapsDistance() const;
-
- /**
- * Set the style id of the text style used for dropcaps
- * @see setDropCapsDistance
- */
- void setDropCapsTextStyleId(int id);
-
- /**
- * The style id of the text style used for dropcaps
- * @see setDropCapsTextStyleId
- */
- int dropCapsTextStyleId() const;
-
- /**
- * If true the baselines will be aligned with the doc-wide grid
- */
- void setFollowDocBaseline(bool on);
- /**
- * return if baseline alignment is used
- * @see setFollowDocBaseline
- */
- bool followDocBaseline() const;
-
- /// See similar named method on QTextBlockFormat
- void setBackground(const QBrush &brush);
- /// See similar named method on QTextBlockFormat
- QBrush background() const;
- /// See similar named method on QTextBlockFormat
- void clearBackground();
-
- qreal backgroundTransparency() const;
- void setBackgroundTransparency(qreal transparency);
-
- bool snapToLayoutGrid() const;
- void setSnapToLayoutGrid(bool value);
-
- bool registerTrue() const;
- void setRegisterTrue(bool value);
-
- bool strictLineBreak() const;
- void setStrictLineBreak(bool value);
-
- bool justifySingleWord() const;
- void setJustifySingleWord(bool value);
-
- bool automaticWritingMode() const;
- void setAutomaticWritingMode(bool value);
-
- void setPageNumber(int pageNumber);
- int pageNumber() const;
-
- void setKeepWithNext(bool value);
- bool keepWithNext() const;
-
- void setPunctuationWrap(bool value);
- bool punctuationWrap() const;
-
- void setTextAutoSpace(AutoSpace value);
- AutoSpace textAutoSpace() const;
-
- void setKeepHyphenation(bool value);
- bool keepHyphenation() const;
-
- void setHyphenationLadderCount(int value);
- int hyphenationLadderCount() const;
-
- VerticalAlign verticalAlignment() const;
- void setVerticalAlignment(VerticalAlign value);
-
- void setBreakBefore(KoText::KoTextBreakProperty value);
- KoText::KoTextBreakProperty breakBefore() const;
- void setBreakAfter(KoText::KoTextBreakProperty value);
- KoText::KoTextBreakProperty breakAfter() const;
- void setLeftPadding(qreal padding);
- qreal leftPadding() const;
- void setTopPadding(qreal padding);
- qreal topPadding() const;
- void setRightPadding(qreal padding);
- qreal rightPadding() const;
- void setBottomPadding(qreal padding);
- qreal bottomPadding() const;
- void setPadding(qreal padding);
-
- void setLeftBorderWidth(qreal width);
- qreal leftBorderWidth() const;
- void setLeftInnerBorderWidth(qreal width);
- qreal leftInnerBorderWidth() const;
- void setLeftBorderSpacing(qreal width);
- qreal leftBorderSpacing() const;
- void setLeftBorderStyle(KoBorder::BorderStyle style);
- KoBorder::BorderStyle leftBorderStyle() const;
- void setLeftBorderColor(const QColor &color);
- QColor leftBorderColor() const;
- void setTopBorderWidth(qreal width);
- qreal topBorderWidth() const;
- void setTopInnerBorderWidth(qreal width);
- qreal topInnerBorderWidth() const;
- void setTopBorderSpacing(qreal width);
- qreal topBorderSpacing() const;
- void setTopBorderStyle(KoBorder::BorderStyle style);
- KoBorder::BorderStyle topBorderStyle() const;
- void setTopBorderColor(const QColor &color);
- QColor topBorderColor() const;
- void setRightBorderWidth(qreal width);
- qreal rightBorderWidth() const;
- void setRightInnerBorderWidth(qreal width);
- qreal rightInnerBorderWidth() const;
- void setRightBorderSpacing(qreal width);
- qreal rightBorderSpacing() const;
- void setRightBorderStyle(KoBorder::BorderStyle style);
- KoBorder::BorderStyle rightBorderStyle() const;
- void setRightBorderColor(const QColor &color);
- QColor rightBorderColor() const;
- void setBottomBorderWidth(qreal width);
- qreal bottomBorderWidth() const;
- void setBottomInnerBorderWidth(qreal width);
- qreal bottomInnerBorderWidth() const;
- void setBottomBorderSpacing(qreal width);
- qreal bottomBorderSpacing() const;
- void setBottomBorderStyle(KoBorder::BorderStyle style);
- KoBorder::BorderStyle bottomBorderStyle() const;
- void setBottomBorderColor(const QColor &color);
- QColor bottomBorderColor() const;
-
- bool joinBorder() const;
- void setJoinBorder(bool value);
-
- KoText::Direction textProgressionDirection() const;
- void setTextProgressionDirection(KoText::Direction dir);
-
- // ************ properties from QTextBlockFormat
- /// duplicated property from QTextBlockFormat
- void setTopMargin(QTextLength topMargin);
- /// duplicated property from QTextBlockFormat
- qreal topMargin() const;
- /// duplicated property from QTextBlockFormat
- void setBottomMargin(QTextLength margin);
- /// duplicated property from QTextBlockFormat
- qreal bottomMargin() const;
- /// duplicated property from QTextBlockFormat
- void setLeftMargin(QTextLength margin);
- /// duplicated property from QTextBlockFormat
- qreal leftMargin() const;
- /// duplicated property from QTextBlockFormat
- void setRightMargin(QTextLength margin);
- /// duplicated property from QTextBlockFormat
- qreal rightMargin() const;
- /// set the margin around the paragraph, making the margin on all sides equal.
- void setMargin(QTextLength margin);
-
- void setIsListHeader(bool on);
- bool isListHeader() const;
-
- /// duplicated property from QTextBlockFormat
- void setAlignment(Qt::Alignment alignment);
- /// duplicated property from QTextBlockFormat
- Qt::Alignment alignment() const;
- /// duplicated property from QTextBlockFormat
- void setTextIndent(QTextLength margin);
- /// duplicated property from QTextBlockFormat
- qreal textIndent() const;
- /// Custom KoParagraphStyle property for auto-text-indent
- void setAutoTextIndent(bool on);
- bool autoTextIndent() const;
-
- /// duplicated property from QTextBlockFormat
- void setNonBreakableLines(bool on);
- /// duplicated property from QTextBlockFormat
- bool nonBreakableLines() const;
-
- /// set the default style this one inherits its unset properties from if no parent style.
- void setDefaultStyle(KoParagraphStyle *parent);
-
- /// set the parent style this one inherits its unset properties from.
- void setParentStyle(KoParagraphStyle *parent);
-
- /// return the parent style
- KoParagraphStyle *parentStyle() const;
-
- /// the 'next' style is the one used when the user creates a new paragraph after this one.
- void setNextStyle(int next);
-
- /// the 'next' style is the one used when the user creates a new paragraph after this one.
- int nextStyle() const;
-
- /// return the name of the style.
- QString name() const;
-
- /// set a user-visible name on the style.
- void setName(const QString &name);
-
- /// each style has a unique ID (non persistent) given out by the styleManager
- int styleId() const;
-
- /// each style has a unique ID (non persistent) given out by the styleManager
- void setStyleId(int id);
-
- /// return the optional name of the master-page or a QString() if this paragraph isn't attached to a master-page.
- QString masterPageName() const;
- /// Set the name of the master-page.
- void setMasterPageName(const QString &name);
-
-
- /// Set the list start value
- void setListStartValue(int value);
- /// Returns the list start value
- int listStartValue() const;
-
- /// Set to true if this paragraph is marked to start the list numbering from the first entry.
- void setRestartListNumbering(bool on);
- /// return if this paragraph is marked to start the list numbering from the first entry.
- bool restartListNumbering();
-
- /// Set the tab stop distance for this paragraph style.
- void setTabStopDistance(qreal value);
- /// return the tab stop distance for this paragraph style
- qreal tabStopDistance() const;
- /// Set the tab data for this paragraph style.
- void setTabPositions(const QList<KoText::Tab> &tabs);
- /// return the tabs data for this paragraph style
- QList<KoText::Tab> tabPositions() const;
-
- /// If this style is a list, then this sets the nested-ness (aka level) of this paragraph. A H2 has level 2.
- void setListLevel(int value);
- /// return the list level.
- int listLevel() const;
-
- /**
- * Return the outline level of this block, or 0 if it's not a heading.
- * This information is here and not in the styles because the OpenDocument specification says so.
- * See ODF Spec 1.1, §14.1, Outline Numbering Level, but also other parts of the specification.
- */
- int outlineLevel() const;
-
- /**
- * Change this block outline level
- */
- void setOutlineLevel(int outline);
-
- /**
- * Return the default outline level of this style, or 0 if there is none.
- */
- int defaultOutlineLevel() const;
-
- /**
- * Change the default outline level for this style.
- */
- void setDefaultOutlineLevel(int outline);
-
-
- /**
- * 15.5.30: The text:number-lines attribute controls whether or not lines are numbered
- */
- bool lineNumbering() const;
- void setLineNumbering(bool lineNumbering);
-
- /**
- * 15.5.31:
- * The text:line-number property specifies a new start value for line numbering. The attribute is
- * only recognized if there is also a text:number-lines attribute with a value of true in the
- * same properties element.
- */
- int lineNumberStartValue() const;
- void setLineNumberStartValue(int lineNumberStartValue);
-
- /**
- * 20.349 style:shadow
- * The style:shadow attribute specifies a shadow effect.
- * The defined values for this attribute are those defined in §7.16.5 of [XSL], except the value
- * inherit.
- * The shadow effect is not applied to the text content of an element, but depending on the element
- * where the attribute appears, to a paragraph, a text box, a page body, a header, a footer, a table
- * or a table cell.
- */
- KoShadowStyle shadow() const;
- void setShadow (const KoShadowStyle &shadow);
-
- /// copy all the properties from the other style to this style, effectively duplicating it.
- void copyProperties(const KoParagraphStyle *style);
-
- void unapplyStyle(QTextBlock &block) const;
-
- /**
- * Apply this style to a blockFormat by copying all properties from this, and parent
- * styles to the target block format. Note that the character format will not be applied
- * using this method, use the other applyStyle() method for that.
- */
- void applyStyle(QTextBlockFormat &format) const;
-
- /**
- * Apply this style to the textBlock by copying all properties from this, parent and
- * the character style (where relevant) to the target block formats.
- */
- void applyStyle(QTextBlock &block, bool applyListStyle = true) const;
-/*
- /// return the character "properties" for this paragraph style, Note it does not inherit
- KoCharacterStyle *characterStyle();
- /// return the character "properties" for this paragraph style, Note it does not inherit
- const KoCharacterStyle *characterStyle() const;
- /// set the character "properties" for this paragraph style
- void setCharacterStyle(KoCharacterStyle *style);
-*/
- /**
- * Returns the list style for this paragraph style.
- * @see KoListStyle::isValid()
- * @see setListStyle()
- * @see removeListStyle()
- */
- KoListStyle *listStyle() const;
- /**
- * Set a new liststyle on this paragraph style, making all paragraphs that use this style
- * automatically be part of the list.
- * @see setListStyle()
- * @see removeListStyle()
- */
- void setListStyle(KoListStyle *style);
-
- void remove(int key);
-
- /// Compare the paragraph, character and list properties of this style with the other
- bool operator==(const KoParagraphStyle &other) const;
- /// Compare the paragraph properties of this style with other
- bool compareParagraphProperties(const KoParagraphStyle &other) const;
-
- void removeDuplicates(const KoParagraphStyle &other);
-
- /**
- * Load the style form the element
- *
- * @param context the odf loading context
- * @param element the element containing the style
- * @param loadParents true = use the stylestack, false = use just the element
- */
- void loadOdf(const KoXmlElement *element, KoShapeLoadingContext &context,
- bool loadParents = false);
-
- void saveOdf(KoGenStyle &style, KoShapeSavingContext &context) const;
-
- /**
- * Returns true if this paragraph style has the property set.
- * Note that this method does not delegate to the parent style.
- * @param key the key as found in the Property enum
- */
- bool hasProperty(int key) const;
-
- /**
- * Set a property with key to a certain value, overriding the value from the parent style.
- * If the value set is equal to the value of the parent style, the key will be removed instead.
- * @param key the Property to set.
- * @param value the new value to set on this style.
- * @see hasProperty(), value()
- */
- void setProperty(int key, const QVariant &value);
- /**
- * Return the value of key as represented on this style, taking into account parent styles.
- * You should consider using the direct accessors for individual properties instead.
- * @param key the Property to request.
- * @returns a QVariant which holds the property value.
- */
- QVariant value(int key) const;
- /**
- * Returns true if this pragraph style has default properties
- * Note that the value of StyleId property is not considered
- */
- bool hasDefaults() const;
-
- KoList *list() const;
-
- void applyParagraphListStyle(QTextBlock &block, const QTextBlockFormat &blockFormat) const;
-
- /** Returns true if the style is in use.
- */
- bool isApplied() const;
-
-
-Q_SIGNALS:
- void nameChanged(const QString &newName);
- void styleApplied(const KoParagraphStyle*) const;
-
-private:
- /**
- * Load the style from the \a KoStyleStack style stack using the
- * OpenDocument format.
- */
- void loadOdfProperties(KoShapeLoadingContext &scontext);
- qreal propertyDouble(int key) const;
- QTextLength propertyLength(int key) const;
- int propertyInt(int key) const;
- bool propertyBoolean(int key) const;
- QColor propertyColor(int key) const;
-
- class Private;
- Private * const d;
-};
-Q_DECLARE_METATYPE(KoParagraphStyle *)
-Q_DECLARE_METATYPE(const KoParagraphStyle *)
-Q_DECLARE_METATYPE(QSharedPointer<KoParagraphStyle>)
-#endif
diff --git a/plugins/flake/textshape/kotext/styles/KoSectionStyle.cpp b/plugins/flake/textshape/kotext/styles/KoSectionStyle.cpp
deleted file mode 100644
index e2ac72de8d..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoSectionStyle.cpp
+++ /dev/null
@@ -1,573 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Roopesh Chander <roop@forwardbias.in>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- * Copyright 2012 Friedrich W. H. Kossebau <kossebau@kde.org>
- *
- * 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 "KoSectionStyle.h"
-
-#include <KoGenStyle.h>
-#include "Styles_p.h"
-
-#include <QTextFrame>
-#include <QTextFrameFormat>
-#include <QBuffer>
-
-#include <KoColumns.h>
-#include <KoUnit.h>
-#include <KoStyleStack.h>
-#include <KoOdfLoadingContext.h>
-#include <KoXmlNS.h>
-#include <KoXmlWriter.h>
-#include <KoXmlReader.h>
-
-#include "TextDebug.h"
-
-
-Q_DECLARE_METATYPE(QList<KoColumns::ColumnDatum>)
-
-class Q_DECL_HIDDEN KoSectionStyle::Private
-{
-public:
- Private() : parentStyle(0) {}
-
- ~Private() {
- }
-
- void setProperty(int key, const QVariant &value) {
- stylesPrivate.add(key, value);
- }
- int propertyInt(int key) const {
- QVariant variant = stylesPrivate.value(key);
- if (variant.isNull())
- return 0;
- return variant.toInt();
- }
- bool propertyBoolean(int key) const {
- QVariant variant = stylesPrivate.value(key);
- if (variant.isNull())
- return false;
- return variant.toBool();
- }
- qreal propertyDouble(int key) const {
- QVariant variant = stylesPrivate.value(key);
- if (variant.isNull())
- return 0.0;
- return variant.toDouble();
- }
- QColor propertyColor(int key) const {
- QVariant variant = stylesPrivate.value(key);
- if (variant.isNull())
- return QColor();
- return variant.value<QColor>();
- }
- QList<KoColumns::ColumnDatum> propertyColumnData() const{
- QVariant variant = stylesPrivate.value(ColumnData);
- if (variant.isNull())
- return QList<KoColumns::ColumnDatum>();
- return variant.value<QList<KoColumns::ColumnDatum> >();
- }
-
- QString name;
- KoSectionStyle *parentStyle;
- StylePrivate stylesPrivate;
-};
-
-KoSectionStyle::KoSectionStyle(QObject *parent)
- : QObject(parent), d(new Private())
-{
-}
-
-KoSectionStyle::KoSectionStyle(const QTextFrameFormat &sectionFormat, QObject *parent)
- : QObject(parent),
- d(new Private())
-{
- d->stylesPrivate = sectionFormat.properties();
-}
-
-KoSectionStyle::~KoSectionStyle()
-{
- delete d;
-}
-
-void KoSectionStyle::setParentStyle(KoSectionStyle *parent)
-{
- d->parentStyle = parent;
-}
-
-void KoSectionStyle::setProperty(int key, const QVariant &value)
-{
- if (d->parentStyle) {
- QVariant var = d->parentStyle->value(key);
- if (!var.isNull() && var == value) { // same as parent, so its actually a reset.
- d->stylesPrivate.remove(key);
- return;
- }
- }
- d->stylesPrivate.add(key, value);
-}
-
-void KoSectionStyle::remove(int key)
-{
- d->stylesPrivate.remove(key);
-}
-
-QVariant KoSectionStyle::value(int key) const
-{
- QVariant var = d->stylesPrivate.value(key);
- if (var.isNull() && d->parentStyle)
- var = d->parentStyle->value(key);
- return var;
-}
-
-bool KoSectionStyle::hasProperty(int key) const
-{
- return d->stylesPrivate.contains(key);
-}
-
-void KoSectionStyle::applyStyle(QTextFrameFormat &format) const
-{
- if (d->parentStyle) {
- d->parentStyle->applyStyle(format);
- }
- QList<int> keys = d->stylesPrivate.keys();
- for (int i = 0; i < keys.count(); i++) {
- QVariant variant = d->stylesPrivate.value(keys[i]);
- format.setProperty(keys[i], variant);
- }
-}
-
-void KoSectionStyle::applyStyle(QTextFrame &section) const
-{
- QTextFrameFormat format = section.frameFormat();
- applyStyle(format);
- section.setFrameFormat(format);
-}
-
-void KoSectionStyle::unapplyStyle(QTextFrame &section) const
-{
- if (d->parentStyle)
- d->parentStyle->unapplyStyle(section);
-
- QTextFrameFormat format = section.frameFormat();
-
- QList<int> keys = d->stylesPrivate.keys();
- for (int i = 0; i < keys.count(); i++) {
- QVariant variant = d->stylesPrivate.value(keys[i]);
- if (variant == format.property(keys[i]))
- format.clearProperty(keys[i]);
- }
- section.setFrameFormat(format);
-}
-
-void KoSectionStyle::setLeftMargin(qreal margin)
-{
- setProperty(QTextFormat::BlockLeftMargin, margin);
-}
-
-qreal KoSectionStyle::leftMargin() const
-{
- return d->propertyDouble(QTextFormat::BlockLeftMargin);
-}
-
-void KoSectionStyle::setRightMargin(qreal margin)
-{
- setProperty(QTextFormat::BlockRightMargin, margin);
-}
-
-qreal KoSectionStyle::rightMargin() const
-{
- return d->propertyDouble(QTextFormat::BlockRightMargin);
-}
-
-void KoSectionStyle::setColumnCount(int columnCount)
-{
- setProperty(ColumnCount, columnCount);
-}
-
-int KoSectionStyle::columnCount() const
-{
- return d->propertyInt(ColumnCount);
-}
-
-void KoSectionStyle::setColumnGapWidth(qreal columnGapWidth)
-{
- setProperty(ColumnGapWidth, columnGapWidth);
-}
-
-qreal KoSectionStyle::columnGapWidth() const
-{
- return d->propertyDouble(ColumnGapWidth);
-}
-
-void KoSectionStyle::setColumnData(const QList<KoColumns::ColumnDatum> &columnData)
-{
- setProperty(ColumnData, QVariant::fromValue<QList<KoColumns::ColumnDatum> >(columnData));
-}
-
-QList<KoColumns::ColumnDatum> KoSectionStyle::columnData() const
-{
- return d->propertyColumnData();
-}
-
-void KoSectionStyle::setSeparatorStyle(KoColumns::SeparatorStyle separatorStyle)
-{
- setProperty(SeparatorStyle, separatorStyle);
-}
-
-KoColumns::SeparatorStyle KoSectionStyle::separatorStyle() const
-{
- return static_cast<KoColumns::SeparatorStyle>(d->propertyInt(SeparatorStyle));
-}
-
-void KoSectionStyle::setSeparatorColor(const QColor &separatorColor)
-{
- setProperty(SeparatorColor, separatorColor);
-}
-
-QColor KoSectionStyle::separatorColor() const
-{
- return d->propertyColor(SeparatorColor);
-}
-
-void KoSectionStyle::setSeparatorWidth(qreal separatorWidth)
-{
- setProperty(SeparatorWidth, separatorWidth);
-}
-
-qreal KoSectionStyle::separatorWidth() const
-{
- return d->propertyDouble(SeparatorWidth);
-}
-
-void KoSectionStyle::setSeparatorHeight( int separatorHeight)
-{
- setProperty(SeparatorHeight, separatorHeight);
-}
-
-int KoSectionStyle::separatorHeight() const
-{
- return d->propertyInt(SeparatorHeight);
-}
-
-void KoSectionStyle::setSeparatorVerticalAlignment(KoColumns::SeparatorVerticalAlignment separatorVerticalAlignment)
-{
- setProperty(SeparatorVerticalAlignment, separatorVerticalAlignment);
-}
-
-KoColumns::SeparatorVerticalAlignment KoSectionStyle::separatorVerticalAlignment() const
-{
- return static_cast<KoColumns::SeparatorVerticalAlignment>(d->propertyInt(SeparatorVerticalAlignment));
-}
-
-
-KoSectionStyle *KoSectionStyle::parentStyle() const
-{
- return d->parentStyle;
-}
-
-QString KoSectionStyle::name() const
-{
- return d->name;
-}
-
-void KoSectionStyle::setName(const QString &name)
-{
- if (name == d->name)
- return;
- d->name = name;
- emit nameChanged(name);
-}
-
-int KoSectionStyle::styleId() const
-{
- return d->propertyInt(StyleId);
-}
-
-void KoSectionStyle::setStyleId(int id)
-{
- setProperty(StyleId, id);
-}
-
-
-KoText::Direction KoSectionStyle::textProgressionDirection() const
-{
- return static_cast<KoText::Direction>(d->propertyInt(TextProgressionDirection));
-}
-
-void KoSectionStyle::setTextProgressionDirection(KoText::Direction dir)
-{
- setProperty(TextProgressionDirection, dir);
-}
-
-void KoSectionStyle::setBackground(const QBrush &brush)
-{
- d->setProperty(QTextFormat::BackgroundBrush, brush);
-}
-
-void KoSectionStyle::clearBackground()
-{
- d->stylesPrivate.remove(QTextCharFormat::BackgroundBrush);
-}
-
-QBrush KoSectionStyle::background() const
-{
- QVariant variant = d->stylesPrivate.value(QTextFormat::BackgroundBrush);
-
- if (variant.isNull()) {
- QBrush brush;
- return brush;
- }
- return qvariant_cast<QBrush>(variant);
-}
-
-void KoSectionStyle::loadOdf(const KoXmlElement *element, KoOdfLoadingContext &context)
-{
- if (element->hasAttributeNS(KoXmlNS::style, "display-name"))
- d->name = element->attributeNS(KoXmlNS::style, "display-name", QString());
-
- if (d->name.isEmpty()) // if no style:display-name is given us the style:name
- d->name = element->attributeNS(KoXmlNS::style, "name", QString());
-
- context.styleStack().save();
- // Load all parents - only because we don't support inheritance.
- QString family = element->attributeNS(KoXmlNS::style, "family", "section");
- context.addStyles(element, family.toLocal8Bit().constData()); // Load all parents - only because we don't support inheritance.
-
- context.styleStack().setTypeProperties("section"); // load all style attributes from "style:section-properties"
-
- KoStyleStack &styleStack = context.styleStack();
-
- // in 1.6 this was defined at KoParagLayout::loadOasisParagLayout(KoParagLayout&, KoOasisContext&)
-
- if (styleStack.hasProperty(KoXmlNS::style, "writing-mode")) { // http://www.w3.org/TR/2004/WD-xsl11-20041216/#writing-mode
- QString writingMode = styleStack.property(KoXmlNS::style, "writing-mode");
- setTextProgressionDirection(KoText::directionFromString(writingMode));
- }
-
- // Indentation (margin)
- bool hasMarginLeft = styleStack.hasProperty(KoXmlNS::fo, "margin-left");
- bool hasMarginRight = styleStack.hasProperty(KoXmlNS::fo, "margin-right");
- if (hasMarginLeft)
- setLeftMargin(KoUnit::parseValue(styleStack.property(KoXmlNS::fo, "margin-left")));
- if (hasMarginRight)
- setRightMargin(KoUnit::parseValue(styleStack.property(KoXmlNS::fo, "margin-right")));
-
-
- // The fo:background-color attribute specifies the background color of a paragraph.
- if (styleStack.hasProperty(KoXmlNS::fo, "background-color")) {
- const QString bgcolor = styleStack.property(KoXmlNS::fo, "background-color");
- QBrush brush = background();
- if (bgcolor == "transparent")
- brush.setStyle(Qt::NoBrush);
- else {
- if (brush.style() == Qt::NoBrush)
- brush.setStyle(Qt::SolidPattern);
- brush.setColor(bgcolor); // #rrggbb format
- }
- setBackground(brush);
- }
-
- if (styleStack.hasChildNode(KoXmlNS::style, "columns")) {
- KoXmlElement columns = styleStack.childNode(KoXmlNS::style, "columns");
- int columnCount = columns.attributeNS(KoXmlNS::fo, "column-count").toInt();
- if (columnCount < 1)
- columnCount = 1;
- setColumnCount(columnCount);
-
- if (styleStack.hasProperty(KoXmlNS::fo, "column-gap")) {
- setColumnGapWidth(KoUnit::parseValue(columns.attributeNS(KoXmlNS::fo, "column-gap")));
- } else {
- QList <KoColumns::ColumnDatum> columnData;
-
- KoXmlElement columnElement;
- forEachElement(columnElement, columns) {
- if(columnElement.localName() != QLatin1String("column") ||
- columnElement.namespaceURI() != KoXmlNS::style)
- continue;
-
- KoColumns::ColumnDatum datum;
- datum.leftMargin = KoUnit::parseValue(columnElement.attributeNS(KoXmlNS::fo, "start-indent"), 0.0);
- datum.rightMargin = KoUnit::parseValue(columnElement.attributeNS(KoXmlNS::fo, "end-indent"), 0.0);
- datum.topMargin = KoUnit::parseValue(columnElement.attributeNS(KoXmlNS::fo, "space-before"), 0.0);
- datum.bottomMargin = KoUnit::parseValue(columnElement.attributeNS(KoXmlNS::fo, "space-after"), 0.0);
- datum.relativeWidth = KoColumns::parseRelativeWidth(columnElement.attributeNS(KoXmlNS::style, "rel-width"));
- // on a bad relativeWidth just drop all data
- if (datum.relativeWidth <= 0) {
- columnData.clear();
- break;
- }
-
- columnData.append(datum);
- }
-
- if (! columnData.isEmpty()) {
- setColumnData(columnData);
- }
- }
-
- KoXmlElement columnSep = KoXml::namedItemNS(columns, KoXmlNS::style, "column-sep");
- if (! columnSep.isNull()) {
- if (columnSep.hasAttributeNS(KoXmlNS::style, "style"))
- setSeparatorStyle(KoColumns::parseSeparatorStyle(columnSep.attributeNS(KoXmlNS::style, "style")));
- if (columnSep.hasAttributeNS(KoXmlNS::style, "width"))
- setSeparatorWidth(KoUnit::parseValue(columnSep.attributeNS(KoXmlNS::style, "width")));
- if (columnSep.hasAttributeNS(KoXmlNS::style, "height"))
- setSeparatorHeight(KoColumns::parseSeparatorHeight(columnSep.attributeNS(KoXmlNS::style, "height")));
- if (columnSep.hasAttributeNS(KoXmlNS::style, "color"))
- setSeparatorColor(KoColumns::parseSeparatorColor(columnSep.attributeNS(KoXmlNS::style, "color")));
- if (columnSep.hasAttributeNS(KoXmlNS::style, "vertical-align"))
- setSeparatorVerticalAlignment(
- KoColumns::parseSeparatorVerticalAlignment(columnSep.attributeNS(KoXmlNS::style, "vertical-align")));
- }
- }
-
- styleStack.restore();
-}
-
-
-void KoSectionStyle::copyProperties(const KoSectionStyle *style)
-{
- d->stylesPrivate = style->d->stylesPrivate;
- setName(style->name()); // make sure we emit property change
- d->parentStyle = style->d->parentStyle;
-}
-
-KoSectionStyle *KoSectionStyle::clone(QObject *parent) const
-{
- KoSectionStyle *newStyle = new KoSectionStyle(parent);
- newStyle->copyProperties(this);
- return newStyle;
-}
-
-bool KoSectionStyle::operator==(const KoSectionStyle &other) const
-{
- return other.d->stylesPrivate == d->stylesPrivate;
-}
-
-void KoSectionStyle::removeDuplicates(const KoSectionStyle &other)
-{
- d->stylesPrivate.removeDuplicates(other.d->stylesPrivate);
-}
-
-
-void KoSectionStyle::saveOdf(KoGenStyle &style)
-{
- // only custom style have a displayname. automatic styles don't have a name set.
- if (!d->name.isEmpty() && !style.isDefaultStyle()) {
- style.addAttribute("style:display-name", d->name);
- }
-
- QList<int> columnsKeys;
-
- QList<int> keys = d->stylesPrivate.keys();
- Q_FOREACH (int key, keys) {
- switch (key) {
- case KoSectionStyle::TextProgressionDirection: {
- int directionValue = 0;
- bool ok = false;
- directionValue = d->stylesPrivate.value(key).toInt(&ok);
- if (ok) {
- QString direction;
- if (directionValue == KoText::LeftRightTopBottom)
- direction = "lr-tb";
- else if (directionValue == KoText::RightLeftTopBottom)
- direction = "rl-tb";
- else if (directionValue == KoText::TopBottomRightLeft)
- direction = "tb-lr";
- else if (directionValue == KoText::InheritDirection)
- direction = "page";
- if (!direction.isEmpty())
- style.addProperty("style:writing-mode", direction, KoGenStyle::DefaultType);
- }
- break;
- }
- case QTextFormat::BackgroundBrush: {
- QBrush backBrush = background();
- if (backBrush.style() != Qt::NoBrush)
- style.addProperty("fo:background-color", backBrush.color().name(), KoGenStyle::ParagraphType);
- else
- style.addProperty("fo:background-color", "transparent", KoGenStyle::DefaultType);
- break;
- }
- case QTextFormat::BlockLeftMargin:
- style.addPropertyPt("fo:margin-left", leftMargin(), KoGenStyle::DefaultType);
- break;
- case QTextFormat::BlockRightMargin:
- style.addPropertyPt("fo:margin-right", rightMargin(), KoGenStyle::DefaultType);
- break;
- case ColumnCount:
- case ColumnGapWidth:
- case SeparatorStyle:
- case SeparatorColor:
- case SeparatorVerticalAlignment:
- case SeparatorWidth:
- case SeparatorHeight:
- columnsKeys.append(key);
- break;
- }
- }
-
- if (!columnsKeys.isEmpty()) {
- QBuffer buffer;
- buffer.open(QIODevice::WriteOnly);
- KoXmlWriter elementWriter(&buffer); // TODO pass indentation level
-
- elementWriter.startElement("style:columns");
- // seems these two are mandatory
- elementWriter.addAttribute("fo:column-count", columnCount());
- elementWriter.addAttribute("fo:column-gap", columnGapWidth());
- columnsKeys.removeOne(ColumnCount);
- columnsKeys.removeOne(ColumnGapWidth);
-
- if (!columnsKeys.isEmpty()) {
- elementWriter.startElement("style:column-sep");
- Q_FOREACH (int key, columnsKeys) {
- switch (key) {
- case SeparatorStyle:
- elementWriter.addAttribute("style:style",
- KoColumns::separatorStyleString(separatorStyle()));
- break;
- case SeparatorColor:
- elementWriter.addAttribute("style:color",
- separatorColor().name());
- break;
- case SeparatorVerticalAlignment:
- elementWriter.addAttribute("style:vertical-align",
- KoColumns::separatorVerticalAlignmentString(separatorVerticalAlignment()));
- break;
- case SeparatorWidth:
- elementWriter.addAttribute("style:width",
- separatorWidth());
- break;
- case SeparatorHeight:
- elementWriter.addAttribute("style:height",
- QString::fromLatin1("%1%").arg(separatorHeight()));
- break;
- }
- }
- elementWriter.endElement(); // style:column-sep
- }
-
- elementWriter.endElement(); // style:columns
- const QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
- style.addChildElement("style:columns", elementContents);
- }
-}
diff --git a/plugins/flake/textshape/kotext/styles/KoSectionStyle.h b/plugins/flake/textshape/kotext/styles/KoSectionStyle.h
deleted file mode 100644
index 5bbe9d9cd3..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoSectionStyle.h
+++ /dev/null
@@ -1,216 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- *
- * 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 KOSECTIONSTYLE_H
-#define KOSECTIONSTYLE_H
-
-#include "KoColumns.h"
-#include "KoText.h"
-#include "kritatext_export.h"
-
-#include <QObject>
-#include <QTextFormat>
-
-class QTextFrame;
-class QTextFrameFormat;
-class KoGenStyle;
-class KoOdfLoadingContext;
-
-class QString;
-class QVariant;
-
-/**
- * A container for all properties for the section wide style.
- * Each section in the main text either is based on a section style, or its not. Where
- * it is based on a section style this is indecated that it has a property 'StyleId'
- * with an integer as value. The integer value corresponds to the styleId() output of
- * a specific KoSectionStyle.
- * @see KoStyleManager
- */
-class KRITATEXT_EXPORT KoSectionStyle : public QObject
-{
- Q_OBJECT
-public:
- enum Property {
- StyleId = QTextFormat::UserProperty + 1,
- TextProgressionDirection,
- ColumnCount,
- ColumnData,
- ColumnGapWidth,
- SeparatorStyle,
- SeparatorColor,
- SeparatorVerticalAlignment,
- SeparatorWidth,
- SeparatorHeight
- };
-
- /// Constructor
- explicit KoSectionStyle(QObject *parent = 0);
- /// Creates a KoSectionStyle with the given frame format and \a parent
- explicit KoSectionStyle(const QTextFrameFormat &frameFormat, QObject *parent = 0);
- /// Destructor
- ~KoSectionStyle() override;
-
- /// creates a clone of this style with the specified parent
- KoSectionStyle *clone(QObject *parent = 0) const;
-
-
- /// duplicated property from QTextBlockFormat
- void setLeftMargin(qreal margin);
- /// duplicated property from QTextBlockFormat
- qreal leftMargin() const;
- /// duplicated property from QTextBlockFormat
- void setRightMargin(qreal margin);
- /// duplicated property from QTextBlockFormat
- qreal rightMargin() const;
-
- KoText::Direction textProgressionDirection() const;
-
- void setTextProgressionDirection(KoText::Direction dir);
-
- /// See similar named method on QTextBlockFormat
- void setBackground(const QBrush &brush);
- /// See similar named method on QTextBlockFormat
- QBrush background() const;
- /// See similar named method on QTextBlockFormat
- void clearBackground();
-
-#if 0
- as this is a duplicate of leftMargin, lets make it very clear we are using that one.
- /// duplicated property from QTextBlockFormat
- void setIndent(int indent);
- /// duplicated property from QTextBlockFormat
- int indent() const;
-#endif
-
- void setColumnCount(int columnCount);
- int columnCount() const;
-
- void setColumnGapWidth(qreal columnGapWidth);
- qreal columnGapWidth() const;
-
- void setColumnData(const QList<KoColumns::ColumnDatum> &columnData);
- QList<KoColumns::ColumnDatum> columnData() const;
-
- void setSeparatorStyle(KoColumns::SeparatorStyle separatorStyle);
- KoColumns::SeparatorStyle separatorStyle() const;
-
- void setSeparatorColor(const QColor &separatorColor);
- QColor separatorColor() const;
-
- void setSeparatorVerticalAlignment(KoColumns::SeparatorVerticalAlignment separatorVerticalAlignment);
- KoColumns::SeparatorVerticalAlignment separatorVerticalAlignment() const;
-
- void setSeparatorWidth(qreal separatorWidth);
- qreal separatorWidth() const;
-
- void setSeparatorHeight(int separatorHeight);
- int separatorHeight() const;
-
- /// set the parent style this one inherits its unset properties from.
- void setParentStyle(KoSectionStyle *parent);
-
- /// return the parent style
- KoSectionStyle *parentStyle() const;
-
- /// return the name of the style.
- QString name() const;
-
- /// set a user-visible name on the style.
- void setName(const QString &name);
-
- /// each style has a unique ID (non persistent) given out by the styleManager
- int styleId() const;
-
- /// each style has a unique ID (non persistent) given out by the styleManager
- void setStyleId(int id);
-
- /// copy all the properties from the other style to this style, effectively duplicating it.
- void copyProperties(const KoSectionStyle *style);
-
- void unapplyStyle(QTextFrame &section) const;
-
- /**
- * Apply this style to a frameFormat by copying all properties from this, and parent
- * styles to the target frame format. Note that the character format will not be applied
- * using this method, use the other applyStyle() method for that.
- */
- void applyStyle(QTextFrameFormat &format) const;
-
- /**
- * Apply this style to the section (QTextFrame) by copying all properties from this and parent
- * to the target frame formats.
- */
- void applyStyle(QTextFrame &section) const;
-
- void remove(int key);
-
- /// Compare the section of this style with the other
- bool operator==(const KoSectionStyle &other) const;
- /// Compare the section properties of this style with other
- bool compareSectionProperties(const KoSectionStyle &other) const;
-
- void removeDuplicates(const KoSectionStyle &other);
-
- /**
- * Load the style form the element
- *
- * @param context the odf loading context
- * @param element the element containing the
- */
- void loadOdf(const KoXmlElement *element, KoOdfLoadingContext &context);
-
- void saveOdf(KoGenStyle &style);
-
- /**
- * Returns true if this section style has the property set.
- * Note that this method does not delegate to the parent style.
- * @param key the key as found in the Property enum
- */
- bool hasProperty(int key) const;
-
- /**
- * Set a property with key to a certain value, overriding the value from the parent style.
- * If the value set is equal to the value of the parent style, the key will be removed instead.
- * @param key the Property to set.
- * @param value the new value to set on this style.
- * @see hasProperty(), value()
- */
- void setProperty(int key, const QVariant &value);
- /**
- * Return the value of key as represented on this style, taking into account parent styles.
- * You should consider using the direct accessors for individual properties instead.
- * @param key the Property to request.
- * @returns a QVariant which holds the property value.
- */
- QVariant value(int key) const;
-
-Q_SIGNALS:
- void nameChanged(const QString &newName);
-
-private:
- class Private;
- Private * const d;
-};
-
-Q_DECLARE_METATYPE(KoSectionStyle *)
-
-#endif
diff --git a/plugins/flake/textshape/kotext/styles/KoStyleManager.cpp b/plugins/flake/textshape/kotext/styles/KoStyleManager.cpp
deleted file mode 100644
index 9544133069..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoStyleManager.cpp
+++ /dev/null
@@ -1,1157 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006, 2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2007 Sebastian Sauer <mail@dipe.org>
- * Copyright (C) 2007 Pierre Ducroquet <pinaraf@gmail.com>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- *
- * 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 "KoStyleManager.h"
-
-#include "KoParagraphStyle.h"
-#include "KoCharacterStyle.h"
-#include "KoListStyle.h"
-#include "KoListLevelProperties.h"
-#include "KoTableStyle.h"
-#include "KoTableColumnStyle.h"
-#include "KoTableRowStyle.h"
-#include "KoTableCellStyle.h"
-#include "KoSectionStyle.h"
-#include "commands/ChangeStylesMacroCommand.h"
-#include "KoTextDocument.h"
-#include "KoTextTableTemplate.h"
-
-#include <KoOdfBibliographyConfiguration.h>
-#include <KoGenStyle.h>
-#include <KoGenStyles.h>
-#include <KoShapeSavingContext.h>
-#include <KoTextSharedSavingData.h>
-#include <KoXmlWriter.h>
-#include <KoOdfNumberDefinition.h>
-
-#include <kundo2stack.h>
-
-#include <QUrl>
-#include <QBuffer>
-#include "TextDebug.h"
-#include <klocalizedstring.h>
-
-class Q_DECL_HIDDEN KoStyleManager::Private
-{
-public:
- Private()
- : defaultCharacterStyle(0)
- , defaultParagraphStyle(0)
- , defaultListStyle(0)
- , defaultOutlineStyle(0)
- , outlineStyle(0)
- {
- }
-
- ~Private() {
- qDeleteAll(automaticListStyles);
- }
-
- static int s_stylesNumber; // For giving out unique numbers to the styles for referencing
-
- QHash<int, KoCharacterStyle*> charStyles;
- QHash<int, KoParagraphStyle*> paragStyles;
- QHash<int, KoListStyle*> listStyles;
- QHash<int, KoListStyle *> automaticListStyles;
- QHash<int, KoTableStyle *> tableStyles;
- QHash<int, KoTableColumnStyle *> tableColumnStyles;
- QHash<int, KoTableRowStyle *> tableRowStyles;
- QHash<int, KoTableCellStyle *> tableCellStyles;
- QHash<int, KoSectionStyle *> sectionStyles;
- QHash<int, KoParagraphStyle *> unusedParagraphStyles;
- QHash<int, KoTextTableTemplate *> tableTemplates;
-
- KoCharacterStyle *defaultCharacterStyle;
- KoParagraphStyle *defaultParagraphStyle;
- KoListStyle *defaultListStyle;
- KoListStyle *defaultOutlineStyle;
- KoListStyle *outlineStyle;
- QList<int> defaultToCEntriesStyleId;
- QList<int> defaultBibEntriesStyleId;
- KoOdfNotesConfiguration *footNotesConfiguration;
- KoOdfNotesConfiguration *endNotesConfiguration;
- KoOdfBibliographyConfiguration *bibliographyConfiguration;
-
- QVector<int> m_usedCharacterStyles;
- QVector<int> m_usedParagraphStyles;
-};
-
-// static
-int KoStyleManager::Private::s_stylesNumber = 100;
-
-KoStyleManager::KoStyleManager(QObject *parent)
- : QObject(parent), d(new Private())
-{
- d->defaultCharacterStyle = new KoCharacterStyle(this);
- d->defaultCharacterStyle->setName(i18n("Default"));
-
- add(d->defaultCharacterStyle);
-
- d->defaultParagraphStyle = new KoParagraphStyle(this);
- d->defaultParagraphStyle->setName(i18n("Default"));
-
- add(d->defaultParagraphStyle);
-
- //TODO: also use the defaultstyles.xml mechanism. see KoOdfLoadingContext and KoTextSharedLoadingData
- d->defaultListStyle = new KoListStyle(this);
- const int margin = 10; // we specify the margin for the default list style(Note: Even ChangeListCommand has this value)
- const int maxListLevel = 10;
- for (int level = 1; level <= maxListLevel; level++) {
- KoListLevelProperties llp;
- llp.setLevel(level);
- llp.setStartValue(1);
- llp.setStyle(KoListStyle::DecimalItem);
- llp.setListItemSuffix(".");
- llp.setAlignmentMode(true);
- llp.setLabelFollowedBy(KoListStyle::ListTab);
- llp.setTabStopPosition(margin*(level+2));
- llp.setMargin(margin*(level+1));
- llp.setTextIndent(margin);
-
- d->defaultListStyle->setLevelProperties(llp);
- }
-
- //default styles for ToCs
- int maxOutLineLevel = 10;
- for (int outlineLevel = 1; outlineLevel <= maxOutLineLevel; outlineLevel++) {
- KoParagraphStyle *style = new KoParagraphStyle();
- style->setName("Contents " + QString::number(outlineLevel));
- style->setLeftMargin(QTextLength(QTextLength::FixedLength, (outlineLevel - 1) * 8));
- add(style);
- d->defaultToCEntriesStyleId.append(style->styleId());
- }
-
- for (int typeIndex = 0; typeIndex < KoOdfBibliographyConfiguration::bibTypes.size(); typeIndex++) {
- KoParagraphStyle *style = new KoParagraphStyle();
- style->setName("Bibliography " + KoOdfBibliographyConfiguration::bibTypes.at(typeIndex));
- add(style);
- d->defaultBibEntriesStyleId.append(style->styleId());
- }
-
- d->footNotesConfiguration = new KoOdfNotesConfiguration(KoOdfNotesConfiguration::Footnote);
- d->endNotesConfiguration = new KoOdfNotesConfiguration(KoOdfNotesConfiguration::Endnote);
-
- KoParagraphStyle *style = new KoParagraphStyle();
- style->setName("Footnote");
- style->setParentStyle(d->defaultParagraphStyle);
- add(style);
- d->footNotesConfiguration->setDefaultNoteParagraphStyle(style);
- style = new KoParagraphStyle();
- style->setName("Endnote");
- style->setParentStyle(d->defaultParagraphStyle);
- add(style);
- d->endNotesConfiguration->setDefaultNoteParagraphStyle(style);
- KoCharacterStyle *cStyle = new KoCharacterStyle();
- cStyle->setName("Footnote anchor");
- cStyle->setVerticalAlignment(QTextCharFormat::AlignSuperScript);
- add(cStyle);
- d->footNotesConfiguration->setCitationBodyTextStyle(cStyle);
- cStyle = new KoCharacterStyle();
- cStyle->setName("Footnote Symbol");
- add(cStyle);
- d->footNotesConfiguration->setCitationTextStyle(cStyle);
- cStyle = new KoCharacterStyle();
- cStyle->setName("Endnote anchor");
- cStyle->setVerticalAlignment(QTextCharFormat::AlignSuperScript);
- add(cStyle);
- d->endNotesConfiguration->setCitationBodyTextStyle(cStyle);
- cStyle = new KoCharacterStyle();
- cStyle->setName("Endnote Symbol");
- add(cStyle);
- d->endNotesConfiguration->setCitationTextStyle(cStyle);
-
- d->footNotesConfiguration = 0;
- d->endNotesConfiguration = 0;
- d->bibliographyConfiguration = 0;
-}
-
-KoStyleManager::~KoStyleManager()
-{
- delete d->footNotesConfiguration;
- delete d->endNotesConfiguration;
- delete d;
-}
-
-void KoStyleManager::saveOdfDefaultStyles(KoShapeSavingContext &context)
-{
- KoGenStyle pstyle(KoGenStyle::ParagraphStyle, "paragraph");
- pstyle.setDefaultStyle(true);
- d->defaultParagraphStyle->saveOdf(pstyle, context);
- if (!pstyle.isEmpty()) {
- context.mainStyles().insert(pstyle);
- }
-
- KoGenStyle tstyle(KoGenStyle::TextStyle, "text");
- tstyle.setDefaultStyle(true);
- d->defaultCharacterStyle->saveOdf(tstyle);
- if (!tstyle.isEmpty()) {
- context.mainStyles().insert(tstyle);
- }
-
-}
-
-void KoStyleManager::saveReferredStylesToOdf(KoShapeSavingContext &context)
-{
- KoTextSharedSavingData *textSharedSavingData = 0;
- // we need KoTextSharedSavingData, so create it if not already there
- if (!(textSharedSavingData = dynamic_cast<KoTextSharedSavingData *>(context.sharedData(KOTEXT_SHARED_SAVING_ID)))) {
- textSharedSavingData = new KoTextSharedSavingData;
- context.addSharedData(KOTEXT_SHARED_SAVING_ID, textSharedSavingData);
- }
-
- QSet<KoParagraphStyle *> savedParaStyles;
- QList<KoGenStyles::NamedStyle> namedStyles = context.mainStyles().styles(KoGenStyle::ParagraphAutoStyle);
- namedStyles += context.mainStyles().styles(KoGenStyle::ParagraphStyle);
- Q_FOREACH (const KoGenStyles::NamedStyle &namedStyle, namedStyles) {
- KoParagraphStyle *paraStyle = 0;
- // first find the parent style
- Q_FOREACH (KoParagraphStyle *p, d->paragStyles) {
- QString name(QString(QUrl::toPercentEncoding(p->name(), "", " ")).replace('%', '_'));
-
- if (name == namedStyle.style->parentName()) {
- paraStyle = p;
- break;
- }
- }
- // next save it and also parents to the parent
- while (paraStyle && !savedParaStyles.contains(paraStyle)) {
- QString name(QString(QUrl::toPercentEncoding(paraStyle->name(), "", " ")).replace('%', '_'));
- KoGenStyle style(KoGenStyle::ParagraphStyle, "paragraph");
- paraStyle->saveOdf(style, context);
- QString newName = context.mainStyles().insert(style, name, KoGenStyles::DontAddNumberToName);
- textSharedSavingData->setStyleName(paraStyle->styleId(), newName);
-
- savedParaStyles.insert(paraStyle);
- paraStyle = paraStyle->parentStyle();
- }
- }
-
- QSet<KoCharacterStyle *> savedCharStyles;
- namedStyles = context.mainStyles().styles(KoGenStyle::TextAutoStyle);
- namedStyles += context.mainStyles().styles(KoGenStyle::TextStyle);
-
- Q_FOREACH (const KoGenStyles::NamedStyle &namedStyle, namedStyles) {
- KoCharacterStyle *charStyle = 0;
- // first find the parent style
- Q_FOREACH (KoCharacterStyle *c, d->charStyles) {
- QString name(QString(QUrl::toPercentEncoding(c->name(), "", " ")).replace('%', '_'));
-
- if (name == namedStyle.style->parentName()) {
- charStyle = c;
- break;
- }
- }
- // next save it and also parents to the parent
- while (charStyle && !savedCharStyles.contains(charStyle)) {
- QString name(QString(QUrl::toPercentEncoding(charStyle->name(), "", " ")).replace('%', '_'));
- KoGenStyle style(KoGenStyle::TextStyle, "text");
- charStyle->saveOdf(style);
- QString newName = context.mainStyles().insert(style, name, KoGenStyles::DontAddNumberToName);
- textSharedSavingData->setStyleName(charStyle->styleId(), newName);
-
- savedCharStyles.insert(charStyle);
- charStyle = charStyle->parentStyle();
- }
- }
-}
-
-void KoStyleManager::saveOdf(KoShapeSavingContext &context)
-{
- KoTextSharedSavingData *textSharedSavingData = 0;
- if (!(textSharedSavingData = dynamic_cast<KoTextSharedSavingData *>(context.sharedData(KOTEXT_SHARED_SAVING_ID)))) {
- textSharedSavingData = new KoTextSharedSavingData;
- context.addSharedData(KOTEXT_SHARED_SAVING_ID, textSharedSavingData);
- }
-
- saveOdfDefaultStyles(context);
-
- // don't save character styles that are already saved as part of a paragraph style
- QHash<KoParagraphStyle*, QString> savedNames;
- Q_FOREACH (KoParagraphStyle *paragraphStyle, d->paragStyles) {
- if (paragraphStyle == d->defaultParagraphStyle)
- continue;
-
- QString name(QString(QUrl::toPercentEncoding(paragraphStyle->name(), "", " ")).replace('%', '_'));
- if (name.isEmpty()) {
- name = 'P';
- }
-
- KoGenStyle style(KoGenStyle::ParagraphStyle, "paragraph");
- paragraphStyle->saveOdf(style, context);
- QString newName = context.mainStyles().insert(style, name, KoGenStyles::DontAddNumberToName);
- textSharedSavingData->setStyleName(paragraphStyle->styleId(), newName);
- savedNames.insert(paragraphStyle, newName);
- }
-
- Q_FOREACH (KoParagraphStyle *p, d->paragStyles) {
- if (p->nextStyle() > 0 && savedNames.contains(p) && paragraphStyle(p->nextStyle())) {
- KoParagraphStyle *next = paragraphStyle(p->nextStyle());
- if (next == p) // this is the default
- continue;
- context.mainStyles().insertStyleRelation(savedNames.value(p), savedNames.value(next), "style:next-style-name");
- }
- }
-
- Q_FOREACH (KoCharacterStyle *characterStyle, d->charStyles) {
- if (characterStyle == d->defaultCharacterStyle)
- continue;
-
- QString name(QString(QUrl::toPercentEncoding(characterStyle->name(), "", " ")).replace('%', '_'));
- if (name.isEmpty()) {
- name = 'T';
- }
-
- KoGenStyle style(KoGenStyle::ParagraphStyle, "text");
- characterStyle->saveOdf(style);
- QString newName = context.mainStyles().insert(style, name, KoGenStyles::DontAddNumberToName);
- textSharedSavingData->setStyleName(characterStyle->styleId(), newName);
- }
-
- Q_FOREACH (KoListStyle *listStyle, d->listStyles) {
- if (listStyle == d->defaultListStyle)
- continue;
- QString name(QString(QUrl::toPercentEncoding(listStyle->name(), "", " ")).replace('%', '_'));
- if (name.isEmpty())
- name = 'L';
-
- KoGenStyle style(KoGenStyle::ListStyle);
- listStyle->saveOdf(style, context);
- context.mainStyles().insert(style, name, KoGenStyles::DontAddNumberToName);
- QString newName = context.mainStyles().insert(style, name, KoGenStyles::DontAddNumberToName);
- textSharedSavingData->setStyleName(listStyle->styleId(), newName);
- }
-
- Q_FOREACH (KoTableStyle *tableStyle, d->tableStyles) {
- QString name(QString(QUrl::toPercentEncoding(tableStyle->name(), "", " ")).replace('%', '_'));
- if (name.isEmpty())
- name = 'T'; //TODO is this correct?
-
- KoGenStyle style(KoGenStyle::TableStyle, "table");
- tableStyle->saveOdf(style);
- context.mainStyles().insert(style, name, KoGenStyles::DontAddNumberToName);
- }
-
- Q_FOREACH (KoTableColumnStyle *tableColumnStyle, d->tableColumnStyles) {
- QString name(QString(QUrl::toPercentEncoding(tableColumnStyle->name(), "", " ")).replace('%', '_'));
- if (name.isEmpty())
- name = 'T'; //TODO is this correct?
-
- KoGenStyle style(KoGenStyle::TableColumnStyle, "table-column");
- tableColumnStyle->saveOdf(style);
- context.mainStyles().insert(style, name, KoGenStyles::DontAddNumberToName);
- }
-
- Q_FOREACH (KoTableRowStyle *tableRowStyle, d->tableRowStyles) {
- QString name(QString(QUrl::toPercentEncoding(tableRowStyle->name(), "", " ")).replace('%', '_'));
- if (name.isEmpty())
- name = 'T'; //TODO is this correct?
-
- KoGenStyle style(KoGenStyle::TableRowStyle, "table-row");
- tableRowStyle->saveOdf(style);
- context.mainStyles().insert(style, name, KoGenStyles::DontAddNumberToName);
- }
-
- Q_FOREACH (KoTableCellStyle *tableCellStyle, d->tableCellStyles) {
- QString name(QString(QUrl::toPercentEncoding(tableCellStyle->name(), "", " ")).replace('%', '_'));
- if (name.isEmpty())
- name = "T."; //TODO is this correct?
-
- KoGenStyle style(KoGenStyle::TableCellStyle, "table-cell");
- tableCellStyle->saveOdf(style, context);
- QString newName = context.mainStyles().insert(style, name, KoGenStyles::DontAddNumberToName);
- textSharedSavingData->setStyleName(tableCellStyle->styleId(), newName);
- }
-
- Q_FOREACH (KoSectionStyle *sectionStyle, d->sectionStyles) {
- QString name(QString(QUrl::toPercentEncoding(sectionStyle->name(), "", " ")).replace('%', '_'));
- if (name.isEmpty())
- name = "T."; //TODO is this correct?
-
- KoGenStyle style(KoGenStyle::SectionStyle, "section");
- sectionStyle->saveOdf(style);
- context.mainStyles().insert(style, name, KoGenStyles::DontAddNumberToName);
- }
-
- //save note configuration in styles.xml
- if (d->footNotesConfiguration) {
- QBuffer xmlBufferFootNote;
- KoXmlWriter xmlWriter(&xmlBufferFootNote);
- d->footNotesConfiguration->saveOdf(&xmlWriter);
- context.mainStyles().insertRawOdfStyles(KoGenStyles::DocumentStyles, xmlBufferFootNote.data());
- }
-
- if (d->endNotesConfiguration) {
- QBuffer xmlBufferEndNote;
- KoXmlWriter xmlWriter(&xmlBufferEndNote);
- d->endNotesConfiguration->saveOdf(&xmlWriter);
- context.mainStyles().insertRawOdfStyles(KoGenStyles::DocumentStyles, xmlBufferEndNote.data());
- }
-
- if (d->bibliographyConfiguration) {
- QBuffer xmlBufferBib;
- KoXmlWriter xmlWriter(&xmlBufferBib);
- d->bibliographyConfiguration->saveOdf(&xmlWriter);
- context.mainStyles().insertRawOdfStyles(KoGenStyles::DocumentStyles, xmlBufferBib.data());
- }
-
- if (d->outlineStyle) {
- QString name(QString(QUrl::toPercentEncoding(d->outlineStyle->name(), "", " ")).replace('%', '_'));
- if (name.isEmpty())
- name = 'O';
-
- KoGenStyle style(KoGenStyle::OutlineLevelStyle);
- d->outlineStyle->saveOdf(style, context);
- context.mainStyles().insert(style, name, KoGenStyles::DontAddNumberToName);
- }
-
- Q_FOREACH (KoTextTableTemplate *textTableTemplate, d->tableTemplates) {
- QBuffer xmlBufferTableTemplate;
- KoXmlWriter xmlWriter(&xmlBufferTableTemplate);
- textTableTemplate->saveOdf(&xmlWriter, textSharedSavingData);
- context.mainStyles().insertRawOdfStyles(KoGenStyles::DocumentStyles, xmlBufferTableTemplate.data());
- }
-}
-
-void KoStyleManager::add(KoCharacterStyle *style)
-{
- if (d->charStyles.key(style, -1) != -1) {
- return;
- }
- if (characterStyle(style->name())) {
- return;
- }
- style->setParent(this);
- style->setStyleId(d->s_stylesNumber);
- d->charStyles.insert(d->s_stylesNumber, style);
-
- if (style != defaultCharacterStyle()) { //defaultStyle should not be user visible
- if (style->isApplied() && !d->m_usedCharacterStyles.contains(d->s_stylesNumber)) {
- d->m_usedCharacterStyles.append(d->s_stylesNumber);
- }
- connect(style, SIGNAL(styleApplied(const KoCharacterStyle*)), this, SLOT(slotAppliedStyle(const KoCharacterStyle*)));
- }
-
- ++d->s_stylesNumber;
- emit styleAdded(style);
-}
-
-void KoStyleManager::add(KoParagraphStyle *style)
-{
- if (d->paragStyles.key(style, -1) != -1) {
- return;
- }
- if (paragraphStyle(style->name())) {
- return;
- }
- style->setParent(this);
- style->setStyleId(d->s_stylesNumber);
- d->paragStyles.insert(d->s_stylesNumber, style);
-
- if (style->listStyle() && style->listStyle()->styleId() == 0)
- add(style->listStyle());
- KoParagraphStyle *root = style;
- while (root->parentStyle()) {
- root = root->parentStyle();
- if (root->styleId() == 0)
- add(root);
- }
-
- if (style != defaultParagraphStyle()) { //defaultStyle should not be user visible
- if (style->isApplied() && !d->m_usedParagraphStyles.contains(d->s_stylesNumber)) {
- d->m_usedParagraphStyles.append(d->s_stylesNumber);
- }
- connect(style, SIGNAL(styleApplied(const KoParagraphStyle*)), this, SLOT(slotAppliedStyle(const KoParagraphStyle*)));
- }
-
- ++d->s_stylesNumber;
- emit styleAdded(style);
-}
-
-void KoStyleManager::add(KoListStyle *style)
-{
- if (d->listStyles.key(style, -1) != -1)
- return;
- style->setParent(this);
- style->setStyleId(d->s_stylesNumber);
- d->listStyles.insert(d->s_stylesNumber, style);
-
- ++d->s_stylesNumber;
- emit styleAdded(style);
-}
-
-void KoStyleManager::addAutomaticListStyle(KoListStyle *style)
-{
- if (d->automaticListStyles.key(style, -1) != -1)
- return;
- style->setStyleId(d->s_stylesNumber);
- d->automaticListStyles.insert(d->s_stylesNumber, style);
- ++d->s_stylesNumber;
-}
-
-void KoStyleManager::add(KoTableStyle *style)
-{
- if (d->tableStyles.key(style, -1) != -1)
- return;
- style->setParent(this);
- style->setStyleId(d->s_stylesNumber);
- d->tableStyles.insert(d->s_stylesNumber, style);
- ++d->s_stylesNumber;
- emit styleAdded(style);
-}
-
-void KoStyleManager::add(KoTableColumnStyle *style)
-{
- if (d->tableColumnStyles.key(style, -1) != -1)
- return;
- style->setStyleId(d->s_stylesNumber);
- d->tableColumnStyles.insert(d->s_stylesNumber, style);
- ++d->s_stylesNumber;
- emit styleAdded(style);
-}
-
-void KoStyleManager::add(KoTableRowStyle *style)
-{
- if (d->tableRowStyles.key(style, -1) != -1)
- return;
- style->setStyleId(d->s_stylesNumber);
- d->tableRowStyles.insert(d->s_stylesNumber, style);
- ++d->s_stylesNumber;
- emit styleAdded(style);
-}
-
-void KoStyleManager::add(KoTableCellStyle *style)
-{
- if (d->tableCellStyles.key(style, -1) != -1)
- return;
- style->setParent(this);
- style->setStyleId(d->s_stylesNumber);
- d->tableCellStyles.insert(d->s_stylesNumber, style);
- ++d->s_stylesNumber;
- emit styleAdded(style);
-}
-
-void KoStyleManager::add(KoSectionStyle *style)
-{
- if (d->sectionStyles.key(style, -1) != -1)
- return;
- style->setParent(this);
- style->setStyleId(d->s_stylesNumber);
- d->sectionStyles.insert(d->s_stylesNumber, style);
- ++d->s_stylesNumber;
- emit styleAdded(style);
-}
-
-void KoStyleManager::add(KoTextTableTemplate *tableTemplate)
-{
- if (d->tableTemplates.key(tableTemplate, -1) != -1) {
- return;
- }
-
- tableTemplate->setParent(this);
- tableTemplate->setStyleId(d->s_stylesNumber);
-
- d->tableTemplates.insert(d->s_stylesNumber, tableTemplate);
- ++d->s_stylesNumber;
-}
-
-void KoStyleManager::slotAppliedStyle(const KoParagraphStyle *style)
-{
- d->m_usedParagraphStyles.append(style->styleId());
- emit styleApplied(style);
-}
-
-void KoStyleManager::slotAppliedStyle(const KoCharacterStyle *style)
-{
- d->m_usedCharacterStyles.append(style->styleId());
- emit styleApplied(style);
-}
-
-void KoStyleManager::setNotesConfiguration(KoOdfNotesConfiguration *notesConfiguration)
-{
- if (notesConfiguration->noteClass() == KoOdfNotesConfiguration::Footnote) {
- d->footNotesConfiguration = notesConfiguration;
- } else if (notesConfiguration->noteClass() == KoOdfNotesConfiguration::Endnote) {
- d->endNotesConfiguration = notesConfiguration;
- }
-}
-
-void KoStyleManager::setBibliographyConfiguration(KoOdfBibliographyConfiguration *bibliographyConfiguration)
-{
- d->bibliographyConfiguration = bibliographyConfiguration;
-}
-
-void KoStyleManager::remove(KoCharacterStyle *style)
-{
- if (!style) {
- return;
- }
-
- if (d->charStyles.remove(style->styleId()))
- emit styleRemoved(style);
-}
-
-void KoStyleManager::remove(KoParagraphStyle *style)
-{
- if (!style) {
- return;
- }
-
- if (d->paragStyles.remove(style->styleId()))
- emit styleRemoved(style);
-}
-
-void KoStyleManager::remove(KoListStyle *style)
-{
- if (!style) {
- return;
- }
-
- if (d->listStyles.remove(style->styleId()))
- emit styleRemoved(style);
-}
-
-void KoStyleManager::remove(KoTableStyle *style)
-{
- if (!style) {
- return;
- }
-
- if (d->tableStyles.remove(style->styleId()))
- emit styleRemoved(style);
-}
-
-void KoStyleManager::remove(KoTableColumnStyle *style)
-{
- if (!style) {
- return;
- }
-
- if (d->tableColumnStyles.remove(style->styleId()))
- emit styleRemoved(style);
-}
-
-void KoStyleManager::remove(KoTableRowStyle *style)
-{
- if (!style) {
- return;
- }
-
- if (d->tableRowStyles.remove(style->styleId()))
- emit styleRemoved(style);
-}
-
-void KoStyleManager::remove(KoTableCellStyle *style)
-{
- if (!style) {
- return;
- }
-
- if (d->tableCellStyles.remove(style->styleId()))
- emit styleRemoved(style);
-}
-
-void KoStyleManager::remove(KoSectionStyle *style)
-{
- if (!style) {
- return;
- }
-
- if (d->sectionStyles.remove(style->styleId()))
- emit styleRemoved(style);
-}
-
-void KoStyleManager::alteredStyle(const KoParagraphStyle *newStyle)
-{
- Q_ASSERT(newStyle);
- if (!newStyle) {
- return;
- }
-
- int id = newStyle->styleId();
- if (id <= 0) {
- warnText << "alteredStyle received from a non registered style!";
- return;
- }
- KoParagraphStyle *style = paragraphStyle(id);
- emit styleHasChanged(id, style, newStyle);
-
- // check if anyone that uses 'style' as a parent needs to be flagged as changed as well.
- Q_FOREACH (const KoParagraphStyle *ps, d->paragStyles) {
- if (ps->parentStyle() == style)
- alteredStyle(ps); //since it's our own copy it will only be flagged
- }
-}
-
-void KoStyleManager::alteredStyle(const KoCharacterStyle *newStyle)
-{
- Q_ASSERT(newStyle);
- if (!newStyle) {
- return;
- }
-
- int id = newStyle->styleId();
- if (id <= 0) {
- warnText << "alteredStyle received from a non registered style!";
- return;
- }
- KoCharacterStyle *style = characterStyle(id);
- emit styleHasChanged(id, style, newStyle);
-
- // check if anyone that uses 'style' as a parent needs to be flagged as changed as well.
- Q_FOREACH (const KoCharacterStyle *cs, d->charStyles) {
- if (cs->parentStyle() == style)
- alteredStyle(cs); //since it's our own copy it will only be flagged
- }
-}
-
-void KoStyleManager::alteredStyle(const KoListStyle *style)
-{
- Q_ASSERT(style);
- if (!style) {
- return;
- }
-
- int id = style->styleId();
- if (id <= 0) {
- warnText << "alteredStyle received from a non registered style!";
- return;
- }
- emit styleHasChanged(id);
-}
-
-void KoStyleManager::alteredStyle(const KoTableStyle *style)
-{
- Q_ASSERT(style);
- if (!style) {
- return;
- }
-
- int id = style->styleId();
- if (id <= 0) {
- warnText << "alteredStyle received from a non registered style!";
- return;
- }
- emit styleHasChanged(id);
-}
-
-void KoStyleManager::alteredStyle(const KoTableColumnStyle *style)
-{
- Q_ASSERT(style);
- if (!style) {
- return;
- }
-
- int id = style->styleId();
- if (id <= 0) {
- warnText << "alteredStyle received from a non registered style!";
- return;
- }
- emit styleHasChanged(id);
-}
-
-void KoStyleManager::alteredStyle(const KoTableRowStyle *style)
-{
- Q_ASSERT(style);
- if (!style) {
- return;
- }
-
- int id = style->styleId();
- if (id <= 0) {
- warnText << "alteredStyle received from a non registered style!";
- return;
- }
- emit styleHasChanged(id);
-}
-
-void KoStyleManager::alteredStyle(const KoTableCellStyle *style)
-{
- Q_ASSERT(style);
- if (!style) {
- return;
- }
-
- int id = style->styleId();
- if (id <= 0) {
- warnText << "alteredStyle received from a non registered style!";
- return;
- }
- emit styleHasChanged(id);
-}
-
-void KoStyleManager::alteredStyle(const KoSectionStyle *style)
-{
- Q_ASSERT(style);
- int id = style->styleId();
- if (id <= 0) {
- warnText << "alteredStyle received from a non registered style!";
- return;
- }
- emit styleHasChanged(id);
-}
-
-
-void KoStyleManager::beginEdit()
-{
- emit editHasBegun();
-}
-
-void KoStyleManager::endEdit()
-{
- emit editHasEnded();
-}
-
-KoCharacterStyle *KoStyleManager::characterStyle(int id) const
-{
- return d->charStyles.value(id);
-}
-
-KoParagraphStyle *KoStyleManager::paragraphStyle(int id) const
-{
- return d->paragStyles.value(id);
-}
-
-KoListStyle *KoStyleManager::listStyle(int id) const
-{
- return d->listStyles.value(id);
-}
-
-KoListStyle *KoStyleManager::listStyle(int id, bool *automatic) const
-{
- if (KoListStyle *style = listStyle(id)) {
- *automatic = false;
- return style;
- }
-
- KoListStyle *style = d->automaticListStyles.value(id);
-
- if (style) {
- *automatic = true;
- }
- else {
- // *automatic is unchanged
- }
- return style;
-}
-
-KoTableStyle *KoStyleManager::tableStyle(int id) const
-{
- return d->tableStyles.value(id);
-}
-
-KoTableColumnStyle *KoStyleManager::tableColumnStyle(int id) const
-{
- return d->tableColumnStyles.value(id);
-}
-
-KoTableRowStyle *KoStyleManager::tableRowStyle(int id) const
-{
- return d->tableRowStyles.value(id);
-}
-
-KoTableCellStyle *KoStyleManager::tableCellStyle(int id) const
-{
- return d->tableCellStyles.value(id);
-}
-
-KoSectionStyle *KoStyleManager::sectionStyle(int id) const
-{
- return d->sectionStyles.value(id);
-}
-
-KoCharacterStyle *KoStyleManager::characterStyle(const QString &name) const
-{
- Q_FOREACH (KoCharacterStyle *style, d->charStyles) {
- if (style->name() == name)
- return style;
- }
- return 0;
-}
-
-KoParagraphStyle *KoStyleManager::paragraphStyle(const QString &name) const
-{
- Q_FOREACH (KoParagraphStyle *style, d->paragStyles) {
- if (style->name() == name)
- return style;
- }
- return 0;
-}
-
-KoListStyle *KoStyleManager::listStyle(const QString &name) const
-{
- Q_FOREACH (KoListStyle *style, d->listStyles) {
- if (style->name() == name)
- return style;
- }
- return 0;
-}
-
-KoTableStyle *KoStyleManager::tableStyle(const QString &name) const
-{
- Q_FOREACH (KoTableStyle *style, d->tableStyles) {
- if (style->name() == name)
- return style;
- }
- return 0;
-}
-
-KoTableColumnStyle *KoStyleManager::tableColumnStyle(const QString &name) const
-{
- Q_FOREACH (KoTableColumnStyle *style, d->tableColumnStyles) {
- if (style->name() == name)
- return style;
- }
- return 0;
-}
-
-KoTableRowStyle *KoStyleManager::tableRowStyle(const QString &name) const
-{
- Q_FOREACH (KoTableRowStyle *style, d->tableRowStyles) {
- if (style->name() == name)
- return style;
- }
- return 0;
-}
-
-KoTableCellStyle *KoStyleManager::tableCellStyle(const QString &name) const
-{
- Q_FOREACH (KoTableCellStyle *style, d->tableCellStyles) {
- if (style->name() == name)
- return style;
- }
- return 0;
-}
-
-KoSectionStyle *KoStyleManager::sectionStyle(const QString &name) const
-{
- Q_FOREACH (KoSectionStyle *style, d->sectionStyles) {
- if (style->name() == name)
- return style;
- }
- return 0;
-}
-
-KoOdfNotesConfiguration *KoStyleManager::notesConfiguration(KoOdfNotesConfiguration::NoteClass noteClass) const
-{
- if (noteClass == KoOdfNotesConfiguration::Endnote) {
- return d->endNotesConfiguration;
- } else if (noteClass == KoOdfNotesConfiguration::Footnote) {
- return d->footNotesConfiguration;
- } else {
- return 0;
- }
-}
-
-KoOdfBibliographyConfiguration *KoStyleManager::bibliographyConfiguration() const
-{
- return d->bibliographyConfiguration;
-}
-
-KoCharacterStyle *KoStyleManager::defaultCharacterStyle() const
-{
- return d->defaultCharacterStyle;
-}
-
-KoParagraphStyle *KoStyleManager::defaultParagraphStyle() const
-{
- return d->defaultParagraphStyle;
-}
-
-KoListStyle *KoStyleManager::defaultListStyle() const
-{
- return d->defaultListStyle;
-}
-
-KoListStyle *KoStyleManager::defaultOutlineStyle() const
-{
- if (!d->defaultOutlineStyle) {
- d->defaultOutlineStyle = d->defaultListStyle->clone();
-
- QList<int> levels = d->defaultOutlineStyle->listLevels();
- foreach (int level, levels) {
- KoListLevelProperties llp = d->defaultOutlineStyle->levelProperties(level);
- llp.setOutlineList(true);
- llp.setDisplayLevel(level);
- llp.setTabStopPosition(0);
- llp.setMargin(0);
- llp.setTextIndent(0);
- d->defaultOutlineStyle->setLevelProperties(llp);
- }
- d->defaultOutlineStyle->setStyleId(d->s_stylesNumber);
- ++d->s_stylesNumber;
- }
-
- return d->defaultOutlineStyle;
-}
-
-void KoStyleManager::setOutlineStyle(KoListStyle* listStyle)
-{
- if (d->outlineStyle && d->outlineStyle->parent() == this)
- delete d->outlineStyle;
- listStyle->setParent(this);
- d->outlineStyle = listStyle;
-}
-
-KoListStyle *KoStyleManager::outlineStyle() const
-{
- return d->outlineStyle;
-}
-
-QList<KoCharacterStyle*> KoStyleManager::characterStyles() const
-{
- return d->charStyles.values();
-}
-
-QList<KoParagraphStyle*> KoStyleManager::paragraphStyles() const
-{
- return d->paragStyles.values();
-}
-
-QList<KoListStyle*> KoStyleManager::listStyles() const
-{
- return d->listStyles.values();
-}
-
-QList<KoTableStyle*> KoStyleManager::tableStyles() const
-{
- return d->tableStyles.values();
-}
-
-QList<KoTableColumnStyle*> KoStyleManager::tableColumnStyles() const
-{
- return d->tableColumnStyles.values();
-}
-
-QList<KoTableRowStyle*> KoStyleManager::tableRowStyles() const
-{
- return d->tableRowStyles.values();
-}
-
-QList<KoTableCellStyle*> KoStyleManager::tableCellStyles() const
-{
- return d->tableCellStyles.values();
-}
-
-QList<KoSectionStyle*> KoStyleManager::sectionStyles() const
-{
- return d->sectionStyles.values();
-}
-
-KoParagraphStyle *KoStyleManager::defaultTableOfContentsEntryStyle(int outlineLevel) const
-{
- KoParagraphStyle *style = paragraphStyle(d->defaultToCEntriesStyleId.at(outlineLevel - 1));
- return style;
-}
-
-KoParagraphStyle *KoStyleManager::defaultTableOfcontentsTitleStyle() const
-{
- return defaultParagraphStyle();
-}
-
-KoParagraphStyle *KoStyleManager::defaultBibliographyEntryStyle(const QString &bibType)
-{
- KoParagraphStyle *style = paragraphStyle(d->defaultBibEntriesStyleId
- .at(KoOdfBibliographyConfiguration::bibTypes.indexOf(bibType)));
- return style;
-}
-
-KoParagraphStyle *KoStyleManager::defaultBibliographyTitleStyle() const
-{
- KoParagraphStyle *style = new KoParagraphStyle();
- style->setName("Bibliography Heading");
- style->setFontPointSize(16);
- return style;
-}
-
-void KoStyleManager::addUnusedStyle(KoParagraphStyle *style)
-{
- if (d->unusedParagraphStyles.key(style, -1) != -1)
- return;
- style->setParent(this);
- style->setStyleId(d->s_stylesNumber);
- d->unusedParagraphStyles.insert(d->s_stylesNumber, style);
-
- KoParagraphStyle *root = style;
- while (root->parentStyle()) {
- root = root->parentStyle();
- if (root->styleId() == 0)
- addUnusedStyle(root);
- }
- if (root != d->defaultParagraphStyle && root->parentStyle() == 0)
- root->setParentStyle(d->defaultParagraphStyle);
- ++d->s_stylesNumber;
-}
-
-void KoStyleManager::moveToUsedStyles(int id)
-{
- if (d->paragStyles.contains(id))
- return;
-
- KoParagraphStyle *style = d->unusedParagraphStyles.value(id);
- d->unusedParagraphStyles.remove(id);
-
- d->paragStyles.insert(style->styleId(), style);
-
- if (style->listStyle() && style->listStyle()->styleId() == 0)
- add(style->listStyle());
- KoParagraphStyle *root = style;
- while (root->parentStyle()) {
- root = root->parentStyle();
- if (d->paragStyles.contains(id) == false)
- moveToUsedStyles(root->styleId());
- }
-
- if (root != d->defaultParagraphStyle && root->parentStyle() == 0)
- root->setParentStyle(d->defaultParagraphStyle);
-
- emit styleAdded(style);
-}
-
-KoParagraphStyle *KoStyleManager::unusedStyle(int id) const
-{
- return d->unusedParagraphStyles.value(id);
-}
-
-QVector<int> KoStyleManager::usedCharacterStyles() const
-{
- return d->m_usedCharacterStyles;
-}
-
-QVector<int> KoStyleManager::usedParagraphStyles() const
-{
- return d->m_usedParagraphStyles;
-}
-
-KoTextTableTemplate *KoStyleManager::tableTemplate(const QString &name) const
-{
- Q_FOREACH (KoTextTableTemplate *tableTemplate, d->tableTemplates) {
- if (tableTemplate->name() == name)
- return tableTemplate;
- }
- return 0;
-}
-
-KoTextTableTemplate *KoStyleManager::tableTemplate(int id) const
-{
- return d->tableTemplates.value(id, 0);
-}
diff --git a/plugins/flake/textshape/kotext/styles/KoStyleManager.h b/plugins/flake/textshape/kotext/styles/KoStyleManager.h
deleted file mode 100644
index b747162b64..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoStyleManager.h
+++ /dev/null
@@ -1,551 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006 Thomas Zander <zander@kde.org>
- * Copyright (C) 2007 Sebastian Sauer <mail@dipe.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- *
- * 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 KOSTYLEMANAGER_H
-#define KOSTYLEMANAGER_H
-
-#include "kritatext_export.h"
-#include "KoOdfNotesConfiguration.h"
-
-#include <QObject>
-#include <QMetaType>
-#include <QVector>
-
-class KoCharacterStyle;
-class KoParagraphStyle;
-class KoListStyle;
-class KoTableStyle;
-class KoTableColumnStyle;
- /// This signal is to allow listener to make an undo command out of it
-class KoTableRowStyle;
-class KoTableCellStyle;
-class KoSectionStyle;
-class KoShapeSavingContext;
-class KoTextShapeData;
-class KoTextTableTemplate;
-class KoOdfBibliographyConfiguration;
-
-/**
- * Manages all character, paragraph, table and table cell styles for any number
- * of documents.
- */
-class KRITATEXT_EXPORT KoStyleManager : public QObject
-{
- Q_OBJECT
-public:
- /**
- * Create a new style manager.
- * @param parent pass a parent to use qobject memory management
- */
- explicit KoStyleManager(QObject *parent = 0);
-
- /**
- * Destructor.
- */
- ~KoStyleManager() override;
-
- /**
- * Mark the beginning of a sequence of style changes, additions, and deletions
- *
- * Important: This method must be called even if only working on a single style.
- *
- * See also \ref endEdit
- */
- void beginEdit();
-
- /**
- * Mark the end of a sequence of style changes, additions, and deletions.
- *
- * Manipulation to the styles happen immediately, but calling this method
- * will allow applications to put a command on the stack for undo, and for qtextdocuments
- * to reflect the style changes.
- *
- * Important: This method must be called even if only working on a single style.
- *
- * See also \ref beginEdit
- */
- void endEdit();
-
- // load is not needed as it is done in KoTextSharedLoadingData
-
- /**
- * Save document styles
- */
- void saveOdf(KoShapeSavingContext &context);
-
- /**
- * Save document styles that are being referred to but not yet saved
- */
- void saveReferredStylesToOdf(KoShapeSavingContext &context);
-
- /**
- * Save the default-style styles
- */
- void saveOdfDefaultStyles(KoShapeSavingContext &context);
-
- /**
- * Add a new style, automatically giving it a new styleId.
- */
- void add(KoCharacterStyle *style);
- /**
- * Add a new style, automatically giving it a new styleId.
- */
- void add(KoParagraphStyle *style);
- /**
- * Add a new list style, automatically giving it a new styleId.
- */
- void add(KoListStyle *style);
- /**
- * Add a new table style, automatically giving it a new styleId.
- */
- void add(KoTableStyle *style);
- /**
- * Add a new table column style, automatically giving it a new styleId.
- */
- void add(KoTableColumnStyle *style);
- /**
- * Add a new table row style, automatically giving it a new styleId.
- */
- void add(KoTableRowStyle *style);
- /**
- * Add a new table cell style, automatically giving it a new styleId.
- */
- void add(KoTableCellStyle *style);
- /**
- * Add a new section style, automatically giving it a new styleId.
- */
- void add(KoSectionStyle *style);
-
- /**
- * Add a table template, automatically giving it a new styleId.
- */
- void add(KoTextTableTemplate *tableTemplate);
-
- /**
- * set the notes configuration of the document
- */
- void setNotesConfiguration(KoOdfNotesConfiguration *notesConfiguration);
- /**
- * set the notes configuration of the document
- */
- void setBibliographyConfiguration(KoOdfBibliographyConfiguration *bibliographyConfiguration);
- /**
- * Remove a style.
- */
- void remove(KoCharacterStyle *style);
- /**
- * Remove a style.
- */
- void remove(KoParagraphStyle *style);
- /**
- * Remove a list style.
- */
- void remove(KoListStyle *style);
- /**
- * Remove a table style.
- */
- void remove(KoTableStyle *style);
- /**
- * Remove a table column style.
- */
- void remove(KoTableColumnStyle *style);
- /**
- * Remove a table row style.
- */
- void remove(KoTableRowStyle *style);
- /**
- * Remove a table cell style.
- */
- void remove(KoTableCellStyle *style);
- /**
- * Remove a section style.
- */
- void remove(KoSectionStyle *style);
-
- /**
- * Return a characterStyle by its id.
- * From documents you can retrieve the id out of each QTextCharFormat
- * by requesting the KoCharacterStyle::StyleId property.
- * @param id the unique Id to search for.
- * @see KoCharacterStyle::styleId()
- */
- KoCharacterStyle *characterStyle(int id) const;
-
- /**
- * Return a paragraphStyle by its id.
- * From documents you can retrieve the id out of each QTextBlockFormat
- * by requesting the KoParagraphStyle::StyleId property.
- * @param id the unique Id to search for.
- * @see KoParagraphStyle::styleId()
- */
- KoParagraphStyle *paragraphStyle(int id) const;
-
- /**
- * Return a list style by its id.
- */
- KoListStyle *listStyle(int id) const;
-
- /**
- * Return a tableStyle by its id.
- * From documents you can retrieve the id out of each QTextTableFormat
- * by requesting the KoTableStyle::StyleId property.
- * @param id the unique Id to search for.
- * @see KoTableStyle::styleId()
- */
- KoTableStyle *tableStyle(int id) const;
-
- /**
- * Return a tableColumnStyle by its id.
- * From documents you can retrieve the id out of the KoTableRowandColumnStyleManager
- * @param id the unique Id to search for.
- * @see KoTableColumnStyle::styleId()
- */
- KoTableColumnStyle *tableColumnStyle(int id) const;
-
- /**
- * Return a tableRowStyle by its id.
- * From documents you can retrieve the id out of the KoTableRowandColumnStyleManager
- * @param id the unique Id to search for.
- * @see KoTableRowStyle::styleId()
- */
- KoTableRowStyle *tableRowStyle(int id) const;
-
- /**
- * Return a tableCellStyle by its id.
- * From documents you can retrieve the id out of each QTextTableCellFormat
- * by requesting the KoTableCellStyle::StyleId property.
- * @param id the unique Id to search for.
- * @see KoTableCellStyle::styleId()
- */
- KoTableCellStyle *tableCellStyle(int id) const;
-
- /**
- * Return a tableTemplate by its id.
- * From documents you can retrieve the id out of each QTextTableFormat
- * by requesting the KoTextTableTemplate::StyleId property.
- * @param id the unique Id to search for.
- * @see KoTextTableTemplate::styleId()
- */
- KoTextTableTemplate *tableTemplate(int id) const;
-
- /**
- * Return a sectionStyle by its id.
- * From documents you can retrieve the id out of each QTextFrameFormat
- * by requesting the KoSectionStyle::StyleId property.
- * @param id the unique Id to search for.
- * @see KoSectionStyle::styleId()
- */
- KoSectionStyle *sectionStyle(int id) const;
-
- /**
- * Return the first characterStyle with the param user-visible-name.
- * Since the name does not have to be unique there can be multiple
- * styles registered with that name, only the first is returned
- * @param name the name of the style.
- * @see characterStyle(id);
- */
- KoCharacterStyle *characterStyle(const QString &name) const;
-
- /**
- * Return the first paragraphStyle with the param user-visible-name.
- * Since the name does not have to be unique there can be multiple
- * styles registered with that name, only the first is returned
- * @param name the name of the style.
- * @see paragraphStyle(id);
- */
- KoParagraphStyle *paragraphStyle(const QString &name) const;
-
- /**
- * Returns the first listStyle ith the param use-visible-name.
- */
- KoListStyle *listStyle(const QString &name) const;
-
- /**
- * Return the first tableStyle with the param user-visible-name.
- * Since the name does not have to be unique there can be multiple
- * styles registered with that name, only the first is returned
- * @param name the name of the style.
- * @see tableStyle(id);
- */
- KoTableStyle *tableStyle(const QString &name) const;
-
- /**
- * Return the first tableColumnStyle with the param user-visible-name.
- * Since the name does not have to be unique there can be multiple
- * styles registered with that name, only the first is returned
- * @param name the name of the style.
- * @see tableColumnStyle(id);
- */
- KoTableColumnStyle *tableColumnStyle(const QString &name) const;
-
- /**
- * Return the first tableRowStyle with the param user-visible-name.
- * Since the name does not have to be unique there can be multiple
- * styles registered with that name, only the first is returned
- * @param name the name of the style.
- * @see tableRowStyle(id);
- */
- KoTableRowStyle *tableRowStyle(const QString &name) const;
-
- /**
- * Return the first tableCellStyle with the param user-visible-name.
- * Since the name does not have to be unique there can be multiple
- * styles registered with that name, only the first is returned
- * @param name the name of the style.
- * @see tableCellStyle(id);
- */
- KoTableCellStyle *tableCellStyle(const QString &name) const;
-
- /**
- * Return the first tableTemplate with the param user-visible-name.
- * Since the name does not have to be unique there can be multiple
- * styles registered with that name, only the first is returned
- * @param name the name of the style.
- * @see tableTemplate(id);
- */
- KoTextTableTemplate *tableTemplate(const QString &name) const;
-
- /**
- * Return the first sectionStyle with the param user-visible-name.
- * Since the name does not have to be unique there can be multiple
- * styles registered with that name, only the first is returned
- * @param name the name of the style.
- * @see sectionStyle(id);
- */
- KoSectionStyle *sectionStyle(const QString &name) const;
-
- /**
- * Return the default character style that will always be present in each
- * document. You can alter the style, but you can never delete it.
- * The default is suppost to stay invisible to the user and its called
- * i18n("Default") for that reason. Applications should not
- * show this style in their document-level configure dialogs.
- */
- KoCharacterStyle *defaultCharacterStyle() const;
-
- /**
- * Return the default paragraph style that will always be present in each
- * document. You can alter the style, but you can never delete it.
- * The default is suppost to stay invisible to the user and its called
- * i18n("Default") for that reason. Applications should not
- * show this style in their document-level configure dialogs.
- */
- KoParagraphStyle *defaultParagraphStyle() const;
-
- /**
- * @return the notes configuration
- */
- KoOdfNotesConfiguration *notesConfiguration(KoOdfNotesConfiguration::NoteClass noteClass) const;
-
- /**
- * @return the bibliography configuration
- */
- KoOdfBibliographyConfiguration *bibliographyConfiguration() const;
-
- /**
- * Returns the default list style to be used for lists, headers, paragraphs
- * that do not specify a list-style
- */
- KoListStyle *defaultListStyle() const;
-
- /**
- * Returns the default outline style to be used if outline-style is not specified in the document
- * that do not specify a list-style
- */
- KoListStyle *defaultOutlineStyle() const;
-
- /**
- * Sets the outline style to be used for headers that are not specified as lists
- */
- void setOutlineStyle(KoListStyle *listStyle);
-
- /**
- * Returns the outline style to be used for headers that are not specified as lists
- */
- KoListStyle *outlineStyle() const;
-
- /// return all the characterStyles registered.
- QList<KoCharacterStyle*> characterStyles() const;
-
- /// return all the paragraphStyles registered.
- QList<KoParagraphStyle*> paragraphStyles() const;
-
- /// return all the listStyles registered.
- QList<KoListStyle*> listStyles() const;
-
- /// return all the tableStyles registered.
- QList<KoTableStyle*> tableStyles() const;
-
- /// return all the tableColumnStyles registered.
- QList<KoTableColumnStyle*> tableColumnStyles() const;
-
- /// return all the tableRowStyles registered.
- QList<KoTableRowStyle*> tableRowStyles() const;
-
- /// return all the tableCellStyles registered.
- QList<KoTableCellStyle*> tableCellStyles() const;
-
- /// return all the sectionStyles registered.
- QList<KoSectionStyle*> sectionStyles() const;
-
- /// returns the default style for the ToC entries for the specified outline level
- KoParagraphStyle *defaultTableOfContentsEntryStyle(int outlineLevel) const;
-
- /// returns the default style for the ToC title
- KoParagraphStyle *defaultTableOfcontentsTitleStyle() const;
-
- /// returns the default style for the Bibliography entries for the specified bibliography type
- KoParagraphStyle *defaultBibliographyEntryStyle(const QString &bibType);
-
- /// returns the default style for the Bibliography title
- KoParagraphStyle *defaultBibliographyTitleStyle() const;
-
- /// adds a paragraph style to unused paragraph style list
- void addUnusedStyle(KoParagraphStyle *style);
-
- /// moves a style from the unused list to the used list i.e paragStyles list
- void moveToUsedStyles(int id);
-
- KoParagraphStyle *unusedStyle(int id) const;
-
- QVector<int> usedCharacterStyles() const;
- QVector<int> usedParagraphStyles() const;
-
-Q_SIGNALS:
- void styleAdded(KoParagraphStyle*);
- void styleAdded(KoCharacterStyle*);
- void styleAdded(KoListStyle*);
- void styleAdded(KoTableStyle*);
- void styleAdded(KoTableColumnStyle*);
- void styleAdded(KoTableRowStyle*);
- void styleAdded(KoTableCellStyle*);
- void styleAdded(KoSectionStyle*);
- void styleRemoved(KoParagraphStyle*);
- void styleRemoved(KoCharacterStyle*);
- void styleRemoved(KoListStyle*);
- void styleRemoved(KoTableStyle*);
- void styleRemoved(KoTableColumnStyle*);
- void styleRemoved(KoTableRowStyle*);
- void styleRemoved(KoTableCellStyle*);
- void styleRemoved(KoSectionStyle*);
-
- /// This signal is emitted whenever the style has been applied to a qtextdocument
- /// This allows listeners to know which styles are in use
- void styleApplied(const KoCharacterStyle*);
-
- /// This signal is emitted whenever the style has been applied to a qtextdocument
- /// This allows listeners to know which styles are in use
- void styleApplied(const KoParagraphStyle*);
-
- /// This signal is to allow listener to start an undo command
- void editHasBegun();
-
- /// This signal is to allow listener to end an undo command, and add it to the undo stack
- void editHasEnded();
-
- /// This signal is to allow listener to record into an undo command and apply to text
- /// It's emitted when someone calls alteredStyle (not paragraph or character)
- void styleHasChanged(int);
-
- /// This signal is to allow listener to record into an undo command and apply to text
- /// It's emitted when someone calls alteredStyle on a paragraph style
- void styleHasChanged(int, const KoParagraphStyle*, const KoParagraphStyle*);
-
- /// This signal is to allow listener to record into an undo command and apply to text
- /// It's emitted when someone calls alteredStyle on a character style
- void styleHasChanged(int, const KoCharacterStyle*, const KoCharacterStyle*);
-
-public Q_SLOTS:
- /**
- * Slot that should be called whenever a style is changed. This will update
- * all documents with the style.
- * Note that successive calls are aggregated.
- */
- void alteredStyle(const KoParagraphStyle *style);
- /**
- * Slot that should be called whenever a style is changed. This will update
- * all documents with the style.
- * Note that successive calls are aggregated.
- */
- void alteredStyle(const KoCharacterStyle *style);
-
- /**
- * Slot that should be called whenever a style is changed. This will update
- * all documents with the style.
- * Note that successive calls are aggregated.
- */
- void alteredStyle(const KoListStyle *style);
-
- /**
- * Slot that should be called whenever a style is changed. This will update
- * all documents with the style.
- * Note that successive calls are aggregated.
- */
- void alteredStyle(const KoTableStyle *style);
-
- /**
- * Slot that should be called whenever a style is changed. This will update
- * all documents with the style.
- * Note that successive calls are aggregated.
- */
- void alteredStyle(const KoTableColumnStyle *style);
-
- /**
- * Slot that should be called whenever a style is changed. This will update
- * all documents with the style.
- * Note that successive calls are aggregated.
- */
- void alteredStyle(const KoTableRowStyle *style);
-
- /**
- * Slot that should be called whenever a style is changed. This will update
- * all documents with the style.
- * Note that successive calls are aggregated.
- */
- void alteredStyle(const KoTableCellStyle *style);
-
- /**
- * Slot that should be called whenever a style is changed. This will update
- * all documents with the style.
- * Note that successive calls are aggregated.
- */
- void alteredStyle(const KoSectionStyle *style);
-
- void slotAppliedStyle(const KoCharacterStyle*);
- void slotAppliedStyle(const KoParagraphStyle*);
-
-private:
- friend class KoTextSharedLoadingData;
- void addAutomaticListStyle(KoListStyle *listStyle);
- friend class KoTextShapeData;
- friend class KoTextShapeDataPrivate;
- KoListStyle *listStyle(int id, bool *automatic) const;
-
-private:
- class Private;
- Private* const d;
-};
-
-Q_DECLARE_METATYPE(KoStyleManager*)
-
-#endif
diff --git a/plugins/flake/textshape/kotext/styles/KoTableCellStyle.cpp b/plugins/flake/textshape/kotext/styles/KoTableCellStyle.cpp
deleted file mode 100644
index 9f89357c88..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoTableCellStyle.cpp
+++ /dev/null
@@ -1,1047 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Roopesh Chander <roop@forwardbias.in>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
- *
- * 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 "KoTableCellStyle.h"
-#include "KoTableCellStyle_p.h"
-
-#include <KoXmlReaderForward.h>
-
-#include <KoGenStyle.h>
-#include <KoShapeLoadingContext.h>
-#include <KoOdfGraphicStyles.h>
-#include "KoParagraphStyle.h"
-
-#include <KoTextDebug.h>
-
-#include <QTextTableFormat>
-#include <QTextTableCell>
-
-#include <KoUnit.h>
-#include <KoStyleStack.h>
-#include <KoOdfLoadingContext.h>
-#include <KoXmlNS.h>
-#include <KoXmlReader.h>
-
-#include "TextDebug.h"
-
-#include <cfloat>
-
-KoTableCellStyle::RotationAlignment rotationAlignmentFromString(const QString& align)
-{
- if (align == "bottom")
- return KoTableCellStyle::RAlignBottom;
- if (align == "center")
- return KoTableCellStyle::RAlignCenter;
- if (align == "top")
- return KoTableCellStyle::RAlignTop;
-
- return KoTableCellStyle::RAlignNone;
-}
-
-QString rotationAlignmentToString(KoTableCellStyle::RotationAlignment align)
-{
- if (align == KoTableCellStyle::RAlignBottom)
- return "bottom";
- if (align == KoTableCellStyle::RAlignTop)
- return "top";
- if (align == KoTableCellStyle::RAlignCenter)
- return "center";
- return "none";
-}
-
-KoTableCellStylePrivate::KoTableCellStylePrivate()
- : paragraphStyle(0)
- , parentStyle(0)
- , next(0)
-{
-}
-
-KoTableCellStylePrivate::~KoTableCellStylePrivate()
-{
-}
-
-void KoTableCellStylePrivate::setProperty(int key, const QVariant &value)
-{
- stylesPrivate.add(key, value);
-}
-
-KoTableCellStyle::KoTableCellStyle(QObject *parent)
- : QObject(parent)
- , d_ptr(new KoTableCellStylePrivate)
-{
- Q_D(KoTableCellStyle);
- d->paragraphStyle = new KoParagraphStyle(this);
-}
-
-KoTableCellStyle::KoTableCellStyle(const QTextTableCellFormat &format, QObject *parent)
- : QObject(parent)
- , d_ptr(new KoTableCellStylePrivate)
-{
- Q_D(KoTableCellStyle);
- d->stylesPrivate = format.properties();
- d->paragraphStyle = new KoParagraphStyle(this);
-}
-
-KoTableCellStyle::KoTableCellStyle(const KoTableCellStyle &other)
- :QObject(other.parent())
- , d_ptr(new KoTableCellStylePrivate)
-{
- Q_D(KoTableCellStyle);
-
- copyProperties(&other);
- d->paragraphStyle = other.paragraphStyle()->clone(this);
-}
-
-KoTableCellStyle& KoTableCellStyle::operator=(const KoTableCellStyle &other)
-{
- Q_D(KoTableCellStyle);
-
- if (this == &other) {
- return *this;
- }
-
- copyProperties(&other);
- d->paragraphStyle = other.paragraphStyle()->clone(this);
-
- return *this;
-}
-
-KoTableCellStyle::~KoTableCellStyle()
-{
- delete d_ptr;
-}
-
-KoTableCellStyle *KoTableCellStyle::fromTableCell(const QTextTableCell &tableCell, QObject *parent)
-{
- QTextTableCellFormat tableCellFormat = tableCell.format().toTableCellFormat();
- return new KoTableCellStyle(tableCellFormat, parent);
-}
-
-QTextCharFormat KoTableCellStyle::cleanCharFormat(const QTextCharFormat &charFormat)
-{
- if (charFormat.isTableCellFormat()) {
- QTextTableCellFormat format;
- const QMap<int, QVariant> props = charFormat.properties();
- QMap<int, QVariant>::const_iterator it = props.begin();
- while (it != props.end()) {
- // lets save all Qt's table cell properties
- if (it.key()>=QTextFormat::TableCellRowSpan && it.key()<QTextFormat::ImageName)
- format.setProperty(it.key(), it.value());
-
- // lets save all our table cell properties
- if (it.key()>=StyleId && it.key()<LastCellStyleProperty)
- format.setProperty(it.key(), it.value());
-
- ++it;
- }
- return QTextCharFormat(format);
- }
- return QTextCharFormat();
-}
-
-QRectF KoTableCellStyle::contentRect(const QRectF &boundingRect) const
-{
- const KoBorder::BorderData &leftEdge = getEdge(KoBorder::LeftBorder);
- const KoBorder::BorderData &topEdge = getEdge(KoBorder::TopBorder);
- const KoBorder::BorderData &rightEdge = getEdge(KoBorder::RightBorder);
- const KoBorder::BorderData &bottomEdge = getEdge(KoBorder::BottomBorder);
-
- return boundingRect.adjusted(
- leftEdge.outerPen.widthF() + leftEdge.spacing + leftEdge.innerPen.widthF() + propertyDouble(QTextFormat::TableCellLeftPadding),
- topEdge.outerPen.widthF() + topEdge .spacing + topEdge .innerPen.widthF() + propertyDouble(QTextFormat::TableCellTopPadding),
- - rightEdge.outerPen.widthF() - rightEdge.spacing - rightEdge.innerPen.widthF() - propertyDouble(QTextFormat::TableCellRightPadding),
- - bottomEdge.outerPen.widthF() - bottomEdge.spacing - bottomEdge.innerPen.widthF() - propertyDouble(QTextFormat::TableCellBottomPadding)
- );
-}
-
-QRectF KoTableCellStyle::boundingRect(const QRectF &contentRect) const
-{
- const KoBorder::BorderData &leftEdge = getEdge(KoBorder::LeftBorder);
- const KoBorder::BorderData &topEdge = getEdge(KoBorder::TopBorder);
- const KoBorder::BorderData &rightEdge = getEdge(KoBorder::RightBorder);
- const KoBorder::BorderData &bottomEdge = getEdge(KoBorder::BottomBorder);
-
- return contentRect.adjusted(
- - leftEdge.outerPen.widthF() - leftEdge.spacing - leftEdge.innerPen.widthF() - propertyDouble(QTextFormat::TableCellLeftPadding),
- - topEdge.outerPen.widthF() - topEdge.spacing - topEdge.innerPen.widthF() - propertyDouble(QTextFormat::TableCellTopPadding),
- rightEdge.outerPen.widthF() + rightEdge.spacing + rightEdge.innerPen.widthF() + propertyDouble(QTextFormat::TableCellRightPadding),
- bottomEdge.outerPen.widthF() + bottomEdge.spacing + bottomEdge.innerPen.widthF() + propertyDouble(QTextFormat::TableCellBottomPadding)
- );
-}
-
-void KoTableCellStyle::setParentStyle(KoTableCellStyle *parent)
-{
- Q_D(KoTableCellStyle);
- d->parentStyle = parent;
-}
-
-void KoTableCellStyle::setLeftPadding(qreal padding)
-{
- setProperty(QTextFormat::TableCellLeftPadding, padding);
-}
-
-void KoTableCellStyle::setTopPadding(qreal padding)
-{
- setProperty(QTextFormat::TableCellTopPadding, padding);
-}
-
-void KoTableCellStyle::setRightPadding(qreal padding)
-{
- setProperty(QTextFormat::TableCellRightPadding, padding);
-}
-
-void KoTableCellStyle::setBottomPadding(qreal padding)
-{
- setProperty(QTextFormat::TableCellBottomPadding, padding);
-}
-
-qreal KoTableCellStyle::leftPadding() const
-{
- return propertyDouble(QTextFormat::TableCellLeftPadding);
-}
-
-qreal KoTableCellStyle::rightPadding() const
-{
- return propertyDouble(QTextFormat::TableCellRightPadding);
-}
-
-qreal KoTableCellStyle::topPadding() const
-{
- return propertyDouble(QTextFormat::TableCellTopPadding);
-}
-
-qreal KoTableCellStyle::bottomPadding() const
-{
- return propertyDouble(QTextFormat::TableCellBottomPadding);
-}
-
-void KoTableCellStyle::setPadding(qreal padding)
-{
- setBottomPadding(padding);
- setTopPadding(padding);
- setRightPadding(padding);
- setLeftPadding(padding);
-}
-
-KoParagraphStyle *KoTableCellStyle::paragraphStyle() const
-{
- Q_D(const KoTableCellStyle);
- return d->paragraphStyle;
-}
-
-bool KoTableCellStyle::shrinkToFit() const
-{
- return propertyBoolean(ShrinkToFit);
-}
-
-void KoTableCellStyle::setShrinkToFit(bool state)
-{
- setProperty(ShrinkToFit, state);
-}
-
-void KoTableCellStyle::setProperty(int key, const QVariant &value)
-{
- Q_D(KoTableCellStyle);
- if (d->parentStyle) {
- QVariant var = d->parentStyle->value(key);
- if (!var.isNull() && var == value) { // same as parent, so its actually a reset.
- d->stylesPrivate.remove(key);
- return;
- }
- }
- d->stylesPrivate.add(key, value);
-}
-
-void KoTableCellStyle::remove(int key)
-{
- Q_D(KoTableCellStyle);
- d->stylesPrivate.remove(key);
-}
-
-QVariant KoTableCellStyle::value(int key) const
-{
- Q_D(const KoTableCellStyle);
- QVariant var = d->stylesPrivate.value(key);
- if (var.isNull() && d->parentStyle)
- var = d->parentStyle->value(key);
- return var;
-}
-
-bool KoTableCellStyle::hasProperty(int key) const
-{
- Q_D(const KoTableCellStyle);
- return d->stylesPrivate.contains(key);
-}
-
-qreal KoTableCellStyle::propertyDouble(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull())
- return 0.0;
- return variant.toDouble();
-}
-
-QPen KoTableCellStyle::propertyPen(int key) const
-{
- const QVariant prop = value(key);
- if (prop.userType() != QVariant::Pen)
- return QPen(Qt::NoPen);
- return qvariant_cast<QPen>(prop);
-}
-
-int KoTableCellStyle::propertyInt(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull())
- return 0;
- return variant.toInt();
-}
-
-bool KoTableCellStyle::propertyBoolean(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull())
- return false;
- return variant.toBool();
-}
-
-QColor KoTableCellStyle::propertyColor(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull()) {
- return QColor();
- }
- return qvariant_cast<QColor>(variant);
-}
-
-void KoTableCellStyle::applyStyle(QTextTableCellFormat &format) const
-{
- Q_D(const KoTableCellStyle);
- if (d->parentStyle) {
- d->parentStyle->applyStyle(format);
- }
- QList<int> keys = d->stylesPrivate.keys();
- for (int i = 0; i < keys.count(); i++) {
- QVariant variant = d->stylesPrivate.value(keys[i]);
- format.setProperty(keys[i], variant);
- }
- // Hack : build KoBorder here
- if (d->parentStyle && d->parentStyle->hasProperty(Borders) && this->hasProperty(Borders)) {
- KoBorder parentBorder = d->parentStyle->borders();
- KoBorder childBorder = this->borders();
- if (childBorder.hasBorder(KoBorder::LeftBorder))
- parentBorder.setBorderData(KoBorder::LeftBorder, childBorder.borderData(KoBorder::LeftBorder));
- if (childBorder.hasBorder(KoBorder::RightBorder))
- parentBorder.setBorderData(KoBorder::RightBorder, childBorder.borderData(KoBorder::RightBorder));
- if (childBorder.hasBorder(KoBorder::TopBorder))
- parentBorder.setBorderData(KoBorder::TopBorder, childBorder.borderData(KoBorder::TopBorder));
- if (childBorder.hasBorder(KoBorder::BottomBorder))
- parentBorder.setBorderData(KoBorder::BottomBorder, childBorder.borderData(KoBorder::BottomBorder));
- if (childBorder.hasBorder(KoBorder::BltrBorder))
- parentBorder.setBorderData(KoBorder::BltrBorder, childBorder.borderData(KoBorder::BltrBorder));
- if (childBorder.hasBorder(KoBorder::TlbrBorder))
- parentBorder.setBorderData(KoBorder::TlbrBorder, childBorder.borderData(KoBorder::TlbrBorder));
- format.setProperty(Borders, QVariant::fromValue<KoBorder>(parentBorder));
- }
-}
-
-void KoTableCellStyle::applyStyle(QTextTableCell &cell) const
-{
- Q_D(const KoTableCellStyle);
- QTextTableCellFormat format = cell.format().toTableCellFormat();
- applyStyle(format);
-
- if (d->paragraphStyle) {
- d->paragraphStyle->KoCharacterStyle::applyStyle(format);
- }
- cell.setFormat(format);
-}
-
-void KoTableCellStyle::setBackground(const QBrush &brush)
-{
- setProperty(CellBackgroundBrush, brush);
-}
-
-void KoTableCellStyle::clearBackground()
-{
- Q_D(KoTableCellStyle);
- d->stylesPrivate.remove(CellBackgroundBrush);
-}
-
-QBrush KoTableCellStyle::background() const
-{
- Q_D(const KoTableCellStyle);
- QVariant variant = d->stylesPrivate.value(CellBackgroundBrush);
-
- if (variant.isNull()) {
- return QBrush();
- }
- return qvariant_cast<QBrush>(variant);
-}
-
-void KoTableCellStyle::setWrap(bool state)
-{
- setProperty(Wrap, state);
-}
-
-bool KoTableCellStyle::wrap() const
-{
- return propertyBoolean(Wrap);
-}
-
-void KoTableCellStyle::setAlignment(Qt::Alignment alignment)
-{
- setProperty(VerticalAlignment, (int) alignment);
-}
-
-Qt::Alignment KoTableCellStyle::alignment() const
-{
- if (propertyInt(VerticalAlignment) == 0)
- return Qt::AlignTop;
- return static_cast<Qt::Alignment>(propertyInt(VerticalAlignment));
-}
-
-KoTableCellStyle *KoTableCellStyle::parentStyle() const
-{
- Q_D(const KoTableCellStyle);
- return d->parentStyle;
-}
-
-QString KoTableCellStyle::name() const
-{
- Q_D(const KoTableCellStyle);
- return d->name;
-}
-
-void KoTableCellStyle::setName(const QString &name)
-{
- Q_D(KoTableCellStyle);
- if (name == d->name)
- return;
- d->name = name;
- emit nameChanged(name);
-}
-
-int KoTableCellStyle::styleId() const
-{
- return propertyInt(StyleId);
-}
-
-void KoTableCellStyle::setStyleId(int id)
-{
- Q_D(KoTableCellStyle);
- setProperty(StyleId, id); if (d->next == 0) d->next = id;
-}
-
-QString KoTableCellStyle::masterPageName() const
-{
- return value(MasterPageName).toString();
-}
-
-void KoTableCellStyle::setMasterPageName(const QString &name)
-{
- setProperty(MasterPageName, name);
-}
-
-void KoTableCellStyle::setCellProtection(KoTableCellStyle::CellProtectionFlag protection)
-{
- setProperty(CellProtection, protection);
-}
-
-KoTableCellStyle::CellProtectionFlag KoTableCellStyle::cellProtection() const
-{
- return (CellProtectionFlag) propertyInt(CellProtection);
-}
-
-void KoTableCellStyle::setTextDirection(KoText::Direction value)
-{
- setProperty(TextWritingMode, value);
-}
-
-KoText::Direction KoTableCellStyle::textDirection() const
-{
- return (KoText::Direction) propertyInt(TextWritingMode);
-}
-
-bool KoTableCellStyle::printContent() const
-{
- return (hasProperty(PrintContent) && propertyBoolean(PrintContent));
-}
-
-void KoTableCellStyle::setPrintContent(bool state)
-{
- setProperty(PrintContent, state);
-}
-
-bool KoTableCellStyle::repeatContent() const
-{
- return (hasProperty(RepeatContent) && propertyBoolean(RepeatContent));
-}
-
-void KoTableCellStyle::setRepeatContent(bool state)
-{
- setProperty(RepeatContent, state);
-}
-
-int KoTableCellStyle::decimalPlaces() const
-{
- return propertyInt(DecimalPlaces);
-}
-
-void KoTableCellStyle::setDecimalPlaces(int places)
-{
- setProperty(DecimalPlaces, places);
-}
-
-bool KoTableCellStyle::alignFromType() const
-{
- return (hasProperty(AlignFromType) && propertyBoolean(AlignFromType));
-}
-
-void KoTableCellStyle::setAlignFromType(bool state)
-{
- setProperty(AlignFromType, state);
-}
-
-qreal KoTableCellStyle::rotationAngle() const
-{
- return propertyDouble(RotationAngle);
-}
-
-void KoTableCellStyle::setRotationAngle(qreal value)
-{
- if (value >= 0)
- setProperty(RotationAngle, value);
-}
-
-void KoTableCellStyle::setVerticalGlyphOrientation(bool state)
-{
- setProperty(VerticalGlyphOrientation, state);
-}
-
-bool KoTableCellStyle::verticalGlyphOrientation() const
-{
- if (hasProperty(VerticalGlyphOrientation))
- return propertyBoolean(VerticalGlyphOrientation);
- return true;
-}
-
-void KoTableCellStyle::setDirection(KoTableCellStyle::CellTextDirection direction)
-{
- setProperty(Direction, direction);
-}
-
-KoBorder KoTableCellStyle::borders() const
-{
- if (hasProperty(Borders))
- return value(Borders).value<KoBorder>();
- return KoBorder();
-}
-
-void KoTableCellStyle::setBorders(const KoBorder& borders)
-{
- setProperty(Borders, QVariant::fromValue<KoBorder>(borders));
-}
-
-KoShadowStyle KoTableCellStyle::shadow() const
-{
- if (hasProperty(Shadow))
- return value(Shadow).value<KoShadowStyle>();
- return KoShadowStyle();
-}
-
-void KoTableCellStyle::setShadow(const KoShadowStyle& shadow)
-{
- setProperty(Shadow, QVariant::fromValue<KoShadowStyle>(shadow));
-}
-
-KoTableCellStyle::RotationAlignment KoTableCellStyle::rotationAlignment() const
-{
- return static_cast<RotationAlignment>(propertyInt(RotationAlign));
-}
-
-void KoTableCellStyle::setRotationAlignment(KoTableCellStyle::RotationAlignment align)
-{
- setProperty(RotationAlign, align);
-}
-
-KoTableCellStyle::CellTextDirection KoTableCellStyle::direction() const
-{
- if (hasProperty(Direction))
- return (KoTableCellStyle::CellTextDirection) propertyInt(Direction);
- return KoTableCellStyle::Default;
-}
-
-void KoTableCellStyle::loadOdf(const KoXmlElement *element, KoShapeLoadingContext &scontext)
-{
- KoOdfLoadingContext &context = scontext.odfLoadingContext();
- Q_D(KoTableCellStyle);
- if (element->hasAttributeNS(KoXmlNS::style, "display-name"))
- d->name = element->attributeNS(KoXmlNS::style, "display-name", QString());
-
- if (d->name.isEmpty()) // if no style:display-name is given us the style:name
- d->name = element->attributeNS(KoXmlNS::style, "name", QString());
-
- QString masterPage = element->attributeNS(KoXmlNS::style, "master-page-name", QString());
- if (! masterPage.isEmpty()) {
- setMasterPageName(masterPage);
- }
-
- paragraphStyle()->loadOdf(element, scontext, true); // load the par and char properties
- context.styleStack().save();
- QString family = element->attributeNS(KoXmlNS::style, "family", "table-cell");
- context.addStyles(element, family.toLocal8Bit().constData()); // Load all parents - only because we don't support inheritance.
-
- context.styleStack().setTypeProperties("table-cell");
- loadOdfProperties(scontext, context.styleStack());
-
- context.styleStack().setTypeProperties("graphic");
- loadOdfProperties(scontext, context.styleStack());
-
- context.styleStack().restore();
-}
-
-void KoTableCellStyle::loadOdfProperties(KoShapeLoadingContext &context, KoStyleStack &styleStack)
-{
- // Padding
- if (styleStack.hasProperty(KoXmlNS::fo, "padding-left"))
- setLeftPadding(KoUnit::parseValue(styleStack.property(KoXmlNS::fo, "padding-left")));
- if (styleStack.hasProperty(KoXmlNS::fo, "padding-right"))
- setRightPadding(KoUnit::parseValue(styleStack.property(KoXmlNS::fo, "padding-right")));
- if (styleStack.hasProperty(KoXmlNS::fo, "padding-top"))
- setTopPadding(KoUnit::parseValue(styleStack.property(KoXmlNS::fo, "padding-top")));
- if (styleStack.hasProperty(KoXmlNS::fo, "padding-bottom"))
- setBottomPadding(KoUnit::parseValue(styleStack.property(KoXmlNS::fo, "padding-bottom")));
- if (styleStack.hasProperty(KoXmlNS::fo, "padding"))
- setPadding(KoUnit::parseValue(styleStack.property(KoXmlNS::fo, "padding")));
-
- if (styleStack.hasProperty(KoXmlNS::style, "shadow")) {
- KoShadowStyle shadow;
- if (shadow.loadOdf(styleStack.property(KoXmlNS::style, "shadow"))) {
- setShadow(shadow);
- }
- }
-
- // The fo:background-color attribute specifies the background color of a cell.
- if (styleStack.hasProperty(KoXmlNS::fo, "background-color")) {
- const QString bgcolor = styleStack.property(KoXmlNS::fo, "background-color");
- QBrush brush = background();
- if (bgcolor == "transparent")
- setBackground(Qt::NoBrush);
- else {
- if (brush.style() == Qt::NoBrush)
- brush.setStyle(Qt::SolidPattern);
- brush.setColor(bgcolor); // #rrggbb format
- setBackground(brush);
- }
- }
-
- QString fillStyle = styleStack.property(KoXmlNS::draw, "fill");
- if (fillStyle == "solid" || fillStyle == "hatch") {
- styleStack.save();
- QBrush brush = KoOdfGraphicStyles::loadOdfFillStyle(styleStack, fillStyle, context.odfLoadingContext().stylesReader());
- setBackground(brush);
- styleStack.restore();
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "shrink-to-fit")) {
- setShrinkToFit(styleStack.property(KoXmlNS::style, "shrink-to-fit") == "true");
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "print-content")) {
- setPrintContent(styleStack.property(KoXmlNS::style, "print-content") == "true");
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "repeat-content")) {
- setRepeatContent(styleStack.property(KoXmlNS::style, "repeat-content") == "true");
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "decimal-places")) {
- bool ok;
- int value = styleStack.property(KoXmlNS::style, "decimal-places").toInt(&ok);
- if (ok)
- setDecimalPlaces(value);
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "rotation-angle")) {
- setRotationAngle(KoUnit::parseAngle(styleStack.property(KoXmlNS::style, "rotation-angle")));
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "glyph-orientation-vertical"))
- {
- setVerticalGlyphOrientation(styleStack.property(KoXmlNS::style, "glyph-orientation-vertical") == "auto");
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "direction")) {
- if (styleStack.property(KoXmlNS::style, "direction") == "ltr")
- setDirection(KoTableCellStyle::LeftToRight);
- else
- setDirection(KoTableCellStyle::TopToBottom);
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "rotation-align")) {
- setRotationAlignment(rotationAlignmentFromString(styleStack.property(KoXmlNS::style, "rotation-align")));
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "text-align-source")) {
- setAlignFromType(styleStack.property(KoXmlNS::style, "text-align-source") == "value-type");
- }
-
- if (styleStack.hasProperty(KoXmlNS::fo, "wrap-option")) {
- setWrap(styleStack.property(KoXmlNS::fo, "wrap-option") == "wrap");
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "cell-protect")) {
- QString protection = styleStack.property(KoXmlNS::style, "cell-protect");
- if (protection == "none")
- setCellProtection(NoProtection);
- else if (protection == "hidden-and-protected")
- setCellProtection(HiddenAndProtected);
- else if (protection == "protected")
- setCellProtection(Protected);
- else if (protection == "formula-hidden")
- setCellProtection(FormulaHidden);
- else if ((protection == "protected formula-hidden") || (protection == "formula-hidden protected"))
- setCellProtection(ProtectedAndFormulaHidden);
- }
- // Alignment
- const QString verticalAlign(styleStack.property(KoXmlNS::style, "vertical-align"));
- if (!verticalAlign.isEmpty()) {
- if (verticalAlign == "automatic")
- setAlignment((Qt::AlignmentFlag) 0);
- else
- setAlignment(KoText::valignmentFromString(verticalAlign));
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "writing-mode"))
- setTextDirection(KoText::directionFromString(styleStack.property(KoXmlNS::style, "writing-mode")));
-}
-
-void KoTableCellStyle::copyProperties(const KoTableCellStyle *style)
-{
- Q_D(KoTableCellStyle);
- const KoTableCellStylePrivate *styleD = static_cast<const KoTableCellStylePrivate*>(style->d_func());
-
- d->stylesPrivate = styleD->stylesPrivate;
- setName(style->name()); // make sure we emit property change
- d->next = styleD->next;
- d->parentStyle = styleD->parentStyle;
-}
-
-KoTableCellStyle *KoTableCellStyle::clone(QObject *parent)
-{
- KoTableCellStyle *newStyle = new KoTableCellStyle(parent);
- newStyle->copyProperties(this);
- return newStyle;
-}
-
-
-bool KoTableCellStyle::operator==(const KoTableCellStyle &other) const
-{
- Q_D(const KoTableCellStyle);
- const KoTableCellStylePrivate *otherD = static_cast<const KoTableCellStylePrivate*>(other.d_func());
- return otherD->stylesPrivate == d->stylesPrivate;
-}
-
-void KoTableCellStyle::removeDuplicates(const KoTableCellStyle &other)
-{
- Q_D(KoTableCellStyle);
- const KoTableCellStylePrivate *otherD = static_cast<const KoTableCellStylePrivate*>(other.d_func());
- d->stylesPrivate.removeDuplicates(otherD->stylesPrivate);
-}
-
-void KoTableCellStyle::saveOdf(KoGenStyle &style, KoShapeSavingContext &context)
-{
- Q_D(KoTableCellStyle);
- QList<int> keys = d->stylesPrivate.keys();
- bool donePadding = false;
- if (hasProperty(QTextFormat::TableCellLeftPadding) &&
- hasProperty(QTextFormat::TableCellRightPadding) &&
- hasProperty(QTextFormat::TableCellTopPadding) &&
- hasProperty(QTextFormat::TableCellBottomPadding) &&
- leftPadding() == rightPadding() &&
- topPadding() == bottomPadding() &&
- topPadding() == leftPadding()) {
- donePadding = true;
- style.addPropertyPt("fo:padding", leftPadding(), KoGenStyle::TableCellType);
- }
- Q_FOREACH (int key, keys) {
- if (key == CellBackgroundBrush) {
- QBrush backBrush = background();
- if (backBrush.style() != Qt::NoBrush)
- style.addProperty("fo:background-color", backBrush.color().name(), KoGenStyle::TableCellType);
- else
- style.addProperty("fo:background-color", "transparent", KoGenStyle::TableCellType);
- } else if (key == VerticalAlignment) {
- if (propertyInt(VerticalAlignment) == 0)
- style.addProperty("style:vertical-align", "automatic", KoGenStyle::TableCellType);
- else
- style.addProperty("style:vertical-align", KoText::valignmentToString(alignment()), KoGenStyle::TableCellType);
- } else if ((key == QTextFormat::TableCellLeftPadding) && (!donePadding)) {
- style.addPropertyPt("fo:padding-left", leftPadding(), KoGenStyle::TableCellType);
- } else if ((key == QTextFormat::TableCellRightPadding) && (!donePadding)) {
- style.addPropertyPt("fo:padding-right", rightPadding(), KoGenStyle::TableCellType);
- } else if ((key == QTextFormat::TableCellTopPadding) && (!donePadding)) {
- style.addPropertyPt("fo:padding-top", topPadding(), KoGenStyle::TableCellType);
- } else if ((key == QTextFormat::TableCellBottomPadding) && (!donePadding)) {
- style.addPropertyPt("fo:padding-bottom", bottomPadding(), KoGenStyle::TableCellType);
- } else if (key == ShrinkToFit) {
- style.addProperty("style:shrink-to-fit", shrinkToFit(), KoGenStyle::TableCellType);
- } else if (key == PrintContent) {
- style.addProperty("style:print-content", printContent(), KoGenStyle::TableCellType);
- } else if (key == RepeatContent) {
- style.addProperty("style:repeat-content", repeatContent(), KoGenStyle::TableCellType);
- } else if (key == DecimalPlaces) {
- style.addProperty("style:decimal-places", decimalPlaces(), KoGenStyle::TableCellType);
- } else if (key == RotationAngle) {
- style.addProperty("style:rotation-angle", QString::number(rotationAngle()), KoGenStyle::TableCellType);
- } else if (key == Wrap) {
- if (wrap())
- style.addProperty("fo:wrap-option", "wrap", KoGenStyle::TableCellType);
- else
- style.addProperty("fo:wrap-option", "no-wrap", KoGenStyle::TableCellType);
- } else if (key == Direction) {
- if (direction() == LeftToRight)
- style.addProperty("style:direction", "ltr", KoGenStyle::TableCellType);
- else if (direction() == TopToBottom)
- style.addProperty("style:direction", "ttb", KoGenStyle::TableCellType);
- } else if (key == CellProtection) {
- if (cellProtection() == NoProtection)
- style.addProperty("style:cell-protect", "none", KoGenStyle::TableCellType);
- else if (cellProtection() == HiddenAndProtected)
- style.addProperty("style:cell-protect", "hidden-and-protected", KoGenStyle::TableCellType);
- else if (cellProtection() == Protected)
- style.addProperty("style:cell-protect", "protected", KoGenStyle::TableCellType);
- else if (cellProtection() == FormulaHidden)
- style.addProperty("style:cell-protect", "formula-hidden", KoGenStyle::TableCellType);
- else if (cellProtection() == ProtectedAndFormulaHidden)
- style.addProperty("style:cell-protect", "protected formula-hidden", KoGenStyle::TableCellType);
- } else if (key == AlignFromType) {
- if (alignFromType())
- style.addProperty("style:text-align-source", "value-type", KoGenStyle::TableCellType);
- else
- style.addProperty("style:text-align-source", "fix", KoGenStyle::TableCellType);
- } else if (key == RotationAlign) {
- style.addProperty("style:rotation-align", rotationAlignmentToString(rotationAlignment()), KoGenStyle::TableCellType);
- } else if (key == TextWritingMode) {
- style.addProperty("style:writing-mode", KoText::directionToString(textDirection()), KoGenStyle::TableCellType);
- } else if (key == VerticalGlyphOrientation) {
- if (verticalGlyphOrientation())
- style.addProperty("style:glyph-orientation-vertical", "auto", KoGenStyle::TableCellType);
- else
- style.addProperty("style:glyph-orientation-vertical", "0", KoGenStyle::TableCellType);
- } else if (key == Borders) {
- borders().saveOdf(style, KoGenStyle::TableCellType);
- } else if (key == Shadow) {
- style.addProperty("style:shadow", shadow().saveOdf());
- }
- }
- if (d->paragraphStyle) {
- d->paragraphStyle->saveOdf(style, context);
- }
-
-}
-
-void KoTableCellStyle::setEdge(KoBorder::BorderSide side, KoBorder::BorderStyle style,
- qreal width, const QColor &color)
-{
- KoBorder::BorderData edge;
- qreal innerWidth = 0;
- qreal middleWidth = 0;
- qreal space = 0;
- QVector<qreal> dashes;
- switch (style) {
- case KoBorder::BorderNone:
- width = 0.0;
- break;
- case KoBorder::BorderDouble:
- innerWidth = space = width/3; //some nice default look
- width -= (space + innerWidth);
- edge.outerPen.setStyle(Qt::SolidLine);
- break;
- case KoBorder::BorderDotted:
- dashes << 1 << 1;
- edge.outerPen.setDashPattern(dashes);
- break;
- case KoBorder::BorderDashed:
- dashes << 4 << 1;
- edge.outerPen.setDashPattern(dashes);
- break;
- case KoBorder::BorderDashedLong: {
- dashes << 4 << 4;
- edge.outerPen.setDashPattern(dashes);
- break;
- }
- case KoBorder::BorderTriple:
- innerWidth = middleWidth = space = width/6;
- width -= (space + innerWidth);
- edge.outerPen.setStyle(Qt::SolidLine);
- break;
- case KoBorder::BorderDashDot:
- dashes << 3 << 3<< 7 << 3;
- edge.outerPen.setDashPattern(dashes);
- break;
- case KoBorder::BorderDashDotDot:
- dashes << 2 << 2<< 6 << 2 << 2 << 2;
- edge.outerPen.setDashPattern(dashes);
- break;
- case KoBorder::BorderWave:
- edge.outerPen.setStyle(Qt::SolidLine);
- break;
- case KoBorder::BorderSlash:
- edge.outerPen.setStyle(Qt::SolidLine);
- break;
- case KoBorder::BorderDoubleWave:
- innerWidth = space = width/3; //some nice default look
- width -= (space + innerWidth);
- edge.outerPen.setStyle(Qt::SolidLine);
- break;
- default:
- edge.outerPen.setStyle(Qt::SolidLine);
- break;
- }
- edge.outerPen.setColor(color);
- edge.outerPen.setJoinStyle(Qt::MiterJoin);
- edge.outerPen.setCapStyle(Qt::FlatCap);
- edge.outerPen.setWidthF(width);
-
- edge.spacing = space;
- edge.innerPen = edge.outerPen;
- edge.innerPen.setWidthF(innerWidth);
- QPen middlePen;
- middlePen = edge.outerPen;
- middlePen.setWidthF(middleWidth);
-
- setEdge(side, edge, style);
-}
-
-void KoTableCellStyle::setEdge(KoBorder::BorderSide side, const KoBorder::BorderData &edge, KoBorder::BorderStyle style)
-{
- KoBorder borders = this->borders();
- KoBorder::BorderData edgeCopy(edge);
- edgeCopy.style = style; // Just for safety.
- borders.setBorderData(side, edgeCopy);
- setBorders(borders);
-}
-
-void KoTableCellStyle::setEdgeDoubleBorderValues(KoBorder::BorderSide side, qreal innerWidth, qreal space)
-{
- KoBorder::BorderData edge = getEdge(side);
-
- qreal totalWidth = edge.outerPen.widthF() + edge.spacing + edge.innerPen.widthF();
- if (edge.innerPen.widthF() > 0.0) {
- edge.outerPen.setWidthF(totalWidth - innerWidth - space);
- edge.spacing = space;
- edge.innerPen.setWidthF(innerWidth);
- setEdge(side, edge, getBorderStyle(side));
- }
-}
-
-bool KoTableCellStyle::hasBorders() const
-{
- return borders().hasBorder();
-}
-
-qreal KoTableCellStyle::leftBorderWidth() const
-{
- const KoBorder::BorderData &edge = getEdge(KoBorder::LeftBorder);
- return edge.spacing + edge.innerPen.widthF() + edge.outerPen.widthF();
-}
-
-qreal KoTableCellStyle::rightBorderWidth() const
-{
- const KoBorder::BorderData &edge = getEdge(KoBorder::RightBorder);
- return edge.spacing + edge.innerPen.widthF() + edge.outerPen.widthF();
-}
-
-qreal KoTableCellStyle::topBorderWidth() const
-{
- const KoBorder::BorderData &edge = getEdge(KoBorder::TopBorder);
- return edge.spacing + edge.innerPen.widthF() + edge.outerPen.widthF();
-}
-
-qreal KoTableCellStyle::bottomBorderWidth() const
-{
- const KoBorder::BorderData &edge = getEdge(KoBorder::BottomBorder);
- return edge.spacing + edge.innerPen.widthF() + edge.outerPen.widthF();
-}
-
-qreal KoTableCellStyle::leftInnerBorderWidth() const
-{
- const KoBorder::BorderData &edge = getEdge(KoBorder::LeftBorder);
- return edge.innerPen.widthF();
-}
-
-qreal KoTableCellStyle::rightInnerBorderWidth() const
-{
- const KoBorder::BorderData &edge = getEdge(KoBorder::RightBorder);
- return edge.innerPen.widthF();
-}
-
-qreal KoTableCellStyle::topInnerBorderWidth() const
-{
- const KoBorder::BorderData &edge = getEdge(KoBorder::TopBorder);
- return edge.innerPen.widthF();
-}
-
-qreal KoTableCellStyle::bottomInnerBorderWidth() const
-{
- const KoBorder::BorderData &edge = getEdge(KoBorder::BottomBorder);
- return edge.innerPen.widthF();
-}
-
-qreal KoTableCellStyle::leftOuterBorderWidth() const
-{
- const KoBorder::BorderData &edge = getEdge(KoBorder::LeftBorder);
- return edge.outerPen.widthF();
-}
-
-qreal KoTableCellStyle::rightOuterBorderWidth() const
-{
- const KoBorder::BorderData &edge = getEdge(KoBorder::RightBorder);
- return edge.outerPen.widthF();
-}
-
-qreal KoTableCellStyle::topOuterBorderWidth() const
-{
- const KoBorder::BorderData &edge = getEdge(KoBorder::TopBorder);
- return edge.outerPen.widthF();
-}
-
-qreal KoTableCellStyle::bottomOuterBorderWidth() const
-{
- const KoBorder::BorderData &edge = getEdge(KoBorder::BottomBorder);
- return edge.outerPen.widthF();
-}
-
-KoBorder::BorderData KoTableCellStyle::getEdge(KoBorder::BorderSide side) const
-{
- KoBorder border = this->borders();
- return border.borderData(side);
-}
-
-KoBorder::BorderStyle KoTableCellStyle::getBorderStyle(KoBorder::BorderSide side) const
-{
- KoBorder::BorderData edge = getEdge(side);
- return edge.style;
-}
diff --git a/plugins/flake/textshape/kotext/styles/KoTableCellStyle.h b/plugins/flake/textshape/kotext/styles/KoTableCellStyle.h
deleted file mode 100644
index f8dadfd088..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoTableCellStyle.h
+++ /dev/null
@@ -1,376 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- *
- * 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 KOTABLECELLSTYLE_H
-#define KOTABLECELLSTYLE_H
-
-#include "KoText.h"
-#include "kritatext_export.h"
-
-#include <KoXmlReaderForward.h>
-
-#include <KoBorder.h>
-#include <KoShadowStyle.h>
-#include <QColor>
-
-#include <QObject>
-
-struct Property;
-class QTextTableCell;
-class QRectF;
-class KoStyleStack;
-class KoGenStyle;
-class KoParagraphStyle;
-class KoShapeLoadingContext;
-class KoShapeSavingContext;
-class KoTableCellStylePrivate;
-class QString;
-class QVariant;
-
-/**
- * A container for all properties for the table cell style.
- * Each tablecell in the main text either is based on a table cell style, or its not. Where
- * it is based on a table cell style this is indecated that it has a property 'StyleId'
- * with an integer as value. The integer value corresponds to the styleId() output of
- * a specific KoTableCellStyle.
- * @see KoStyleManager
- */
-class KRITATEXT_EXPORT KoTableCellStyle : public QObject
-{
- Q_OBJECT
-public:
- enum CellProtectionFlag {
- NoProtection,
- HiddenAndProtected,
- Protected,
- FormulaHidden,
- ProtectedAndFormulaHidden
- };
-
- enum CellTextDirection {
- Default = 0,
- LeftToRight,
- TopToBottom
- };
-
- enum RotationAlignment {
- RAlignNone,
- RAlignBottom,
- RAlignTop,
- RAlignCenter
- };
-
- enum Property {
- StyleId = QTextTableCellFormat::UserProperty + 7001,
- ShrinkToFit, ///< Shrink the cell content to fit the size
- Wrap, ///< Wrap the text within the cell
- CellProtection, ///< The cell protection when the table is protected
- PrintContent, ///< Should the content of this cell be printed
- RepeatContent, ///< Display the cell content as many times as possible
- DecimalPlaces, ///< Count the maximum number of decimal places to display
- AlignFromType, ///< Should the alignment property be respected or should the alignment be based on the value type
- RotationAngle, ///< Rotation angle of the cell content, in degrees
- Direction, ///< The direction of the text in the cell. This is a CellTextDirection.
- RotationAlign, ///< How the edge of the text is aligned after rotation. This is a RotationAlignment
- TextWritingMode, ///< KoText::Direction, the direction for writing text in the cell
- VerticalGlyphOrientation, ///< bool, specify whether this feature is enabled or not
- CellBackgroundBrush, ///< the cell background brush, as QTextFormat::BackgroundBrush is used by paragraphs
- VerticalAlignment, ///< the vertical alignment oinside the cell
- MasterPageName, ///< Optional name of the master-page
- InlineRdf, ///< Optional KoTextInlineRdf object
- Borders, ///< KoBorder, the borders of this cell
- Shadow, ///< KoShadowStyle, the shadow of this cell
- CellIsProtected ///< boolean, if true, the cell is protected against edits
- /// It's not really a property of KoTableCellStyle but defined here for convenience
- ,LastCellStyleProperty
- };
-
- /// Constructor
- explicit KoTableCellStyle(QObject *parent = 0);
- /// Creates a KoTableCellStyle with the given table cell format, and \a parent
- explicit KoTableCellStyle(const QTextTableCellFormat &tableCellFormat, QObject *parent = 0);
- KoTableCellStyle(const KoTableCellStyle &other);
- KoTableCellStyle& operator=(const KoTableCellStyle &other);
-
- /// Destructor
- ~KoTableCellStyle() override;
-
- /// Creates a KoTableCellStyle that represents the formatting of \a block.
- static KoTableCellStyle *fromTableCell(const QTextTableCell &table, QObject *parent = 0);
-
- /// Creates a clean QTextCharFormat, but keeps all the table cell properties.
- /// This is needed since block.charformat doubles as the QTextTableCellFormat
- /// This method works even if \a charFormat is not a QTextTableCellFormat
- static QTextCharFormat cleanCharFormat(const QTextCharFormat &charFormat);
-
- /// creates a clone of this style with the specified parent
- KoTableCellStyle *clone(QObject *parent = 0);
-
- /**
- * Adjust the bounding rectangle \p boundingRect according to the paddings and margins
- * of this border data. The inverse of this function is boundingRect().
- *
- * \sa boundingRect()
- *
- * @param boundingRect the bounding rectangle.
- * @return the adjusted rectangle.
- */
- QRectF contentRect(const QRectF &boundingRect) const;
-
- /**
- * Get the bounding rect given a content rect, this is the inverse of contentRect().
- *
- * \sa contentRect()
- *
- * @param contentRect the content rectangle.
- * @return the bounding rectangle.
- */
- QRectF boundingRect(const QRectF &contentRect) const;
-
- void setBackground(const QBrush &brush);
- /// See similar named method on QTextBlockFormat
- QBrush background() const;
- /// See similar named method on QTextBlockFormat
- void clearBackground();
-
- /**
- * Get the paragraph style for this cell style
- *
- * @return the paragraph style
- */
- KoParagraphStyle *paragraphStyle() const;
-
- bool shrinkToFit() const;
- void setShrinkToFit(bool state);
-
- bool repeatContent() const;
- void setRepeatContent(bool state);
-
- void setLeftPadding(qreal padding);
- void setTopPadding(qreal padding);
- void setRightPadding(qreal padding);
- void setBottomPadding(qreal padding);
- void setPadding(qreal padding);
-
- qreal leftPadding() const;
- qreal rightPadding() const;
- qreal topPadding() const;
- qreal bottomPadding() const;
-
- void setAlignment(Qt::Alignment alignment);
- Qt::Alignment alignment() const;
-
- KoText::Direction textDirection() const;
- void setTextDirection (KoText::Direction value);
-
- void setWrap(bool state);
- bool wrap() const;
-
- CellProtectionFlag cellProtection() const;
- void setCellProtection (CellProtectionFlag protection);
-
- void setPrintContent(bool state);
- bool printContent() const;
-
- void setDecimalPlaces(int places);
- int decimalPlaces() const;
-
- void setAlignFromType(bool state);
- bool alignFromType() const;
-
- void setRotationAngle(qreal value);
- qreal rotationAngle() const;
-
- void setDirection(CellTextDirection direction);
- CellTextDirection direction() const;
-
- void setRotationAlignment(RotationAlignment align);
- RotationAlignment rotationAlignment () const;
-
- void setVerticalGlyphOrientation(bool state);
- bool verticalGlyphOrientation() const;
-
- void setBorders(const KoBorder &borders);
- KoBorder borders() const;
-
- void setShadow (const KoShadowStyle &shadow);
- KoShadowStyle shadow() const;
-
- /// set the parent style this one inherits its unset properties from.
- void setParentStyle(KoTableCellStyle *parent);
-
- /// return the parent style
- KoTableCellStyle *parentStyle() const;
-
- /// return the name of the style.
- QString name() const;
-
- /// set a user-visible name on the style.
- void setName(const QString &name);
-
- /// each style has a unique ID (non persistent) given out by the styleManager
- int styleId() const;
-
- /// each style has a unique ID (non persistent) given out by the styleManager
- void setStyleId(int id);
-
- /// return the optional name of the master-page or a QString() if this paragraph isn't attached to a master-page.
- QString masterPageName() const;
- /// Set the name of the master-page.
- void setMasterPageName(const QString &name);
-
-
- /// copy all the properties from the other style to this style, effectively duplicating it.
- void copyProperties(const KoTableCellStyle *style);
-
- /**
- * Apply this style to a textTableCellFormat by copying all properties from this, and parent
- * styles to the target textTableCellFormat. Note that the paragraph format will not be applied
- * using this method, use the other method for that.
- * No default values are applied.
- */
- void applyStyle(QTextTableCellFormat &format) const;
-
- void applyStyle(QTextTableCell &cell) const;
-
- void remove(int key);
-
- /// Compare the paragraph, character and list properties of this style with the other
- bool operator==(const KoTableCellStyle &other) const;
-
- void removeDuplicates(const KoTableCellStyle &other);
-
- /**
- * Load the style form the element
- *
- * @param context the odf loading context
- * @param element the element containing the
- */
- void loadOdf(const KoXmlElement *element, KoShapeLoadingContext &context);
-
- void saveOdf(KoGenStyle &style, KoShapeSavingContext &context);
-
- /**
- * Returns true if this paragraph style has the property set.
- * Note that this method does not delegate to the parent style.
- * @param key the key as found in the Property enum
- */
- bool hasProperty(int key) const;
-
- /**
- * Set a property with key to a certain value, overriding the value from the parent style.
- * If the value set is equal to the value of the parent style, the key will be removed instead.
- * @param key the Property to set.
- * @param value the new value to set on this style.
- * @see hasProperty(), value()
- */
- void setProperty(int key, const QVariant &value);
- /**
- * Return the value of key as represented on this style, taking into account parent styles.
- * You should consider using the direct accessors for individual properties instead.
- * @param key the Property to request.
- * @returns a QVariant which holds the property value.
- */
- QVariant value(int key) const;
-
-
- /**
- * Set the properties of an edge.
- *
- * @param side defines which edge this is for.
- * @param style the border style for this side.
- * @param totalWidth the thickness of the border. Sum of outerwidth, spacing and innerwidth for double borders
- * @param color the color of the border line(s).
- */
- void setEdge(KoBorder::BorderSide side, KoBorder::BorderStyle style,
- qreal totalWidth, const QColor &color);
-
- /**
- * Set the properties of a double border.
- * Note: you need to set the edge first or that would overwrite these values.
- *
- * The values will not be set if the border doesn't have a double style
- *
- * @param side defines which edge this is for.
- * @param space the amount of spacing between the outer border and the inner border in case of style being double
- * @param innerWidth the thickness of the inner border line in case of style being double
- */
- void setEdgeDoubleBorderValues(KoBorder::BorderSide side, qreal innerWidth, qreal space);
-
- /**
- * Check if the border data has any borders.
- *
- * @return true if there has been at least one border set.
- */
- bool hasBorders() const;
-
- qreal leftBorderWidth() const;
- qreal rightBorderWidth() const;
- qreal topBorderWidth() const;
- qreal bottomBorderWidth() const;
-
- qreal leftInnerBorderWidth() const;
- qreal rightInnerBorderWidth() const;
- qreal topInnerBorderWidth() const;
- qreal bottomInnerBorderWidth() const;
-
- qreal leftOuterBorderWidth() const;
- qreal rightOuterBorderWidth() const;
- qreal topOuterBorderWidth() const;
- qreal bottomOuterBorderWidth() const;
-
- KoBorder::BorderData getEdge(KoBorder::BorderSide side) const;
- KoBorder::BorderStyle getBorderStyle(KoBorder::BorderSide side) const;
-Q_SIGNALS:
- void nameChanged(const QString &newName);
-
-protected:
- KoTableCellStylePrivate * const d_ptr;
-
-private:
- /**
- * Load the style from the \a KoStyleStack style stack using the
- * OpenDocument format.
- */
- void loadOdfProperties(KoShapeLoadingContext &context, KoStyleStack &styleStack);
- qreal propertyDouble(int key) const;
- QPen propertyPen(int key) const;
- int propertyInt(int key) const;
- bool propertyBoolean(int key) const;
- QColor propertyColor(int key) const;
-
-
- /**
- * Set the format properties from an Edge structure
- *
- * @param side defines which edge this is for.
- * @param style the border style for this side.
- * @param edge the Edge that hold the properties values
- */
- void setEdge(KoBorder::BorderSide side, const KoBorder::BorderData &edge, KoBorder::BorderStyle style);
-
- Q_DECLARE_PRIVATE(KoTableCellStyle)
-
-};
-
-Q_DECLARE_METATYPE(KoTableCellStyle *)
-
-#endif
diff --git a/plugins/flake/textshape/kotext/styles/KoTableCellStyle_p.h b/plugins/flake/textshape/kotext/styles/KoTableCellStyle_p.h
deleted file mode 100644
index eb89bbd93a..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoTableCellStyle_p.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008,2010 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- *
- * 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 KOTABLECELLSTYLE_P_H
-#define KOTABLECELLSTYLE_P_H
-
-#include "Styles_p.h"
-
-class KoTableCellStylePrivate
-{
-public:
- KoTableCellStylePrivate();
- virtual ~KoTableCellStylePrivate();
-
- void setProperty(int key, const QVariant &value);
-
- QString name;
- KoParagraphStyle *paragraphStyle;
- KoTableCellStyle *parentStyle;
- int next;
- StylePrivate stylesPrivate;
-};
-
-#endif // KOTABLECELLSTYLE_P_H
diff --git a/plugins/flake/textshape/kotext/styles/KoTableColumnStyle.cpp b/plugins/flake/textshape/kotext/styles/KoTableColumnStyle.cpp
deleted file mode 100644
index 749f2fbe6a..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoTableColumnStyle.cpp
+++ /dev/null
@@ -1,327 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Roopesh Chander <roop@forwardbias.in>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
- *
- * 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 "KoTableColumnStyle.h"
-
-#include <KoGenStyle.h>
-#include <KoGenStyles.h>
-#include "Styles_p.h"
-#include "KoTextDocument.h"
-
-#include "TextDebug.h"
-
-#include <QTextTable>
-#include <QTextTableFormat>
-
-#include <KoUnit.h>
-#include <KoStyleStack.h>
-#include <KoOdfLoadingContext.h>
-#include <KoXmlNS.h>
-
-class Q_DECL_HIDDEN KoTableColumnStyle::Private : public QSharedData
-{
-public:
- Private() : QSharedData(), parentStyle(0) {}
-
- ~Private() {
- }
-
- void setProperty(int key, const QVariant &value) {
- stylesPrivate.add(key, value);
- }
-
- QString name;
- KoTableColumnStyle *parentStyle;
- StylePrivate stylesPrivate;
-};
-
-
-KoTableColumnStyle::KoTableColumnStyle()
- : d(new Private())
-{
- Q_ASSERT (d);
-}
-
-KoTableColumnStyle::KoTableColumnStyle(const KoTableColumnStyle &rhs)
- : d(rhs.d)
-{
-}
-
-KoTableColumnStyle &KoTableColumnStyle::operator=(const KoTableColumnStyle &rhs)
-{
- d = rhs.d;
- return *this;
-}
-
-KoTableColumnStyle::~KoTableColumnStyle()
-{
-}
-
-void KoTableColumnStyle::copyProperties(const KoTableColumnStyle *style)
-{
- d->stylesPrivate = style->d->stylesPrivate;
- setName(style->name()); // make sure we emit property change
- d->parentStyle = style->d->parentStyle;
-}
-
-KoTableColumnStyle *KoTableColumnStyle::clone() const
-{
- KoTableColumnStyle *newStyle = new KoTableColumnStyle();
- newStyle->copyProperties(this);
- return newStyle;
-}
-
-void KoTableColumnStyle::setParentStyle(KoTableColumnStyle *parent)
-{
- d->parentStyle = parent;
-}
-
-void KoTableColumnStyle::setProperty(int key, const QVariant &value)
-{
- if (d->parentStyle) {
- QVariant var = d->parentStyle->value(key);
- if (!var.isNull() && var == value) { // same as parent, so its actually a reset.
- d->stylesPrivate.remove(key);
- return;
- }
- }
- d->stylesPrivate.add(key, value);
-}
-
-void KoTableColumnStyle::remove(int key)
-{
- d->stylesPrivate.remove(key);
-}
-
-QVariant KoTableColumnStyle::value(int key) const
-{
- QVariant var = d->stylesPrivate.value(key);
- if (var.isNull() && d->parentStyle)
- var = d->parentStyle->value(key);
- return var;
-}
-
-bool KoTableColumnStyle::hasProperty(int key) const
-{
- return d->stylesPrivate.contains(key);
-}
-
-qreal KoTableColumnStyle::propertyDouble(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull())
- return 0.0;
- return variant.toDouble();
-}
-
-int KoTableColumnStyle::propertyInt(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull())
- return 0;
- return variant.toInt();
-}
-
-bool KoTableColumnStyle::propertyBoolean(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull())
- return false;
- return variant.toBool();
-}
-
-QColor KoTableColumnStyle::propertyColor(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull()) {
- QColor color;
- return color;
- }
- return qvariant_cast<QColor>(variant);
-}
-
-void KoTableColumnStyle::setColumnWidth(qreal width)
-{
- setProperty(ColumnWidth, width);
-}
-
-qreal KoTableColumnStyle::columnWidth() const
-{
- return propertyDouble(ColumnWidth);
-}
-
-void KoTableColumnStyle::setRelativeColumnWidth(qreal width)
-{
- setProperty(RelativeColumnWidth, width);
-}
-
-qreal KoTableColumnStyle::relativeColumnWidth() const
-{
- return propertyDouble(RelativeColumnWidth);
-}
-
-void KoTableColumnStyle::setBreakBefore(KoText::KoTextBreakProperty state)
-{
- setProperty(BreakBefore, state);
-}
-
-KoText::KoTextBreakProperty KoTableColumnStyle::breakBefore() const
-{
- return (KoText::KoTextBreakProperty) propertyInt(BreakBefore);
-}
-
-void KoTableColumnStyle::setBreakAfter(KoText::KoTextBreakProperty state)
-{
- setProperty(BreakAfter, state);
-}
-
-KoText::KoTextBreakProperty KoTableColumnStyle::breakAfter() const
-{
- return (KoText::KoTextBreakProperty) propertyInt(BreakAfter);
-}
-
-KoTableColumnStyle *KoTableColumnStyle::parentStyle() const
-{
- return d->parentStyle;
-}
-
-QString KoTableColumnStyle::name() const
-{
- return d->name;
-}
-
-void KoTableColumnStyle::setName(const QString &name)
-{
- if (name == d->name)
- return;
- d->name = name;
-}
-
-int KoTableColumnStyle::styleId() const
-{
- return propertyInt(StyleId);
-}
-
-void KoTableColumnStyle::setStyleId(int id)
-{
- setProperty(StyleId, id);
-}
-
-QString KoTableColumnStyle::masterPageName() const
-{
- return value(MasterPageName).toString();
-}
-
-void KoTableColumnStyle::setMasterPageName(const QString &name)
-{
- setProperty(MasterPageName, name);
-}
-
-bool KoTableColumnStyle::optimalColumnWidth() const
-{
- return propertyBoolean(OptimalColumnWidth);
-}
-
-void KoTableColumnStyle::setOptimalColumnWidth(bool state)
-{
- setProperty(OptimalColumnWidth, state);
-}
-
-void KoTableColumnStyle::loadOdf(const KoXmlElement *element, KoOdfLoadingContext &context)
-{
- if (element->hasAttributeNS(KoXmlNS::style, "display-name"))
- d->name = element->attributeNS(KoXmlNS::style, "display-name", QString());
-
- if (d->name.isEmpty()) // if no style:display-name is given us the style:name
- d->name = element->attributeNS(KoXmlNS::style, "name", QString());
-
- QString masterPage = element->attributeNS(KoXmlNS::style, "master-page-name", QString());
- if (! masterPage.isEmpty()) {
- setMasterPageName(masterPage);
- }
- context.styleStack().save();
- QString family = element->attributeNS(KoXmlNS::style, "family", "table-column");
- context.addStyles(element, family.toLocal8Bit().constData()); // Load all parents - only because we don't support inheritance.
-
- context.styleStack().setTypeProperties("table-column"); // load all style attributes from "style:table-column-properties"
- loadOdfProperties(context.styleStack()); // load the KoTableColumnStyle from the stylestack
- context.styleStack().restore();
-}
-
-
-void KoTableColumnStyle::loadOdfProperties(KoStyleStack &styleStack)
-{
- // Column width.
- if (styleStack.hasProperty(KoXmlNS::style, "column-width")) {
- setColumnWidth(KoUnit::parseValue(styleStack.property(KoXmlNS::style, "column-width")));
- }
- // Relative column width.
- if (styleStack.hasProperty(KoXmlNS::style, "rel-column-width")) {
- setRelativeColumnWidth(styleStack.property(KoXmlNS::style, "rel-column-width").remove('*').toDouble());
- }
- // Optimal column width
- if (styleStack.hasProperty(KoXmlNS::style, "use-optimal-column-width")) {
- setOptimalColumnWidth(styleStack.property(KoXmlNS::style, "use-optimal-column-width") == "true");
- }
-
- // The fo:break-before and fo:break-after attributes insert a page or column break before or after a column.
- if (styleStack.hasProperty(KoXmlNS::fo, "break-before")) {
- setBreakBefore(KoText::textBreakFromString(styleStack.property(KoXmlNS::fo, "break-before")));
- }
- if (styleStack.hasProperty(KoXmlNS::fo, "break-after")) {
- setBreakAfter(KoText::textBreakFromString(styleStack.property(KoXmlNS::fo, "break-after")));
- }
-}
-
-bool KoTableColumnStyle::operator==(const KoTableColumnStyle &other) const
-{
- return other.d == d;
-}
-
-bool KoTableColumnStyle::operator!=(const KoTableColumnStyle &other) const
-{
- return other.d != d;
-}
-
-void KoTableColumnStyle::removeDuplicates(const KoTableColumnStyle &other)
-{
- d->stylesPrivate.removeDuplicates(other.d->stylesPrivate);
-}
-
-void KoTableColumnStyle::saveOdf(KoGenStyle &style) const
-{
- QList<int> keys = d->stylesPrivate.keys();
- Q_FOREACH (int key, keys) {
- if (key == KoTableColumnStyle::BreakBefore) {
- style.addProperty("fo:break-before", KoText::textBreakToString(breakBefore()), KoGenStyle::TableColumnType);
- } else if (key == KoTableColumnStyle::BreakAfter) {
- style.addProperty("fo:break-after", KoText::textBreakToString(breakAfter()), KoGenStyle::TableColumnType);
- } else if (key == KoTableColumnStyle::OptimalColumnWidth) {
- style.addProperty("style:use-optimal-column-width", optimalColumnWidth(), KoGenStyle::TableColumnType);
- } else if (key == KoTableColumnStyle::ColumnWidth) {
- style.addPropertyPt("style:column-width", columnWidth(), KoGenStyle::TableColumnType);
- } else if (key == KoTableColumnStyle::RelativeColumnWidth) {
- style.addProperty("style:rel-column-width", QString("%1*").arg(relativeColumnWidth()), KoGenStyle::TableColumnType);
- }
- }
-}
diff --git a/plugins/flake/textshape/kotext/styles/KoTableColumnStyle.h b/plugins/flake/textshape/kotext/styles/KoTableColumnStyle.h
deleted file mode 100644
index cadc024add..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoTableColumnStyle.h
+++ /dev/null
@@ -1,198 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
- *
- * 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 KOTABLECOLUMNSTYLE_H
-#define KOTABLECOLUMNSTYLE_H
-
-#include "KoText.h"
-#include "kritatext_export.h"
-#include <KoXmlReaderForward.h>
-
-#include <QTextTableFormat>
-
-class KoStyleStack;
-class KoGenStyle;
-class KoOdfLoadingContext;
-
-class QString;
-class QVariant;
-
-/**
- * A container for all properties for the table column style.
- *
- * Named column styles are stored in the KoStyleManager and automatic ones in the
- * KoTableColumnAndRowStyleManager.
- *
- * The style has a property 'StyleId' with an integer as value. The integer value
- * corresponds to the styleId() output of a specific KoTableColumnStyle.
- * *
- * @see KoStyleManager, KoTableRowAndColumnStyleManager
- */
-class KRITATEXT_EXPORT KoTableColumnStyle
-{
-public:
- enum Property {
- StyleId = QTextTableFormat::UserProperty + 1,
- ColumnWidth, ///< Column width.
- RelativeColumnWidth, ///< Relative column width.
- OptimalColumnWidth, ///< Use optimal column width
- BreakBefore, ///< If true, insert a frame break before this table
- BreakAfter, ///< If true, insert a frame break after this table
- MasterPageName ///< Optional name of the master-page
- };
-
- /// Constructor
- KoTableColumnStyle();
- /// Constructor
- KoTableColumnStyle(const KoTableColumnStyle &rhs);
- /// assign operator
- KoTableColumnStyle &operator=(const KoTableColumnStyle &rhs);
-
- /// Destructor
- ~KoTableColumnStyle();
-
- void copyProperties(const KoTableColumnStyle *style);
-
- KoTableColumnStyle *clone() const;
-
- /// Set the column width.
- void setColumnWidth(qreal width);
-
- /// Get the column width.
- qreal columnWidth() const;
-
- /// Set the column width.
- void setRelativeColumnWidth(qreal width);
-
- /// Get the column width.
- qreal relativeColumnWidth() const;
-
- /// Get the optimalColumnWidth state
- bool optimalColumnWidth() const;
-
- /// Set the optimalColumnWidth state
- void setOptimalColumnWidth(bool state);
-
- /// Set break before. See §7.19.2 of [XSL].
- void setBreakBefore(KoText::KoTextBreakProperty state);
-
- /// Get break before. See §7.19.2 of [XSL].
- KoText::KoTextBreakProperty breakBefore() const;
-
- /// Set break after. See §7.19.1 of [XSL].
- void setBreakAfter(KoText::KoTextBreakProperty state);
-
- /// Get break after. See §7.19.1 of [XSL].
- KoText::KoTextBreakProperty breakAfter() const;
-
- /// Set the parent style this one inherits its unset properties from.
- void setParentStyle(KoTableColumnStyle *parent);
-
- /// Return the parent style.
- KoTableColumnStyle *parentStyle() const;
-
- /// Return the name of the style.
- QString name() const;
-
- /// Set a user-visible name on the style.
- void setName(const QString &name);
-
- /// Each style has a unique ID (non persistent) given out by the style manager.
- int styleId() const;
-
- /// Each style has a unique ID (non persistent) given out by the styleManager.
- void setStyleId(int id);
-
- /**
- * Return the optional name of the master-page or a QString() if this paragraph
- * isn't attached to a master-page.
- */
- QString masterPageName() const;
-
- /// Set the name of the master-page.
- void setMasterPageName(const QString &name);
-
- /// Remove the property \key from this style.
- void remove(int key);
-
- /// Remove properties in this style that are already in other.
- void removeDuplicates(const KoTableColumnStyle &other);
-
- /// Compare the properties of this style with the other.
- bool operator==(const KoTableColumnStyle &other) const;
-
- /// Compare the properties of this style with the other.
- bool operator!=(const KoTableColumnStyle &other) const;
-
- /**
- * Load the style form the element
- *
- * @param context the odf loading context
- * @param element the element containing the
- */
- void loadOdf(const KoXmlElement *element, KoOdfLoadingContext &context);
-
- void saveOdf(KoGenStyle &style) const;
-
- /**
- * Returns true if this table column style has the property set.
- * Note that this method does not delegate to the parent style.
- * @param key the key as found in the Property enum
- */
- bool hasProperty(int key) const;
-
- /**
- * Set a property with key to a certain value, overriding the value from the parent style.
- * If the value set is equal to the value of the parent style, the key will be removed instead.
- *
- * @param key the Property to set.
- * @param value the new value to set on this style.
- * @see hasProperty(), value()
- */
- void setProperty(int key, const QVariant &value);
-
- /**
- * Return the value of key as represented on this style, taking into account parent styles.
- * You should consider using the direct accessors for individual properties instead.
- * @param key the Property to request.
- * @returns a QVariant which holds the property value.
- */
- QVariant value(int key) const;
-
-private:
- /**
- * Load the style from the \a KoStyleStack style stack using the
- * OpenDocument format.
- */
- void loadOdfProperties(KoStyleStack &styleStack);
- qreal propertyDouble(int key) const;
- int propertyInt(int key) const;
- bool propertyBoolean(int key) const;
- QColor propertyColor(int key) const;
-
- class Private;
- QSharedDataPointer<Private> d;
-};
-
-Q_DECLARE_METATYPE(KoTableColumnStyle *)
-
-#endif
diff --git a/plugins/flake/textshape/kotext/styles/KoTableRowStyle.cpp b/plugins/flake/textshape/kotext/styles/KoTableRowStyle.cpp
deleted file mode 100644
index b327d72924..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoTableRowStyle.cpp
+++ /dev/null
@@ -1,388 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Roopesh Chander <roop@forwardbias.in>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
- *
- * 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 "KoTableRowStyle.h"
-
-#include <KoGenStyle.h>
-#include "Styles_p.h"
-
-#include <KoUnit.h>
-#include <KoStyleStack.h>
-#include <KoOdfLoadingContext.h>
-#include <KoXmlNS.h>
-#include <KoXmlReader.h>
-
-#include "TextDebug.h"
-
-
-class Q_DECL_HIDDEN KoTableRowStyle::Private : public QSharedData
-{
-public:
- Private() : QSharedData(), parentStyle(0), next(0) {}
-
- ~Private() {
- }
-
- void setProperty(int key, const QVariant &value) {
- stylesPrivate.add(key, value);
- }
-
- QString name;
- KoTableRowStyle *parentStyle;
- int next;
- StylePrivate stylesPrivate;
-};
-
-KoTableRowStyle::KoTableRowStyle()
- : d(new Private())
-{
-}
-
-KoTableRowStyle::KoTableRowStyle(const KoTableRowStyle &rhs)
- : d(rhs.d)
-{
-}
-
-KoTableRowStyle &KoTableRowStyle::operator=(const KoTableRowStyle &rhs)
-{
- d = rhs.d;
- return *this;
-}
-
-KoTableRowStyle::~KoTableRowStyle()
-{
-}
-
-void KoTableRowStyle::copyProperties(const KoTableRowStyle *style)
-{
- d->stylesPrivate = style->d->stylesPrivate;
- setName(style->name()); // make sure we emit property change
- d->parentStyle = style->d->parentStyle;
-}
-
-KoTableRowStyle *KoTableRowStyle::clone() const
-{
- KoTableRowStyle *newStyle = new KoTableRowStyle();
- newStyle->copyProperties(this);
- return newStyle;
-}
-
-void KoTableRowStyle::setParentStyle(KoTableRowStyle *parent)
-{
- d->parentStyle = parent;
-}
-
-void KoTableRowStyle::setProperty(int key, const QVariant &value)
-{
- if (d->parentStyle) {
- QVariant var = d->parentStyle->value(key);
- if (!var.isNull() && var == value) { // same as parent, so its actually a reset.
- d->stylesPrivate.remove(key);
- return;
- }
- }
- d->stylesPrivate.add(key, value);
-}
-
-void KoTableRowStyle::remove(int key)
-{
- d->stylesPrivate.remove(key);
-}
-
-QVariant KoTableRowStyle::value(int key) const
-{
- QVariant var = d->stylesPrivate.value(key);
- if (var.isNull() && d->parentStyle)
- return d->parentStyle->value(key);
- return var;
-}
-
-bool KoTableRowStyle::hasProperty(int key) const
-{
- return d->stylesPrivate.contains(key);
-}
-
-qreal KoTableRowStyle::propertyDouble(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull())
- return 0.0;
- return variant.toDouble();
-}
-
-int KoTableRowStyle::propertyInt(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull())
- return 0;
- return variant.toInt();
-}
-
-bool KoTableRowStyle::propertyBoolean(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull())
- return false;
- return variant.toBool();
-}
-
-QColor KoTableRowStyle::propertyColor(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull()) {
- return QColor();
- }
- return qvariant_cast<QColor>(variant);
-}
-
-void KoTableRowStyle::setBackground(const QBrush &brush)
-{
- d->setProperty(QTextFormat::BackgroundBrush, brush);
-}
-
-void KoTableRowStyle::clearBackground()
-{
- d->stylesPrivate.remove(QTextFormat::BackgroundBrush);
-}
-
-QBrush KoTableRowStyle::background() const
-{
- QVariant variant = d->stylesPrivate.value(QTextFormat::BackgroundBrush);
-
- if (variant.isNull()) {
- return QBrush();
- }
- return qvariant_cast<QBrush>(variant);
-}
-
-void KoTableRowStyle::setBreakBefore(KoText::KoTextBreakProperty state)
-{
- setProperty(BreakBefore, state);
-}
-
-KoText::KoTextBreakProperty KoTableRowStyle::breakBefore() const
-{
- return (KoText::KoTextBreakProperty) propertyInt(BreakBefore);
-}
-
-void KoTableRowStyle::setBreakAfter(KoText::KoTextBreakProperty state)
-{
- setProperty(BreakAfter, state);
-}
-
-KoText::KoTextBreakProperty KoTableRowStyle::breakAfter() const
-{
- return (KoText::KoTextBreakProperty) propertyInt(BreakAfter);
-}
-
-void KoTableRowStyle::setUseOptimalHeight(bool on)
-{
- setProperty(UseOptimalHeight, on);
-}
-
-bool KoTableRowStyle::useOptimalHeight() const
-{
- return propertyBoolean(UseOptimalHeight);
-}
-
-void KoTableRowStyle::setMinimumRowHeight(const qreal height)
-{
- setProperty(MinimumRowHeight, height);
-}
-
-
-qreal KoTableRowStyle::minimumRowHeight() const
-{
- return propertyDouble(MinimumRowHeight);
-}
-
-void KoTableRowStyle::setRowHeight(qreal height)
-{
- if(height <= 0)
- d->stylesPrivate.remove(RowHeight);
- else
- setProperty(RowHeight, height);
-}
-
-qreal KoTableRowStyle::rowHeight() const
-{
- return propertyDouble(RowHeight);
-}
-
-void KoTableRowStyle::setKeepTogether(bool on)
-{
- setProperty(KeepTogether, on);
-}
-
-bool KoTableRowStyle::keepTogether() const
-{
- return propertyBoolean(KeepTogether);
-}
-
-KoTableRowStyle *KoTableRowStyle::parentStyle() const
-{
- return d->parentStyle;
-}
-
-QString KoTableRowStyle::name() const
-{
- return d->name;
-}
-
-void KoTableRowStyle::setName(const QString &name)
-{
- if (name == d->name)
- return;
- d->name = name;
-}
-
-int KoTableRowStyle::styleId() const
-{
- return propertyInt(StyleId);
-}
-
-void KoTableRowStyle::setStyleId(int id)
-{
- setProperty(StyleId, id); if (d->next == 0) d->next = id;
-}
-
-QString KoTableRowStyle::masterPageName() const
-{
- return value(MasterPageName).toString();
-}
-
-void KoTableRowStyle::setMasterPageName(const QString &name)
-{
- setProperty(MasterPageName, name);
-}
-
-void KoTableRowStyle::loadOdf(const KoXmlElement *element, KoOdfLoadingContext &context)
-{
- if (element->hasAttributeNS(KoXmlNS::style, "display-name"))
- d->name = element->attributeNS(KoXmlNS::style, "display-name", QString());
-
- if (d->name.isEmpty()) // if no style:display-name is given us the style:name
- d->name = element->attributeNS(KoXmlNS::style, "name", QString());
-
- QString masterPage = element->attributeNS(KoXmlNS::style, "master-page-name", QString());
- if (! masterPage.isEmpty()) {
- setMasterPageName(masterPage);
- }
- context.styleStack().save();
- QString family = element->attributeNS(KoXmlNS::style, "family", "table-row");
- context.addStyles(element, family.toLocal8Bit().constData()); // Load all parents - only because we don't support inheritance.
-
- context.styleStack().setTypeProperties("table-row"); // load all style attributes from "style:table-column-properties"
- loadOdfProperties(context.styleStack()); // load the KoTableRowStyle from the stylestack
- context.styleStack().restore();
-}
-
-
-void KoTableRowStyle::loadOdfProperties(KoStyleStack &styleStack)
-{
- // The fo:background-color attribute specifies the background color of a cell.
- if (styleStack.hasProperty(KoXmlNS::fo, "background-color")) {
- const QString bgcolor = styleStack.property(KoXmlNS::fo, "background-color");
- QBrush brush = background();
- if (bgcolor == "transparent")
- setBackground(Qt::NoBrush);
- else {
- if (brush.style() == Qt::NoBrush)
- brush.setStyle(Qt::SolidPattern);
- brush.setColor(bgcolor); // #rrggbb format
- setBackground(brush);
- }
- }
-
- // minimum row height
- if (styleStack.hasProperty(KoXmlNS::style, "min-row-height")) {
- setMinimumRowHeight(KoUnit::parseValue(styleStack.property(KoXmlNS::style, "min-row-height")));
- }
-
- // optimal row height
- if (styleStack.hasProperty(KoXmlNS::style, "use-optimal-row-height")) {
- setUseOptimalHeight(styleStack.property(KoXmlNS::style, "use-optimal-row-height") == "true");
- }
-
- // row height
- if (styleStack.hasProperty(KoXmlNS::style, "row-height")) {
- setRowHeight(KoUnit::parseValue(styleStack.property(KoXmlNS::style, "row-height")));
- }
-
- // The fo:keep-together specifies if a row is allowed to break in the middle of the row.
- if (styleStack.hasProperty(KoXmlNS::fo, "keep-together")) {
- setKeepTogether(styleStack.property(KoXmlNS::fo, "keep-together") != "auto");
- }
-
- // The fo:break-before and fo:break-after attributes insert a page or column break before or after a column.
- if (styleStack.hasProperty(KoXmlNS::fo, "break-before")) {
- setBreakBefore(KoText::textBreakFromString(styleStack.property(KoXmlNS::fo, "break-before")));
- }
- if (styleStack.hasProperty(KoXmlNS::fo, "break-after")) {
- setBreakAfter(KoText::textBreakFromString(styleStack.property(KoXmlNS::fo, "break-after")));
- }
-}
-
-bool KoTableRowStyle::operator==(const KoTableRowStyle &other) const
-{
- return other.d == d;
-}
-
-void KoTableRowStyle::removeDuplicates(const KoTableRowStyle &other)
-{
- d->stylesPrivate.removeDuplicates(other.d->stylesPrivate);
-}
-
-bool KoTableRowStyle::isEmpty() const
-{
- return d->stylesPrivate.isEmpty();
-}
-
-void KoTableRowStyle::saveOdf(KoGenStyle &style) const
-{
- QList<int> keys = d->stylesPrivate.keys();
- Q_FOREACH (int key, keys) {
- if (key == QTextFormat::BackgroundBrush) {
- QBrush backBrush = background();
- if (backBrush.style() != Qt::NoBrush)
- style.addProperty("fo:background-color", backBrush.color().name(), KoGenStyle::TableRowType);
- else
- style.addProperty("fo:background-color", "transparent", KoGenStyle::TableRowType);
- } else if (key == MinimumRowHeight) {
- style.addPropertyPt("style:min-row-height", minimumRowHeight(), KoGenStyle::TableRowType);
- } else if (key == RowHeight) {
- style.addPropertyPt("style:row-height", rowHeight(), KoGenStyle::TableRowType);
- } else if (key == UseOptimalHeight) {
- style.addProperty("style:use-optimal-row-height", useOptimalHeight(), KoGenStyle::TableRowType);
- } else if (key == BreakBefore) {
- style.addProperty("fo:break-before", KoText::textBreakToString(breakBefore()), KoGenStyle::TableRowType);
- } else if (key == BreakAfter) {
- style.addProperty("fo:break-after", KoText::textBreakToString(breakAfter()), KoGenStyle::TableRowType);
- } else if (key == KeepTogether) {
- if (keepTogether())
- style.addProperty("fo:keep-together", "always", KoGenStyle::TableRowType);
- else
- style.addProperty("fo:keep-together", "auto", KoGenStyle::TableRowType);
- }
- }
-}
diff --git a/plugins/flake/textshape/kotext/styles/KoTableRowStyle.h b/plugins/flake/textshape/kotext/styles/KoTableRowStyle.h
deleted file mode 100644
index 768f069ade..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoTableRowStyle.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
- *
- * 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 KOTABLEROWSTYLE_H
-#define KOTABLEROWSTYLE_H
-
-#include "KoText.h"
-#include "kritatext_export.h"
-
-#include <KoXmlReaderForward.h>
-
-#include <QTextTableFormat>
-
-class KoStyleStack;
-class KoGenStyle;
-class KoOdfLoadingContext;
-class QString;
-class QVariant;
-
-/**
- * A container for all properties for the table row style.
- * Each table column in the main text is based on a table row style.
- * Row styles are stored (besides in the KoStyleManager) in the KoTableColumnAndRowStyleManager.
- * The style has a property 'StyleId' with an integer as value. The integer value corresponds to the styleId() output of
- * a specific KoTableRowStyle.
- * @see KoStyleManager
- * @see KoTableRowAndColumnStyleManager
- */
-class KRITATEXT_EXPORT KoTableRowStyle
-{
-public:
- enum Property {
- StyleId = QTextTableFormat::UserProperty + 1,
- // Linespacing properties
- KeepTogether, ///< If true, the row is not allowed to break
- MinimumRowHeight, ///< a qreal specifying the minimum row height in pt
- RowHeight, ///< a qreal specifying the exact row height in pt
- BreakBefore, ///< If true, insert a frame break before this table row
- BreakAfter, ///< If true, insert a frame break after this table row
- MasterPageName, ///< Optional name of the master-page
- UseOptimalHeight ///< If true, the row height should fit the content
- };
-
- /// Constructor
- KoTableRowStyle();
- /// Constructor
- KoTableRowStyle(const KoTableRowStyle &rhs);
- /// assign operator
- KoTableRowStyle &operator=(const KoTableRowStyle &rhs);
-
- /// Destructor
- ~KoTableRowStyle();
-
- void copyProperties(const KoTableRowStyle *style);
-
- KoTableRowStyle *clone() const;
-
- void setBackground(const QBrush &brush);
- /// See similar named method on QTextBlockFormat
- QBrush background() const;
- /// See similar named method on QTextBlockFormat
- void clearBackground();
-
- void setBreakBefore(KoText::KoTextBreakProperty state);
- KoText::KoTextBreakProperty breakBefore() const;
- void setBreakAfter(KoText::KoTextBreakProperty state);
- KoText::KoTextBreakProperty breakAfter() const;
-
- void setUseOptimalHeight(bool on);
- bool useOptimalHeight() const;
-
- /// Set minimum height of row
- void setMinimumRowHeight(const qreal height);
- qreal minimumRowHeight() const;
-
- /// Set exact and fixed height of row in a table, even if the row could be smaller because of less content
- void setRowHeight(qreal height);
- /// Get the exact and fixed height of row in a table
- qreal rowHeight() const;
-
- void setKeepTogether(bool on);
- bool keepTogether() const;
-
- /// set the parent style this one inherits its unset properties from.
- void setParentStyle(KoTableRowStyle *parent);
-
- /// return the parent style
- KoTableRowStyle *parentStyle() const;
-
- /// return the name of the style.
- QString name() const;
-
- /// set a user-visible name on the style.
- void setName(const QString &name);
-
- /// each style has a unique ID (non persistent) given out by the styleManager
- int styleId() const;
-
- /// each style has a unique ID (non persistent) given out by the styleManager
- void setStyleId(int id);
-
- /// return the optional name of the master-page or a QString() if this paragraph isn't attached to a master-page.
- QString masterPageName() const;
- /// Set the name of the master-page.
- void setMasterPageName(const QString &name);
-
- void remove(int key);
-
- /// Compare the properties of this style with the other
- bool operator==(const KoTableRowStyle &other) const;
-
- void removeDuplicates(const KoTableRowStyle &other);
-
- /**
- * Load the style from the element
- *
- * @param context the odf loading context
- * @param element the element containing the
- */
- void loadOdf(const KoXmlElement *element, KoOdfLoadingContext &context);
-
- void saveOdf(KoGenStyle &style) const;
-
- /**
- * Returns true if this table column style has the property set.
- * Note that this method does not delegate to the parent style.
- * @param key the key as found in the Property enum
- */
- bool hasProperty(int key) const;
-
- /**
- * Set a property with key to a certain value, overriding the value from the parent style.
- * If the value set is equal to the value of the parent style, the key will be removed instead.
- * @param key the Property to set.
- * @param value the new value to set on this style.
- * @see hasProperty(), value()
- */
- void setProperty(int key, const QVariant &value);
- /**
- * Return the value of key as represented on this style, taking into account parent styles.
- * You should consider using the direct accessors for individual properties instead.
- * @param key the Property to request.
- * @returns a QVariant which holds the property value.
- */
- QVariant value(int key) const;
-
- /**
- * Returns true if this table row style is empty.
- */
- bool isEmpty() const;
-private:
- /**
- * Load the style from the \a KoStyleStack style stack using the
- * OpenDocument format.
- */
- void loadOdfProperties(KoStyleStack &styleStack);
- qreal propertyDouble(int key) const;
- int propertyInt(int key) const;
- bool propertyBoolean(int key) const;
- QColor propertyColor(int key) const;
-
- class Private;
- QSharedDataPointer<Private> d;
-};
-
-Q_DECLARE_METATYPE(KoTableRowStyle *)
-
-#endif
diff --git a/plugins/flake/textshape/kotext/styles/KoTableStyle.cpp b/plugins/flake/textshape/kotext/styles/KoTableStyle.cpp
deleted file mode 100644
index fb94ef9967..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoTableStyle.cpp
+++ /dev/null
@@ -1,663 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Roopesh Chander <roop@forwardbias.in>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
- *
- * 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 "KoTableStyle.h"
-
-#include <KoGenStyle.h>
-#include "Styles_p.h"
-
-#include <QTextTable>
-#include <QTextTableFormat>
-
-#include <KoShadowStyle.h>
-#include <KoUnit.h>
-#include <KoStyleStack.h>
-#include <KoOdfLoadingContext.h>
-#include <KoXmlNS.h>
-#include <KoXmlReader.h>
-
-#include "TextDebug.h"
-
-class Q_DECL_HIDDEN KoTableStyle::Private
-{
-public:
- Private() : parentStyle(0), next(0) {}
-
- ~Private() {
- }
-
- void setProperty(int key, const QVariant &value) {
- stylesPrivate.add(key, value);
- }
-
- QString name;
- KoTableStyle *parentStyle;
- int next;
- StylePrivate stylesPrivate;
-};
-
-KoTableStyle::KoTableStyle(QObject *parent)
- : QObject(parent), d(new Private())
-{
-}
-
-KoTableStyle::KoTableStyle(const QTextTableFormat &tableFormat, QObject *parent)
- : QObject(parent),
- d(new Private())
-{
- d->stylesPrivate = tableFormat.properties();
-}
-
-KoTableStyle *KoTableStyle::fromTable(const QTextTable &table, QObject *parent)
-{
- QTextTableFormat tableFormat = table.format();
- return new KoTableStyle(tableFormat, parent);
-}
-
-KoTableStyle::~KoTableStyle()
-{
- delete d;
-}
-
-void KoTableStyle::setParentStyle(KoTableStyle *parent)
-{
- d->parentStyle = parent;
-}
-
-void KoTableStyle::setProperty(int key, const QVariant &value)
-{
- if (d->parentStyle) {
- QVariant var = d->parentStyle->value(key);
- if (!var.isNull() && var == value) { // same as parent, so its actually a reset.
- d->stylesPrivate.remove(key);
- return;
- }
- }
- d->stylesPrivate.add(key, value);
-}
-
-void KoTableStyle::remove(int key)
-{
- d->stylesPrivate.remove(key);
-}
-
-QVariant KoTableStyle::value(int key) const
-{
- QVariant var = d->stylesPrivate.value(key);
- if (var.isNull() && d->parentStyle)
- return d->parentStyle->value(key);
- return var;
-}
-
-bool KoTableStyle::hasProperty(int key) const
-{
- return d->stylesPrivate.contains(key);
-}
-
-qreal KoTableStyle::propertyDouble(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull())
- return 0.0;
- return variant.toDouble();
-}
-
-QTextLength KoTableStyle::propertyLength(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull())
- return QTextLength(QTextLength::FixedLength, 0.0);
- if (!variant.canConvert<QTextLength>())
- {
- // Fake support, for compatibility sake
- if (variant.canConvert<qreal>())
- {
- return QTextLength(QTextLength::FixedLength, variant.toReal());
- }
-
- warnText << "This should never happen : requested property can't be converted to QTextLength";
- return QTextLength(QTextLength::FixedLength, 0.0);
- }
- return variant.value<QTextLength>();
-}
-
-int KoTableStyle::propertyInt(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull())
- return 0;
- return variant.toInt();
-}
-
-bool KoTableStyle::propertyBoolean(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull())
- return false;
- return variant.toBool();
-}
-
-QColor KoTableStyle::propertyColor(int key) const
-{
- QVariant variant = value(key);
- if (variant.isNull()) {
- return QColor();
- }
- return qvariant_cast<QColor>(variant);
-}
-
-void KoTableStyle::applyStyle(QTextTableFormat &format) const
-{/*
- if (d->parentStyle) {
- d->parentStyle->applyStyle(format);
- }*/
- QList<int> keys = d->stylesPrivate.keys();
- for (int i = 0; i < keys.count(); i++) {
- QVariant variant = d->stylesPrivate.value(keys[i]);
- int key = keys[i];
- switch(key) {
- // Qt expects qreal's for the Frame*Margin's unlike the Block*Margin's
- case QTextFormat::FrameTopMargin:
- case QTextFormat::FrameBottomMargin:
- case QTextFormat::FrameLeftMargin:
- case QTextFormat::FrameRightMargin:
- variant = propertyLength(key).rawValue();
- break;
- default:
- break;
- }
- format.setProperty(key, variant);
- }
-}
-
-void KoTableStyle::setWidth(const QTextLength &width)
-{
- d->setProperty(QTextFormat::FrameWidth, width);
-}
-
-void KoTableStyle::setKeepWithNext(bool keep)
-{
- d->setProperty(KeepWithNext, keep);
-}
-
-bool KoTableStyle::keepWithNext() const
-{
- return propertyBoolean(KeepWithNext);
-}
-
-void KoTableStyle::setShadow(const KoShadowStyle &shadow)
-{
- d->setProperty(Shadow, QVariant::fromValue<KoShadowStyle>(shadow));
-}
-
-KoShadowStyle KoTableStyle::shadow() const
-{
- if (hasProperty(Shadow))
- return value(Shadow).value<KoShadowStyle>();
- return KoShadowStyle();
-}
-
-void KoTableStyle::setMayBreakBetweenRows(bool allow)
-{
- d->setProperty(MayBreakBetweenRows, allow);
-}
-
-void KoTableStyle::setBackground(const QBrush &brush)
-{
- d->setProperty(QTextFormat::BackgroundBrush, brush);
-}
-
-void KoTableStyle::clearBackground()
-{
- d->stylesPrivate.remove(QTextCharFormat::BackgroundBrush);
-}
-
-QBrush KoTableStyle::background() const
-{
- QVariant variant = d->stylesPrivate.value(QTextFormat::BackgroundBrush);
-
- if (variant.isNull()) {
- return QBrush();
- }
- return qvariant_cast<QBrush>(variant);
-}
-
-void KoTableStyle::setBreakBefore(KoText::KoTextBreakProperty state)
-{
- setProperty(BreakBefore, state);
-}
-
-KoText::KoTextBreakProperty KoTableStyle::breakBefore() const
-{
- return (KoText::KoTextBreakProperty) propertyInt(BreakBefore);
-}
-
-void KoTableStyle::setBreakAfter(KoText::KoTextBreakProperty state)
-{
- setProperty(BreakAfter, state);
-}
-
-KoText::KoTextBreakProperty KoTableStyle::breakAfter() const
-{
- return (KoText::KoTextBreakProperty) propertyInt(BreakAfter);
-}
-
-void KoTableStyle::setCollapsingBorderModel(bool on)
-{
- setProperty(CollapsingBorders, on);
-}
-
-bool KoTableStyle::collapsingBorderModel() const
-{
- return propertyBoolean(CollapsingBorders);
-}
-
-void KoTableStyle::setTopMargin(QTextLength topMargin)
-{
- setProperty(QTextFormat::FrameTopMargin, topMargin);
-}
-
-qreal KoTableStyle::topMargin() const
-{
- if (parentStyle())
- return propertyLength(QTextFormat::FrameTopMargin).value(parentStyle()->topMargin());
- else
- return propertyLength(QTextFormat::FrameTopMargin).value(0);
-}
-
-void KoTableStyle::setBottomMargin(QTextLength margin)
-{
- setProperty(QTextFormat::FrameBottomMargin, margin);
-}
-
-qreal KoTableStyle::bottomMargin() const
-{
- if (parentStyle())
- return propertyLength(QTextFormat::FrameBottomMargin).value(parentStyle()->bottomMargin());
- else
- return propertyLength(QTextFormat::FrameBottomMargin).value(0);
-}
-
-void KoTableStyle::setLeftMargin(QTextLength margin)
-{
- setProperty(QTextFormat::FrameLeftMargin, margin);
-}
-
-qreal KoTableStyle::leftMargin() const
-{
- if (parentStyle())
- return propertyLength(QTextFormat::FrameLeftMargin).value(parentStyle()->leftMargin());
- else
- return propertyLength(QTextFormat::FrameLeftMargin).value(0);
-}
-
-void KoTableStyle::setRightMargin(QTextLength margin)
-{
- setProperty(QTextFormat::FrameRightMargin, margin);
-}
-
-qreal KoTableStyle::rightMargin() const
-{
- if (parentStyle())
- return propertyLength(QTextFormat::FrameRightMargin).value(parentStyle()->rightMargin());
- else
- return propertyLength(QTextFormat::FrameRightMargin).value(0);
-}
-
-void KoTableStyle::setMargin(QTextLength margin)
-{
- setTopMargin(margin);
- setBottomMargin(margin);
- setLeftMargin(margin);
- setRightMargin(margin);
-}
-
-void KoTableStyle::setAlignment(Qt::Alignment alignment)
-{
- setProperty(QTextFormat::BlockAlignment, (int) alignment);
-}
-
-Qt::Alignment KoTableStyle::alignment() const
-{
- return static_cast<Qt::Alignment>(propertyInt(QTextFormat::BlockAlignment));
-}
-
-KoTableStyle *KoTableStyle::parentStyle() const
-{
- return d->parentStyle;
-}
-
-QString KoTableStyle::name() const
-{
- return d->name;
-}
-
-void KoTableStyle::setName(const QString &name)
-{
- if (name == d->name)
- return;
- d->name = name;
- emit nameChanged(name);
-}
-
-int KoTableStyle::styleId() const
-{
- return propertyInt(StyleId);
-}
-
-void KoTableStyle::setStyleId(int id)
-{
- setProperty(StyleId, id); if (d->next == 0) d->next = id;
-}
-
-QString KoTableStyle::masterPageName() const
-{
- return value(MasterPageName).toString();
-}
-
-void KoTableStyle::setMasterPageName(const QString &name)
-{
- setProperty(MasterPageName, name);
-}
-
-Qt::Alignment KoTableStyle::alignmentFromString(const QString &align)
-{
- Qt::Alignment alignment = Qt::AlignLeft;
- if (align == "left")
- alignment = Qt::AlignLeft;
- else if (align == "right")
- alignment = Qt::AlignRight;
- else if (align == "center")
- alignment = Qt::AlignHCenter;
- else if (align == "margins") // in tables this is effectively the same as justify
- alignment = Qt::AlignJustify;
- return alignment;
-}
-
-QString KoTableStyle::alignmentToString(Qt::Alignment alignment)
-{
- QString align;
- if (alignment == Qt::AlignLeft)
- align = "left";
- else if (alignment == Qt::AlignRight)
- align = "right";
- else if (alignment == Qt::AlignHCenter)
- align = "center";
- else if (alignment == Qt::AlignJustify)
- align = "margins";
- return align;
-}
-
-bool KoTableStyle::mayBreakBetweenRows() const
-{
- return propertyBoolean(MayBreakBetweenRows);
-}
-
-void KoTableStyle::setPageNumber(int page)
-{
- if (page >= 0)
- setProperty(PageNumber, page);
-}
-
-int KoTableStyle::pageNumber() const
-{
- return propertyInt(PageNumber);
-}
-
-bool KoTableStyle::visible() const
-{
- if (hasProperty(Visible))
- return propertyBoolean(Visible);
- return true;
-}
-
-void KoTableStyle::setVisible(bool on)
-{
- setProperty(Visible, on);
-}
-
-KoText::Direction KoTableStyle::textDirection() const
-{
- return (KoText::Direction) propertyInt(TextProgressionDirection);
-}
-
-void KoTableStyle::setTextDirection(KoText::Direction direction)
-{
- setProperty(TextProgressionDirection, direction);
-}
-
-void KoTableStyle::loadOdf(const KoXmlElement *element, KoOdfLoadingContext &context)
-{
- if (element->hasAttributeNS(KoXmlNS::style, "display-name"))
- d->name = element->attributeNS(KoXmlNS::style, "display-name", QString());
-
- if (d->name.isEmpty()) // if no style:display-name is given us the style:name
- d->name = element->attributeNS(KoXmlNS::style, "name", QString());
-
- QString masterPage = element->attributeNS(KoXmlNS::style, "master-page-name", QString());
- if (! masterPage.isEmpty()) {
- setMasterPageName(masterPage);
- }
- context.styleStack().save();
- QString family = element->attributeNS(KoXmlNS::style, "family", "table");
- context.addStyles(element, family.toLocal8Bit().constData()); // Load all parents - only because we don't support inheritance.
-
- context.styleStack().setTypeProperties("table"); // load all style attributes from "style:table-properties"
- loadOdfProperties(context.styleStack()); // load the KoTableStyle from the stylestack
- context.styleStack().restore();
-}
-
-void KoTableStyle::loadOdfProperties(KoStyleStack &styleStack)
-{
- if (styleStack.hasProperty(KoXmlNS::style, "writing-mode")) { // http://www.w3.org/TR/2004/WD-xsl11-20041216/#writing-mode
- setTextDirection(KoText::directionFromString(styleStack.property(KoXmlNS::style, "writing-mode")));
- }
-
- if (styleStack.hasProperty(KoXmlNS::table, "display")) {
- setVisible(styleStack.property(KoXmlNS::table, "display") == "true");
- }
-
- // Width
- if (styleStack.hasProperty(KoXmlNS::style, "width")) {
- setWidth(QTextLength(QTextLength::FixedLength, KoUnit::parseValue(styleStack.property(KoXmlNS::style, "width"))));
- }
- if (styleStack.hasProperty(KoXmlNS::style, "rel-width")) {
- setWidth(QTextLength(QTextLength::PercentageLength, styleStack.property(KoXmlNS::style, "rel-width").remove('%').remove('*').toDouble()));
- }
-
- // Alignment
- if (styleStack.hasProperty(KoXmlNS::table, "align")) {
- setAlignment(alignmentFromString(styleStack.property(KoXmlNS::table, "align")));
- }
-
- // Margin
- bool hasMarginLeft = styleStack.hasProperty(KoXmlNS::fo, "margin-left");
- bool hasMarginRight = styleStack.hasProperty(KoXmlNS::fo, "margin-right");
- if (hasMarginLeft)
- setLeftMargin(KoText::parseLength(styleStack.property(KoXmlNS::fo, "margin-left")));
- if (hasMarginRight)
- setRightMargin(KoText::parseLength(styleStack.property(KoXmlNS::fo, "margin-right")));
- if (styleStack.hasProperty(KoXmlNS::fo, "margin-top"))
- setTopMargin(KoText::parseLength(styleStack.property(KoXmlNS::fo, "margin-top")));
- if (styleStack.hasProperty(KoXmlNS::fo, "margin-bottom"))
- setBottomMargin(KoText::parseLength(styleStack.property(KoXmlNS::fo, "margin-bottom")));
- if (styleStack.hasProperty(KoXmlNS::fo, "margin")) {
- setMargin(KoText::parseLength(styleStack.property(KoXmlNS::fo, "margin")));
- }
-
- // keep table with next paragraph?
- if (styleStack.hasProperty(KoXmlNS::fo, "keep-with-next")) {
- // OASIS spec says it's "auto"/"always", not a boolean.
- QString val = styleStack.property(KoXmlNS::fo, "keep-with-next");
- setKeepWithNext(val == "true" || val == "always");
- }
-
- // The fo:break-before and fo:break-after attributes insert a page or column break before or after a table.
- if (styleStack.hasProperty(KoXmlNS::fo, "break-before")) {
- setBreakBefore(KoText::textBreakFromString(styleStack.property(KoXmlNS::fo, "break-before")));
- }
- if (styleStack.hasProperty(KoXmlNS::fo, "break-after")) {
- setBreakAfter(KoText::textBreakFromString(styleStack.property(KoXmlNS::fo, "break-after")));
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "may-break-between-rows")) {
- setMayBreakBetweenRows(styleStack.property(KoXmlNS::style, "may-break-between-rows") == "true");
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "page-number")) {
- setPageNumber(styleStack.property(KoXmlNS::style, "page-number").toInt());
- }
-
- if (styleStack.hasProperty(KoXmlNS::style, "shadow")) {
- KoShadowStyle shadow;
- if (shadow.loadOdf(styleStack.property(KoXmlNS::style, "shadow")))
- setShadow(shadow);
- }
-
- // The fo:background-color attribute specifies the background color of a paragraph.
- if (styleStack.hasProperty(KoXmlNS::fo, "background-color")) {
- const QString bgcolor = styleStack.property(KoXmlNS::fo, "background-color");
- QBrush brush = background();
- if (bgcolor == "transparent")
- brush.setStyle(Qt::NoBrush);
- else {
- if (brush.style() == Qt::NoBrush)
- brush.setStyle(Qt::SolidPattern);
- brush.setColor(bgcolor); // #rrggbb format
- }
- setBackground(brush);
- }
-
- // border-model
- if (styleStack.hasProperty(KoXmlNS::table, "border-model")) {
- QString val = styleStack.property(KoXmlNS::table, "border-model");
- setCollapsingBorderModel(val == "collapsing");
- }
-}
-
-void KoTableStyle::copyProperties(const KoTableStyle *style)
-{
- d->stylesPrivate = style->d->stylesPrivate;
- setName(style->name()); // make sure we emit property change
- d->next = style->d->next;
- d->parentStyle = style->d->parentStyle;
-}
-
-KoTableStyle *KoTableStyle::clone(QObject *parent)
-{
- KoTableStyle *newStyle = new KoTableStyle(parent);
- newStyle->copyProperties(this);
- return newStyle;
-}
-
-
-bool KoTableStyle::operator==(const KoTableStyle &other) const
-{
- return other.d->stylesPrivate == d->stylesPrivate;
-}
-
-void KoTableStyle::removeDuplicates(const KoTableStyle &other)
-{
- d->stylesPrivate.removeDuplicates(other.d->stylesPrivate);
-}
-
-bool KoTableStyle::isEmpty() const
-{
- return d->stylesPrivate.isEmpty();
-}
-
-void KoTableStyle::saveOdf(KoGenStyle &style)
-{
- QList<int> keys = d->stylesPrivate.keys();
- if ((hasProperty(QTextFormat::FrameLeftMargin)) &&
- (hasProperty(QTextFormat::FrameRightMargin)) &&
- (hasProperty(QTextFormat::FrameTopMargin)) &&
- (hasProperty(QTextFormat::FrameBottomMargin)) &&
- (rightMargin() == leftMargin()) && (leftMargin() == topMargin()) && (topMargin() == bottomMargin()))
- {
- style.addPropertyLength("fo:margin", propertyLength(QTextFormat::FrameBottomMargin), KoGenStyle::TableType);
- keys.removeAll(QTextFormat::FrameBottomMargin);
- keys.removeAll(QTextFormat::FrameTopMargin);
- keys.removeAll(QTextFormat::FrameRightMargin);
- keys.removeAll(QTextFormat::FrameLeftMargin);
- }
- Q_FOREACH (int key, keys) {
- if (key == QTextFormat::FrameWidth) {
- QTextLength width = propertyLength(QTextFormat::FrameWidth);
- if (width.type() == QTextLength::PercentageLength) {
- style.addPropertyLength("style:rel-width", width, KoGenStyle::TableType);
- } else if (width.type() == QTextLength::FixedLength) {
- style.addPropertyLength("style:width", width, KoGenStyle::TableType);
- }
- } else if (key == QTextFormat::BlockAlignment) {
- bool ok = false;
- int alignValue = value(QTextFormat::BlockAlignment).toInt(&ok);
- if (ok) {
- QString alignment = alignmentToString((Qt::Alignment) alignValue);
- if (!alignment.isEmpty())
- style.addProperty("table:align", alignment, KoGenStyle::TableType);
- }
- } else if (key == KoTableStyle::BreakBefore) {
- style.addProperty("fo:break-before", KoText::textBreakToString(breakBefore()), KoGenStyle::TableType);
- } else if (key == KoTableStyle::BreakAfter) {
- style.addProperty("fo:break-after", KoText::textBreakToString(breakAfter()), KoGenStyle::TableType);
- } else if (key == KoTableStyle::MayBreakBetweenRows) {
- style.addProperty("style:may-break-between-rows", mayBreakBetweenRows(), KoGenStyle::TableType);
- } else if (key == QTextFormat::BackgroundBrush) {
- QBrush backBrush = background();
- if (backBrush.style() != Qt::NoBrush)
- style.addProperty("fo:background-color", backBrush.color().name(), KoGenStyle::TableType);
- else
- style.addProperty("fo:background-color", "transparent", KoGenStyle::TableType);
- } else if (key == QTextFormat::FrameLeftMargin) {
- style.addPropertyLength("fo:margin-left", propertyLength(QTextFormat::FrameLeftMargin), KoGenStyle::TableType);
- } else if (key == QTextFormat::FrameRightMargin) {
- style.addPropertyLength("fo:margin-right", propertyLength(QTextFormat::FrameRightMargin), KoGenStyle::TableType);
- } else if (key == QTextFormat::FrameTopMargin) {
- style.addPropertyLength("fo:margin-top", propertyLength(QTextFormat::FrameTopMargin), KoGenStyle::TableType);
- } else if (key == QTextFormat::FrameBottomMargin) {
- style.addPropertyLength("fo:margin-bottom", propertyLength(QTextFormat::FrameBottomMargin), KoGenStyle::TableType);
- } else if (key == KoTableStyle::CollapsingBorders) {
- if (collapsingBorderModel())
- style.addProperty("table:border-model", "collapsing", KoGenStyle::TableType);
- else
- style.addProperty("table:border-model", "separating", KoGenStyle::TableType);
- } else if (key == KoTableStyle::KeepWithNext) {
- if (keepWithNext())
- style.addProperty("fo:keep-with-next", "always", KoGenStyle::TableType);
- else
- style.addProperty("fo:keep-with-next", "auto", KoGenStyle::TableType);
- } else if (key == KoTableStyle::Visible) {
- style.addProperty("table:display", visible(), KoGenStyle::TableType);
- } else if (key == KoTableStyle::PageNumber) {
- if (pageNumber() > 0)
- style.addProperty("style:page-number", pageNumber(), KoGenStyle::TableType);
- else
- style.addProperty("style:page-number", "auto", KoGenStyle::TableType);
- } else if (key == TextProgressionDirection) {
- style.addProperty("style:writing-mode", KoText::directionToString(textDirection()), KoGenStyle::TableType);
- } else if (key == KoTableStyle::Shadow) {
- style.addProperty("style:shadow", shadow().saveOdf());
- }
- }
-}
diff --git a/plugins/flake/textshape/kotext/styles/KoTableStyle.h b/plugins/flake/textshape/kotext/styles/KoTableStyle.h
deleted file mode 100644
index cb468d7cd7..0000000000
--- a/plugins/flake/textshape/kotext/styles/KoTableStyle.h
+++ /dev/null
@@ -1,258 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
- *
- * 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 KOTABLESTYLE_H
-#define KOTABLESTYLE_H
-
-#include "KoText.h"
-#include "kritatext_export.h"
-#include <KoXmlReaderForward.h>
-
-#include <QObject>
-
-class KoStyleStack;
-class KoGenStyle;
-class KoShadowStyle;
-
-class KoOdfLoadingContext;
-
-class QTextTable;
-class QVariant;
-
-/**
- * A container for all properties for the table wide style.
- * Each table in the main text either is based on a table style, or its not. Where
- * it is based on a table style this is indecated that it has a property 'StyleId'
- * with an integer as value. The integer value corresponds to the styleId() output of
- * a specific KoTableStyle.
- * @see KoStyleManager
- */
-class KRITATEXT_EXPORT KoTableStyle : public QObject
-{
- Q_OBJECT
-public:
- enum Property {
- StyleId = QTextTableFormat::UserProperty + 100,
- // Linespacing properties
- KeepWithNext, ///< If true, keep table with next paragraph
- BreakBefore, ///< If true, insert a frame break before this table
- BreakAfter, ///< If true, insert a frame break after this table
- MayBreakBetweenRows, ///< If true, then the table is allowed to break between rows
- ColumnAndRowStyleManager, ///< QVariant of a KoColumnAndRowStyleManager
- /// It's not really a property of KoTableStyle but defined here for convenience
- CollapsingBorders, ///< If true, then the table has collapsing border model
- MasterPageName, ///< Optional name of the master-page
- NumberHeadingRows, ///< Count the number of heading rows
- Visible, ///< If true, the table is visible
- PageNumber, ///< The page number that is applied after the page break
- TextProgressionDirection, ///< The direction of the text in the table
- TableIsProtected, ///< boolean, if true, the table is protected against edits
- /// It's not really a property of KoTableStyle but defined here for convenience
- Shadow, ///< KoShadowStyle, the table shadow
- TableTemplate, ///< KoTextTableTemplate, template for the table
- UseBandingColumnStyles, ///< table:use-banding-column-styles ODF 1.2 19.736
- UseBandingRowStyles, ///< table:use-banding-row-styles ODF 1.2 19.737
- UseFirstColumnStyles, ///< table:use-first-column-styles ODF 1.2 19.738
- UseFirstRowStyles, ///< table:use-first-row-styles ODF 1.2 19.739
- UseLastColumnStyles, ///< table:use-last-column-styles ODF 1.2 19.740
- UseLastRowStyles ///< table:use-last-row-styles ODF 1.2 19.741
- };
-
- /// Constructor
- explicit KoTableStyle(QObject *parent = 0);
- /// Creates a KoTableStyle with the given table format, and \a parent
- explicit KoTableStyle(const QTextTableFormat &blockFormat, QObject *parent = 0);
- /// Destructor
- ~KoTableStyle() override;
-
- /// Creates a KoTableStyle that represents the formatting of \a table.
- static KoTableStyle *fromTable(const QTextTable &table, QObject *parent = 0);
-
- /// creates a clone of this style with the specified parent
- KoTableStyle *clone(QObject *parent = 0);
-
- /// See similar named method on QTextFrameFormat
- void setWidth(const QTextLength &width);
-
- /// The property specifies if the table should be kept together with the next paragraph
- void setKeepWithNext(bool keep);
-
- bool keepWithNext() const;
-
- /// This property describe the shadow of the table, if any
- void setShadow (const KoShadowStyle &shadow);
-
- KoShadowStyle shadow() const;
-
- /// The property specifies if the table should allow it to be break. Break within a row is specified per row
- void setMayBreakBetweenRows(bool allow);
- bool mayBreakBetweenRows() const;
-
- /// See similar named method on QTextBlockFormat
- void setBackground(const QBrush &brush);
- /// See similar named method on QTextBlockFormat
- QBrush background() const;
- /// See similar named method on QTextBlockFormat
- void clearBackground();
-
- int pageNumber() const;
- void setPageNumber (int page);
-
- void setBreakBefore(KoText::KoTextBreakProperty state);
- KoText::KoTextBreakProperty breakBefore() const;
- void setBreakAfter(KoText::KoTextBreakProperty state);
- KoText::KoTextBreakProperty breakAfter() const;
-
- void setVisible(bool on);
- bool visible() const;
-
- void setCollapsingBorderModel(bool on);
- bool collapsingBorderModel() const;
-
- KoText::Direction textDirection() const;
- void setTextDirection(KoText::Direction direction);
-
- // ************ properties from QTextTableFormat
- /// duplicated property from QTextBlockFormat
- void setTopMargin(QTextLength topMargin);
- /// duplicated property from QTextBlockFormat
- qreal topMargin() const;
- /// duplicated property from QTextBlockFormat
- void setBottomMargin(QTextLength margin);
- /// duplicated property from QTextBlockFormat
- qreal bottomMargin() const;
- /// duplicated property from QTextBlockFormat
- void setLeftMargin(QTextLength margin);
- /// duplicated property from QTextBlockFormat
- qreal leftMargin() const;
- /// duplicated property from QTextBlockFormat
- void setRightMargin(QTextLength margin);
- /// duplicated property from QTextBlockFormat
- qreal rightMargin() const;
- /// set the margin around the table, making the margin on all sides equal.
- void setMargin(QTextLength margin);
-
- /// duplicated property from QTextBlockFormat
- void setAlignment(Qt::Alignment alignment);
- /// duplicated property from QTextBlockFormat
- Qt::Alignment alignment() const;
-
- /// set the parent style this one inherits its unset properties from.
- void setParentStyle(KoTableStyle *parent);
-
- /// return the parent style
- KoTableStyle *parentStyle() const;
-
- /// return the name of the style.
- QString name() const;
-
- /// set a user-visible name on the style.
- void setName(const QString &name);
-
- /// each style has a unique ID (non persistent) given out by the styleManager
- int styleId() const;
-
- /// each style has a unique ID (non persistent) given out by the styleManager
- void setStyleId(int id);
-
- /// return the optional name of the master-page or a QString() if this paragraph isn't attached to a master-page.
- QString masterPageName() const;
- /// Set the name of the master-page.
- void setMasterPageName(const QString &name);
-
-
- /// copy all the properties from the other style to this style, effectively duplicating it.
- void copyProperties(const KoTableStyle *style);
-
- /**
- * Apply this style to a tableFormat by copying all properties from this, and parent
- * styles to the target table format.
- */
- void applyStyle(QTextTableFormat &format) const;
-
- void remove(int key);
-
- /// Compare the properties of this style with the other
- bool operator==(const KoTableStyle &other) const;
-
- void removeDuplicates(const KoTableStyle &other);
-
- /// return true when there are keys defined for this style
- bool isEmpty() const;
-
- /**
- * Load the style form the element
- *
- * @param context the odf loading context
- * @param element the element containing the
- */
- void loadOdf(const KoXmlElement *element, KoOdfLoadingContext &context);
-
- void saveOdf(KoGenStyle &style);
-
- /**
- * Returns true if this table style has the property set.
- * Note that this method does not delegate to the parent style.
- * @param key the key as found in the Property enum
- */
- bool hasProperty(int key) const;
-
- /**
- * Set a property with key to a certain value, overriding the value from the parent style.
- * If the value set is equal to the value of the parent style, the key will be removed instead.
- * @param key the Property to set.
- * @param value the new value to set on this style.
- * @see hasProperty(), value()
- */
- void setProperty(int key, const QVariant &value);
- /**
- * Return the value of key as represented on this style, taking into account parent styles.
- * You should consider using the direct accessors for individual properties instead.
- * @param key the Property to request.
- * @returns a QVariant which holds the property value.
- */
- QVariant value(int key) const;
-
-Q_SIGNALS:
- void nameChanged(const QString &newName);
-
-private:
- /**
- * Load the style from the \a KoStyleStack style stack using the
- * OpenDocument format.
- */
- void loadOdfProperties(KoStyleStack &styleStack);
- static Qt::Alignment alignmentFromString(const QString &align);
- static QString alignmentToString(Qt::Alignment alignment);
- qreal propertyDouble(int key) const;
- QTextLength propertyLength(int key) const;
- int propertyInt(int key) const;
- bool propertyBoolean(int key) const;
- QColor propertyColor(int key) const;
-
- class Private;
- Private * const d;
-};
-
-Q_DECLARE_METATYPE(KoTableStyle *)
-
-#endif
diff --git a/plugins/flake/textshape/kotext/styles/Styles_p.cpp b/plugins/flake/textshape/kotext/styles/Styles_p.cpp
deleted file mode 100644
index 4884432d6a..0000000000
--- a/plugins/flake/textshape/kotext/styles/Styles_p.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- *
- * 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 "Styles_p.h"
-
-#include "TextDebug.h"
-
-StylePrivate::StylePrivate()
-{
-}
-
-StylePrivate::StylePrivate(const StylePrivate &other)
- : m_properties(other.m_properties)
-{
-}
-
-StylePrivate::~StylePrivate()
-{
-}
-
-StylePrivate::StylePrivate(const QMap<int, QVariant> &other)
- : m_properties(other)
-{
-}
-
-void StylePrivate::add(int key, const QVariant &value)
-{
- m_properties.insert(key, value);
-}
-
-void StylePrivate::remove(int key)
-{
- m_properties.remove(key);
-}
-
-const QVariant StylePrivate::value(int key) const
-{
- return m_properties.value(key);
-}
-
-bool StylePrivate::contains(int key) const
-{
- return m_properties.contains(key);
-}
-
-bool StylePrivate::isEmpty() const
-{
- return m_properties.isEmpty();
-}
-
-void StylePrivate::copyMissing(const StylePrivate &other)
-{
- copyMissing(other.m_properties);
-}
-
-void StylePrivate::copyMissing(const QMap<int, QVariant> &other)
-{
- for (QMap<int,QVariant>::const_iterator it(other.constBegin()); it != other.constEnd(); ++it) {
- if (!m_properties.contains(it.key()))
- m_properties.insert(it.key(), it.value());
- }
-}
-
-void StylePrivate::removeDuplicates(const StylePrivate &other)
-{
- Q_FOREACH (int key, other.m_properties.keys()) {
- if (m_properties.value(key) == other.value(key)) {
- m_properties.remove(key);
- }
- }
-}
-
-void StylePrivate::removeDuplicates(const QMap<int, QVariant> &other)
-{
- Q_FOREACH (int key, other.keys()) {
- if (m_properties.value(key) == other.value(key))
- m_properties.remove(key);
- }
-}
-
-QList<int> StylePrivate::keys() const
-{
- return m_properties.keys();
-}
-
-bool StylePrivate::operator==(const StylePrivate &other) const
-{
- if (other.m_properties.size() != m_properties.size())
- return false;
- Q_FOREACH (int key, m_properties.keys()) {
- if (m_properties.value(key) != other.value(key))
- return false;
- }
- return true;
-}
-
-bool StylePrivate::operator!=(const StylePrivate &other) const
-{
- return !operator==(other);
-}
diff --git a/plugins/flake/textshape/kotext/styles/Styles_p.h b/plugins/flake/textshape/kotext/styles/Styles_p.h
deleted file mode 100644
index 5151869a08..0000000000
--- a/plugins/flake/textshape/kotext/styles/Styles_p.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- *
- * 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 KOTEXT_STYLES_PRIVATE_H
-#define KOTEXT_STYLES_PRIVATE_H
-
-#include <QVariant>
-#include <QMap>
-
-class StylePrivate
-{
-public:
- StylePrivate();
- StylePrivate(const StylePrivate &other);
- StylePrivate(const QMap<int, QVariant> &other);
- ~StylePrivate();
-
- void add(int key, const QVariant &value);
- void remove(int key);
- const QVariant value(int key) const;
- bool contains(int key) const;
- void copyMissing(const StylePrivate &other);
- void copyMissing(const QMap<int, QVariant> &other);
- void removeDuplicates(const StylePrivate &other);
- void removeDuplicates(const QMap<int, QVariant> &other);
- void clearAll() {
- m_properties.clear();
- }
- QList<int> keys() const;
- bool operator==(const StylePrivate &other) const;
- bool operator!=(const StylePrivate &other) const;
- bool isEmpty() const;
- const QMap<int, QVariant> properties() const {
- return m_properties;
- }
-
-private:
- QMap<int, QVariant> m_properties;
-};
-
-#endif
diff --git a/plugins/flake/textshape/kotext/texteditingplugin.json b/plugins/flake/textshape/kotext/texteditingplugin.json
deleted file mode 100644
index 0c0c34ddfb..0000000000
--- a/plugins/flake/textshape/kotext/texteditingplugin.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "Comment": "Definition of a text-editing plugin",
- "Id": "Text Editing plugin for the Krita text tool",
- "Type": "ServiceType",
- "X-KDE-ServiceType": "Krita/Text-EditingPlugin"
-}
diff --git a/plugins/flake/textshape/pics/22-actions-edit-table-cell-merge.png b/plugins/flake/textshape/pics/22-actions-edit-table-cell-merge.png
deleted file mode 100644
index 11a2405d05..0000000000
Binary files a/plugins/flake/textshape/pics/22-actions-edit-table-cell-merge.png and /dev/null differ
diff --git a/plugins/flake/textshape/pics/22-actions-edit-table-cell-split.png b/plugins/flake/textshape/pics/22-actions-edit-table-cell-split.png
deleted file mode 100644
index 9d335a12ed..0000000000
Binary files a/plugins/flake/textshape/pics/22-actions-edit-table-cell-split.png and /dev/null differ
diff --git a/plugins/flake/textshape/pics/22-actions-tool-text.png b/plugins/flake/textshape/pics/22-actions-tool-text.png
deleted file mode 100644
index c17c09d515..0000000000
Binary files a/plugins/flake/textshape/pics/22-actions-tool-text.png and /dev/null differ
diff --git a/plugins/flake/textshape/pics/22-actions-tool_references.png b/plugins/flake/textshape/pics/22-actions-tool_references.png
deleted file mode 100644
index ead9d11933..0000000000
Binary files a/plugins/flake/textshape/pics/22-actions-tool_references.png and /dev/null differ
diff --git a/plugins/flake/textshape/pics/22-actions-tool_review.png b/plugins/flake/textshape/pics/22-actions-tool_review.png
deleted file mode 100644
index e1923606e7..0000000000
Binary files a/plugins/flake/textshape/pics/22-actions-tool_review.png and /dev/null differ
diff --git a/plugins/flake/textshape/pics/settings-icon1_1.png b/plugins/flake/textshape/pics/settings-icon1_1.png
deleted file mode 100644
index e0ef574afe..0000000000
Binary files a/plugins/flake/textshape/pics/settings-icon1_1.png and /dev/null differ
diff --git a/plugins/flake/textshape/pics/tool-text.svg b/plugins/flake/textshape/pics/tool-text.svg
deleted file mode 100644
index 219a2ce3e8..0000000000
--- a/plugins/flake/textshape/pics/tool-text.svg
+++ /dev/null
@@ -1,300 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- id="svg864"
- version="1.1"
- inkscape:version="0.48+devel r12017"
- width="20"
- height="20"
- sodipodi:docname="tool-text.svg"
- inkscape:export-xdpi="99"
- inkscape:export-ydpi="99"
- inkscape:export-filename="hi22-action-tool-text.png">
- <metadata
- id="metadata870">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <defs
- id="defs868">
- <marker
- inkscape:stockid="Arrow1Lend"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="Arrow1Lend"
- style="overflow:visible;"
- inkscape:isstock="true">
- <path
- id="path1260"
- d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
- style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
- transform="scale(0.8) rotate(180) translate(12.5,0)" />
- </marker>
- <marker
- inkscape:stockid="Arrow1Lstart"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="marker5177"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path5179"
- d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
- style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
- transform="scale(0.8) translate(12.5,0)" />
- </marker>
- <marker
- inkscape:stockid="Scissors"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="Scissors"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="schere"
- d="M 9.0898857,-3.6061018 C 8.1198849,-4.7769976 6.3697607,-4.7358294 5.0623558,-4.2327734 L -3.1500488,-1.1548705 C -5.5383421,-2.4615840 -7.8983361,-2.0874077 -7.8983361,-2.7236578 C -7.8983361,-3.2209742 -7.4416699,-3.1119800 -7.5100293,-4.4068519 C -7.5756648,-5.6501286 -8.8736064,-6.5699315 -10.100428,-6.4884954 C -11.327699,-6.4958500 -12.599867,-5.5553341 -12.610769,-4.2584343 C -12.702194,-2.9520479 -11.603560,-1.7387447 -10.304005,-1.6532027 C -8.7816644,-1.4265411 -6.0857470,-2.3487593 -4.8210600,-0.082342643 C -5.7633447,1.6559151 -7.4350844,1.6607341 -8.9465707,1.5737277 C -10.201445,1.5014928 -11.708664,1.8611256 -12.307219,3.0945882 C -12.885586,4.2766744 -12.318421,5.9591904 -10.990470,6.3210002 C -9.6502788,6.8128279 -7.8098011,6.1912892 -7.4910978,4.6502760 C -7.2454393,3.4624530 -8.0864637,2.9043186 -7.7636052,2.4731223 C -7.5199917,2.1477623 -5.9728246,2.3362771 -3.2164999,1.0982979 L 5.6763468,4.2330688 C 6.8000164,4.5467672 8.1730685,4.5362646 9.1684433,3.4313614 L -0.051640930,- 0.053722219 L 9.0898857,-3.6061018 z M -9.2179159,-5.5066058 C -7.9233569,-4.7838060 -8.0290767,-2.8230356 -9.3743431,-2.4433169 C -10.590861,-2.0196559 -12.145370,-3.2022863 -11.757521,-4.5207817 C -11.530373,-5.6026336 -10.104134,-6.0014137 -9.2179159,-5.5066058 z M -9.1616516,2.5107591 C -7.8108215,3.0096239 -8.0402087,5.2951947 -9.4138723,5.6023681 C -10.324932,5.9187072 -11.627422,5.4635705 -11.719569,4.3902287 C -11.897178,3.0851737 -10.363484,1.9060805 -9.1616516,2.5107591 z "
- style="fill:#ffffff;stroke:#000000;stroke-opacity:1;fill-opacity:1" />
- </marker>
- <marker
- inkscape:stockid="StopS"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="StopS"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path5070"
- d="M 0.0,5.65 L 0.0,-5.65"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
- transform="scale(0.2)" />
- </marker>
- <marker
- inkscape:stockid="EmptyDiamondMstart"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="EmptyDiamondMstart"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path5013"
- d="M 0,-7.0710768 L -7.0710894,0 L 0,7.0710589 L 7.0710462,0 L 0,-7.0710768 z "
- style="fill-rule:evenodd;fill:#ffffff;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill-opacity:1"
- transform="scale(0.4) translate(6.5,0)" />
- </marker>
- <marker
- inkscape:stockid="EmptyDiamondSstart"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="EmptyDiamondSstart"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path5016"
- d="M 0,-7.0710768 L -7.0710894,0 L 0,7.0710589 L 7.0710462,0 L 0,-7.0710768 z "
- style="fill-rule:evenodd;fill:#ffffff;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill-opacity:1"
- transform="scale(0.2) translate(6,0)" />
- </marker>
- <marker
- inkscape:stockid="TriangleInL"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="TriangleInL"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path5028"
- d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
- style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
- transform="scale(-0.8)" />
- </marker>
- <marker
- inkscape:stockid="Arrow1Lstart"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="marker5163"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path5165"
- d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
- style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
- transform="scale(0.8) translate(12.5,0)" />
- </marker>
- <marker
- inkscape:stockid="Arrow2Lstart"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="Arrow2Lstart"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path4913"
- style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
- d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
- transform="scale(1.1) translate(1,0)" />
- </marker>
- <marker
- inkscape:stockid="Arrow2Lend"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="marker5157"
- style="overflow:visible;"
- inkscape:isstock="true">
- <path
- id="path5159"
- style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
- d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
- transform="scale(1.1) rotate(180) translate(1,0)" />
- </marker>
- <marker
- inkscape:stockid="Arrow1Mend"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="Arrow1Mend"
- style="overflow:visible;"
- inkscape:isstock="true">
- <path
- id="path4904"
- d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
- style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
- transform="scale(0.4) rotate(180) translate(10,0)" />
- </marker>
- <marker
- inkscape:stockid="Arrow1Lstart"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="Arrow1Lstart"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path4895"
- d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
- style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
- transform="scale(0.8) translate(12.5,0)" />
- </marker>
- <marker
- inkscape:stockid="Arrow2Lend"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="Arrow2Lend"
- style="overflow:visible;"
- inkscape:isstock="true">
- <path
- id="path4916"
- style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
- d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
- transform="scale(1.1) rotate(180) translate(1,0)" />
- </marker>
- <inkscape:path-effect
- effect="skeletal"
- id="path-effect4889"
- is_visible="true"
- pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
- copytype="single_stretched"
- prop_scale="1"
- scale_y_rel="false"
- spacing="0"
- normal_offset="0"
- tang_offset="0"
- prop_units="false"
- vertical_pattern="false"
- fuse_tolerance="0" />
- </defs>
- <sodipodi:namedview
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1"
- objecttolerance="10"
- gridtolerance="10"
- guidetolerance="10"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:window-width="1920"
- inkscape:window-height="1060"
- id="namedview866"
- showgrid="true"
- inkscape:zoom="43.45"
- inkscape:cx="11.09972"
- inkscape:cy="10.109321"
- inkscape:window-x="-2"
- inkscape:window-y="-3"
- inkscape:window-maximized="1"
- inkscape:current-layer="svg864"
- showguides="true">
- <inkscape:grid
- type="xygrid"
- id="grid980" />
- </sodipodi:namedview>
- <path
- sodipodi:type="inkscape:offset"
- inkscape:radius="0.31319982"
- inkscape:original="M 4.21875 6.5625 L 0.6875 15.21875 L 1.90625 15.21875 L 2.875 12.6875 L 6.84375 12.6875 L 7.8125 15.21875 L 9.03125 15.21875 L 5.53125 6.5625 L 4.21875 6.5625 z M 4.875 7.4375 C 4.8790974 7.4579869 4.8775683 7.5307601 4.90625 7.625 C 4.9390291 7.7151425 4.9861787 7.8294389 5.03125 7.96875 C 5.0763213 8.1039638 5.1301366 8.2382572 5.1875 8.40625 C 5.2489608 8.5742428 5.3094418 8.7423545 5.375 8.90625 L 6.46875 11.78125 L 3.25 11.78125 L 4.34375 8.9375 C 4.4052108 8.7736045 4.4738866 8.6054928 4.53125 8.4375 C 4.5927108 8.2695072 4.6424287 8.1080611 4.6875 7.96875 C 4.7366686 7.8294389 4.7838183 7.7192399 4.8125 7.625 C 4.8411817 7.5307601 4.8668052 7.4579869 4.875 7.4375 z "
- style="font-size:12.58717155px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:0;stroke:none;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
- id="path1200"
- d="M 4.125,6.25 A 0.31323114,0.31323114 0 0 0 4.03125,6.3125 0.31323114,0.31323114 0 0 0 3.9375,6.4375 L 0.40625,15.09375 A 0.31323114,0.31323114 0 0 0 0.5625,15.5 a 0.31323114,0.31323114 0 0 0 0.125,0.03125 l 1.21875,0 a 0.31323114,0.31323114 0 0 0 0.1875,-0.0625 0.31323114,0.31323114 0 0 0 0.09375,-0.125 L 3.09375,13 6.625,13 7.53125,15.34375 a 0.31323114,0.31323114 0 0 0 0.09375,0.125 0.31323114,0.31323114 0 0 0 0.1875,0.0625 l 1.21875,0 a 0.31323114,0.31323114 0 0 0 0.1875,-0.0625 0.31323114,0.31323114 0 0 0 0.09375,-0.375 L 5.8125,6.4375 A 0.31323114,0.31323114 0 0 0 5.78125,6.375 0.31323114,0.31323114 0 0 0 5.71875,6.3125 0.31323114,0.31323114 0 0 0 5.53125,6.25 l -1.3125,0 A 0.31323114,0.31323114 0 0 0 4.125,6.25 z m 0.75,2.15625 c 0.011155,0.031099 0.019974,0.060728 0.03125,0.09375 0.061075,0.1669394 0.119183,0.3604575 0.1875,0.53125 l 0.9375,2.4375 -2.34375,0 L 4.625,9.0625 C 4.6842513,8.9044965 4.7510821,8.7111166 4.8125,8.53125 4.8304259,8.4822525 4.8590433,8.4531247 4.875,8.40625 Z"
- transform="matrix(1.0234068,0,0,0.97712853,-0.34711051,-3.414843)" />
- <g
- id="g3448"
- transform="translate(0.11507479,0)">
- <path
- d="m 11.78125,1.90625 a 0.98974224,0.98974224 0 0 0 -0.90625,1 l 0,2.03125 a 0.98974224,0.98974224 0 0 0 1,1 l 0.625,0 0,8.0625 -0.625,0 a 0.98974224,0.98974224 0 0 0 -1,1 l 0,2 a 0.98974224,0.98974224 0 0 0 1,1 l 5.625,0 a 0.98974224,0.98974224 0 0 0 1,-1 l 0,-2 a 0.98974224,0.98974224 0 0 0 -1,-1 l -0.59375,0 0,-8.0625 0.59375,0 a 0.98974224,0.98974224 0 0 0 1,-1 l 0,-2.03125 a 0.98974224,0.98974224 0 0 0 -1,-1 l -5.625,0 A 0.98974224,0.98974224 0 0 0 11.78125,1.90625 Z"
- id="path3446"
- style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.89980268px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
- inkscape:original="M 11.875 2.90625 L 11.875 4.9375 L 13.5 4.9375 L 13.5 15 L 11.875 15 L 11.875 17 L 17.5 17 L 17.5 15 L 15.90625 15 L 15.90625 4.9375 L 17.5 4.9375 L 17.5 2.90625 L 11.875 2.90625 z "
- inkscape:radius="0.98964328"
- sodipodi:type="inkscape:offset" />
- <path
- inkscape:connector-curvature="0"
- id="path3426"
- d="m 13.501297,4.9642152 -1.607783,0 0,-2.0143139 5.62724,0 0,2.0143139 -1.607783,0 0,10.0715698 1.607783,0 0,2.014314 -5.62724,0 0,-2.014314 L 13.501297,15.035785 Z"
- style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.89980268px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
- </g>
- <g
- id="g3422"
- transform="matrix(1.0500042,0,0,1.1944836,0.19100345,3.8861029)">
- <path
- transform="matrix(1.0234068,0,0,0.97712853,0.18223308,-5.4165706)"
- d="M 4,5.5625 A 0.68583259,0.68583259 0 0 0 3.75,5.65625 c 0.00768,-0.00421 -0.069867,0.035997 -0.0625,0.03125 0.00737,-0.00475 -0.038261,0.036507 -0.03125,0.03125 0.00701,-0.00526 -0.069121,0.068242 -0.0625,0.0625 0.00662,-0.00574 -0.068697,0.037447 -0.0625,0.03125 0.0062,-0.0062 -0.036992,0.069121 -0.03125,0.0625 0.00574,-0.00662 -0.067757,0.069511 -0.0625,0.0625 0.00526,-0.00701 -0.035997,0.038617 -0.03125,0.03125 0.0019,-0.00295 0.00775,0.018187 0,0.03125 -0.01162,0.019594 -0.033777,0.035861 -0.03125,0.03125 -0.00619,0.010132 -0.00136,0.033629 0,0.03125 0.0034,-0.00595 -0.034313,0.037376 -0.03125,0.03125 0.00306,-0.00613 -0.033969,0.068787 -0.03125,0.0625 0.00136,-0.00314 0.00579,0.016765 0,0.03125 l -3.53125,8.65625 c 0.002256,-0.0054 -0.0332451,0.03677 -0.03125,0.03125 0.001995,-0.0055 -0.00173,0.03686 0,0.03125 0.00173,-0.0056 -0.0327111,0.06819 -0.03125,0.0625 0.001461,-0.0057 -0.001189,0.037 0,0.03125 0.001189,-0.0058 -9.1394e-4,0.0683 0,0.0625 9.1394e-4,-0.0058 -0.0318869,0.03709 -0.03125,0.03125 6.3694e-4,-0.0058 -3.5849e-4,0.06836 0,0.0625 3.5849e-4,-0.0059 -7.924e-5,0.03712 0,0.03125 7.924e-5,-0.0059 2.002e-4,0.06837 0,0.0625 -2.002e-4,-0.0059 4.7918e-4,0.0371 0,0.03125 -4.7918e-4,-0.0059 0.0320071,0.06832 0.03125,0.0625 -7.5707e-4,-0.0058 0.001033,0.06828 0,0.0625 -0.001033,-0.0058 0.001307,0.03698 0,0.03125 -0.001307,-0.0057 0.001578,0.03691 0,0.03125 -0.001578,-0.0057 0.0330953,0.06808 0.03125,0.0625 -0.001845,-0.0056 0.002108,0.03673 0,0.03125 -0.002108,-0.0055 0.0336168,0.06788 0.03125,0.0625 -0.002367,-0.0054 0.0338698,0.03651 0.03125,0.03125 -0.00262,-0.0053 0.002867,0.06763 0,0.0625 -0.002867,-0.0051 0.0343575,0.03623 0.03125,0.03125 -0.003107,-0.005 0.034591,0.03608 0.03125,0.03125 -0.003341,-0.0048 0.034817,0.03592 0.03125,0.03125 -0.003567,-0.0047 0.03503491,0.06699 0.03125,0.0625 -0.0037849,-0.0045 0.03524425,0.03556 0.03125,0.03125 -0.0039942,-0.0043 0.03544456,0.03536 0.03125,0.03125 -0.00419456,-0.0041 0.03563536,0.03516 0.03125,0.03125 -0.0043854,-0.0039 0.03581624,0.03494 0.03125,0.03125 -0.0045662,-0.0037 0.03598679,0.03472 0.03125,0.03125 -0.0047368,-0.0035 0.06739661,0.03449 0.0625,0.03125 -0.004897,-0.0032 0.0362953,0.003 0.03125,0 -0.005045,-0.003 0.0364327,0.03401 0.03125,0.03125 -0.00311,-0.0017 0.0176167,0.02437 0.03125,0.03125 0.009089,0.0046 0.0333733,0.001 0.03125,0 0.0131692,0.006 0.0341738,0.0012 0.03125,0 -0.005848,-0.0025 0.0372166,0.03341 0.03125,0.03125 -0.005967,-0.0022 0.0685699,0.0331 0.0625,0.03125 -0.00607,-0.0019 0.0686572,0.0015 0.0625,0 -0.006157,-0.0015 0.0374781,0.0012 0.03125,0 -0.006228,-0.0012 0.0687826,0.03215 0.0625,0.03125 -0.006283,-8.99e-4 0.0375705,5.75e-4 0.03125,0 -0.006321,-5.75e-4 0.0688417,2.49e-4 0.0625,0 a 0.68583259,0.68583259 0 0 0 0.03125,0 l 1.21875,0 c -0.00872,1.97e-4 0.1024359,-8.13e-4 0.09375,0 -0.00869,8.13e-4 0.071107,-0.0014 0.0625,0 -0.00861,0.0014 0.070985,-0.03328 0.0625,-0.03125 -0.00848,0.002 0.07082,-0.03387 0.0625,-0.03125 -0.00832,0.0026 0.1018645,-0.0032 0.09375,0 -0.00811,0.0032 0.070368,-0.03502 0.0625,-0.03125 -0.00787,0.0038 0.070082,-0.03556 0.0625,-0.03125 -0.00758,0.0043 0.069759,-0.03609 0.0625,-0.03125 -0.00726,0.0048 0.038149,-0.06784 0.03125,-0.0625 -0.0069,0.0053 0.069005,-0.03706 0.0625,-0.03125 -0.0065,0.0058 0.068578,-0.06876 0.0625,-0.0625 -0.00608,0.0063 0.036871,-0.03792 0.03125,-0.03125 -0.00562,0.0067 0.067636,-0.06955 0.0625,-0.0625 -0.00514,0.0071 0.035875,-0.0699 0.03125,-0.0625 -0.00462,0.0074 0.035341,-0.0702 0.03125,-0.0625 -0.00409,0.0077 0.034786,-0.07048 0.03125,-0.0625 a 0.68583259,0.68583259 0 0 0 0,-0.03125 l 0.75,-1.90625 2.59375,0 0.6875,1.71875 0,0.03125 a 0.68583259,0.68583259 0 0 0 0.03125,0.09375 0.68583259,0.68583259 0 0 0 0.0625,0.1875 c -0.00421,-0.0077 0.035997,0.06987 0.03125,0.0625 -0.00475,-0.0074 0.036507,0.03826 0.03125,0.03125 -0.00526,-0.007 0.068242,0.06912 0.0625,0.0625 -0.00574,-0.0066 0.037447,0.0687 0.03125,0.0625 -0.0062,-0.0062 0.069121,0.03699 0.0625,0.03125 -0.00662,-0.0057 0.069511,0.06776 0.0625,0.0625 -0.00701,-0.0053 0.038617,0.036 0.03125,0.03125 -0.00737,-0.0047 0.070185,0.03546 0.0625,0.03125 A 0.68583259,0.68583259 0 0 0 7.34375,16.125 c -0.00709,-0.0034 0.069791,0.03424 0.0625,0.03125 -0.00729,-0.003 0.069966,0.0025 0.0625,0 -0.00747,-0.0025 0.070112,0.03328 0.0625,0.03125 -0.00761,-0.002 0.070226,0.0015 0.0625,0 -0.00773,-0.0015 0.070309,0.0323 0.0625,0.03125 -0.00781,-0.001 0.07036,5.49e-4 0.0625,0 -0.00786,-5.49e-4 0.070379,4.7e-5 0.0625,0 -0.00394,-2.3e-5 0.013313,4.67e-4 0.03125,0 0.017937,-4.67e-4 0.035183,-2.28e-4 0.03125,0 l 1.1875,0 a 0.68583259,0.68583259 0 0 0 0.03125,0 c -0.00747,2.27e-4 0.069945,-6.79e-4 0.0625,0 -0.00745,6.79e-4 0.06989,-0.0011 0.0625,0 -0.00739,0.0011 0.038559,-0.03282 0.03125,-0.03125 -0.00731,0.0016 0.0697,-0.002 0.0625,0 -0.0072,0.002 0.069565,-0.0337 0.0625,-0.03125 -0.00706,0.0024 0.069404,-0.03412 0.0625,-0.03125 -0.0069,0.0029 0.069218,-0.0033 0.0625,0 -0.00672,0.0033 0.037757,-0.03493 0.03125,-0.03125 -0.00651,0.0037 0.068772,-0.03532 0.0625,-0.03125 -0.00627,0.0041 0.068514,-0.03569 0.0625,-0.03125 -0.00601,0.0044 0.036984,-0.0673 0.03125,-0.0625 -0.00573,0.0048 0.067933,-0.03638 0.0625,-0.03125 -0.00543,0.0051 0.036363,-0.0367 0.03125,-0.03125 -0.00511,0.0055 0.036023,-0.06825 0.03125,-0.0625 -0.00477,0.0058 0.066916,-0.03728 0.0625,-0.03125 -0.00442,0.006 0.035293,-0.06879 0.03125,-0.0625 -0.00404,0.0063 0.034905,-0.03777 0.03125,-0.03125 -0.00365,0.0065 0.034503,-0.06923 0.03125,-0.0625 -0.00325,0.0067 0.00284,-0.06942 0,-0.0625 -0.00284,0.0069 0.033666,-0.06958 0.03125,-0.0625 -0.00242,0.0071 0.033233,-0.06971 0.03125,-0.0625 -0.00198,0.0072 0.0015,-0.03857 0,-0.03125 -0.00154,0.0073 0.0011,-0.0699 0,-0.0625 -0.0011,0.0074 0.0319,-0.06995 0.03125,-0.0625 -6.48e-4,0.0074 1.96e-4,-0.06997 0,-0.0625 -1.96e-4,0.0075 -2.57e-4,-0.06997 0,-0.0625 2.57e-4,0.0075 -7.08e-4,-0.06994 0,-0.0625 7.08e-4,0.0074 -0.032408,-0.06989 -0.03125,-0.0625 0.0012,0.0074 -0.0016,-0.0698 0,-0.0625 0.0016,0.0073 -0.00204,-0.06969 0,-0.0625 0.002,0.0072 -0.033723,-0.06955 -0.03125,-0.0625 0.00247,0.0071 -0.034146,-0.03814 -0.03125,-0.03125 l -3.5,-8.65625 c -0.00579,-0.014485 -0.00136,-0.034393 0,-0.03125 0.00272,0.00629 -0.034313,-0.068626 -0.03125,-0.0625 C 6.4093132,6.0998764 6.3716017,6.0565529 6.375,6.0625 6.3783983,6.0684471 6.3400271,5.9942506 6.34375,6 A 0.68583259,0.68583259 0 0 0 6.3125,5.9375 C 6.3153376,5.9407662 6.2946874,5.920664 6.28125,5.90625 6.2840876,5.9095162 6.2634374,5.889414 6.25,5.875 6.2530594,5.8780594 6.233164,5.8571874 6.21875,5.84375 6.2218094,5.8468094 6.201914,5.8259374 6.1875,5.8125 6.173086,5.7990626 6.1529838,5.7784124 6.15625,5.78125 A 0.68583259,0.68583259 0 0 0 6.125,5.75 c 0.00788,0.00587 -0.070827,-0.036479 -0.0625,-0.03125 0.00833,0.00523 -0.071216,-0.0358 -0.0625,-0.03125 0.00872,0.00455 -0.1028008,-0.035092 -0.09375,-0.03125 0.00905,0.00384 -0.071828,-0.034359 -0.0625,-0.03125 0.00933,0.00311 -0.072046,-0.033607 -0.0625,-0.03125 0.00955,0.00236 -0.1034529,-0.03284 -0.09375,-0.03125 0.0097,0.00159 -0.072299,-8.13e-4 -0.0625,0 0.0098,8.13e-4 -0.1035823,-3.07e-5 -0.09375,0 l -1.21875,0 -0.0625,0 c 0.00459,3.429e-4 -0.010303,7.814e-4 -0.03125,0 -0.020947,-7.814e-4 -0.035852,0 -0.03125,0 0.00307,0 -0.019179,-4.884e-4 -0.03125,0 -0.012071,4.884e-4 -0.019176,-4.122e-4 -0.03125,0 0.00306,0 -0.017324,-3.451e-4 -0.03125,0 0.00459,-3.429e-4 -0.01042,-0.00234 -0.03125,0 a 0.68583259,0.68583259 0 0 0 -0.03125,0 A 0.68583259,0.68583259 0 0 0 4,5.5625 z m 0.875,4.75 0.15625,0.46875 -0.34375,0 L 4.875,10.3125 Z"
- id="path1222"
- style="font-size:12.58717155px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
- inkscape:original="M 4.09375 6.25 A 0.31545968 0.31545968 0 0 0 3.96875 6.375 A 0.31545968 0.31545968 0 0 0 3.9375 6.4375 L 0.40625 15.09375 A 0.31545968 0.31545968 0 0 0 0.5625 15.5 A 0.31545968 0.31545968 0 0 0 0.6875 15.53125 L 1.90625 15.53125 A 0.31545968 0.31545968 0 0 0 2.1875 15.34375 L 3.09375 13 L 6.625 13 L 7.53125 15.34375 A 0.31545968 0.31545968 0 0 0 7.53125 15.375 A 0.31545968 0.31545968 0 0 0 7.65625 15.5 A 0.31545968 0.31545968 0 0 0 7.8125 15.53125 L 9.03125 15.53125 A 0.31545968 0.31545968 0 0 0 9.3125 15.09375 L 5.8125 6.4375 A 0.31545968 0.31545968 0 0 0 5.78125 6.375 A 0.31545968 0.31545968 0 0 0 5.75 6.34375 A 0.31545968 0.31545968 0 0 0 5.71875 6.3125 A 0.31545968 0.31545968 0 0 0 5.53125 6.25 L 4.21875 6.25 A 0.31545968 0.31545968 0 0 0 4.125 6.25 A 0.31545968 0.31545968 0 0 0 4.09375 6.25 z M 4.84375 8.4375 C 4.8518272 8.4602721 4.8668649 8.4761759 4.875 8.5 A 0.31545968 0.31545968 0 0 0 4.90625 8.5 C 4.9673227 8.6669319 5.0254134 8.8604084 5.09375 9.03125 L 6.03125 11.46875 L 3.6875 11.46875 L 4.625 9.0625 C 4.6842356 8.9045384 4.7823033 8.711201 4.84375 8.53125 L 4.8125 8.53125 C 4.8252024 8.4965301 4.8320576 8.47121 4.84375 8.4375 z "
- inkscape:radius="0.68576401"
- sodipodi:type="inkscape:offset" />
- <path
- transform="matrix(1.0234068,0,0,0.97712853,0.18411968,-5.4085155)"
- d="m 4.21875,6.5625 -3.53125,8.65625 1.21875,0 0.96875,-2.53125 3.96875,0 0.96875,2.53125 1.21875,0 -3.5,-8.65625 L 4.21875,6.5625 Z M 4.875,7.4375 c 0.0041,0.020487 0.00257,0.09326 0.03125,0.1875 0.032779,0.090142 0.079929,0.2044389 0.125,0.34375 0.045071,0.1352138 0.098887,0.2695072 0.15625,0.4375 0.061461,0.1679928 0.1219418,0.3361045 0.1875,0.5 l 1.09375,2.875 -3.21875,0 L 4.34375,8.9375 C 4.4052108,8.7736045 4.4738866,8.6054928 4.53125,8.4375 4.5927108,8.2695072 4.6424287,8.1080611 4.6875,7.96875 4.7366686,7.8294389 4.7838183,7.7192399 4.8125,7.625 4.8411817,7.5307601 4.8668052,7.4579869 4.875,7.4375 Z"
- id="path1180"
- style="font-size:12.58717155px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
- inkscape:original="M 4.21875 6.5625 L 0.6875 15.21875 L 1.90625 15.21875 L 2.875 12.6875 L 6.84375 12.6875 L 7.8125 15.21875 L 9.03125 15.21875 L 5.53125 6.5625 L 4.21875 6.5625 z M 4.875 7.4375 C 4.8790974 7.4579869 4.8775683 7.5307601 4.90625 7.625 C 4.9390291 7.7151425 4.9861787 7.8294389 5.03125 7.96875 C 5.0763213 8.1039638 5.1301366 8.2382572 5.1875 8.40625 C 5.2489608 8.5742428 5.3094418 8.7423545 5.375 8.90625 L 6.46875 11.78125 L 3.25 11.78125 L 4.34375 8.9375 C 4.4052108 8.7736045 4.4738866 8.6054928 4.53125 8.4375 C 4.5927108 8.2695072 4.6424287 8.1080611 4.6875 7.96875 C 4.7366686 7.8294389 4.7838183 7.7192399 4.8125 7.625 C 4.8411817 7.5307601 4.8668052 7.4579869 4.875 7.4375 z "
- inkscape:radius="0"
- sodipodi:type="inkscape:offset" />
- </g>
-</svg>
diff --git a/plugins/flake/textshape/pics/tool_references.svg b/plugins/flake/textshape/pics/tool_references.svg
deleted file mode 100644
index 3ab583588e..0000000000
--- a/plugins/flake/textshape/pics/tool_references.svg
+++ /dev/null
@@ -1,335 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- id="svg864"
- version="1.1"
- inkscape:version="0.48+devel r12017"
- width="20"
- height="20"
- sodipodi:docname="tool_references.svg"
- inkscape:export-xdpi="99"
- inkscape:export-ydpi="99"
- inkscape:export-filename="hi22-action-tool_references.png">
- <metadata
- id="metadata870">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <defs
- id="defs868">
- <marker
- inkscape:stockid="Arrow1Lend"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="Arrow1Lend"
- style="overflow:visible;"
- inkscape:isstock="true">
- <path
- id="path1260"
- d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
- style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
- transform="scale(0.8) rotate(180) translate(12.5,0)" />
- </marker>
- <marker
- inkscape:stockid="Arrow1Lstart"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="marker5177"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path5179"
- d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
- style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
- transform="scale(0.8) translate(12.5,0)" />
- </marker>
- <marker
- inkscape:stockid="Scissors"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="Scissors"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="schere"
- d="M 9.0898857,-3.6061018 C 8.1198849,-4.7769976 6.3697607,-4.7358294 5.0623558,-4.2327734 L -3.1500488,-1.1548705 C -5.5383421,-2.4615840 -7.8983361,-2.0874077 -7.8983361,-2.7236578 C -7.8983361,-3.2209742 -7.4416699,-3.1119800 -7.5100293,-4.4068519 C -7.5756648,-5.6501286 -8.8736064,-6.5699315 -10.100428,-6.4884954 C -11.327699,-6.4958500 -12.599867,-5.5553341 -12.610769,-4.2584343 C -12.702194,-2.9520479 -11.603560,-1.7387447 -10.304005,-1.6532027 C -8.7816644,-1.4265411 -6.0857470,-2.3487593 -4.8210600,-0.082342643 C -5.7633447,1.6559151 -7.4350844,1.6607341 -8.9465707,1.5737277 C -10.201445,1.5014928 -11.708664,1.8611256 -12.307219,3.0945882 C -12.885586,4.2766744 -12.318421,5.9591904 -10.990470,6.3210002 C -9.6502788,6.8128279 -7.8098011,6.1912892 -7.4910978,4.6502760 C -7.2454393,3.4624530 -8.0864637,2.9043186 -7.7636052,2.4731223 C -7.5199917,2.1477623 -5.9728246,2.3362771 -3.2164999,1.0982979 L 5.6763468,4.2330688 C 6.8000164,4.5467672 8.1730685,4.5362646 9.1684433,3.4313614 L -0.051640930,- 0.053722219 L 9.0898857,-3.6061018 z M -9.2179159,-5.5066058 C -7.9233569,-4.7838060 -8.0290767,-2.8230356 -9.3743431,-2.4433169 C -10.590861,-2.0196559 -12.145370,-3.2022863 -11.757521,-4.5207817 C -11.530373,-5.6026336 -10.104134,-6.0014137 -9.2179159,-5.5066058 z M -9.1616516,2.5107591 C -7.8108215,3.0096239 -8.0402087,5.2951947 -9.4138723,5.6023681 C -10.324932,5.9187072 -11.627422,5.4635705 -11.719569,4.3902287 C -11.897178,3.0851737 -10.363484,1.9060805 -9.1616516,2.5107591 z "
- style="fill:#ffffff;stroke:#000000;stroke-opacity:1;fill-opacity:1" />
- </marker>
- <marker
- inkscape:stockid="StopS"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="StopS"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path5070"
- d="M 0.0,5.65 L 0.0,-5.65"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
- transform="scale(0.2)" />
- </marker>
- <marker
- inkscape:stockid="EmptyDiamondMstart"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="EmptyDiamondMstart"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path5013"
- d="M 0,-7.0710768 L -7.0710894,0 L 0,7.0710589 L 7.0710462,0 L 0,-7.0710768 z "
- style="fill-rule:evenodd;fill:#ffffff;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill-opacity:1"
- transform="scale(0.4) translate(6.5,0)" />
- </marker>
- <marker
- inkscape:stockid="EmptyDiamondSstart"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="EmptyDiamondSstart"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path5016"
- d="M 0,-7.0710768 L -7.0710894,0 L 0,7.0710589 L 7.0710462,0 L 0,-7.0710768 z "
- style="fill-rule:evenodd;fill:#ffffff;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill-opacity:1"
- transform="scale(0.2) translate(6,0)" />
- </marker>
- <marker
- inkscape:stockid="TriangleInL"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="TriangleInL"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path5028"
- d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
- style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
- transform="scale(-0.8)" />
- </marker>
- <marker
- inkscape:stockid="Arrow1Lstart"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="marker5163"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path5165"
- d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
- style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
- transform="scale(0.8) translate(12.5,0)" />
- </marker>
- <marker
- inkscape:stockid="Arrow2Lstart"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="Arrow2Lstart"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path4913"
- style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
- d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
- transform="scale(1.1) translate(1,0)" />
- </marker>
- <marker
- inkscape:stockid="Arrow2Lend"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="marker5157"
- style="overflow:visible;"
- inkscape:isstock="true">
- <path
- id="path5159"
- style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
- d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
- transform="scale(1.1) rotate(180) translate(1,0)" />
- </marker>
- <marker
- inkscape:stockid="Arrow1Mend"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="Arrow1Mend"
- style="overflow:visible;"
- inkscape:isstock="true">
- <path
- id="path4904"
- d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
- style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
- transform="scale(0.4) rotate(180) translate(10,0)" />
- </marker>
- <marker
- inkscape:stockid="Arrow1Lstart"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="Arrow1Lstart"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path4895"
- d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
- style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
- transform="scale(0.8) translate(12.5,0)" />
- </marker>
- <marker
- inkscape:stockid="Arrow2Lend"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="Arrow2Lend"
- style="overflow:visible;"
- inkscape:isstock="true">
- <path
- id="path4916"
- style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
- d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
- transform="scale(1.1) rotate(180) translate(1,0)" />
- </marker>
- <inkscape:path-effect
- effect="skeletal"
- id="path-effect4889"
- is_visible="true"
- pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
- copytype="single_stretched"
- prop_scale="1"
- scale_y_rel="false"
- spacing="0"
- normal_offset="0"
- tang_offset="0"
- prop_units="false"
- vertical_pattern="false"
- fuse_tolerance="0" />
- </defs>
- <sodipodi:namedview
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1"
- objecttolerance="10"
- gridtolerance="10"
- guidetolerance="10"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:window-width="1920"
- inkscape:window-height="1060"
- id="namedview866"
- showgrid="true"
- inkscape:zoom="43.45"
- inkscape:cx="6.3701458"
- inkscape:cy="10.120828"
- inkscape:window-x="-2"
- inkscape:window-y="-3"
- inkscape:window-maximized="1"
- inkscape:current-layer="svg864"
- showguides="true">
- <inkscape:grid
- type="xygrid"
- id="grid980" />
- </sodipodi:namedview>
- <path
- style="fill:none;stroke:#ffffff;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0.80000001;stroke-opacity:1;stroke-dasharray:none"
- d="m 9.8734172,3.2594937 5.1726128,0 0,4.4821634 0,0 0,0.04603"
- id="path1251-6"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccc" />
- <path
- sodipodi:type="inkscape:offset"
- inkscape:radius="1.4870844"
- inkscape:original="M 11.84375 5.75 C 11.779262 5.8616974 13.871023 9.46875 14 9.46875 C 14.128977 9.46875 16.220739 5.8616974 16.15625 5.75 C 16.091761 5.6383026 11.908238 5.6383026 11.84375 5.75 z "
- style="fill:#ffffff;fill-opacity:1;stroke:#fefeff;stroke-width:0.69999999;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:0.80000001;stroke-opacity:1;stroke-dasharray:none"
- id="path3358"
- d="m 12.46875,4.1875 c -0.215222,0.00747 -0.393616,0.016597 -0.5625,0.03125 -0.08444,0.00733 -0.165442,0.041815 -0.28125,0.0625 -0.0579,0.010342 -0.09099,0.019877 -0.21875,0.0625 -0.06388,0.021312 -0.151694,0.020428 -0.28125,0.09375 -0.06478,0.036661 -0.154235,0.1054587 -0.25,0.1875 -0.04788,0.041021 -0.101271,0.093137 -0.15625,0.15625 C 10.663771,4.8443629 10.562752,4.9995637 10.5625,5 c -2.52e-4,4.363e-4 -0.09783,0.2021361 -0.125,0.28125 -0.02717,0.079114 -0.05089,0.125485 -0.0625,0.1875 -0.02322,0.12403 -0.03189,0.2379091 -0.03125,0.3125 0.0013,0.1491818 0.01769,0.2150798 0.03125,0.28125 0.02713,0.1323404 0.07365,0.1945962 0.09375,0.25 0.0402,0.1108077 0.0578,0.1733477 0.09375,0.25 0.07191,0.1533046 0.148808,0.341836 0.25,0.53125 0.202383,0.3788281 0.47794,0.8433252 0.75,1.3125 0.27206,0.4691748 0.55301,0.9174201 0.78125,1.28125 0.11412,0.1819149 0.215243,0.330251 0.3125,0.46875 0.04863,0.06925 0.08025,0.128986 0.15625,0.21875 0.038,0.04488 0.08658,0.09845 0.1875,0.1875 0.05046,0.04453 0.121851,0.11237 0.25,0.1875 0.06407,0.03757 0.131416,0.08339 0.25,0.125 0.05929,0.0208 0.136924,0.04658 0.21875,0.0625 0.08183,0.01592 0.280746,0.03125 0.28125,0.03125 5.04e-4,0 0.199424,-0.01533 0.28125,-0.03125 0.08183,-0.01592 0.159458,-0.0417 0.21875,-0.0625 0.118584,-0.04161 0.185926,-0.08743 0.25,-0.125 0.128149,-0.07513 0.199538,-0.142973 0.25,-0.1875 0.100923,-0.08905 0.149502,-0.142618 0.1875,-0.1875 0.076,-0.08976 0.107621,-0.149501 0.15625,-0.21875 0.09726,-0.138498 0.19838,-0.2868351 0.3125,-0.46875 0.22824,-0.3638299 0.50919,-0.8120752 0.78125,-1.28125 0.27206,-0.4691748 0.547616,-0.9336717 0.75,-1.3125 0.101192,-0.1894141 0.178092,-0.377945 0.25,-0.53125 0.03595,-0.076652 0.05355,-0.1391916 0.09375,-0.25 0.0201,-0.055404 0.06662,-0.1176584 0.09375,-0.25 0.01356,-0.066171 0.02997,-0.132067 0.03125,-0.28125 6.43e-4,-0.074592 -0.008,-0.1884694 -0.03125,-0.3125 -0.01161,-0.062015 -0.03533,-0.1083859 -0.0625,-0.1875 C 17.535327,5.2021359 17.437752,5.0004363 17.4375,5 17.437248,4.9995637 17.336229,4.8443621 17.28125,4.78125 17.226271,4.7181379 17.172882,4.6660201 17.125,4.625 c -0.09577,-0.08204 -0.185222,-0.1508396 -0.25,-0.1875 -0.129555,-0.073321 -0.21737,-0.072439 -0.28125,-0.09375 -0.12776,-0.042623 -0.192096,-0.052158 -0.25,-0.0625 -0.115808,-0.020685 -0.165558,-0.055174 -0.25,-0.0625 -0.168884,-0.014653 -0.347278,-0.02378 -0.5625,-0.03125 -0.430445,-0.01494 -0.987215,0 -1.53125,0 C 13.455965,4.1875 12.899195,4.1725603 12.46875,4.1875 Z"
- transform="matrix(0.75294531,0,0,0.79940288,4.4642413,1.5938059)" />
- <path
- sodipodi:type="inkscape:offset"
- inkscape:radius="0.82853854"
- inkscape:original="M 12.8125 10.90625 L 12.8125 19.53125 L 16.3125 19.53125 C 16.735677 19.53125 17.148763 19.464518 17.53125 19.375 C 17.913737 19.285482 18.24235 19.159993 18.53125 18.96875 C 18.82015 18.773438 19.047852 18.523926 19.21875 18.21875 C 19.389648 17.909505 19.46875 17.529134 19.46875 17.09375 C 19.46875 16.812988 19.437337 16.552572 19.34375 16.3125 C 19.250163 16.068359 19.116536 15.870605 18.9375 15.6875 C 18.758464 15.504395 18.518555 15.336751 18.25 15.21875 C 17.985514 15.100749 17.689616 15.00944 17.34375 14.96875 C 17.616374 14.907715 17.859049 14.84082 18.0625 14.71875 C 18.27002 14.592611 18.428223 14.420898 18.5625 14.25 C 18.700846 14.075033 18.809896 13.899089 18.875 13.6875 C 18.944173 13.475911 18.96875 13.240072 18.96875 13 C 18.96875 12.633789 18.919596 12.322917 18.78125 12.0625 C 18.646973 11.798014 18.447917 11.577148 18.1875 11.40625 C 17.927083 11.235352 17.593099 11.108561 17.21875 11.03125 C 16.844401 10.94987 16.413574 10.90625 15.9375 10.90625 L 12.8125 10.90625 z M 14 11.84375 L 15.9375 11.84375 C 16.539714 11.84375 17.026367 11.956868 17.34375 12.15625 C 17.661133 12.355632 17.8125 12.692383 17.8125 13.15625 C 17.8125 13.375977 17.783854 13.575033 17.71875 13.75 C 17.653646 13.924967 17.552734 14.061361 17.40625 14.1875 C 17.259766 14.30957 17.048503 14.399577 16.8125 14.46875 C 16.576497 14.533854 16.279297 14.5625 15.9375 14.5625 L 14 14.5625 L 14 11.84375 z M 14 15.46875 L 16.15625 15.46875 C 16.481771 15.46875 16.770833 15.505534 17.03125 15.5625 C 17.295736 15.619466 17.531576 15.72168 17.71875 15.84375 C 17.905924 15.96582 18.058594 16.121257 18.15625 16.3125 C 18.257975 16.503743 18.3125 16.727376 18.3125 17 C 18.3125 17.305176 18.257975 17.577799 18.15625 17.78125 C 18.054525 17.984701 17.901855 18.12793 17.71875 18.25 C 17.539714 18.37207 17.314779 18.451172 17.0625 18.5 C 16.81429 18.548828 16.547038 18.59375 16.25 18.59375 L 14 18.59375 L 14 15.46875 z "
- style="font-size:12.5px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#fffffd;fill-opacity:1;stroke:none;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
- id="path1249"
- d="m 12.8125,10.0625 a 0.82862139,0.82862139 0 0 0 -0.84375,0.84375 l 0,8.625 A 0.82862139,0.82862139 0 0 0 12.8125,20.375 l 3.5,0 c 0.51028,0 0.98384,-0.08864 1.40625,-0.1875 0.447249,-0.104675 0.890319,-0.272465 1.28125,-0.53125 0.392796,-0.265551 0.707374,-0.620309 0.9375,-1.03125 0.257664,-0.46625 0.375,-0.995512 0.375,-1.53125 0,-0.333054 -0.0528,-0.702352 -0.1875,-1.0625 -0.0032,-0.0083 0.0033,-0.02296 0,-0.03125 l -0.03125,0 c -0.134748,-0.333814 -0.328521,-0.666953 -0.5625,-0.90625 -0.110409,-0.112919 -0.275869,-0.154777 -0.40625,-0.25 0.02404,-0.0291 0.07202,-0.0661 0.09375,-0.09375 0.174572,-0.220783 0.333884,-0.475746 0.4375,-0.8125 0.107666,-0.329332 0.15625,-0.640881 0.15625,-0.9375 0,-0.44035 -0.08413,-0.88263 -0.3125,-1.3125 l 0.03125,0 c -0.199615,-0.393183 -0.502735,-0.724452 -0.875,-0.96875 -0.366993,-0.240838 -0.806318,-0.405629 -1.25,-0.5 -0.0093,-0.002 -0.02189,0.002 -0.03125,0 -0.435729,-0.09232 -0.921897,-0.15625 -1.4375,-0.15625 L 12.8125,10.0625 z m 2.03125,2.625 1.09375,0 c 0.498461,0 0.854884,0.08472 0.96875,0.15625 0.06202,0.03896 0.0625,0.02888 0.0625,0.3125 0,0.147715 -0.01007,0.255579 -0.03125,0.3125 -0.0166,0.0446 0.0028,0.03754 -0.0625,0.09375 6.18e-4,-5.15e-4 -0.103336,0.07285 -0.28125,0.125 l 0,-0.03125 c -0.124168,0.03425 -0.360746,0.0625 -0.65625,0.0625 l -1.09375,0 L 14.84375,12.6875 z m 0,3.625 1.3125,0 c 0.263104,0 0.479382,0.01697 0.6875,0.0625 0.164165,0.03536 0.339802,0.09253 0.4375,0.15625 0.09028,0.05888 0.103709,0.114556 0.125,0.15625 a 0.82862139,0.82862139 0 0 0 0.03125,0 c 0.03361,0.06318 0.03125,0.150348 0.03125,0.3125 0,0.206487 -0.04022,0.361681 -0.0625,0.40625 -0.02299,0.04599 -0.04517,0.0822 -0.15625,0.15625 -0.04981,0.03396 -0.165163,0.09043 -0.34375,0.125 C 16.674126,17.733164 16.463503,17.75 16.25,17.75 l -1.40625,0 L 14.84375,16.3125 Z"
- transform="translate(-0.27617952,-0.29919448)" />
- <path
- sodipodi:type="inkscape:offset"
- inkscape:radius="0.68576401"
- inkscape:original="M 4.09375 6.25 A 0.31545968 0.31545968 0 0 0 3.96875 6.375 A 0.31545968 0.31545968 0 0 0 3.9375 6.4375 L 0.40625 15.09375 A 0.31545968 0.31545968 0 0 0 0.5625 15.5 A 0.31545968 0.31545968 0 0 0 0.6875 15.53125 L 1.90625 15.53125 A 0.31545968 0.31545968 0 0 0 2.1875 15.34375 L 3.09375 13 L 6.625 13 L 7.53125 15.34375 A 0.31545968 0.31545968 0 0 0 7.53125 15.375 A 0.31545968 0.31545968 0 0 0 7.65625 15.5 A 0.31545968 0.31545968 0 0 0 7.8125 15.53125 L 9.03125 15.53125 A 0.31545968 0.31545968 0 0 0 9.3125 15.09375 L 5.8125 6.4375 A 0.31545968 0.31545968 0 0 0 5.78125 6.375 A 0.31545968 0.31545968 0 0 0 5.75 6.34375 A 0.31545968 0.31545968 0 0 0 5.71875 6.3125 A 0.31545968 0.31545968 0 0 0 5.53125 6.25 L 4.21875 6.25 A 0.31545968 0.31545968 0 0 0 4.125 6.25 A 0.31545968 0.31545968 0 0 0 4.09375 6.25 z M 4.84375 8.4375 C 4.8518272 8.4602721 4.8668649 8.4761759 4.875 8.5 A 0.31545968 0.31545968 0 0 0 4.90625 8.5 C 4.9673227 8.6669319 5.0254134 8.8604084 5.09375 9.03125 L 6.03125 11.46875 L 3.6875 11.46875 L 4.625 9.0625 C 4.6842356 8.9045384 4.7823033 8.711201 4.84375 8.53125 L 4.8125 8.53125 C 4.8252024 8.4965301 4.8320576 8.47121 4.84375 8.4375 z "
- style="font-size:12.58717155px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
- id="path1222"
- d="M 4,5.5625 A 0.68583259,0.68583259 0 0 0 3.75,5.65625 c 0.00768,-0.00421 -0.069867,0.035997 -0.0625,0.03125 0.00737,-0.00475 -0.038261,0.036507 -0.03125,0.03125 0.00701,-0.00526 -0.069121,0.068242 -0.0625,0.0625 0.00662,-0.00574 -0.068697,0.037447 -0.0625,0.03125 0.0062,-0.0062 -0.036992,0.069121 -0.03125,0.0625 0.00574,-0.00662 -0.067757,0.069511 -0.0625,0.0625 0.00526,-0.00701 -0.035997,0.038617 -0.03125,0.03125 0.0019,-0.00295 0.00775,0.018187 0,0.03125 -0.01162,0.019594 -0.033777,0.035861 -0.03125,0.03125 -0.00619,0.010132 -0.00136,0.033629 0,0.03125 0.0034,-0.00595 -0.034313,0.037376 -0.03125,0.03125 0.00306,-0.00613 -0.033969,0.068787 -0.03125,0.0625 0.00136,-0.00314 0.00579,0.016765 0,0.03125 l -3.53125,8.65625 c 0.002256,-0.0054 -0.0332451,0.03677 -0.03125,0.03125 0.001995,-0.0055 -0.00173,0.03686 0,0.03125 0.00173,-0.0056 -0.0327111,0.06819 -0.03125,0.0625 0.001461,-0.0057 -0.001189,0.037 0,0.03125 0.001189,-0.0058 -9.1394e-4,0.0683 0,0.0625 9.1394e-4,-0.0058 -0.0318869,0.03709 -0.03125,0.03125 6.3694e-4,-0.0058 -3.5849e-4,0.06836 0,0.0625 3.5849e-4,-0.0059 -7.924e-5,0.03712 0,0.03125 7.924e-5,-0.0059 2.002e-4,0.06837 0,0.0625 -2.002e-4,-0.0059 4.7918e-4,0.0371 0,0.03125 -4.7918e-4,-0.0059 0.0320071,0.06832 0.03125,0.0625 -7.5707e-4,-0.0058 0.001033,0.06828 0,0.0625 -0.001033,-0.0058 0.001307,0.03698 0,0.03125 -0.001307,-0.0057 0.001578,0.03691 0,0.03125 -0.001578,-0.0057 0.0330953,0.06808 0.03125,0.0625 -0.001845,-0.0056 0.002108,0.03673 0,0.03125 -0.002108,-0.0055 0.0336168,0.06788 0.03125,0.0625 -0.002367,-0.0054 0.0338698,0.03651 0.03125,0.03125 -0.00262,-0.0053 0.002867,0.06763 0,0.0625 -0.002867,-0.0051 0.0343575,0.03623 0.03125,0.03125 -0.003107,-0.005 0.034591,0.03608 0.03125,0.03125 -0.003341,-0.0048 0.034817,0.03592 0.03125,0.03125 -0.003567,-0.0047 0.03503491,0.06699 0.03125,0.0625 -0.0037849,-0.0045 0.03524425,0.03556 0.03125,0.03125 -0.0039942,-0.0043 0.03544456,0.03536 0.03125,0.03125 -0.00419456,-0.0041 0.03563536,0.03516 0.03125,0.03125 -0.0043854,-0.0039 0.03581624,0.03494 0.03125,0.03125 -0.0045662,-0.0037 0.03598679,0.03472 0.03125,0.03125 -0.0047368,-0.0035 0.06739661,0.03449 0.0625,0.03125 -0.004897,-0.0032 0.0362953,0.003 0.03125,0 -0.005045,-0.003 0.0364327,0.03401 0.03125,0.03125 -0.00311,-0.0017 0.0176167,0.02437 0.03125,0.03125 0.009089,0.0046 0.0333733,0.001 0.03125,0 0.0131692,0.006 0.0341738,0.0012 0.03125,0 -0.005848,-0.0025 0.0372166,0.03341 0.03125,0.03125 -0.005967,-0.0022 0.0685699,0.0331 0.0625,0.03125 -0.00607,-0.0019 0.0686572,0.0015 0.0625,0 -0.006157,-0.0015 0.0374781,0.0012 0.03125,0 -0.006228,-0.0012 0.0687826,0.03215 0.0625,0.03125 -0.006283,-8.99e-4 0.0375705,5.75e-4 0.03125,0 -0.006321,-5.75e-4 0.0688417,2.49e-4 0.0625,0 a 0.68583259,0.68583259 0 0 0 0.03125,0 l 1.21875,0 c -0.00872,1.97e-4 0.1024359,-8.13e-4 0.09375,0 -0.00869,8.13e-4 0.071107,-0.0014 0.0625,0 -0.00861,0.0014 0.070985,-0.03328 0.0625,-0.03125 -0.00848,0.002 0.07082,-0.03387 0.0625,-0.03125 -0.00832,0.0026 0.1018645,-0.0032 0.09375,0 -0.00811,0.0032 0.070368,-0.03502 0.0625,-0.03125 -0.00787,0.0038 0.070082,-0.03556 0.0625,-0.03125 -0.00758,0.0043 0.069759,-0.03609 0.0625,-0.03125 -0.00726,0.0048 0.038149,-0.06784 0.03125,-0.0625 -0.0069,0.0053 0.069005,-0.03706 0.0625,-0.03125 -0.0065,0.0058 0.068578,-0.06876 0.0625,-0.0625 -0.00608,0.0063 0.036871,-0.03792 0.03125,-0.03125 -0.00562,0.0067 0.067636,-0.06955 0.0625,-0.0625 -0.00514,0.0071 0.035875,-0.0699 0.03125,-0.0625 -0.00462,0.0074 0.035341,-0.0702 0.03125,-0.0625 -0.00409,0.0077 0.034786,-0.07048 0.03125,-0.0625 a 0.68583259,0.68583259 0 0 0 0,-0.03125 l 0.75,-1.90625 2.59375,0 0.6875,1.71875 0,0.03125 a 0.68583259,0.68583259 0 0 0 0.03125,0.09375 0.68583259,0.68583259 0 0 0 0.0625,0.1875 c -0.00421,-0.0077 0.035997,0.06987 0.03125,0.0625 -0.00475,-0.0074 0.036507,0.03826 0.03125,0.03125 -0.00526,-0.007 0.068242,0.06912 0.0625,0.0625 -0.00574,-0.0066 0.037447,0.0687 0.03125,0.0625 -0.0062,-0.0062 0.069121,0.03699 0.0625,0.03125 -0.00662,-0.0057 0.069511,0.06776 0.0625,0.0625 -0.00701,-0.0053 0.038617,0.036 0.03125,0.03125 -0.00737,-0.0047 0.070185,0.03546 0.0625,0.03125 A 0.68583259,0.68583259 0 0 0 7.34375,16.125 c -0.00709,-0.0034 0.069791,0.03424 0.0625,0.03125 -0.00729,-0.003 0.069966,0.0025 0.0625,0 -0.00747,-0.0025 0.070112,0.03328 0.0625,0.03125 -0.00761,-0.002 0.070226,0.0015 0.0625,0 -0.00773,-0.0015 0.070309,0.0323 0.0625,0.03125 -0.00781,-0.001 0.07036,5.49e-4 0.0625,0 -0.00786,-5.49e-4 0.070379,4.7e-5 0.0625,0 -0.00394,-2.3e-5 0.013313,4.67e-4 0.03125,0 0.017937,-4.67e-4 0.035183,-2.28e-4 0.03125,0 l 1.1875,0 a 0.68583259,0.68583259 0 0 0 0.03125,0 c -0.00747,2.27e-4 0.069945,-6.79e-4 0.0625,0 -0.00745,6.79e-4 0.06989,-0.0011 0.0625,0 -0.00739,0.0011 0.038559,-0.03282 0.03125,-0.03125 -0.00731,0.0016 0.0697,-0.002 0.0625,0 -0.0072,0.002 0.069565,-0.0337 0.0625,-0.03125 -0.00706,0.0024 0.069404,-0.03412 0.0625,-0.03125 -0.0069,0.0029 0.069218,-0.0033 0.0625,0 -0.00672,0.0033 0.037757,-0.03493 0.03125,-0.03125 -0.00651,0.0037 0.068772,-0.03532 0.0625,-0.03125 -0.00627,0.0041 0.068514,-0.03569 0.0625,-0.03125 -0.00601,0.0044 0.036984,-0.0673 0.03125,-0.0625 -0.00573,0.0048 0.067933,-0.03638 0.0625,-0.03125 -0.00543,0.0051 0.036363,-0.0367 0.03125,-0.03125 -0.00511,0.0055 0.036023,-0.06825 0.03125,-0.0625 -0.00477,0.0058 0.066916,-0.03728 0.0625,-0.03125 -0.00442,0.006 0.035293,-0.06879 0.03125,-0.0625 -0.00404,0.0063 0.034905,-0.03777 0.03125,-0.03125 -0.00365,0.0065 0.034503,-0.06923 0.03125,-0.0625 -0.00325,0.0067 0.00284,-0.06942 0,-0.0625 -0.00284,0.0069 0.033666,-0.06958 0.03125,-0.0625 -0.00242,0.0071 0.033233,-0.06971 0.03125,-0.0625 -0.00198,0.0072 0.0015,-0.03857 0,-0.03125 -0.00154,0.0073 0.0011,-0.0699 0,-0.0625 -0.0011,0.0074 0.0319,-0.06995 0.03125,-0.0625 -6.48e-4,0.0074 1.96e-4,-0.06997 0,-0.0625 -1.96e-4,0.0075 -2.57e-4,-0.06997 0,-0.0625 2.57e-4,0.0075 -7.08e-4,-0.06994 0,-0.0625 7.08e-4,0.0074 -0.032408,-0.06989 -0.03125,-0.0625 0.0012,0.0074 -0.0016,-0.0698 0,-0.0625 0.0016,0.0073 -0.00204,-0.06969 0,-0.0625 0.002,0.0072 -0.033723,-0.06955 -0.03125,-0.0625 0.00247,0.0071 -0.034146,-0.03814 -0.03125,-0.03125 l -3.5,-8.65625 c -0.00579,-0.014485 -0.00136,-0.034393 0,-0.03125 0.00272,0.00629 -0.034313,-0.068626 -0.03125,-0.0625 C 6.4093132,6.0998764 6.3716017,6.0565529 6.375,6.0625 6.3783983,6.0684471 6.3400271,5.9942506 6.34375,6 A 0.68583259,0.68583259 0 0 0 6.3125,5.9375 C 6.3153376,5.9407662 6.2946874,5.920664 6.28125,5.90625 6.2840876,5.9095162 6.2634374,5.889414 6.25,5.875 6.2530594,5.8780594 6.233164,5.8571874 6.21875,5.84375 6.2218094,5.8468094 6.201914,5.8259374 6.1875,5.8125 6.173086,5.7990626 6.1529838,5.7784124 6.15625,5.78125 A 0.68583259,0.68583259 0 0 0 6.125,5.75 c 0.00788,0.00587 -0.070827,-0.036479 -0.0625,-0.03125 0.00833,0.00523 -0.071216,-0.0358 -0.0625,-0.03125 0.00872,0.00455 -0.1028008,-0.035092 -0.09375,-0.03125 0.00905,0.00384 -0.071828,-0.034359 -0.0625,-0.03125 0.00933,0.00311 -0.072046,-0.033607 -0.0625,-0.03125 0.00955,0.00236 -0.1034529,-0.03284 -0.09375,-0.03125 0.0097,0.00159 -0.072299,-8.13e-4 -0.0625,0 0.0098,8.13e-4 -0.1035823,-3.07e-5 -0.09375,0 l -1.21875,0 -0.0625,0 c 0.00459,3.429e-4 -0.010303,7.814e-4 -0.03125,0 -0.020947,-7.814e-4 -0.035852,0 -0.03125,0 0.00307,0 -0.019179,-4.884e-4 -0.03125,0 -0.012071,4.884e-4 -0.019176,-4.122e-4 -0.03125,0 0.00306,0 -0.017324,-3.451e-4 -0.03125,0 0.00459,-3.429e-4 -0.01042,-0.00234 -0.03125,0 a 0.68583259,0.68583259 0 0 0 -0.03125,0 A 0.68583259,0.68583259 0 0 0 4,5.5625 z m 0.875,4.75 0.15625,0.46875 -0.34375,0 L 4.875,10.3125 Z"
- transform="matrix(1.0234068,0,0,0.97712853,0.18223308,-5.4165706)" />
- <path
- sodipodi:type="inkscape:offset"
- inkscape:radius="0"
- inkscape:original="M 4.21875 6.5625 L 0.6875 15.21875 L 1.90625 15.21875 L 2.875 12.6875 L 6.84375 12.6875 L 7.8125 15.21875 L 9.03125 15.21875 L 5.53125 6.5625 L 4.21875 6.5625 z M 4.875 7.4375 C 4.8790974 7.4579869 4.8775683 7.5307601 4.90625 7.625 C 4.9390291 7.7151425 4.9861787 7.8294389 5.03125 7.96875 C 5.0763213 8.1039638 5.1301366 8.2382572 5.1875 8.40625 C 5.2489608 8.5742428 5.3094418 8.7423545 5.375 8.90625 L 6.46875 11.78125 L 3.25 11.78125 L 4.34375 8.9375 C 4.4052108 8.7736045 4.4738866 8.6054928 4.53125 8.4375 C 4.5927108 8.2695072 4.6424287 8.1080611 4.6875 7.96875 C 4.7366686 7.8294389 4.7838183 7.7192399 4.8125 7.625 C 4.8411817 7.5307601 4.8668052 7.4579869 4.875 7.4375 z "
- style="font-size:12.58717155px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
- id="path1180"
- d="m 4.21875,6.5625 -3.53125,8.65625 1.21875,0 0.96875,-2.53125 3.96875,0 0.96875,2.53125 1.21875,0 -3.5,-8.65625 L 4.21875,6.5625 Z M 4.875,7.4375 c 0.0041,0.020487 0.00257,0.09326 0.03125,0.1875 0.032779,0.090142 0.079929,0.2044389 0.125,0.34375 0.045071,0.1352138 0.098887,0.2695072 0.15625,0.4375 0.061461,0.1679928 0.1219418,0.3361045 0.1875,0.5 l 1.09375,2.875 -3.21875,0 L 4.34375,8.9375 C 4.4052108,8.7736045 4.4738866,8.6054928 4.53125,8.4375 4.5927108,8.2695072 4.6424287,8.1080611 4.6875,7.96875 4.7366686,7.8294389 4.7838183,7.7192399 4.8125,7.625 4.8411817,7.5307601 4.8668052,7.4579869 4.875,7.4375 Z"
- transform="matrix(1.0234068,0,0,0.97712853,0.18411968,-5.4085155)" />
- <path
- sodipodi:type="inkscape:offset"
- inkscape:radius="0.31319982"
- inkscape:original="M 4.21875 6.5625 L 0.6875 15.21875 L 1.90625 15.21875 L 2.875 12.6875 L 6.84375 12.6875 L 7.8125 15.21875 L 9.03125 15.21875 L 5.53125 6.5625 L 4.21875 6.5625 z M 4.875 7.4375 C 4.8790974 7.4579869 4.8775683 7.5307601 4.90625 7.625 C 4.9390291 7.7151425 4.9861787 7.8294389 5.03125 7.96875 C 5.0763213 8.1039638 5.1301366 8.2382572 5.1875 8.40625 C 5.2489608 8.5742428 5.3094418 8.7423545 5.375 8.90625 L 6.46875 11.78125 L 3.25 11.78125 L 4.34375 8.9375 C 4.4052108 8.7736045 4.4738866 8.6054928 4.53125 8.4375 C 4.5927108 8.2695072 4.6424287 8.1080611 4.6875 7.96875 C 4.7366686 7.8294389 4.7838183 7.7192399 4.8125 7.625 C 4.8411817 7.5307601 4.8668052 7.4579869 4.875 7.4375 z "
- style="font-size:12.58717155px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:0;stroke:none;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
- id="path1200"
- d="M 4.125,6.25 A 0.31323114,0.31323114 0 0 0 4.03125,6.3125 0.31323114,0.31323114 0 0 0 3.9375,6.4375 L 0.40625,15.09375 A 0.31323114,0.31323114 0 0 0 0.5625,15.5 a 0.31323114,0.31323114 0 0 0 0.125,0.03125 l 1.21875,0 a 0.31323114,0.31323114 0 0 0 0.1875,-0.0625 0.31323114,0.31323114 0 0 0 0.09375,-0.125 L 3.09375,13 6.625,13 7.53125,15.34375 a 0.31323114,0.31323114 0 0 0 0.09375,0.125 0.31323114,0.31323114 0 0 0 0.1875,0.0625 l 1.21875,0 a 0.31323114,0.31323114 0 0 0 0.1875,-0.0625 0.31323114,0.31323114 0 0 0 0.09375,-0.375 L 5.8125,6.4375 A 0.31323114,0.31323114 0 0 0 5.78125,6.375 0.31323114,0.31323114 0 0 0 5.71875,6.3125 0.31323114,0.31323114 0 0 0 5.53125,6.25 l -1.3125,0 A 0.31323114,0.31323114 0 0 0 4.125,6.25 z m 0.75,2.15625 c 0.011155,0.031099 0.019974,0.060728 0.03125,0.09375 0.061075,0.1669394 0.119183,0.3604575 0.1875,0.53125 l 0.9375,2.4375 -2.34375,0 L 4.625,9.0625 C 4.6842513,8.9044965 4.7510821,8.7111166 4.8125,8.53125 4.8304259,8.4822525 4.8590433,8.4531247 4.875,8.40625 Z"
- transform="matrix(1.0234068,0,0,0.97712853,-0.34711051,-3.414843)" />
- <text
- xml:space="preserve"
- style="font-size:12.5px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
- x="11.50748"
- y="19.263521"
- id="text1224"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan1226"
- x="11.50748"
- y="19.263521">B</tspan></text>
- <path
- style="fill:none;stroke:#000000;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0.80000001;stroke-opacity:1;stroke-dasharray:none"
- d="m 10.794016,3.250863 4.252014,0 0,4.4821634 0,0 0,0.04603"
- id="path1251"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:type="star"
- style="fill:#010102;fill-opacity:1;stroke:#000000;stroke-width:0.69999999;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:0.80000001;stroke-opacity:1;stroke-dasharray:none"
- id="path3324"
- sodipodi:sides="3"
- sodipodi:cx="14"
- sodipodi:cy="7"
- sodipodi:r1="2.4821634"
- sodipodi:r2="1.2410817"
- sodipodi:arg1="1.5707963"
- sodipodi:arg2="2.6179939"
- inkscape:flatsided="true"
- inkscape:rounded="0.03"
- inkscape:randomized="0"
- d="m 14,9.4821634 c -0.128977,0 -2.214105,-3.6115477 -2.149617,-3.7232451 0.06449,-0.1116973 4.234745,-0.1116974 4.299234,-1e-7 C 16.214105,5.8706156 14.128977,9.4821634 14,9.4821634 Z"
- inkscape:transform-center-y="0.49606217"
- transform="matrix(0.75294531,0,0,0.79940288,4.4829315,1.5662862)" />
-</svg>
diff --git a/plugins/flake/textshape/pics/tool_review.svg b/plugins/flake/textshape/pics/tool_review.svg
deleted file mode 100644
index ffc5e82c8d..0000000000
--- a/plugins/flake/textshape/pics/tool_review.svg
+++ /dev/null
@@ -1,319 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- inkscape:export-filename="hi22-action-tool_review.png"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- sodipodi:docname="tool_review.svg"
- height="22"
- width="22"
- inkscape:version="0.48+devel r12050"
- version="1.1"
- id="svg864">
- <metadata
- id="metadata870">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <defs
- id="defs868">
- <inkscape:path-effect
- effect="bend_path"
- id="path-effect2448"
- is_visible="true"
- bendpath="m 2,20.535338 7,0"
- prop_scale="1"
- scale_y_rel="false"
- vertical="false" />
- <marker
- inkscape:stockid="Arrow1Lend"
- orient="auto"
- refY="0"
- refX="0"
- id="Arrow1Lend"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path1260"
- d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
- style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
- transform="matrix(-0.8,0,0,-0.8,-10,0)"
- inkscape:connector-curvature="0" />
- </marker>
- <marker
- inkscape:stockid="Arrow1Lstart"
- orient="auto"
- refY="0"
- refX="0"
- id="marker5177"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path5179"
- d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
- transform="matrix(0.8,0,0,0.8,10,0)"
- inkscape:connector-curvature="0" />
- </marker>
- <marker
- inkscape:stockid="Scissors"
- orient="auto"
- refY="0"
- refX="0"
- id="Scissors"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="schere"
- d="M 9.0898857,-3.6061018 C 8.1198849,-4.7769976 6.3697607,-4.7358294 5.0623558,-4.2327734 l -8.2124046,3.0779029 c -2.3882933,-1.3067135 -4.7482873,-0.9325372 -4.7482873,-1.5687873 0,-0.4973164 0.4566662,-0.3883222 0.3883068,-1.6831941 -0.065635,-1.2432767 -1.3635771,-2.1630796 -2.5903987,-2.0816435 -1.227271,-0.00735 -2.499439,0.9331613 -2.510341,2.2300611 -0.09143,1.3063864 1.007209,2.5196896 2.306764,2.6052316 1.5223406,0.2266616 4.218258,-0.6955566 5.482945,1.57086006 -0.9422847,1.73825774 -2.6140244,1.74307674 -4.1255107,1.65607034 -1.2548743,-0.072235 -2.7620933,0.2873979 -3.3606483,1.5208605 -0.578367,1.1820862 -0.0112,2.8646022 1.316749,3.226412 1.3401912,0.4918277 3.1806689,-0.129711 3.4993722,-1.6707242 0.2456585,-1.187823 -0.5953659,-1.7459574 -0.2725074,-2.1771537 0.2436135,-0.32536 1.7907806,-0.1368452 4.5471053,-1.3748244 L 5.6763468,4.2330688 C 6.8000164,4.5467672 8.1730685,4.5362646 9.1684433,3.4313614"
- style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-opacity:1"
- inkscape:connector-curvature="0" />
- </marker>
- <marker
- inkscape:stockid="StopS"
- orient="auto"
- refY="0"
- refX="0"
- id="StopS"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path5070"
- d="M 0,5.65 0,-5.65"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
- transform="scale(0.2,0.2)"
- inkscape:connector-curvature="0" />
- </marker>
- <marker
- inkscape:stockid="EmptyDiamondMstart"
- orient="auto"
- refY="0"
- refX="0"
- id="EmptyDiamondMstart"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path5013"
- d="M 0,-7.0710768 -7.0710894,0 0,7.0710589 7.0710462,0 0,-7.0710768 Z"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
- transform="matrix(0.4,0,0,0.4,2.6,0)"
- inkscape:connector-curvature="0" />
- </marker>
- <marker
- inkscape:stockid="EmptyDiamondSstart"
- orient="auto"
- refY="0"
- refX="0"
- id="EmptyDiamondSstart"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path5016"
- d="M 0,-7.0710768 -7.0710894,0 0,7.0710589 7.0710462,0 0,-7.0710768 Z"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
- transform="matrix(0.2,0,0,0.2,1.2,0)"
- inkscape:connector-curvature="0" />
- </marker>
- <marker
- inkscape:stockid="TriangleInL"
- orient="auto"
- refY="0"
- refX="0"
- id="TriangleInL"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path5028"
- d="m 5.77,0 -8.65,5 0,-10 L 5.77,0 Z"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
- transform="scale(-0.8,-0.8)"
- inkscape:connector-curvature="0" />
- </marker>
- <marker
- inkscape:stockid="Arrow1Lstart"
- orient="auto"
- refY="0"
- refX="0"
- id="marker5163"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path5165"
- d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
- transform="matrix(0.8,0,0,0.8,10,0)"
- inkscape:connector-curvature="0" />
- </marker>
- <marker
- inkscape:stockid="Arrow2Lstart"
- orient="auto"
- refY="0"
- refX="0"
- id="Arrow2Lstart"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path4913"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
- d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 Z"
- transform="matrix(1.1,0,0,1.1,1.1,0)"
- inkscape:connector-curvature="0" />
- </marker>
- <marker
- inkscape:stockid="Arrow2Lend"
- orient="auto"
- refY="0"
- refX="0"
- id="marker5157"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path5159"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
- d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 Z"
- transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
- inkscape:connector-curvature="0" />
- </marker>
- <marker
- inkscape:stockid="Arrow1Mend"
- orient="auto"
- refY="0"
- refX="0"
- id="Arrow1Mend"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path4904"
- d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
- transform="matrix(-0.4,0,0,-0.4,-4,0)"
- inkscape:connector-curvature="0" />
- </marker>
- <marker
- inkscape:stockid="Arrow1Lstart"
- orient="auto"
- refY="0"
- refX="0"
- id="Arrow1Lstart"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path4895"
- d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
- transform="matrix(0.8,0,0,0.8,10,0)"
- inkscape:connector-curvature="0" />
- </marker>
- <marker
- inkscape:stockid="Arrow2Lend"
- orient="auto"
- refY="0"
- refX="0"
- id="Arrow2Lend"
- style="overflow:visible"
- inkscape:isstock="true">
- <path
- id="path4916"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
- d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 Z"
- transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
- inkscape:connector-curvature="0" />
- </marker>
- <inkscape:path-effect
- effect="skeletal"
- id="path-effect4889"
- is_visible="true"
- pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
- copytype="single_stretched"
- prop_scale="1"
- scale_y_rel="false"
- spacing="0"
- normal_offset="0"
- tang_offset="0"
- prop_units="false"
- vertical_pattern="false"
- fuse_tolerance="0" />
- </defs>
- <sodipodi:namedview
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1"
- objecttolerance="10"
- gridtolerance="10"
- guidetolerance="10"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:window-width="1920"
- inkscape:window-height="1060"
- id="namedview866"
- showgrid="true"
- inkscape:zoom="43.45"
- inkscape:cx="9.2180344"
- inkscape:cy="11.923378"
- inkscape:window-x="-2"
- inkscape:window-y="-3"
- inkscape:window-maximized="1"
- inkscape:current-layer="svg864"
- showguides="true">
- <inkscape:grid
- type="xygrid"
- id="grid980" />
- </sodipodi:namedview>
- <path
- sodipodi:type="inkscape:offset"
- inkscape:radius="0.9489311"
- inkscape:original="M 20.5 1.40625 L 6.4375 1.5 L 6.46875 7.46875 L 11.5 7.46875 L 9.59375 11.5 L 15.25 7.46875 L 20.46875 7.46875 L 20.5 1.40625 z "
- style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
- id="path5789"
- d="M 20.5,0.46875 6.4375,0.5625 A 0.94902599,0.94902599 0 0 0 5.5,1.5 l 0.03125,5.96875 a 0.94902599,0.94902599 0 0 0 0.9375,0.9375 l 3.5625,0 -1.28125,2.6875 a 0.94902599,0.94902599 0 0 0 1.40625,1.1875 l 5.4375,-3.875 4.875,0 a 0.94902599,0.94902599 0 0 0 0.9375,-0.9375 L 21.4375,1.40625 A 0.94902599,0.94902599 0 0 0 20.5,0.46875 Z"
- transform="translate(0.08400457,0.05785811)" />
- <path
- sodipodi:type="inkscape:offset"
- inkscape:radius="0"
- inkscape:original="M 20.5 1.40625 L 6.4375 1.5 L 6.46875 7.46875 L 11.5 7.46875 L 9.59375 11.5 L 15.25 7.46875 L 20.46875 7.46875 L 20.5 1.40625 z "
- style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
- id="path5769"
- d="M 20.5,1.40625 6.4375,1.5 6.46875,7.46875 11.5,7.46875 9.59375,11.5 15.25,7.46875 l 5.21875,0 L 20.5,1.40625 Z" />
- <path
- style="fill:none;stroke:#ff0000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:4, 2;stroke-dashoffset:0"
- d="M 0.82663738,20.00691 9.9959834,20.03204"
- id="path2370"
- inkscape:connector-curvature="0" />
- <g
- transform="matrix(1.0206197,0,0,0.98222074,6.3930028,1.0300449)"
- style="font-size:10.35105133px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
- id="text2351-5-4">
- <path
- sodipodi:type="inkscape:offset"
- inkscape:radius="1.0171897"
- inkscape:original="M 4.84375 12.25 L 1.9375 19.375 L 2.9375 19.375 L 3.78125 17.3125 L 7.03125 17.3125 L 7.84375 19.375 L 8.8125 19.375 L 5.96875 12.25 L 4.84375 12.25 z M 5.40625 13 C 5.40962 13.016847 5.413914 13.047502 5.4375 13.125 C 5.464456 13.199129 5.494186 13.291688 5.53125 13.40625 C 5.5683144 13.517443 5.6090773 13.643101 5.65625 13.78125 C 5.706792 13.919399 5.758588 14.052721 5.8125 14.1875 L 6.71875 16.53125 L 4.0625 16.53125 L 4.96875 14.21875 C 5.0192923 14.083971 5.0778273 13.919399 5.125 13.78125 C 5.1755419 13.643101 5.2129353 13.520812 5.25 13.40625 C 5.2904333 13.291687 5.3201633 13.202498 5.34375 13.125 C 5.3673367 13.047501 5.3995113 13.016847 5.40625 13 z "
- id="path5727"
- d="M 4.84375,11.21875 A 1.0172915,1.0172915 0 0 0 3.90625,11.875 L 1,19 a 1.0172915,1.0172915 0 0 0 0.9375,1.40625 l 1,0 A 1.0172915,1.0172915 0 0 0 3.875,19.75 l 0.5625,-1.40625 1.90625,0 0.5625,1.40625 a 1.0172915,1.0172915 0 0 0 0.9375,0.65625 l 0.96875,0 A 1.0172915,1.0172915 0 0 0 9.75,19 L 6.90625,11.875 A 1.0172915,1.0172915 0 0 0 5.96875,11.21875 L 4.84375,11.21875 Z"
- style="fill:#ffffff;fill-opacity:1"
- transform="translate(-6.280171,-2.1322715)" />
- </g>
- <g
- transform="matrix(1.0206197,0,0,0.98222074,-0.02301496,-1.0423722)"
- style="font-size:10.35105133px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
- id="text2351">
- <path
- d="m 7.8294678,19.380388 -0.8137301,-2.08234 -3.244812,0 -0.8187843,2.08234 -1.0007364,0 2.906179,-7.121402 1.0967666,0 2.860691,7.121402 L 7.8294678,19.380388 Z M 5.8128324,14.194754 q -0.080868,-0.202169 -0.156681,-0.409392 -0.070759,-0.207223 -0.1263556,-0.374013 -0.055596,-0.171843 -0.09603,-0.283036 -0.035379,-0.116247 -0.040434,-0.141518 -0.010108,0.02527 -0.045488,0.141518 -0.03538,0.116247 -0.09603,0.288091 -0.055597,0.171843 -0.1314099,0.379066 -0.070759,0.207224 -0.1465725,0.409393 l -0.9097603,2.340105 2.6635762,0 L 5.8128324,14.194754 Z"
- id="path5628"
- inkscape:connector-curvature="0" />
- </g>
-</svg>
diff --git a/plugins/flake/textshape/textlayout/AnchorStrategy.cpp b/plugins/flake/textshape/textlayout/AnchorStrategy.cpp
deleted file mode 100644
index 23d0ec7b71..0000000000
--- a/plugins/flake/textshape/textlayout/AnchorStrategy.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007, 2009, 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2011 Matus Hanzes <matus.hanzes@ixonos.com>
- *
- * 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 "AnchorStrategy.h"
-
-#include "KoTextShapeContainerModel.h"
-#include "KoTextLayoutRootArea.h"
-
-#include <KoShapeContainer.h>
-
-#include <TextLayoutDebug.h>
-
-
-
-AnchorStrategy::AnchorStrategy(KoShapeAnchor *anchor, KoTextLayoutRootArea *rootArea)
- : m_anchor(anchor)
- , m_rootArea(rootArea)
- , m_model(0)
- , m_pageRect(0,0,10,10)
- , m_pageContentRect(0,0,10,10)
- , m_paragraphRect(0,0,0,0)
- , m_pageNumber(0)
-{
-}
-
-AnchorStrategy::~AnchorStrategy()
-{
- if (m_model)
- m_model->removeAnchor(m_anchor);
-}
-
-void AnchorStrategy::detachFromModel()
-{
- m_model = 0;
-}
-
-QRectF AnchorStrategy::pageRect() const
-{
- return m_pageRect;
-}
-
-void AnchorStrategy::setPageRect(const QRectF &pageRect)
-{
- m_pageRect = pageRect;
-}
-
-QRectF AnchorStrategy::pageContentRect() const
-{
- return m_pageContentRect;
-}
-
-void AnchorStrategy::setPageContentRect(const QRectF &pageContentRect)
-{
- m_pageContentRect = pageContentRect;
-}
-
-QRectF AnchorStrategy::paragraphRect() const
-{
- return m_paragraphRect;
-}
-
-void AnchorStrategy::setParagraphRect(const QRectF &paragraphRect)
-{
- m_paragraphRect = paragraphRect;
-}
-
-QRectF AnchorStrategy::paragraphContentRect() const
-{
- return m_paragraphContentRect;
-}
-
-void AnchorStrategy::setParagraphContentRect(const QRectF &paragraphContentRect)
-{
- m_paragraphContentRect = paragraphContentRect;
-}
-
-QRectF AnchorStrategy::layoutEnvironmentRect() const
-{
- return m_layoutEnvironmentRect;
-}
-
-void AnchorStrategy::setLayoutEnvironmentRect(const QRectF &layoutEnvironmentRect)
-{
- m_layoutEnvironmentRect = layoutEnvironmentRect;
-}
-
-int AnchorStrategy::pageNumber() const
-{
- return m_pageNumber;
-}
-
-void AnchorStrategy::setPageNumber(int pageNumber)
-{
- m_pageNumber = pageNumber;
-}
-
-void AnchorStrategy::updateContainerModel()
-{
- KoShape *shape = m_anchor->shape();
-
- KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(m_rootArea->associatedShape());
- if (container == 0) {
- if (m_model)
- m_model->removeAnchor(m_anchor);
- m_model = 0;
- shape->setParent(0);
- return;
- }
-
- KoTextShapeContainerModel *theModel = dynamic_cast<KoTextShapeContainerModel*>(container->model());
- if (theModel != m_model) {
- if (m_model)
- m_model->removeAnchor(m_anchor);
- if (shape->parent() != container) {
- if (shape->parent()) {
- shape->parent()->removeShape(shape);
- }
- container->addShape(shape);
- }
- m_model = theModel;
- m_model->addAnchor(m_anchor);
- }
- Q_ASSERT(m_model == theModel);
-}
diff --git a/plugins/flake/textshape/textlayout/AnchorStrategy.h b/plugins/flake/textshape/textlayout/AnchorStrategy.h
deleted file mode 100644
index 597fada8d2..0000000000
--- a/plugins/flake/textshape/textlayout/AnchorStrategy.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Matus Hanzes <matus.hanzes@ixonos.com>
- *
- * 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 ANCHORSTRATEGY_H_
-#define ANCHORSTRATEGY_H_
-
-#include "KoShapeAnchor.h"
-
-#include <QRectF>
-
-class KoTextShapeContainerModel;
-class KoTextLayoutRootArea;
-
-
-class AnchorStrategy : public KoShapeAnchor::PlacementStrategy
-{
-public:
- AnchorStrategy(KoShapeAnchor *anchor, KoTextLayoutRootArea *rootArea);
- ~AnchorStrategy() override;
-
- /**
- * Moves the subject to it's right position.
- *
- * @return true if subject was moved to a new position (or if it couldn't be calculated yet)
- */
- virtual bool moveSubject() = 0;
-
- void detachFromModel() override;
-
- /**
- * Reparent the anchored shape under the rootArea's container this AnchorStrategy acts for
- *
- * If needed changes the parent KoShapeContainerModel and KoShapeContainer of the anchored shape.
- * It is changed so the anchored shape is now under the rootArea
- */
- void updateContainerModel() override;
-
- /// get page rectangle coordinates to which this text anchor is anchored (needed for HPage)
- QRectF pageRect() const;
-
- /// set page rectangle coordinates to which this text anchor is anchored (needed for HPage)
- void setPageRect(const QRectF &pageRect);
-
- /// get content rectangle coordinates to which this text anchor is anchored (needed for
- /// HPageContent)
- QRectF pageContentRect() const;
-
- /// set content rectangle coordinates to which this text anchor is anchored (needed for
- /// HPageContent)
- void setPageContentRect(const QRectF &marginRect);
-
- /// get paragraph rectangle coordinates to which this text anchor is anchored (needed for
- /// HParagraphContent, HParagraphStartMargin, HParagraphEndMargin, VParagraph)
- QRectF paragraphRect() const;
-
- /// set paragraph rectangle to which this text anchor is anchored (needed for HParagraphContent,
- /// HParagraphStartMargin, HParagraphEndMargin, VParagraph)
- void setParagraphRect(const QRectF &paragraphRect);
-
- /// get paragraph rectangle coordinates to which this text anchor is anchored (needed for
- /// HParagraphContent, HParagraphStartMargin, HParagraphEndMargin)
- QRectF paragraphContentRect() const;
-
- /// set paragraph rectangle to which this text anchor is anchored (needed for HParagraphContent,
- /// HParagraphStartMargin, HParagraphEndMargin)
- void setParagraphContentRect(const QRectF &paragraphContentRect);
-
- /// get layout environment rectangle @see odf attribute style:flow-with-text
- QRectF layoutEnvironmentRect() const;
-
- /// set layout environment rect @see odf attribute style:flow-with-text
- void setLayoutEnvironmentRect(const QRectF &layoutEnvironmentRect);
-
- /// get number of page to which this text anchor is anchored (needed for HOutside, HInside,
- /// HFromInside)
- int pageNumber() const;
-
- /// set number of page to which this text anchor is anchored (needed for HOutside, HInside,
- /// HFromInside)
- void setPageNumber(int pageNumber);
-
-protected:
- KoShapeAnchor * const m_anchor;
- KoTextLayoutRootArea *m_rootArea;
-
-private:
- KoTextShapeContainerModel *m_model;
- QRectF m_pageRect;
- QRectF m_pageContentRect;
- QRectF m_paragraphRect;
- QRectF m_paragraphContentRect;
- QRectF m_layoutEnvironmentRect;
- int m_pageNumber;
-};
-
-#endif /* ANCHORSTRATEGY_H_ */
diff --git a/plugins/flake/textshape/textlayout/CMakeLists.txt b/plugins/flake/textshape/textlayout/CMakeLists.txt
deleted file mode 100644
index 3b6a938152..0000000000
--- a/plugins/flake/textshape/textlayout/CMakeLists.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-set(textlayout_LIB_SRCS
- KoTextLayoutCellHelper.cpp
- KoTextLayoutArea.cpp
- KoTextLayoutArea_paint.cpp
- KoTextLayoutEndNotesArea.cpp
- KoTextLayoutTableArea.cpp
- KoTextLayoutNoteArea.cpp
- KoTextLayoutRootArea.cpp
- KoTextLayoutRootAreaProvider.cpp
- KoTextDocumentLayout.cpp
- ListItemsHelper.cpp
- KoTextShapeContainerModel.cpp
- RunAroundHelper.cpp
- KoTextLayoutObstruction.cpp
- FrameIterator.cpp
- TableIterator.cpp
- KoPointedAt.cpp
- KoTextShapeData.cpp
- FloatingAnchorStrategy.cpp
- InlineAnchorStrategy.cpp
- AnchorStrategy.cpp
- ToCGenerator.cpp
- DummyDocumentLayout.cpp
- IndexGeneratorManager.cpp
- KoStyleThumbnailer.cpp
- TextLayoutDebug.cpp
-)
-
-
-add_library(kritatextlayout SHARED ${textlayout_LIB_SRCS})
-generate_export_header(kritatextlayout BASE_NAME kritatextlayout)
-
-target_link_libraries(kritatextlayout kritatext)
-target_link_libraries(kritatextlayout LINK_INTERFACE_LIBRARIES kritatext)
-
-set_target_properties(kritatextlayout PROPERTIES
- VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION}
-)
-install(TARGETS kritatextlayout ${INSTALL_TARGETS_DEFAULT_ARGS})
diff --git a/plugins/flake/textshape/textlayout/DESCRIPTION.txt b/plugins/flake/textshape/textlayout/DESCRIPTION.txt
deleted file mode 100644
index a89bda01f4..0000000000
--- a/plugins/flake/textshape/textlayout/DESCRIPTION.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-The text layout framework
--------------------------
-The data of the document is stored in a QTextDocument (with some resources set by the KoTextDocument helper class) The styles are stored in a KoStyleManager, and we have some other managers and helpers as needed.
-
-The layout of that document is handled by the KoTextDocumentLayout class. It builds a series of KoTextLayoutRootArea which roughly corresponds to a page, but since this is completely abstract such a root area could also be the cell in a spreadsheet. For both the spreadsheet case and a normal textshape only a single root area is created, but for Words we can create many root areas.
-
-A KoTextLayoutRootArea is a subclass of KoTextLayoutArea which is the main worker of text layout. Basically it represents the layout of a series of paragraphs. If there is a table in between the paragraphs it will create a new area, namely a KoTextLayoutTableArea.
-
-A KoTextLayoutTableArea holds a KoTextLayoutArea for each of the cells.
-
-Now if a table or paragraph is visible on more than one root area (page) then it is represented by one area for each page. So it is _not_ the same area but a new one that just start where the previous area ended (due to the page break).
-
-
-How we create a new KoTextLayoutRootArea
-----------------------------------------
-The KoTextDocumentLayout doesn't just create a new KoTextLayoutRootArea whenever it needs to. First of all it keeps a list of the root areas it already have, and only that number of root ares is too small or large do we add/remove root areas.
-
-The actual adding/removing of areas is done by the abstract class KoTextLayoutRootAreaProvider. It has a simple implementation in the TextShape that can only return one root area and that is it. It corresponds to there only being one textshape.
-
-In Words every KWTextFrameSet has an own KWRootAreaProvider. This way headers, footers and the main text have different providers. The provider can depend on each other to allow layouting in a defined order.
-
-In Calligra Sheets it would also be a simple provider with a root area corresponding to a cell.
-
-
-Trigging of (re)layout
-----------------------
-In order to always have an up to date layout of the current QTextDocument we have a system of marking root areas as dirty.
-A root area can be marked as dirty in several ways:
- * through KoTextDocumentLayout::documentChanged () which is called by Qt
- - this goes through all the root areas and marks them as dirty as needed
- * when any calls setDirty() on a root area (eg a shape does this when changing
- size og having collisions
-
-When a root area is marked as dirty it asks the KoTextDocumentLayout to emit a signal (layoutIsDirty) which other people can react to. The plain TextShape just connects that signal to KoTextDocumentLayout::scheduleLayout(). This will schedule a layout for later using QTimer::singleShot. If multiple layouts are scheduled they will be compressed to one single layout run.
-
-The KoTextDocumentLayout class provides the two methods layout() and scheduleLayout(). The first allows synchronous and the second asynchronous layouting.
-
-On layouting all root areas are checked if they are dirty. Those who are will be relayouted. If a root area is relayouted then the change may effect other root areas. This will be detected cause every root area keeps information where content started and ended using the FrameIterator class.
-
-
-FrameIterator and TableIterator
--------------------------------
-
-Iterators are used to mark positions within a QTextDocument. Every root area has a start- and end-iterator that presents a view on a part of the document.
-
-The start-iterator of a root area is the end-iterator of the previous root area.
-
-During layouting every root area becomes dirty and will be relayouted if the start-iterator doesn't match any longer to the end-iterator of the previous root area. This makes it possible to propagate changes within a root area as result of a relayout forward.
diff --git a/plugins/flake/textshape/textlayout/DummyDocumentLayout.cpp b/plugins/flake/textshape/textlayout/DummyDocumentLayout.cpp
deleted file mode 100644
index 1f653326e8..0000000000
--- a/plugins/flake/textshape/textlayout/DummyDocumentLayout.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2011 C. Boemann <cbo@boemann.dk>
- *
- * 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 "DummyDocumentLayout.h"
-
-#include <KoPostscriptPaintDevice.h>
-
-#include <QTextBlock>
-
-#include <TextLayoutDebug.h>
-
-// ------------------- DummyDocumentLayout --------------------
-DummyDocumentLayout::DummyDocumentLayout(QTextDocument *doc)
- : QAbstractTextDocumentLayout(doc)
-{
- setPaintDevice(new KoPostscriptPaintDevice());
-}
-
-DummyDocumentLayout::~DummyDocumentLayout()
-{
-}
-
-QRectF DummyDocumentLayout::blockBoundingRect(const QTextBlock &block) const
-{
- Q_UNUSED(block);
- return QRect();
-}
-
-QSizeF DummyDocumentLayout::documentSize() const
-{
- return QSizeF();
-}
-
-void DummyDocumentLayout::draw(QPainter *painter, const QAbstractTextDocumentLayout::PaintContext &context)
-{
- // WARNING Text shapes ask their root area directly to paint.
- // It saves a lot of extra traversal, that is quite costly for big
- // documents
- Q_UNUSED(painter);
- Q_UNUSED(context);
-}
-
-
-int DummyDocumentLayout::hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const
-{
- Q_UNUSED(point);
- Q_UNUSED(accuracy);
- Q_ASSERT(false); //we should not call this method.
- return -1;
-}
-
-QRectF DummyDocumentLayout::frameBoundingRect(QTextFrame*) const
-{
- return QRectF();
-}
-
-int DummyDocumentLayout::pageCount() const
-{
- return 1;
-}
-
-void DummyDocumentLayout::documentChanged(int position, int charsRemoved, int charsAdded)
-{
- Q_UNUSED(position);
- Q_UNUSED(charsRemoved);
- Q_UNUSED(charsAdded);
-}
-
-/*
-void DummyDocumentLayout::drawInlineObject(QPainter *, const QRectF &, QTextInlineObject , int , const QTextFormat &)
-{
-}
-
-// This method is called by qt every time QTextLine.setWidth()/setNumColumns() is called
-void DummyDocumentLayout::positionInlineObject(QTextInlineObject , int , const QTextFormat &)
-{
-}
-
-void DummyDocumentLayout::resizeInlineObject(QTextInlineObject , int , const QTextFormat &)
-{
-}
-*/
diff --git a/plugins/flake/textshape/textlayout/DummyDocumentLayout.h b/plugins/flake/textshape/textlayout/DummyDocumentLayout.h
deleted file mode 100644
index daf1febd14..0000000000
--- a/plugins/flake/textshape/textlayout/DummyDocumentLayout.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 C. Boemann <cbo@kogmbh.com>
- *
- * 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 DUMMYDOCUMENTLAYOUT_H
-#define DUMMYDOCUMENTLAYOUT_H
-
-#include "kritatextlayout_export.h"
-
-#include <QAbstractTextDocumentLayout>
-
-
-/**
- * Dummy TextLayouter that does nothing really, but without it the Table of Contents/Bibliography
- * can not be layout.TextLayouter
- * The real layout of the ToC/Bib still happens by the KoTextLayoutArea as part of
- * KoTextDocumentLayout of the main document
- *
- * You really shouldn't add anything to this class
- */
-
-class KRITATEXTLAYOUT_EXPORT DummyDocumentLayout : public QAbstractTextDocumentLayout
-{
- Q_OBJECT
-public:
- /// constructor
- explicit DummyDocumentLayout(QTextDocument *doc);
- ~DummyDocumentLayout() override;
-
- /// Returns the bounding rectangle of block.
- QRectF blockBoundingRect(const QTextBlock & block) const override;
- /**
- * Returns the total size of the document. This is useful to display
- * widgets since they can use to information to update their scroll bars
- * correctly
- */
- QSizeF documentSize() const override;
-
- /// Draws the layout on the given painter with the given context.
- void draw(QPainter * painter, const QAbstractTextDocumentLayout::PaintContext & context) override;
-
- QRectF frameBoundingRect(QTextFrame*) const override;
-
- /// reimplemented DO NOT CALL - USE HITTEST IN THE ROOTAREAS INSTEAD
- int hitTest(const QPointF & point, Qt::HitTestAccuracy accuracy) const override;
-
- /// reimplemented to always return 1
- int pageCount() const override;
-
- /// reimplemented from QAbstractTextDocumentLayout
- void documentChanged(int position, int charsRemoved, int charsAdded) override;
-/*
-protected:
- /// reimplemented
- virtual void drawInlineObject(QPainter *painter, const QRectF &rect, QTextInlineObject object, int position, const QTextFormat &format);
- /// reimplemented
- virtual void positionInlineObject(QTextInlineObject item, int position, const QTextFormat &format);
- /// reimplemented
- virtual void resizeInlineObject(QTextInlineObject item, int position, const QTextFormat &format);
-*/
-};
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/FloatingAnchorStrategy.cpp b/plugins/flake/textshape/textlayout/FloatingAnchorStrategy.cpp
deleted file mode 100644
index 7fcda80d02..0000000000
--- a/plugins/flake/textshape/textlayout/FloatingAnchorStrategy.cpp
+++ /dev/null
@@ -1,468 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007, 2009, 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2011 Matus Hanzes <matus.hanzes@ixonos.com>
- *
- * 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 "FloatingAnchorStrategy.h"
-
-#include "KoTextDocumentLayout.h"
-#include "KoTextLayoutObstruction.h"
-
-#include <KoShapeContainer.h>
-#include <KoTextShapeData.h>
-#include <KoTextLayoutRootArea.h>
-#include <KoAnchorTextRange.h>
-
-#include <TextLayoutDebug.h>
-
-#include <QTextLayout>
-#include <QTextBlock>
-
-FloatingAnchorStrategy::FloatingAnchorStrategy(KoAnchorTextRange *anchorRange, KoTextLayoutRootArea *rootArea)
- : AnchorStrategy(anchorRange->anchor(), rootArea)
- , m_obstruction(new KoTextLayoutObstruction(anchorRange->anchor()->shape(), QTransform()))
- , m_anchorRange(anchorRange)
-{
-}
-
-FloatingAnchorStrategy::~FloatingAnchorStrategy()
-{
-}
-
-
-void FloatingAnchorStrategy::updateObstruction(qreal documentOffset)
-{
- KoTextDocumentLayout *layout = dynamic_cast<KoTextDocumentLayout *>(m_anchorRange->document()->documentLayout());
-
- QTransform matrix = m_anchor->shape()->absoluteTransformation();
- matrix = matrix * m_anchor->shape()->parent()->absoluteTransformation().inverted();
- matrix.translate(0, documentOffset);
- m_obstruction->changeMatrix(matrix);
-
- layout->registerAnchoredObstruction(m_obstruction);
-}
-
-//should return true while we are still moving around
-bool FloatingAnchorStrategy::moveSubject()
-{
- if (!m_anchor->shape()->parent()) {
- return false; // let's fake we moved to force another relayout
- }
-
- // get the page data
- KoTextShapeData *data = qobject_cast<KoTextShapeData*>(m_anchor->shape()->parent()->userData());
- if (!data) {
- return false; // let's fake we moved to force another relayout
- }
-
- QTextBlock block = m_anchorRange->document()->findBlock(m_anchorRange->position());
- QTextLayout *layout = block.layout();
-
- // there should be always at least one line
- if (layout->lineCount() == 0) {
- return false; // let's fake we moved to force another relayout
- }
-
- // The bounding rect of the textshape in document coords
- QRectF containerBoundingRect = m_anchor->shape()->parent()->boundingRect();
-
- // The (to be calculated) reference rect for anchoring in document coords
- QRectF anchorBoundingRect;
-
- // This is in coords relative to texshape
- QPointF newPosition;
-
- QPointF offset;
- if (m_anchor->horizontalPos() == KoShapeAnchor::HFromLeft
- || m_anchor->horizontalPos() == KoShapeAnchor::HFromInside) {
- offset.setX(m_anchor->offset().x());
- }
- if (m_anchor->verticalPos() == KoShapeAnchor::VFromTop) {
- offset.setY(m_anchor->offset().y());
- }
-
- // set anchor bounding rectangle horizontal position and size
- if (!countHorizontalRel(anchorBoundingRect, containerBoundingRect, block, layout)) {
- return false; // let's fake we moved to force another relayout
- }
-
- // set anchor bounding rectangle vertical position
- if (!countVerticalRel(anchorBoundingRect, containerBoundingRect, data, block, layout)) {
- return false; // let's fake we moved to force another relayout
- }
-
- // Set shape horizontal alignment inside anchor bounding rectangle
- countHorizontalPos(newPosition, anchorBoundingRect);
-
- // Set shape vertical alignment inside anchor bounding rectangle
- countVerticalPos(newPosition, anchorBoundingRect);
-
- newPosition += offset;
-
- //check the border of page and move the shape back to have it visible
- checkPageBorder(newPosition);
-
- newPosition -= containerBoundingRect.topLeft();
-
- //check the border of layout environment and move the shape back to have it within
- if (m_anchor->flowWithText()) {
- checkLayoutEnvironment(newPosition, data);
- }
-
-
- checkStacking(newPosition);
-
- if (newPosition == m_anchor->shape()->position()) {
- if (m_anchor->shape()->textRunAroundSide() != KoShape::RunThrough) {
- updateObstruction(data->documentOffset());
- }
- return true;
- }
-
- // set the shape to the proper position based on the data
- m_anchor->shape()->update();
- m_anchor->shape()->setPosition(newPosition);
- m_anchor->shape()->update();
-
- if (m_anchor->shape()->textRunAroundSide() != KoShape::RunThrough) {
- updateObstruction(data->documentOffset());
- }
-
- return true;
-}
-
-bool FloatingAnchorStrategy::countHorizontalRel(QRectF &anchorBoundingRect, const QRectF &containerBoundingRect, QTextBlock &block, QTextLayout *layout)
-{
- switch (m_anchor->horizontalRel()) {
- case KoShapeAnchor::HPage:
- anchorBoundingRect.setX(pageRect().x());
- anchorBoundingRect.setWidth(pageRect().width());
- break;
-
- case KoShapeAnchor::HFrameContent:
- case KoShapeAnchor::HFrame:
- anchorBoundingRect.setX(containerBoundingRect.x());
- anchorBoundingRect.setWidth(containerBoundingRect.width());
- break;
-
- case KoShapeAnchor::HPageContent:
- anchorBoundingRect.setX(pageContentRect().x());
- anchorBoundingRect.setWidth(pageContentRect().width());
- break;
-
- case KoShapeAnchor::HParagraph:
- anchorBoundingRect.setX(paragraphRect().x() + containerBoundingRect.x());
- anchorBoundingRect.setWidth(paragraphRect().width());
- break;
-
- case KoShapeAnchor::HParagraphContent:
- anchorBoundingRect.setX(paragraphContentRect().x() + containerBoundingRect.x());
- anchorBoundingRect.setWidth(paragraphContentRect().width());
- break;
-
- case KoShapeAnchor::HChar: {
- QTextLine tl = layout->lineForTextPosition(m_anchorRange->position() - block.position());
- if (!tl.isValid())
- return false; // lets go for a second round.
- anchorBoundingRect.setX(tl.cursorToX(m_anchorRange->position() - block.position()) + containerBoundingRect.x());
- anchorBoundingRect.setWidth(0.1); // just some small value
- break;
- }
- case KoShapeAnchor::HPageStartMargin: {
- int horizontalPos = m_anchor->horizontalPos();
- // if verticalRel is HFromInside or HInside or HOutside and the page number is even,
- // than set anchorBoundingRect to HPageEndMargin area
- if ((pageNumber()%2 == 0) && (horizontalPos == KoShapeAnchor::HFromInside ||
- horizontalPos == KoShapeAnchor::HInside || horizontalPos == KoShapeAnchor::HOutside)) {
- anchorBoundingRect.setX(containerBoundingRect.x() + containerBoundingRect.width());
- anchorBoundingRect.setWidth(pageRect().width() - anchorBoundingRect.x());
- } else {
- anchorBoundingRect.setX(pageRect().x());
- anchorBoundingRect.setWidth(containerBoundingRect.x());
- }
- break;
- }
- case KoShapeAnchor::HPageEndMargin:
- {
- int horizontalPos = m_anchor->horizontalPos();
- // if verticalRel is HFromInside or HInside or HOutside and the page number is even,
- // than set anchorBoundingRect to HPageStartMargin area
- if ((pageNumber()%2 == 0) && (horizontalPos == KoShapeAnchor::HFromInside ||
- horizontalPos == KoShapeAnchor::HInside || horizontalPos == KoShapeAnchor::HOutside)) {
- anchorBoundingRect.setX(pageRect().x());
- anchorBoundingRect.setWidth(containerBoundingRect.x());
- } else {
- anchorBoundingRect.setX(containerBoundingRect.x() + containerBoundingRect.width());
- anchorBoundingRect.setWidth(pageRect().width() - anchorBoundingRect.x());
- }
- break;
- }
- case KoShapeAnchor::HParagraphStartMargin:
- {
- int horizontalPos = m_anchor->horizontalPos();
- // if verticalRel is HFromInside or HInside or HOutside and the page number is even,
- // than set anchorBoundingRect to HParagraphEndMargin area
- if ((pageNumber()%2 == 0) && (horizontalPos == KoShapeAnchor::HFromInside ||
- horizontalPos == KoShapeAnchor::HInside || horizontalPos == KoShapeAnchor::HOutside)) {
-//FIXME anchorBoundingRect.setX(state->x() + containerBoundingRect.x() + state->width());
- anchorBoundingRect.setWidth(containerBoundingRect.x() + containerBoundingRect.width() - anchorBoundingRect.x());
- } else {
- anchorBoundingRect.setX(containerBoundingRect.x());
-//FIXME anchorBoundingRect.setWidth(state->x());
- }
- break;
- }
- case KoShapeAnchor::HParagraphEndMargin:
- {
- int horizontalPos = m_anchor->horizontalPos();
- // if verticalRel is HFromInside or HInside or HOutside and the page number is even,
- // than set anchorBoundingRect to HParagraphStartMargin area
- if ((pageNumber()%2 == 0) && (horizontalPos == KoShapeAnchor::HFromInside ||
- horizontalPos == KoShapeAnchor::HInside || horizontalPos == KoShapeAnchor::HOutside)) {
- anchorBoundingRect.setX(containerBoundingRect.x());
-//FIXME anchorBoundingRect.setWidth(state->x());
- } else {
-//FIXME anchorBoundingRect.setX(state->x() + containerBoundingRect.x() + state->width());
- anchorBoundingRect.setWidth(containerBoundingRect.x() + containerBoundingRect.width() - anchorBoundingRect.x());
- }
- break;
- }
- default :
- warnTextLayout << "horizontal-rel not handled";
- }
- return true;
-}
-
-void FloatingAnchorStrategy::countHorizontalPos(QPointF &newPosition, const QRectF &anchorBoundingRect)
-{
- switch (m_anchor->horizontalPos()) {
- case KoShapeAnchor::HCenter:
- newPosition.setX(anchorBoundingRect.x() + anchorBoundingRect.width()/2
- - m_anchor->shape()->size().width()/2);
- break;
-
- case KoShapeAnchor::HFromInside:
- case KoShapeAnchor::HInside:
- {
- if (pageNumber()%2 == 1) {
- newPosition.setX(anchorBoundingRect.x());
- } else {
- newPosition.setX(anchorBoundingRect.right() -
- m_anchor->shape()->size().width() - 2*m_anchor->offset().x() );
- }
- break;
- }
- case KoShapeAnchor::HLeft:
- case KoShapeAnchor::HFromLeft:
- newPosition.setX(anchorBoundingRect.x());
- break;
-
- case KoShapeAnchor::HOutside:
- {
- if (pageNumber()%2 == 1) {
- newPosition.setX(anchorBoundingRect.right());
- } else {
- QSizeF size = m_anchor->shape()->boundingRect().size();
- newPosition.setX(anchorBoundingRect.x() - size.width() - m_anchor->offset().x());
- }
- break;
- }
- case KoShapeAnchor::HRight: {
- QSizeF size = m_anchor->shape()->boundingRect().size();
- newPosition.setX(anchorBoundingRect.right() - size.width());
- break;
- }
- default :
- warnTextLayout << "horizontal-pos not handled";
- }
-}
-
-bool FloatingAnchorStrategy::countVerticalRel(QRectF &anchorBoundingRect, const QRectF &containerBoundingRect,
- KoTextShapeData *data, QTextBlock &block, QTextLayout *layout)
-{
- //FIXME proper handle VFrame and VFrameContent but fallback to VPage/VPageContent for now to produce better results
-
- switch (m_anchor->verticalRel()) {
- case KoShapeAnchor::VPage:
- anchorBoundingRect.setY(pageRect().y());
- anchorBoundingRect.setHeight(pageRect().height());
- break;
-
- case KoShapeAnchor::VFrame:
- case KoShapeAnchor::VFrameContent:
- anchorBoundingRect.setY(containerBoundingRect.y());
- anchorBoundingRect.setHeight(containerBoundingRect.height());
- break;
-
- case KoShapeAnchor::VPageContent:
- anchorBoundingRect.setY(pageContentRect().y());
- anchorBoundingRect.setHeight(pageContentRect().height());
- break;
-
- case KoShapeAnchor::VParagraph:
- anchorBoundingRect.setY(paragraphRect().y() + containerBoundingRect.y() - data->documentOffset());
- anchorBoundingRect.setHeight(paragraphRect().height());
- break;
-
- case KoShapeAnchor::VParagraphContent: {
- anchorBoundingRect.setY(paragraphContentRect().y() + containerBoundingRect.y() - data->documentOffset());
- anchorBoundingRect.setHeight(paragraphContentRect().height());
- }
- break;
-
- case KoShapeAnchor::VLine: {
- QTextLine tl = layout->lineForTextPosition(m_anchorRange->position() - block.position());
- if (!tl.isValid())
- return false; // lets go for a second round.
- QSizeF size = m_anchor->shape()->boundingRect().size();
- anchorBoundingRect.setY(tl.y() - size.height()
- + containerBoundingRect.y() - data->documentOffset());
- anchorBoundingRect.setHeight(2*size.height());
- }
- break;
-
- case KoShapeAnchor::VText: // same as char apparently only used when as-char
- case KoShapeAnchor::VChar: {
- QTextLine tl = layout->lineForTextPosition(m_anchorRange->position() - block.position());
- if (!tl.isValid())
- return false; // lets go for a second round.
- anchorBoundingRect.setY(tl.y() + containerBoundingRect.y() - data->documentOffset());
- anchorBoundingRect.setHeight(tl.height());
- }
- break;
-
- case KoShapeAnchor::VBaseline: {
- QTextLine tl = layout->lineForTextPosition(m_anchorRange->position() - block.position());
- if (!tl.isValid())
- return false; // lets go for a second round.
- QSizeF size = m_anchor->shape()->boundingRect().size();
- anchorBoundingRect.setY(tl.y() + tl.ascent() - size.height()
- + containerBoundingRect.y() - data->documentOffset());
- anchorBoundingRect.setHeight(2*size.height());
- }
- break;
- default :
- warnTextLayout << "vertical-rel not handled";
- }
- return true;
-}
-
-void FloatingAnchorStrategy::countVerticalPos(QPointF &newPosition, const QRectF &anchorBoundingRect)
-{
- switch (m_anchor->verticalPos()) {
- case KoShapeAnchor::VBottom:
- newPosition.setY(anchorBoundingRect.bottom() - m_anchor->shape()->size().height());
- break;
- case KoShapeAnchor::VBelow:
- newPosition.setY(anchorBoundingRect.bottom());
- break;
-
- case KoShapeAnchor::VMiddle:
- newPosition.setY(anchorBoundingRect.y() + anchorBoundingRect.height()/2 - m_anchor->shape()->size().height()/2);
- break;
-
- case KoShapeAnchor::VFromTop:
- case KoShapeAnchor::VTop:
- newPosition.setY(anchorBoundingRect.y());
- break;
-
- default :
- warnTextLayout << "vertical-pos not handled";
- }
-
-}
-
-void FloatingAnchorStrategy::checkLayoutEnvironment(QPointF &newPosition, KoTextShapeData *data)
-{
- QSizeF size = m_anchor->shape()->boundingRect().size();
-
- //check left border and move the shape back to have the whole shape within
- if (newPosition.x() < layoutEnvironmentRect().x()) {
- newPosition.setX(layoutEnvironmentRect().x());
- }
-
- //check right border and move the shape back to have the whole shape within
- if (newPosition.x() + size.width() > layoutEnvironmentRect().right()) {
- newPosition.setX(layoutEnvironmentRect().right() - size.width());
- }
-
- //check top border and move the shape back to have the whole shape within
- if (newPosition.y() < layoutEnvironmentRect().y() - data->documentOffset()) {
- newPosition.setY(layoutEnvironmentRect().y() - data->documentOffset());
- }
-
- //check bottom border and move the shape back to have the whole shape within
- if (newPosition.y() + size.height() > layoutEnvironmentRect().bottom() - data->documentOffset()) {
- newPosition.setY(layoutEnvironmentRect().bottom() - size.height() - data->documentOffset());
- }
-}
-
-void FloatingAnchorStrategy::checkPageBorder(QPointF &newPosition)
-{
- QSizeF size = m_anchor->shape()->boundingRect().size();
-
- //check left border and move the shape back to have the whole shape visible
- if (newPosition.x() < pageRect().x()) {
- newPosition.setX(pageRect().x());
- }
-
- //check right border and move the shape back to have the whole shape visible
- if (newPosition.x() + size.width() > pageRect().x() + pageRect().width()) {
- newPosition.setX(pageRect().x() + pageRect().width() - size.width());
- }
-
- //check top border and move the shape back to have the whole shape visible
- if (newPosition.y() < pageRect().y()) {
- newPosition.setY(pageRect().y());
- }
-
- //check bottom border and move the shape back to have the whole shape visible
- if (newPosition.y() + size.height() > pageRect().y() + pageRect().height()) {
- newPosition.setY(pageRect().y() + pageRect().height() - size.height());
- }
-}
-
-// If the horizontal-pos is Left or Right then we need to check if there are other
-// objects anchored with horizontal-pos left or right. If there are then we need
-// to "stack" our object on them what means that rather then floating this object
-// over the other it is needed to adjust the position to be sure they are not
-// floating over each other.
-void FloatingAnchorStrategy::checkStacking(QPointF &newPosition)
-{
- if (m_anchor->anchorType() != KoShapeAnchor::AnchorParagraph || (m_anchor->horizontalPos() != KoShapeAnchor::HLeft && m_anchor->horizontalPos() != KoShapeAnchor::HRight))
- return;
-
- int idx = m_rootArea->documentLayout()->textAnchors().indexOf(m_anchor);
- Q_ASSERT_X(idx >= 0, __FUNCTION__, QString("WTF? How can our anchor not be in the anchor-list but still be called?").toLocal8Bit());
-
- QSizeF size = m_anchor->shape()->boundingRect().size();
- for(int i = 0; i < idx; ++i) {
- KoShapeAnchor *a = m_rootArea->documentLayout()->textAnchors()[i];
- if (m_anchor->anchorType() != a->anchorType() || m_anchor->horizontalPos() != a->horizontalPos())
- continue;
-
- QRectF thisRect(newPosition, size);
- QRectF r(a->shape()->boundingRect());
- if (thisRect.intersects(r)) {
- if (m_anchor->horizontalPos() == KoShapeAnchor::HLeft)
- newPosition.setX(a->shape()->position().x() + r.width());
- else // KoShapeAnchor::HRight
- newPosition.setX(a->shape()->position().x() - size.width());
- }
- }
-}
diff --git a/plugins/flake/textshape/textlayout/FloatingAnchorStrategy.h b/plugins/flake/textshape/textlayout/FloatingAnchorStrategy.h
deleted file mode 100644
index 8279208930..0000000000
--- a/plugins/flake/textshape/textlayout/FloatingAnchorStrategy.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007, 2009, 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2011 Matus Hanzes <matus.hanzes@ixonos.com>
- *
- * 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 FLOATINGANCHORSTRATEGY_H
-#define FLOATINGANCHORSTRATEGY_H
-
-#include "AnchorStrategy.h"
-
-class KoTextLayoutRootArea;
-class KoTextShapeData;
-class QTextBlock;
-class QTextLayout;
-class KoTextLayoutObstruction;
-class KoAnchorTextRange;
-
-class FloatingAnchorStrategy : public AnchorStrategy
-{
-public:
- FloatingAnchorStrategy(KoAnchorTextRange *anchor, KoTextLayoutRootArea *rootArea);
- ~FloatingAnchorStrategy() override;
-
- /**
- * This moves the subject (i.e. shape when used with flake) of the anchor.
- *
- * @return true if subject was moved
- */
- bool moveSubject() override;
-
-private:
-
- inline bool countHorizontalRel(QRectF &anchorBoundingRect, const QRectF &containerBoundingRect,
- QTextBlock &block, QTextLayout *layout);
- inline void countHorizontalPos(QPointF &newPosition, const QRectF &anchorBoundingRect);
- inline bool countVerticalRel(QRectF &anchorBoundingRect, const QRectF &containerBoundingRect,
- KoTextShapeData *data, QTextBlock &block, QTextLayout *layout);
- inline void countVerticalPos(QPointF &newPosition, const QRectF &anchorBoundingRect);
-
- //check the layout environment and move the shape back to have it within
- inline void checkLayoutEnvironment(QPointF &newPosition, KoTextShapeData *data);
- //check the border of page and move the shape back to have it visible
- inline void checkPageBorder(QPointF &newPosition);
- //check stacking and reorder to proper position objects according to there z-index
- inline void checkStacking(QPointF &newPosition);
-
- void updateObstruction(qreal documentOffset);
-
- KoTextLayoutObstruction *m_obstruction; // the obstruction representation of the subject
- KoAnchorTextRange *m_anchorRange;
-};
-
-#endif // FLOATINGANCHORSTRATEGY_H
diff --git a/plugins/flake/textshape/textlayout/FrameIterator.cpp b/plugins/flake/textshape/textlayout/FrameIterator.cpp
deleted file mode 100644
index bde238c7f0..0000000000
--- a/plugins/flake/textshape/textlayout/FrameIterator.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 C. Boemann, KO GmbH <cbo@kogmbh.com>
- *
- * 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 "FrameIterator.h"
-
-#include "TableIterator.h"
-
-#include <QTextFrame>
-#include <QTextTableCell>
-
-FrameIterator::FrameIterator(QTextFrame *frame)
-{
- it = frame->begin();
- currentTableIterator = 0;
- currentSubFrameIterator = 0;
- lineTextStart = -1;
- endNoteIndex = 0;
-}
-
-FrameIterator::FrameIterator(const QTextTableCell &cell)
-{
- Q_ASSERT(cell.isValid());
- it = cell.begin();
- currentTableIterator = 0;
- currentSubFrameIterator = 0;
- lineTextStart = -1;
- endNoteIndex = 0;
-}
-
-FrameIterator::FrameIterator(FrameIterator *other)
-{
- it = other->it;
- masterPageName = other->masterPageName;
- lineTextStart = other->lineTextStart;
- fragmentIterator = other->fragmentIterator;
- endNoteIndex = other->endNoteIndex;
- if (other->currentTableIterator)
- currentTableIterator = new TableIterator(other->currentTableIterator);
- else
- currentTableIterator = 0;
-
- if (other->currentSubFrameIterator)
- currentSubFrameIterator = new FrameIterator(other->currentSubFrameIterator);
- else
- currentSubFrameIterator = 0;
-}
-
-FrameIterator::~FrameIterator()
-{
- delete currentTableIterator;
- delete currentSubFrameIterator;
-}
-
-bool FrameIterator::operator ==(const FrameIterator &other) const
-{
- if (it != other.it)
- return false;
- if (endNoteIndex != other.endNoteIndex)
- return false;
- if (currentTableIterator || other.currentTableIterator) {
- if (!currentTableIterator || !other.currentTableIterator)
- return false;
- return *currentTableIterator == *(other.currentTableIterator);
- } else if (currentSubFrameIterator || other.currentSubFrameIterator) {
- if (!currentSubFrameIterator || !other.currentSubFrameIterator)
- return false;
- return *currentSubFrameIterator == *(other.currentSubFrameIterator);
- } else {
- return lineTextStart == other.lineTextStart;
- }
-}
-
-TableIterator *FrameIterator::tableIterator(QTextTable *table)
-{
- if(table == 0) {
- delete currentTableIterator;
- currentTableIterator = 0;
- } else if(currentTableIterator == 0) {
- currentTableIterator = new TableIterator(table);
- currentTableIterator->masterPageName = masterPageName;
- }
- return currentTableIterator;
-}
-
-FrameIterator *FrameIterator::subFrameIterator(QTextFrame *subFrame)
-{
- if(subFrame == 0) {
- delete currentSubFrameIterator;
- currentSubFrameIterator = 0;
- } else if(currentSubFrameIterator == 0) {
- currentSubFrameIterator = new FrameIterator(subFrame);
- currentSubFrameIterator->masterPageName = masterPageName;
- }
- return currentSubFrameIterator;
-}
diff --git a/plugins/flake/textshape/textlayout/FrameIterator.h b/plugins/flake/textshape/textlayout/FrameIterator.h
deleted file mode 100644
index 71e0c15ee9..0000000000
--- a/plugins/flake/textshape/textlayout/FrameIterator.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 C. Boemann, KO GmbH <cbo@kogmbh.com>
- *
- * 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 FRAMEITERATOR_H
-#define FRAMEITERATOR_H
-
-#include <QTextFrame>
-
-class TableIterator;
-class QTextTableCell;
-class QTextTable;
-
-class FrameIterator
-{
-public:
- explicit FrameIterator(QTextFrame *frame);
- explicit FrameIterator(const QTextTableCell &frame);
- explicit FrameIterator(FrameIterator *other);
- ~FrameIterator();
-
- bool operator ==(const FrameIterator &other) const;
-
- TableIterator *tableIterator(QTextTable *);
- FrameIterator *subFrameIterator(QTextFrame *);
-
- QTextFrame::iterator it;
-
- QString masterPageName;
-
- // lineTextStart and fragmentIterator can be seen as the "sub cursor" of text blocks
- int lineTextStart; // a value of -1 indicate block not processed yet
- QTextBlock::Iterator fragmentIterator;
-
- TableIterator *currentTableIterator; //useful if it is pointing to a table
-
- FrameIterator *currentSubFrameIterator; //useful if it is pointing to a subFrame
-
- int endNoteIndex;
-};
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/IndexGeneratorManager.cpp b/plugins/flake/textshape/textlayout/IndexGeneratorManager.cpp
deleted file mode 100644
index aca9fa9fd4..0000000000
--- a/plugins/flake/textshape/textlayout/IndexGeneratorManager.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Ko GmbH <cbo@kogmbh.com>
- *
- * 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 "IndexGeneratorManager.h"
-
-#include "KoTextDocumentLayout.h"
-#include "ToCGenerator.h"
-
-#include <KoTextDocument.h>
-#include <KoParagraphStyle.h>
-#include <KoTableOfContentsGeneratorInfo.h>
-
-#include <QTextDocument>
-#include <TextLayoutDebug.h>
-
-IndexGeneratorManager::IndexGeneratorManager(QTextDocument *document)
- : QObject(document)
- , m_document(document)
- , m_state(FirstRunNeeded)
-{
- m_documentLayout = static_cast<KoTextDocumentLayout *>(document->documentLayout());
-
- // connect to layoutIsDirty
- connect(m_documentLayout, SIGNAL(layoutIsDirty()), this, SLOT(requestGeneration()));
-
- // connect to FinishedLayout
- connect(m_documentLayout, SIGNAL(finishedLayout()), this, SLOT(startDoneTimer()));
-
- connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(timeout()));
- m_updateTimer.setInterval(5000); // after 5 seconds of pause we update
- m_updateTimer.setSingleShot(true);
-
- connect(&m_doneTimer, SIGNAL(timeout()), this, SLOT(layoutDone()));
- m_doneTimer.setInterval(1000); // after 1 seconds of silence we assume layout is done
- m_doneTimer.setSingleShot(true);
-}
-
-IndexGeneratorManager::~IndexGeneratorManager()
-{
-}
-
-IndexGeneratorManager *IndexGeneratorManager::instance(QTextDocument *document)
-{
- QVariant resource = document->resource(KoTextDocument::IndexGeneratorManager, KoTextDocument::IndexGeneratorManagerUrl);
-
- IndexGeneratorManager *igm = resource.value<IndexGeneratorManager *>();
-
- if (!igm) {
- igm = new IndexGeneratorManager(document);
-
- resource.setValue(igm);
-
- document->addResource(KoTextDocument::IndexGeneratorManager, KoTextDocument::IndexGeneratorManagerUrl, resource);
- }
-
- return igm;
-}
-
-void IndexGeneratorManager::requestGeneration()
-{
- if (m_state == FirstRun || m_state == SecondRun) {
- return;
- }
- if (m_document->characterCount() < 2) {
- return;
- }
- m_updateTimer.stop();
- m_updateTimer.start();
-}
-
-void IndexGeneratorManager::startDoneTimer()
-{
- //we delay acting on the finishedLayout signal by 1 second. This way we
- // don't act on it until every header has had a chance to be layouted
- // in words (we assume that a new finishedLayout signal will arrive within that
- // 1 second)
- m_doneTimer.start();
-}
-
-void IndexGeneratorManager::timeout()
-{
- m_updateTimer.stop();
- m_state = FirstRunNeeded;
- m_documentLayout->scheduleLayout();
-}
-
-bool IndexGeneratorManager::generate()
-{
- if (m_state == Resting || m_state == FirstRunLayouting || m_state == SecondRunLayouting) {
- return false;
- }
-
- if (m_state == FirstRun || m_state == SecondRun) {
- return true;
- }
-
- if (m_document->characterCount() < 2) {
- return false;
- }
-
- if (m_state == FirstRunNeeded) {
- m_state = FirstRun;
- }
-
- if (m_state == SecondRunNeeded) {
- m_state = SecondRun;
- }
-
- QTextBlock block = m_document->firstBlock();
-
- bool success = true;
- while (block.isValid()) {
- QTextBlockFormat format = block.blockFormat();
-
- if (format.hasProperty(KoParagraphStyle::TableOfContentsData)) {
- QVariant data = format.property(KoParagraphStyle::TableOfContentsData);
- KoTableOfContentsGeneratorInfo *tocInfo = data.value<KoTableOfContentsGeneratorInfo *>();
-
- data = format.property(KoParagraphStyle::GeneratedDocument);
- QTextDocument *tocDocument = data.value<QTextDocument *>();
-
- ToCGenerator *generator = m_generators[tocInfo];
- if (!generator) {
- generator = new ToCGenerator(tocDocument, tocInfo);
- m_generators[tocInfo] = generator;
- }
-
- generator->setBlock(block);
- success &= generator->generate();
- }
- block = block.next();
- }
-
-
- if (m_state == FirstRun) {
- m_state = FirstRunLayouting;
- }
-
- if (m_state == SecondRun) {
- if (success) {
- m_state = SecondRunLayouting;
- } else {
- m_state = FirstRunLayouting;
- }
- }
-
- return false;
-}
-
-void IndexGeneratorManager::layoutDone()
-{
- switch (m_state) {
- case FirstRunLayouting:
- m_state = SecondRunNeeded;
- m_documentLayout->scheduleLayout();
- break;
- case SecondRunLayouting:
- m_state = Resting;
- break;
- default:
- break;
- }
-}
diff --git a/plugins/flake/textshape/textlayout/IndexGeneratorManager.h b/plugins/flake/textshape/textlayout/IndexGeneratorManager.h
deleted file mode 100644
index 5acd96c03a..0000000000
--- a/plugins/flake/textshape/textlayout/IndexGeneratorManager.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Ko GmbH <cbo@kogmbh.com>
- *
- * 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 INDEXGENERATORMANAGER_H
-#define INDEXGENERATORMANAGER_H
-
-
-#include <QObject>
-#include <QMetaType>
-#include <QHash>
-#include <QTimer>
-
-class QTextDocument;
-class KoTextDocumentLayout;
-class KoTableOfContentsGeneratorInfo;
-class ToCGenerator;
-
-class IndexGeneratorManager : public QObject
-{
- Q_OBJECT
-private:
- explicit IndexGeneratorManager(QTextDocument *document);
-public:
- ~IndexGeneratorManager() override;
-
- static IndexGeneratorManager *instance(QTextDocument *document);
-
- bool generate();
-
-public Q_SLOTS:
- void requestGeneration();
- void startDoneTimer();
-
-private Q_SLOTS:
- void layoutDone();
- void timeout();
-
-private:
- enum State {
- Resting, // We are not doing anything, and don't need to either
- FirstRunNeeded, // We would like to update the indexes, with dummy pg nums
- FirstRun, // Updating indexes, so prevent layout and ignore documentChanged()
- FirstRunLayouting, // KoTextDocumentLayout is layouting so sit still
- SecondRunNeeded, // Would like to update the indexes, getting pg nums right
- SecondRun, // Updating indexes, so prevent layout and ignore documentChanged()
- SecondRunLayouting // KoTextDocumentLayout is layouting so sit still
- };
- QTextDocument *m_document;
- KoTextDocumentLayout *m_documentLayout;
- QHash<KoTableOfContentsGeneratorInfo *, ToCGenerator *> m_generators;
- State m_state;
- QTimer m_updateTimer;
- QTimer m_doneTimer;
-};
-
-Q_DECLARE_METATYPE(IndexGeneratorManager *)
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/InlineAnchorStrategy.cpp b/plugins/flake/textshape/textlayout/InlineAnchorStrategy.cpp
deleted file mode 100644
index af776c3aef..0000000000
--- a/plugins/flake/textshape/textlayout/InlineAnchorStrategy.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Matus Hanzes <matus.hanzes@ixonos.com>
- *
- * 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 "InlineAnchorStrategy.h"
-
-#include <KoShapeContainer.h>
-#include <KoTextShapeData.h>
-#include <KoAnchorInlineObject.h>
-
-#include <QTextLayout>
-#include <QTextBlock>
-#include <QTextDocument>
-#include <TextLayoutDebug.h>
-
-InlineAnchorStrategy::InlineAnchorStrategy(KoAnchorInlineObject *anchorObject, KoTextLayoutRootArea *rootArea)
- : AnchorStrategy(anchorObject->anchor(), rootArea)
- , m_anchorObject(anchorObject)
-{
-}
-
-InlineAnchorStrategy::~InlineAnchorStrategy()
-{
-}
-
-bool InlineAnchorStrategy::moveSubject()
-{
- if (!m_anchor->shape()->parent()) {
- return false; // let's fake we moved to force another relayout
- }
-
- KoTextShapeData *data = qobject_cast<KoTextShapeData*>(m_anchor->shape()->parent()->userData());
- if (!data) {
- return false; // let's fake we moved to force another relayout
- }
-
- QPointF newPosition;
- QTextBlock block = m_anchorObject->document()->findBlock(m_anchorObject->position());
- QTextLayout *layout = block.layout();
-
- // set anchor bounding rectangle horizontal position and size
- if (!countHorizontalPos(newPosition, block, layout)) {
- return false; // let's fake we moved to force another relayout
- }
-
- // set anchor bounding rectangle vertical position
- if (!countVerticalPos(newPosition, data, block, layout)) {
- return false; // let's fake we moved to force another relayout
- }
-
- // check the border of the parent shape an move the shape back to have it inside the parent shape
- checkParentBorder(newPosition);
-
- if (newPosition == m_anchor->shape()->position()) {
- return true;
- }
-
- // set the shape to the proper position based on the data
- m_anchor->shape()->update();
- m_anchor->shape()->setPosition(newPosition);
- m_anchor->shape()->update();
-
- return true; // fake no move as we don't wrap around inline so no need to waste cpu
-}
-
-bool InlineAnchorStrategy::countHorizontalPos(QPointF &newPosition, QTextBlock &block, QTextLayout *layout)
-{
- if (layout->lineCount() != 0) {
- QTextLine tl = layout->lineForTextPosition(m_anchorObject->position() - block.position());
- if (tl.isValid()) {
- newPosition.setX(tl.cursorToX(m_anchorObject->position() - block.position()));
- } else {
- return false; // lets go for a second round.
- }
- } else {
- return false; // lets go for a second round.
- }
- return true;
-}
-
-bool InlineAnchorStrategy::countVerticalPos(QPointF &newPosition, KoTextShapeData *data, QTextBlock &block, QTextLayout *layout)
-{
- if (layout->lineCount()) {
- QTextLine tl = layout->lineForTextPosition(m_anchorObject->position() - block.position());
- Q_ASSERT(tl.isValid());
- if (m_anchorObject->inlineObjectAscent() > 0) {
- newPosition.setY(tl.y() + tl.ascent() - m_anchorObject->inlineObjectAscent() - data->documentOffset());
- } else {
- newPosition.setY(tl.y() + tl.ascent() + m_anchorObject->inlineObjectDescent() - m_anchor->shape()->size().height() - data->documentOffset());
- }
- } else {
- return false; // lets go for a second round.
- }
- return true;
-}
-
-// Compared to FloatingAnchorStrategy::checkPageBorder this method doesn't check against the
-// page borders but against the shape's parent ShapeContainer (aka the page-content) borders.
-//
-// If size.width()>container.width() then the shape needs to align to the most left position
-// (aka x=0.0). We only check for the x/width and not for y/height cause the results are
-// matching more to what OO.org and MSOffice produce.
-void InlineAnchorStrategy::checkParentBorder(QPointF &newPosition)
-{
- QSizeF size = m_anchor->shape()->boundingRect().size();
- QSizeF container = m_anchor->shape()->parent()->boundingRect().size();
- if ((newPosition.x() + size.width()) > container.width()) {
- newPosition.setX(container.width() - size.width());
- }
- if (newPosition.x() < 0.0) {
- newPosition.setX(0.0);
- }
-}
diff --git a/plugins/flake/textshape/textlayout/InlineAnchorStrategy.h b/plugins/flake/textshape/textlayout/InlineAnchorStrategy.h
deleted file mode 100644
index 07b094c577..0000000000
--- a/plugins/flake/textshape/textlayout/InlineAnchorStrategy.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Matus Hanzes <matus.hanzes@ixonos.com>
- *
- * 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 INLINEANCHORSTRATEGY_H_
-#define INLINEANCHORSTRATEGY_H_
-
-#include "AnchorStrategy.h"
-
-class KoTextLayoutRootArea;
-class KoTextShapeData;
-class QTextBlock;
-class QTextLayout;
-class KoAnchorInlineObject;
-
-class InlineAnchorStrategy : public AnchorStrategy
-{
-public:
- InlineAnchorStrategy(KoAnchorInlineObject *anchor, KoTextLayoutRootArea *rootArea);
- ~InlineAnchorStrategy() override;
-
- bool moveSubject() override;
-
-private:
-
- inline bool countHorizontalPos(QPointF &newPosition, QTextBlock &block, QTextLayout *layout);
- inline bool countVerticalPos(QPointF &newPosition, KoTextShapeData *data, QTextBlock &block, QTextLayout *layout);
-
- //check the border of the parent shape an move the shape back to have it inside the parent shape
- inline void checkParentBorder(QPointF &newPosition);
- KoAnchorInlineObject *m_anchorObject;
-};
-
-#endif /* INLINEANCHORSTRATEGY_H_ */
diff --git a/plugins/flake/textshape/textlayout/KoPageProvider.cpp b/plugins/flake/textshape/textlayout/KoPageProvider.cpp
deleted file mode 100644
index e695613181..0000000000
--- a/plugins/flake/textshape/textlayout/KoPageProvider.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/* This file is part of the KDE project
-
- Copyright (C) 2009 Thorsten Zachmann <zachmann@kde.org>
-
- 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 "KoPageProvider.h"
-
-KoPageProvider::KoPageProvider()
-{
-}
-
-KoPageProvider::~KoPageProvider()
-{
-}
diff --git a/plugins/flake/textshape/textlayout/KoPageProvider.h b/plugins/flake/textshape/textlayout/KoPageProvider.h
deleted file mode 100644
index 32c5300827..0000000000
--- a/plugins/flake/textshape/textlayout/KoPageProvider.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* This file is part of the KDE project
-
- Copyright (C) 2009 Thorsten Zachmann <zachmann@kde.org>
-
- 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 KOPAGEPROVIDER_H
-#define KOPAGEPROVIDER_H
-
-#include "kritatextlayout_export.h"
-
-class KoShape;
-class KoTextPage;
-
-/// \internal this is a hack for kpresenter
-class KRITATEXTLAYOUT_EXPORT KoPageProvider
-{
-public:
- KoPageProvider();
- virtual ~KoPageProvider();
-
- /**
- * Get the page number for the given shape
- */
- virtual KoTextPage *page(KoShape *shape) = 0;
-};
-#endif // KOPAGEPROVIDER_H
diff --git a/plugins/flake/textshape/textlayout/KoPointedAt.cpp b/plugins/flake/textshape/textlayout/KoPointedAt.cpp
deleted file mode 100644
index 664bdd0c34..0000000000
--- a/plugins/flake/textshape/textlayout/KoPointedAt.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 C. Boemann, KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2011 C. Boemann <cbo@boemann.dk>
- *
- * 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 "KoPointedAt.h"
-
-#include <KoInlineNote.h>
-#include <KoInlineTextObjectManager.h>
-#include <KoTextRangeManager.h>
-
-#include <TextLayoutDebug.h>
-
-#include <QTextCursor>
-
-KoPointedAt::KoPointedAt()
- : position(-1)
- , bookmark(0)
- , note(0)
- , noteReference(-1)
- , table(0)
- , tableHit(None)
-{
-}
-
-KoPointedAt::KoPointedAt(KoPointedAt *other)
-{
- position = other->position;
- bookmark = other->bookmark;
- note = other->note;
- noteReference = other->noteReference;
- externalHRef = other->externalHRef;
- tableHit = other->tableHit;
- tableRowDivider = other->tableRowDivider;
- tableColumnDivider = other->tableColumnDivider;
- tableLeadSize = other->tableLeadSize;
- tableTrailSize = other->tableTrailSize;
- table = other->table;
-}
-
-void KoPointedAt::fillInLinks(const QTextCursor &cursor, KoInlineTextObjectManager *inlineManager, KoTextRangeManager *rangeManager)
-{
- bookmark = 0;
- externalHRef.clear();
- note = 0;
-
- if (!inlineManager)
- return;
-
- // Is there an href here ?
- if (cursor.charFormat().isAnchor()) {
- QString href = cursor.charFormat().anchorHref();
- // local href starts with #
- if (href.startsWith('#')) {
- // however bookmark does not contain it, so strip it
- href = href.right(href.size() - 1);
-
- if (!href.isEmpty()) {
- bookmark = rangeManager->bookmarkManager()->bookmark(href);
- }
- return;
- } else {
- // Nope, then it must be external;
- externalHRef = href;
- }
- } else {
- note = dynamic_cast<KoInlineNote*>(inlineManager->inlineTextObject(cursor));
- }
-}
diff --git a/plugins/flake/textshape/textlayout/KoPointedAt.h b/plugins/flake/textshape/textlayout/KoPointedAt.h
deleted file mode 100644
index 27f7c53997..0000000000
--- a/plugins/flake/textshape/textlayout/KoPointedAt.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 C. Boemann, KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2011 C. Boemann <cbo@boemann.dk>
- *
- * 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 KOPOINTEDAT_H
-#define KOPOINTEDAT_H
-
-#include "kritatextlayout_export.h"
-
-#include <QString>
-#include <QTextCursor>
-#include <QPointF>
-
-class KoBookmark;
-class QTextTable;
-class KoInlineTextObjectManager;
-class KoTextRangeManager;
-class KoInlineNote;
-
-class KRITATEXTLAYOUT_EXPORT KoPointedAt
-{
-public:
- KoPointedAt();
- explicit KoPointedAt(KoPointedAt *other);
-
- void fillInLinks(const QTextCursor &cursor, KoInlineTextObjectManager *inlineManager, KoTextRangeManager *rangeManager);
-
- enum TableHit {
- None
- , ColumnDivider
- , RowDivider
- };
- int position;
- KoBookmark *bookmark {0};
- QString externalHRef;
- KoInlineNote *note {0};
- int noteReference {0};
- QTextTable *table {0};
- TableHit tableHit {None};
- int tableRowDivider {0};
- int tableColumnDivider {0};
- qreal tableLeadSize {0.0};
- qreal tableTrailSize {0.0};
- QPointF tableDividerPos;
-
-};
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/KoStyleThumbnailer.cpp b/plugins/flake/textshape/textlayout/KoStyleThumbnailer.cpp
deleted file mode 100644
index d085fe1ec4..0000000000
--- a/plugins/flake/textshape/textlayout/KoStyleThumbnailer.cpp
+++ /dev/null
@@ -1,305 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006, 2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2007 Sebastian Sauer <mail@dipe.org>
- * Copyright (C) 2007 Pierre Ducroquet <pinaraf@gmail.com>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009,2011 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2011-2012 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 "KoStyleThumbnailer.h"
-
-#include "KoParagraphStyle.h"
-#include "KoCharacterStyle.h"
-#include "KoTextDocumentLayout.h"
-#include "KoTextLayoutRootArea.h"
-#include "FrameIterator.h"
-
-#include <stdint.h>
-
-#include <klocalizedstring.h>
-
-#include <QCache>
-#include <QFont>
-#include <QImage>
-#include <QPainter>
-#include <QRect>
-#include <QTextBlock>
-#include <QTextCursor>
-#include <QTextLength>
-
-#include <TextLayoutDebug.h>
-
-extern int qt_defaultDpiX();
-extern int qt_defaultDpiY();
-
-class Q_DECL_HIDDEN KoStyleThumbnailer::Private
-{
-public:
- Private() :
- thumbnailHelperDocument(new QTextDocument),
- documentLayout(new KoTextDocumentLayout(thumbnailHelperDocument)),
- defaultSize(QSize(250, 48))
- {
- thumbnailHelperDocument->setDocumentLayout(documentLayout);
- }
-
- ~Private()
- {
- delete documentLayout;
- delete thumbnailHelperDocument;
- }
-
- QTextDocument *thumbnailHelperDocument;
- KoTextDocumentLayout *documentLayout;
- QCache<QString, QImage> thumbnailCache; // cache of QImage representations of the styles
- QSize defaultSize;
- QString thumbnailText;
-};
-
-KoStyleThumbnailer::KoStyleThumbnailer()
- : d(new Private())
-{
-}
-
-KoStyleThumbnailer::~KoStyleThumbnailer()
-{
- delete d;
-}
-
-QImage KoStyleThumbnailer::thumbnail(KoParagraphStyle *style, const QSize &_size, bool recreateThumbnail, KoStyleThumbnailerFlags flags)
-{
- if ((flags & UseStyleNameText) && (!style || style->name().isNull())) {
- return QImage();
- } else if ((! (flags & UseStyleNameText)) && d->thumbnailText.isEmpty()) {
- return QImage();
- }
-
- const QSize &size = (!_size.isValid() || _size.isNull()) ? d->defaultSize : _size;
-
- QString imageKey = "p_" + QString::number(reinterpret_cast<uintptr_t>(style)) + "_" + QString::number(size.width()) + "_" + QString::number(size.height());
-
- if (!recreateThumbnail && d->thumbnailCache.object(imageKey)) {
- return QImage(*(d->thumbnailCache.object(imageKey)));
- }
-
- QImage *im = new QImage(size.width(), size.height(), QImage::Format_ARGB32_Premultiplied);
- im->fill(QColor(Qt::transparent).rgba());
-
- KoParagraphStyle *clone = style->clone();
- //TODO: make the following real options
- //we ignore these properties when the thumbnail would not be sufficient to preview properly the whole paragraph with margins.
- clone->setMargin(QTextLength(QTextLength::FixedLength, 0));
- clone->setPadding(0);
- //
- QTextCursor cursor(d->thumbnailHelperDocument);
- cursor.select(QTextCursor::Document);
- cursor.setBlockFormat(QTextBlockFormat());
- cursor.setBlockCharFormat(QTextCharFormat());
- cursor.setCharFormat(QTextCharFormat());
- QTextBlock block = cursor.block();
- clone->applyStyle(block, true);
-
- QTextCharFormat format;
- // Default to black as text color, to match what KoTextLayoutArea::paint(...)
- // does, setting solid black if no brush is set. Otherwise the UI text color
- // would be used, which might be too bright with dark UI color schemes
- format.setForeground(QColor(Qt::black));
- clone->KoCharacterStyle::applyStyle(format);
- if (flags & UseStyleNameText) {
- cursor.insertText(clone->name(), format);
- } else {
- cursor.insertText(d->thumbnailText, format);
- }
- layoutThumbnail(size, im, flags);
- // Make a copy of the image before inserting in the cache
- QImage res = QImage(*im);
- // Because on inserting, QCache can decide to delete the object immediately
- d->thumbnailCache.insert(imageKey, im);
-
- delete clone;
- return res;
-}
-
-QImage KoStyleThumbnailer::thumbnail(KoCharacterStyle *characterStyle, KoParagraphStyle *paragraphStyle, const QSize &_size, bool recreateThumbnail, KoStyleThumbnailerFlags flags)
-{
- if ((flags & UseStyleNameText) && (!characterStyle || characterStyle->name().isNull())) {
- return QImage();
- } else if ((! (flags & UseStyleNameText)) && d->thumbnailText.isEmpty()) {
- return QImage();
- }
- else if (characterStyle == 0) {
- return QImage();
- }
-
- const QSize &size = (!_size.isValid() || _size.isNull()) ? d->defaultSize : _size;
-
- QString imageKey = "c_" + QString::number(reinterpret_cast<uintptr_t>(characterStyle)) + "_"
- + "p_" + QString::number(reinterpret_cast<uintptr_t>(paragraphStyle)) + "_"
- + QString::number(size.width()) + "_" + QString::number(size.height());
-
- if (!recreateThumbnail && d->thumbnailCache.object(imageKey)) {
- return QImage(*(d->thumbnailCache.object(imageKey)));
- }
-
- QImage *im = new QImage(size.width(), size.height(), QImage::Format_ARGB32_Premultiplied);
- im->fill(QColor(Qt::transparent).rgba());
-
- QTextCursor cursor(d->thumbnailHelperDocument);
- QTextCharFormat format;
- // Default to black as text color, to match what KoTextLayoutArea::paint(...)
- // does, setting solid black if no brush is set. Otherwise the UI text color
- // would be used, which might be too bright with dark UI color schemes
- format.setForeground(QColor(Qt::black));
- KoCharacterStyle *characterStyleClone = characterStyle->clone();
- characterStyleClone->applyStyle(format);
- cursor.select(QTextCursor::Document);
- cursor.setBlockFormat(QTextBlockFormat());
- cursor.setBlockCharFormat(QTextCharFormat());
- cursor.setCharFormat(QTextCharFormat());
-
- if (paragraphStyle) {
- KoParagraphStyle *paragraphStyleClone = paragraphStyle->clone();
- // paragraphStyleClone->KoCharacterStyle::applyStyle(format);
- QTextBlock block = cursor.block();
- paragraphStyleClone->applyStyle(block, true);
- delete paragraphStyleClone;
- paragraphStyleClone = 0;
- }
-
- if (flags & UseStyleNameText) {
- cursor.insertText(characterStyleClone->name(), format);
- } else {
- cursor.insertText(d->thumbnailText, format);
- }
-
- layoutThumbnail(size, im, flags);
- QImage res = QImage(*im);
- d->thumbnailCache.insert(imageKey, im);
- delete characterStyleClone;
- return res;
-}
-
-void KoStyleThumbnailer::setThumbnailSize(const QSize &size)
-{
- d->defaultSize = size;
-}
-
-void KoStyleThumbnailer::layoutThumbnail(const QSize &size, QImage *im, KoStyleThumbnailerFlags flags)
-{
- QPainter p(im);
- d->documentLayout->removeRootArea();
- KoTextLayoutRootArea rootArea(d->documentLayout);
- rootArea.setReferenceRect(0, size.width() * 72.0 / qt_defaultDpiX(), 0, 1E6);
- rootArea.setNoWrap(1E6);
-
- FrameIterator frameCursor(d->thumbnailHelperDocument->rootFrame());
- rootArea.layoutRoot(&frameCursor);
-
- QSizeF documentSize = rootArea.boundingRect().size();
- documentSize.setWidth(documentSize.width() * qt_defaultDpiX() / 72.0);
- documentSize.setHeight(documentSize.height() * qt_defaultDpiY() / 72.0);
- if (documentSize.width() > size.width() || documentSize.height() > size.height()) {
- //calculate the space needed for the font size indicator (should the preview be too big with the style's font size
- QTextCursor cursor(d->thumbnailHelperDocument);
- cursor.select(QTextCursor::Document);
- QString sizeHint = "\t" + QString::number(cursor.charFormat().fontPointSize()) + "pt";
- p.save();
- QFont sizeHintFont = p.font();
- sizeHintFont.setPointSize(8);
- p.setFont(sizeHintFont);
- QRectF sizeHintRect(p.boundingRect(0, 0, 1, 1, Qt::AlignCenter, sizeHint));
- p.restore();
- qreal width = qMax<qreal>(0., size.width()-sizeHintRect.width());
-
- QTextCharFormat fmt = cursor.charFormat();
- if (flags & ScaleThumbnailFont) {
- //calculate the font reduction factor so that the text + the sizeHint fits
- qreal reductionFactor = qMin(width/documentSize.width(), size.height()/documentSize.height());
-
- fmt.setFontPointSize((int)(fmt.fontPointSize()*reductionFactor));
- }
-
- cursor.mergeCharFormat(fmt);
-
- frameCursor = FrameIterator(d->thumbnailHelperDocument->rootFrame());
- rootArea.setReferenceRect(0, width * 72.0 / qt_defaultDpiX(), 0, 1E6);
- rootArea.setNoWrap(1E6);
- rootArea.layoutRoot(&frameCursor);
- documentSize = rootArea.boundingRect().size();
- documentSize.setWidth(documentSize.width() * qt_defaultDpiX() / 72.0);
- documentSize.setHeight(documentSize.height() * qt_defaultDpiY() / 72.0);
- //center the preview in the pixmap
- qreal yOffset = (size.height()-documentSize.height())/2;
- p.save();
- if ((flags & CenterAlignThumbnail) && yOffset) {
- p.translate(0, yOffset);
- }
-
- p.scale(qt_defaultDpiX() / 72.0, qt_defaultDpiY() / 72.0);
-
- KoTextDocumentLayout::PaintContext pc;
- rootArea.paint(&p, pc);
-
- p.restore();
-
- p.setFont(sizeHintFont);
- p.drawText(QRectF(size.width()-sizeHintRect.width(), 0, sizeHintRect.width(),
- size.height() /*because we want to be vertically centered in the pixmap, like the style name*/),Qt::AlignCenter, sizeHint);
- }
- else {
- //center the preview in the pixmap
- qreal yOffset = (size.height()-documentSize.height())/2;
- if ((flags & CenterAlignThumbnail) && yOffset) {
- p.translate(0, yOffset);
- }
-
- p.scale(qt_defaultDpiX() / 72.0, qt_defaultDpiY() / 72.0);
-
- KoTextDocumentLayout::PaintContext pc;
- rootArea.paint(&p, pc);
- }
-}
-
-void KoStyleThumbnailer::removeFromCache(KoParagraphStyle *style)
-{
- QString imageKey = "p_" + QString::number(reinterpret_cast<uintptr_t>(style)) + "_";
- removeFromCache(imageKey);
-}
-
-void KoStyleThumbnailer::removeFromCache(KoCharacterStyle *style)
-{
- QString imageKey = "c_" + QString::number(reinterpret_cast<uintptr_t>(style)) + "_";
- removeFromCache(imageKey);
-}
-
-void KoStyleThumbnailer::setText(const QString &text)
-{
- d->thumbnailText = text;
-}
-
-void KoStyleThumbnailer::removeFromCache(const QString &expr)
-{
- QList<QString> keys = d->thumbnailCache.keys();
- foreach (const QString &key, keys) {
- if (key.contains(expr)) {
- d->thumbnailCache.remove(key);
- }
- }
-}
diff --git a/plugins/flake/textshape/textlayout/KoStyleThumbnailer.h b/plugins/flake/textshape/textlayout/KoStyleThumbnailer.h
deleted file mode 100644
index 96fcfd17c7..0000000000
--- a/plugins/flake/textshape/textlayout/KoStyleThumbnailer.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006 Thomas Zander <zander@kde.org>
- * Copyright (C) 2007 Sebastian Sauer <mail@dipe.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009-2011 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2011-2012 Pierre Stirnweiss <pstirnweiss@googlemail.com>
- * Copyright (C) 2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- *
- * 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 KOSTYLETHUMBNAILER_H
-#define KOSTYLETHUMBNAILER_H
-
-#include "kritatextlayout_export.h"
-
-#include <QSize>
-
-class KoCharacterStyle;
-class KoParagraphStyle;
-
-class QImage;
-
-/**
- * Helper class to create (and cache) thumbnails of styles
- */
-class KRITATEXTLAYOUT_EXPORT KoStyleThumbnailer
-{
-public:
- enum KoStyleThumbnailerFlag {
- NoFlags = 0,
- CenterAlignThumbnail = 1, ///< Vertically Center Align the layout of the thumbnail
- /// i.e the layout is done at the center of the area
- UseStyleNameText = 2, ///< Use the style name as the text that is layouted inside the thumbnail
- ScaleThumbnailFont = 4 ///< If set, then when the layout size is more than the size available
- /// the font size is scaled down to fit the space available
- };
- Q_DECLARE_FLAGS(KoStyleThumbnailerFlags, KoStyleThumbnailerFlag)
-
- /**
- * Create a new style thumbnailer.
- */
- explicit KoStyleThumbnailer();
-
- /**
- * Destructor.
- */
- virtual ~KoStyleThumbnailer();
-
- /**
- * @returns a thumbnail representing the @param style, constrained into the @param size.
- * If there is no specified @param size, the thunbnail is the size specified with @fn setThumbnailSize or 250*48 pt if no size was provided.
- * If the given @param size is too small, the font size will be decreased, so the thumbnail fits.
- * The real font size is indicated in this case.
- * If @param recreateThumbnail is true, do not return the cached thumbnail if it exist, but recreate a new one.
- * The created thumbnail is cached.
- */
- QImage thumbnail(KoParagraphStyle *style,
- const QSize &size = QSize(), bool recreateThumbnail = false,
- KoStyleThumbnailerFlags flags =
- KoStyleThumbnailerFlags(CenterAlignThumbnail | UseStyleNameText | ScaleThumbnailFont));
-
- /**
- * @returns a thumbnail representing the @param characterStyle applied on the given @param paragraphStyle, constrained into the @param size.
- * If there is no specified @param size, the thunbnail is the size specified with @fn setThumbnailSize or 250*48 pt if no size was provided.
- * If the given @param size is too small, the font size will be decreased, so the thumbnail fits.
- * The real font size is indicated in this case.
- * If @param recreateThumbnail is true, do not return the cached thumbnail if it exist, but recreate a new one.
- * The created thumbnail is cached.
- */
- QImage thumbnail(KoCharacterStyle *characterStyle, KoParagraphStyle *paragraphStyle = 0,
- const QSize &size = QSize(), bool recreateThumbnail = false,
- KoStyleThumbnailerFlags flags =
- KoStyleThumbnailerFlags(CenterAlignThumbnail | UseStyleNameText | ScaleThumbnailFont));
-
- /**
- * Sets the size of the thumbnails returned by the @fn thumbnail with no size arguments.
- */
- void setThumbnailSize(const QSize &size);
-
- /**
- * Sets the text that will be layouted.
- * @param text The text that will be layouted inside the thumbnail
- *If the UseStyleNameText flag is set then this text will not be used
- */
- void setText(const QString &text);
-
- /**
- * remove all occurrences of the style from the cache
- */
- void removeFromCache(KoParagraphStyle *style);
-
- /**
- * remove all occurrences of the style from the cache
- */
- void removeFromCache(KoCharacterStyle *style);
-
-private:
- void layoutThumbnail(const QSize &size, QImage *im, KoStyleThumbnailerFlags flags);
- void removeFromCache(const QString &expr);
-
- class Private;
- Private* const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/KoTextBlockPaintStrategyBase.cpp b/plugins/flake/textshape/textlayout/KoTextBlockPaintStrategyBase.cpp
deleted file mode 100644
index 933fce2896..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextBlockPaintStrategyBase.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2010 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2010 Thomas Zander <zander@kde.org>
- *
- * 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 "KoTextBlockPaintStrategyBase.h"
-
-KoTextBlockPaintStrategyBase::KoTextBlockPaintStrategyBase()
-{
-}
-
-KoTextBlockPaintStrategyBase::~KoTextBlockPaintStrategyBase()
-{
-}
-
-QBrush KoTextBlockPaintStrategyBase::background(const QBrush &defaultBackground) const
-{
- return defaultBackground;
-}
-
-void KoTextBlockPaintStrategyBase::applyStrategy(QPainter *)
-{
-}
-
-bool KoTextBlockPaintStrategyBase::isVisible() const {
- return true;
-}
diff --git a/plugins/flake/textshape/textlayout/KoTextBlockPaintStrategyBase.h b/plugins/flake/textshape/textlayout/KoTextBlockPaintStrategyBase.h
deleted file mode 100644
index 463437f876..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextBlockPaintStrategyBase.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2010 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2010 Thomas Zander <zander@kde.org>
- *
- * 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 KOTEXTBLOCKPAINTSTRATEGYBASE_H
-#define KOTEXTBLOCKPAINTSTRATEGYBASE_H
-
-#include "kritatextlayout_export.h"
-
-class QPainter;
-class QBrush;
-
-/**
- * This class is used to control aspects of textblock painting
- * Which is used when KPresenter animates text.
- */
-class KRITATEXTLAYOUT_EXPORT KoTextBlockPaintStrategyBase
-{
-public:
- KoTextBlockPaintStrategyBase();
- virtual ~KoTextBlockPaintStrategyBase();
- /// returns a background for the block, the default implementation returns the defaultBackground
- virtual QBrush background(const QBrush &defaultBackground) const;
- /// A strategy implementing this class can apply its settings by modifying the \a painter
- virtual void applyStrategy(QPainter *painter);
- /// Returns true if the block should be painted at all or false when it should be skipped
- virtual bool isVisible() const;
-};
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/KoTextDocumentLayout.cpp b/plugins/flake/textshape/textlayout/KoTextDocumentLayout.cpp
deleted file mode 100644
index 465fa31162..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextDocumentLayout.cpp
+++ /dev/null
@@ -1,1025 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2007, 2009-2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2010 Johannes Simon <johannes.simon@gmail.com>
- * Copyright (C) 2011-2013 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2011-2013 C.Boemann <cbo@boemann.dk>
- *
- * 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 "KoTextDocumentLayout.h"
-
-#include "styles/KoStyleManager.h"
-#include "KoTextBlockData.h"
-#include "KoInlineTextObjectManager.h"
-#include "KoTextLayoutRootArea.h"
-#include "KoTextLayoutRootAreaProvider.h"
-#include "KoTextLayoutObstruction.h"
-#include "FrameIterator.h"
-#include "InlineAnchorStrategy.h"
-#include "FloatingAnchorStrategy.h"
-#include "AnchorStrategy.h"
-#include "IndexGeneratorManager.h"
-
-#include <KoShapeAnchor.h>
-#include <KoAnchorInlineObject.h>
-#include <KoAnchorTextRange.h>
-#include <KoTextRangeManager.h>
-#include <KoTextPage.h>
-#include <KoPostscriptPaintDevice.h>
-#include <KoShape.h>
-#include <KoShapeContainer.h>
-#include <KoAnnotation.h>
-#include <KoTextDocument.h>
-#include <KoUnit.h>
-#include <KoParagraphStyle.h>
-#include <KoTableStyle.h>
-
-#include <TextLayoutDebug.h>
-#include <QTextBlock>
-#include <QTextTable>
-#include <QTimer>
-#include <QList>
-
-extern int qt_defaultDpiY();
-
-
-KoInlineObjectExtent::KoInlineObjectExtent(qreal ascent, qreal descent)
- : m_ascent(ascent),
- m_descent(descent)
-{
-}
-
-class Q_DECL_HIDDEN KoTextDocumentLayout::Private
-{
-public:
- Private(KoTextDocumentLayout *)
- : styleManager(0)
- , changeTracker(0)
- , inlineTextObjectManager(0)
- , textRangeManager(0)
- , provider(0)
- , layoutPosition(0)
- , anchoringRootArea(0)
- , anchoringIndex(0)
- , anAnchorIsPlaced(false)
- , anchoringSoftBreak(INT_MAX)
- , allowPositionInlineObject(true)
- , continuationObstruction(0)
- , referencedLayout(0)
- , defaultTabSizing(0)
- , y(0)
- , isLayouting(false)
- , layoutScheduled(false)
- , continuousLayout(true)
- , layoutBlocked(false)
- , changesBlocked(false)
- , restartLayout(false)
- , wordprocessingMode(false)
- , showInlineObjectVisualization(false)
- {
- }
- KoStyleManager *styleManager;
-
- KoChangeTracker *changeTracker;
-
- KoInlineTextObjectManager *inlineTextObjectManager;
- KoTextRangeManager *textRangeManager;
- KoTextLayoutRootAreaProvider *provider;
- KoPostscriptPaintDevice *paintDevice;
- QList<KoTextLayoutRootArea *> rootAreaList;
- FrameIterator *layoutPosition;
-
- QHash<int, KoInlineObjectExtent> inlineObjectExtents; // maps text-position to whole-line-height of an inline object
- int inlineObjectOffset;
- QList<KoShapeAnchor *> textAnchors; // list of all inserted inline objects
- QList<KoShapeAnchor *> foundAnchors; // anchors found in an iteration run
- KoTextLayoutRootArea *anchoringRootArea;
- int anchoringIndex; // index of last not positioned inline object inside textAnchors
- bool anAnchorIsPlaced;
- int anchoringSoftBreak;
- QRectF anchoringParagraphRect;
- QRectF anchoringParagraphContentRect;
- QRectF anchoringLayoutEnvironmentRect;
- bool allowPositionInlineObject;
-
- QHash<KoShape*,KoTextLayoutObstruction*> anchoredObstructions; // all obstructions created because KoShapeAnchor from m_textAnchors is in text
- QList<KoTextLayoutObstruction*> freeObstructions; // obstructions affecting the current rootArea, and not anchored to text
- KoTextLayoutObstruction *continuationObstruction;
-
- KoTextDocumentLayout *referencedLayout;
-
- QHash<KoInlineObject *, KoTextLayoutRootArea *> rootAreaForInlineObject;
-
- qreal defaultTabSizing;
- qreal y;
- bool isLayouting;
- bool layoutScheduled;
- bool continuousLayout;
- bool layoutBlocked;
- bool changesBlocked;
- bool restartLayout;
- bool wordprocessingMode;
- bool showInlineObjectVisualization;
-};
-
-
-// ------------------- KoTextDocumentLayout --------------------
-KoTextDocumentLayout::KoTextDocumentLayout(QTextDocument *doc, KoTextLayoutRootAreaProvider *provider)
- : QAbstractTextDocumentLayout(doc),
- d(new Private(this))
-{
- d->paintDevice = new KoPostscriptPaintDevice();
- d->provider = provider;
- setPaintDevice(d->paintDevice);
-
- d->styleManager = KoTextDocument(document()).styleManager();
- d->changeTracker = KoTextDocument(document()).changeTracker();
- d->inlineTextObjectManager = KoTextDocument(document()).inlineTextObjectManager();
- d->textRangeManager = KoTextDocument(document()).textRangeManager();
-
- setTabSpacing(MM_TO_POINT(23)); // use same default as open office
-
- d->layoutPosition = new FrameIterator(doc->rootFrame());
-}
-
-KoTextDocumentLayout::~KoTextDocumentLayout()
-{
- delete d->paintDevice;
- delete d->layoutPosition;
- qDeleteAll(d->freeObstructions);
- qDeleteAll(d->anchoredObstructions);
- qDeleteAll(d->textAnchors);
- delete d;
-}
-
-KoTextLayoutRootAreaProvider *KoTextDocumentLayout::provider() const
-{
- return d->provider;
-}
-
-void KoTextDocumentLayout::setWordprocessingMode()
-{
- d->wordprocessingMode = true;
-}
-
-bool KoTextDocumentLayout::wordprocessingMode() const
-{
- return d->wordprocessingMode;
-}
-
-
-bool KoTextDocumentLayout::relativeTabs(const QTextBlock &block) const
-{
- return KoTextDocument(document()).relativeTabs()
- && KoTextDocument(block.document()).relativeTabs();
-}
-
-KoInlineTextObjectManager *KoTextDocumentLayout::inlineTextObjectManager() const
-{
- return d->inlineTextObjectManager;
-}
-
-void KoTextDocumentLayout::setInlineTextObjectManager(KoInlineTextObjectManager *manager)
-{
- d->inlineTextObjectManager = manager;
-}
-
-KoTextRangeManager *KoTextDocumentLayout::textRangeManager() const
-{
- return d->textRangeManager;
-}
-
-void KoTextDocumentLayout::setTextRangeManager(KoTextRangeManager *manager)
-{
- d->textRangeManager = manager;
-}
-
-KoChangeTracker *KoTextDocumentLayout::changeTracker() const
-{
- return d->changeTracker;
-}
-
-void KoTextDocumentLayout::setChangeTracker(KoChangeTracker *tracker)
-{
- d->changeTracker = tracker;
-}
-
-KoStyleManager *KoTextDocumentLayout::styleManager() const
-{
- return d->styleManager;
-}
-
-void KoTextDocumentLayout::setStyleManager(KoStyleManager *manager)
-{
- d->styleManager = manager;
-}
-
-QRectF KoTextDocumentLayout::blockBoundingRect(const QTextBlock &block) const
-{
- QTextLayout *layout = block.layout();
- return layout->boundingRect();
-}
-
-QSizeF KoTextDocumentLayout::documentSize() const
-{
- return QSizeF();
-}
-
-QRectF KoTextDocumentLayout::selectionBoundingBox(QTextCursor &cursor) const
-{
- QRectF retval;
- Q_FOREACH (const KoTextLayoutRootArea *rootArea, d->rootAreaList) {
- if (!rootArea->isDirty()) {
- QRectF areaBB = rootArea->selectionBoundingBox(cursor);
- if (areaBB.isValid()) {
- retval |= areaBB;
- }
- }
- }
- return retval;
-}
-
-
-void KoTextDocumentLayout::draw(QPainter *painter, const QAbstractTextDocumentLayout::PaintContext &context)
-{
- // WARNING Text shapes ask their root area directly to paint.
- // It saves a lot of extra traversal, that is quite costly for big
- // documents
- Q_UNUSED(painter);
- Q_UNUSED(context);
-}
-
-
-int KoTextDocumentLayout::hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const
-{
- Q_UNUSED(point);
- Q_UNUSED(accuracy);
- Q_ASSERT(false); //we should no longer call this method.
- // There is no need and is just slower than needed
- // call rootArea->hitTest() directly
- // root area is available through KoTextShapeData
- return -1;
-}
-
-int KoTextDocumentLayout::pageCount() const
-{
- return 1;
-}
-
-void KoTextDocumentLayout::setTabSpacing(qreal spacing)
-{
- d->defaultTabSizing = spacing;
-}
-
-qreal KoTextDocumentLayout::defaultTabSpacing() const
-{
- return d->defaultTabSizing;
-}
-
-// this method is called on every char inserted or deleted, on format changes, setting/moving of variables or objects.
-void KoTextDocumentLayout::documentChanged(int position, int charsRemoved, int charsAdded)
-{
- if (d->changesBlocked) {
- return;
- }
-
- int from = position;
- const int to = from + charsAdded;
- while (from < to) { // find blocks that have been added
- QTextBlock block = document()->findBlock(from);
- if (! block.isValid())
- break;
- if (from == block.position() && block.textList()) {
- KoTextBlockData data(block);
- data.setCounterWidth(-1);
- }
-
- from = block.position() + block.length();
- }
-
- // Mark the to the position corresponding root-areas as dirty. If there is no root-area for the position then we
- // don't need to mark anything dirty but still need to go on to force a scheduled relayout.
- if (!d->rootAreaList.isEmpty()) {
- KoTextLayoutRootArea *fromArea;
- if (position) {
- fromArea = rootAreaForPosition(position-1);
- } else {
- fromArea = d->rootAreaList.at(0);
- }
- int startIndex = fromArea ? qMax(0, d->rootAreaList.indexOf(fromArea)) : 0;
- int endIndex = startIndex;
- if (charsRemoved != 0 || charsAdded != 0) {
- // If any characters got removed or added make sure to also catch other root-areas that may be
- // affected by this change. Note that adding, removing or formatting text will always charsRemoved>0
- // and charsAdded>0 cause they are changing a range of characters. One case where both is zero is if
- // the content of a variable changed (see KoVariable::setValue which calls publicDocumentChanged). In
- // those cases we only need to relayout the root-area dirty where the variable is on.
- KoTextLayoutRootArea *toArea = fromArea ? rootAreaForPosition(position + qMax(charsRemoved, charsAdded) + 1) : 0;
- if (toArea) {
- if (toArea != fromArea) {
- endIndex = qMax(startIndex, d->rootAreaList.indexOf(toArea));
- } else {
- endIndex = startIndex;
- }
- } else {
- endIndex = d->rootAreaList.count() - 1;
- }
- // The previous and following root-area of that range are selected too cause they can also be affect by
- // changes done to the range of root-areas.
- if (startIndex >= 1)
- --startIndex;
- if (endIndex + 1 < d->rootAreaList.count())
- ++endIndex;
- }
- // Mark all selected root-areas as dirty so they are relayouted.
- for(int i = startIndex; i <= endIndex; ++i) {
- if (d->rootAreaList.size() > i && d->rootAreaList[i])
- d->rootAreaList[i]->setDirty();
- }
- }
-
- // Once done we emit the layoutIsDirty signal. The consumer (e.g. the TextShape) will then layout dirty
- // root-areas and if needed following ones which got dirty cause content moved to them. Also this will
- // created new root-areas using KoTextLayoutRootAreaProvider::provide if needed.
- emitLayoutIsDirty();
-}
-
-KoTextLayoutRootArea *KoTextDocumentLayout::rootAreaForPosition(int position) const
-{
- QTextBlock block = document()->findBlock(position);
- if (!block.isValid())
- return 0;
- QTextLine line = block.layout()->lineForTextPosition(position - block.position());
- if (!line.isValid())
- return 0;
-
- foreach (KoTextLayoutRootArea *rootArea, d->rootAreaList) {
- QRectF rect = rootArea->boundingRect(); // should already be normalized()
- if (rect.width() <= 0.0 && rect.height() <= 0.0) // ignore the rootArea if it has a size of QSizeF(0,0)
- continue;
- QPointF pos = line.position();
- qreal x = pos.x();
- qreal y = pos.y();
-
- //0.125 needed since Qt Scribe works with fixed point
- if (x + 0.125 >= rect.x() && x<= rect.right() && y + line.height() + 0.125 >= rect.y() && y <= rect.bottom()) {
- return rootArea;
- }
- }
- return 0;
-}
-
-KoTextLayoutRootArea *KoTextDocumentLayout::rootAreaForPoint(const QPointF &point) const
-{
- Q_FOREACH (KoTextLayoutRootArea *rootArea, d->rootAreaList) {
- if (!rootArea->isDirty()) {
- if (rootArea->boundingRect().contains(point)) {
- return rootArea;
- }
- }
- }
- return 0;
-}
-
-void KoTextDocumentLayout::showInlineObjectVisualization(bool show)
-{
- d->showInlineObjectVisualization = show;
-}
-
-void KoTextDocumentLayout::drawInlineObject(QPainter *painter, const QRectF &rect, QTextInlineObject object, int position, const QTextFormat &format)
-{
- Q_ASSERT(format.isCharFormat());
- if (d->inlineTextObjectManager == 0)
- return;
- QTextCharFormat cf = format.toCharFormat();
- if (d->showInlineObjectVisualization) {
- QColor color = cf.foreground().color();
- // initial idea was to use Qt::gray (#A0A0A4)
- // for non-black text on non-white background it was derived to use
- // the text color with a transparency of 0x5F, so white-gray (0xFF-0xA0)
- color.setAlpha(0x5F);
- cf.setBackground(QBrush(color));
- }
- KoInlineObject *obj = d->inlineTextObjectManager->inlineTextObject(cf);
- if (obj)
- obj->paint(*painter, paintDevice(), document(), rect, object, position, cf);
-}
-
-QList<KoShapeAnchor *> KoTextDocumentLayout::textAnchors() const
-{
- return d->textAnchors;
-}
-
-void KoTextDocumentLayout::registerAnchoredObstruction(KoTextLayoutObstruction *obstruction)
-{
- d->anchoredObstructions.insert(obstruction->shape(), obstruction);
-}
-
-qreal KoTextDocumentLayout::maxYOfAnchoredObstructions(int firstCursorPosition, int lastCursorPosition) const
-{
- qreal y = 0.0;
- int index = 0;
-
- while (index < d->anchoringIndex) {
- Q_ASSERT(index < d->textAnchors.count());
- KoShapeAnchor *anchor = d->textAnchors[index];
- if (anchor->flowWithText()) {
- if (anchor->textLocation()->position() >= firstCursorPosition
- && anchor->textLocation()->position() <= lastCursorPosition) {
- y = qMax(y, anchor->shape()->boundingRect().bottom() - anchor->shape()->parent()->boundingRect().y());
- }
- }
- ++index;
- }
- return y;
-}
-
-int KoTextDocumentLayout::anchoringSoftBreak() const
-{
- return d->anchoringSoftBreak;
-}
-void KoTextDocumentLayout::positionAnchoredObstructions()
-{
- if (!d->anchoringRootArea)
- return;
- KoTextPage *page = d->anchoringRootArea->page();
- if (!page)
- return;
- if (d->anAnchorIsPlaced)
- return;
-
- // The specs define 3 different anchor modes using the
- // draw:wrap-influence-on-position. We only implement the
- // once-successive and decided against supporting the other
- // two modes cause;
- // 1. The first mode, once-concurrently, is only for backward-compatibility
- // with pre OpenOffice.org 1.1. No other application supports that. It
- // should never have been added to the specs.
- // 2. The iterative mode is undocumented and it's absolute unclear how to
- // implement it in a way that we would earn 100% the same results OO.org
- // produces. In fact by looking at the OO.org source-code there seem to
- // be lot of extra-conditions, assumptions and OO.org related things going
- // on to handle that mode. We tried to support that mode once and it did
- // hit us bad, our source-code become way more worse, layouting slower and
- // the result was still different from OO.org. So, we decided it's not
- // worth it.
- // 3. The explanation provided at https://lists.oasis-open.org/archives/office/200409/msg00018.html
- // why the specs support those 3 anchor modes is, well, poor. It just doesn't
- // make sense. The specs should be fixed.
- // 4. The only support mode, the once-successive, is the one (only) support by
- // MSOffice. It's clear, logical, easy and needs to be supported by all
- // major office-suites that like to be compatible with MSOffice and OO.org.
- if (d->anchoringIndex < d->textAnchors.count()) {
- KoShapeAnchor *textAnchor = d->textAnchors[d->anchoringIndex];
- AnchorStrategy *strategy = static_cast<AnchorStrategy *>(textAnchor->placementStrategy());
-
- strategy->setPageRect(page->rect());
- strategy->setPageContentRect(page->contentRect());
- strategy->setPageNumber(page->pageNumber());
-
- if (strategy->moveSubject()) {
- ++d->anchoringIndex;
- d->anAnchorIsPlaced = true;
- }
- }
-}
-
-void KoTextDocumentLayout::setAnchoringParagraphRect(const QRectF &paragraphRect)
-{
- d->anchoringParagraphRect = paragraphRect;
-}
-
-void KoTextDocumentLayout::setAnchoringParagraphContentRect(const QRectF &paragraphContentRect)
-{
- d->anchoringParagraphContentRect = paragraphContentRect;
-}
-
-void KoTextDocumentLayout::setAnchoringLayoutEnvironmentRect(const QRectF &layoutEnvironmentRect)
-{
- d->anchoringLayoutEnvironmentRect = layoutEnvironmentRect;
-}
-
-void KoTextDocumentLayout::allowPositionInlineObject(bool allow)
-{
- d->allowPositionInlineObject = allow;
-}
-
-// This method is called by qt every time QTextLine.setWidth()/setNumColumns() is called
-void KoTextDocumentLayout::positionInlineObject(QTextInlineObject item, int position, const QTextFormat &format)
-{
- // Note: "item" used to be what was positioned. We don't actually use qtextinlineobjects anymore
- // for our inline objects, but get the id from the format.
- Q_UNUSED(item);
- //We are called before layout so that we can position objects
- Q_ASSERT(format.isCharFormat());
- if (d->inlineTextObjectManager == 0)
- return;
- if (!d->allowPositionInlineObject)
- return;
- QTextCharFormat cf = format.toCharFormat();
- KoInlineObject *obj = d->inlineTextObjectManager->inlineTextObject(cf);
- // We need some special treatment for anchors as they need to position their object during
- // layout and not this early
- KoAnchorInlineObject *anchorObject = dynamic_cast<KoAnchorInlineObject *>(obj);
- if (anchorObject && d->anchoringRootArea->associatedShape()) {
- // The type can only be KoShapeAnchor::AnchorAsCharacter since it's inline
- KoShapeAnchor *anchor = anchorObject->anchor();
- d->foundAnchors.append(anchor);
-
- // if there is no anchor strategy set then create one
- if (!anchor->placementStrategy()) {
- anchor->setPlacementStrategy(new InlineAnchorStrategy(anchorObject, d->anchoringRootArea));
- d->textAnchors.append(anchor);
- anchorObject->updatePosition(document(), position, cf); // by extension calls updateContainerModel
- }
- static_cast<AnchorStrategy *>(anchor->placementStrategy())->setParagraphRect(d->anchoringParagraphRect);
- static_cast<AnchorStrategy *>(anchor->placementStrategy())->setParagraphContentRect(d->anchoringParagraphContentRect);
- static_cast<AnchorStrategy *>(anchor->placementStrategy())->setLayoutEnvironmentRect(d->anchoringLayoutEnvironmentRect);
- }
- else if (obj) {
- obj->updatePosition(document(), position, cf);
- }
-}
-
-// This method is called by KoTextLauoutArea every time it encounters a KoAnchorTextRange
-void KoTextDocumentLayout::positionAnchorTextRanges(int pos, int length, const QTextDocument *effectiveDocument)
-{
- if (!d->allowPositionInlineObject)
- return;
-
- if (!textRangeManager()) {
- return;
- }
- QHash<int, KoTextRange *> ranges = textRangeManager()->textRangesChangingWithin(effectiveDocument, pos, pos+length, pos, pos+length);
-
- Q_FOREACH (KoTextRange *range, ranges.values()) {
- KoAnchorTextRange *anchorRange = dynamic_cast<KoAnchorTextRange *>(range);
- if (anchorRange) {
- // We need some special treatment for anchors as they need to position their object during
- // layout and not this early
- KoShapeAnchor *anchor = anchorRange->anchor();
- d->foundAnchors.append(anchor);
-
- // At the beginAnchorCollecting the strategy is cleared, so this if will be entered
- // every time we layout a page (though not every time for the inner repeats due to anchors)
- if (!anchor->placementStrategy()) {
- int index = d->textAnchors.count();
- anchor->setPlacementStrategy(new FloatingAnchorStrategy(anchorRange, d->anchoringRootArea));
-
- // The purpose of following code-block is to be sure that our paragraph-anchors are
- // properly sorted by their z-index so the FloatingAnchorStrategy::checkStacking
- // logic stack in the proper order. Bug 274512 has a testdoc for this attached.
- if (index > 0 &&
- anchor->anchorType() == KoShapeAnchor::AnchorParagraph &&
- (anchor->horizontalRel() == KoShapeAnchor::HParagraph || anchor->horizontalRel() == KoShapeAnchor::HParagraphContent) &&
- (anchor->horizontalPos() == KoShapeAnchor::HLeft || anchor->horizontalPos() == KoShapeAnchor::HRight)) {
- QTextBlock anchorBlock = document()->findBlock(anchorRange->position());
- for(int i = index - 1; i >= 0; --i) {
- KoShapeAnchor *a = d->textAnchors[i];
- if (a->anchorType() != anchor->anchorType())
- break;
- if (a->horizontalPos() != anchor->horizontalPos())
- break;
- if (document()->findBlock(a->textLocation()->position()) != anchorBlock)
- break;
- if (a->shape()->zIndex() < anchor->shape()->zIndex())
- break;
- --index;
- }
- }
- d->textAnchors.insert(index, anchor);
- anchorRange->updateContainerModel();
- }
- static_cast<AnchorStrategy *>(anchor->placementStrategy())->setParagraphRect(d->anchoringParagraphRect);
- static_cast<AnchorStrategy *>(anchor->placementStrategy())->setParagraphContentRect(d->anchoringParagraphContentRect);
- static_cast<AnchorStrategy *>(anchor->placementStrategy())->setLayoutEnvironmentRect(d->anchoringLayoutEnvironmentRect);
- }
- KoAnnotation *annotation = dynamic_cast<KoAnnotation *>(range);
- if (annotation) {
- int position = range->rangeStart();
- QTextBlock block = range->document()->findBlock(position);
- QTextLine line = block.layout()->lineForTextPosition(position - block.position());
- QPointF refPos(line.cursorToX(position - block.position()), line.y());
-
- KoShape *refShape = d->anchoringRootArea->associatedShape();
- //KoTextShapeData *refTextShapeData;
- //refPos += QPointF(refTextShapeData->leftPadding(), -refTextShapeData->documentOffset() + refTextShapeData->topPadding());
-
- refPos += QPointF(0, -d->anchoringRootArea->top());
- refPos = refShape->absoluteTransformation().map(refPos);
-
- //FIXME we need a more precise position than anchorParagraph Rect
- emit foundAnnotation(annotation->annotationShape(), refPos);
- }
- }
-}
-
-void KoTextDocumentLayout::beginAnchorCollecting(KoTextLayoutRootArea *rootArea)
-{
- for(int i = 0; i<d->textAnchors.size(); i++ ) {
- d->textAnchors[i]->setPlacementStrategy(0);
- }
-
- qDeleteAll(d->anchoredObstructions);
- d->anchoredObstructions.clear();
- d->textAnchors.clear();
-
- d->anchoringIndex = 0;
- d->anAnchorIsPlaced = false;
- d->anchoringRootArea = rootArea;
- d->allowPositionInlineObject = true;
- d->anchoringSoftBreak = INT_MAX;
-}
-
-void KoTextDocumentLayout::resizeInlineObject(QTextInlineObject item, int position, const QTextFormat &format)
-{
- // Note: This method is called by qt during layout AND during paint
- Q_ASSERT(format.isCharFormat());
- if (d->inlineTextObjectManager == 0)
- return;
- QTextCharFormat cf = format.toCharFormat();
- KoInlineObject *obj = d->inlineTextObjectManager->inlineTextObject(cf);
-
- if (!obj) {
- return;
- }
-
- if (d->isLayouting) {
- d->rootAreaForInlineObject[obj] = d->anchoringRootArea;
- }
- KoTextLayoutRootArea *rootArea = d->rootAreaForInlineObject.value(obj);
-
- if (rootArea == 0 || rootArea->associatedShape() == 0)
- return;
-
- QTextDocument *doc = document();
- QVariant v;
- v.setValue(rootArea->page());
- doc->addResource(KoTextDocument::LayoutTextPage, KoTextDocument::LayoutTextPageUrl, v);
- obj->resize(doc, item, position, cf, paintDevice());
- registerInlineObject(item);
-}
-
-void KoTextDocumentLayout::emitLayoutIsDirty()
-{
- emit layoutIsDirty();
-}
-
-void KoTextDocumentLayout::layout()
-{
- if (d->layoutBlocked) {
- return;
- }
-
- if (IndexGeneratorManager::instance(document())->generate()) {
- return;
- }
-
- Q_ASSERT(!d->isLayouting);
- d->isLayouting = true;
-
- bool finished;
- do {
- // Try to layout as long as d->restartLayout==true. This can happen for example if
- // a schedule layout call interrupts the layouting and asks for a new layout run.
- finished = doLayout();
- } while (d->restartLayout);
-
- Q_ASSERT(d->isLayouting);
- d->isLayouting = false;
-
- if (finished) {
- // We are only finished with layouting if continuousLayout()==true.
- emit finishedLayout();
- }
-}
-
-RootAreaConstraint constraintsForPosition(QTextFrame::iterator it, bool previousIsValid)
-{
- RootAreaConstraint constraints;
- constraints.masterPageName.clear();
- constraints.visiblePageNumber = -1;
- constraints.newPageForced = false;
- QTextBlock block = it.currentBlock();
- QTextTable *table = qobject_cast<QTextTable*>(it.currentFrame());
- if (block.isValid()) {
- constraints.masterPageName = block.blockFormat().stringProperty(KoParagraphStyle::MasterPageName);
- if (block.blockFormat().hasProperty(KoParagraphStyle::PageNumber)) {
- constraints.visiblePageNumber = block.blockFormat().intProperty(KoParagraphStyle::PageNumber);
- }
- constraints.newPageForced = block.blockFormat().intProperty(KoParagraphStyle::BreakBefore) == KoText::PageBreak;
- }
- if (table) {
- constraints.masterPageName = table->frameFormat().stringProperty(KoTableStyle::MasterPageName);
- if (table->frameFormat().hasProperty(KoTableStyle::PageNumber)) {
- constraints.visiblePageNumber = table->frameFormat().intProperty(KoTableStyle::PageNumber);
- }
- constraints.newPageForced = table->frameFormat().intProperty(KoTableStyle::BreakBefore) == KoText::PageBreak;
- }
-
- if (!constraints.masterPageName.isEmpty()) {
- constraints.newPageForced = true;
- }
- if (previousIsValid && !constraints.newPageForced) {
- it--;
- block = it.currentBlock();
- table = qobject_cast<QTextTable*>(it.currentFrame());
- if (block.isValid()) {
- constraints.newPageForced = block.blockFormat().intProperty(KoParagraphStyle::BreakAfter) == KoText::PageBreak;
- }
- if (table) {
- constraints.newPageForced = table->frameFormat().intProperty(KoTableStyle::BreakAfter) == KoText::PageBreak;
- }
- }
-
- return constraints;
-}
-
-bool KoTextDocumentLayout::doLayout()
-{
- delete d->layoutPosition;
- d->layoutPosition = new FrameIterator(document()->rootFrame());
- d->y = 0;
- d->layoutScheduled = false;
- d->restartLayout = false;
- FrameIterator *transferedFootNoteCursor = 0;
- KoInlineNote *transferedContinuedNote = 0;
- int footNoteAutoCount = 0;
- KoTextLayoutRootArea *rootArea = 0;
-
- d->rootAreaList.clear();
-
- int currentAreaNumber = 0;
- do {
- if (d->restartLayout) {
- return false; // Abort layouting to restart from the beginning.
- }
-
- // Build our request for our rootArea provider
- RootAreaConstraint constraints = constraintsForPosition(d->layoutPosition->it, currentAreaNumber > 0);
-
- // Request a new root-area. If 0 is returned then layouting is finished.
- bool newRootArea = false;
- rootArea = d->provider->provide(this, constraints, currentAreaNumber, &newRootArea);
- if (!rootArea) {
- // Out of space ? Nothing more to do
- break;
- }
-
- d->rootAreaList.append(rootArea);
- bool shouldLayout = false;
-
- if (rootArea->top() != d->y) {
- shouldLayout = true;
- }
- else if (rootArea->isDirty()) {
- shouldLayout = true;
- }
- else if (!rootArea->isStartingAt(d->layoutPosition)) {
- shouldLayout = true;
- }
- else if (newRootArea) {
- shouldLayout = true;
- }
-
- if (shouldLayout) {
- QRectF rect = d->provider->suggestRect(rootArea);
- d->freeObstructions = d->provider->relevantObstructions(rootArea);
-
- rootArea->setReferenceRect(rect.left(), rect.right(), d->y + rect.top(), d->y + rect.bottom());
-
- beginAnchorCollecting(rootArea);
-
- // Layout all that can fit into that root area
- bool finished;
- FrameIterator *tmpPosition = 0;
- do {
- rootArea->setFootNoteCountInDoc(footNoteAutoCount);
- rootArea->setFootNoteFromPrevious(transferedFootNoteCursor, transferedContinuedNote);
- d->foundAnchors.clear();
- delete tmpPosition;
- tmpPosition = new FrameIterator(d->layoutPosition);
- finished = rootArea->layoutRoot(tmpPosition);
- if (d->anAnchorIsPlaced) {
- d->anAnchorIsPlaced = false;
- } else {
- ++d->anchoringIndex;
- }
- } while (d->anchoringIndex < d->textAnchors.count());
-
- foreach (KoShapeAnchor *anchor, d->textAnchors) {
- if (!d->foundAnchors.contains(anchor)) {
- d->anchoredObstructions.remove(anchor->shape());
- d->anchoringSoftBreak = qMin(d->anchoringSoftBreak, anchor->textLocation()->position());
- }
- }
-
- if (d->textAnchors.count() > 0) {
- delete tmpPosition;
- tmpPosition = new FrameIterator(d->layoutPosition);
- finished = rootArea->layoutRoot(tmpPosition);
- }
- delete d->layoutPosition;
- d->layoutPosition = tmpPosition;
-
- d->provider->doPostLayout(rootArea, newRootArea);
- updateProgress(d->layoutPosition->it);
-
- if (finished && !rootArea->footNoteCursorToNext()) {
- d->provider->releaseAllAfter(rootArea);
- // We must also delete them from our own list too
- int newsize = d->rootAreaList.indexOf(rootArea) + 1;
- while (d->rootAreaList.size() > newsize) {
- d->rootAreaList.removeLast();
- }
- return true; // Finished layouting
- }
-
- if (d->layoutPosition->it == document()->rootFrame()->end()) {
- return true; // Finished layouting
- }
-
- if (!continuousLayout()) {
- return false; // Let's take a break. We are not finished layouting yet.
- }
- } else {
- // Drop following rootAreas
- delete d->layoutPosition;
- d->layoutPosition = new FrameIterator(rootArea->nextStartOfArea());
- if (d->layoutPosition->it == document()->rootFrame()->end() && !rootArea->footNoteCursorToNext()) {
- d->provider->releaseAllAfter(rootArea);
- // We must also delete them from our own list too
- int newsize = d->rootAreaList.indexOf(rootArea) + 1;
- while (d->rootAreaList.size() > newsize) {
- d->rootAreaList.removeLast();
- }
- return true; // Finished layouting
- }
- }
- transferedFootNoteCursor = rootArea->footNoteCursorToNext();
- transferedContinuedNote = rootArea->continuedNoteToNext();
- footNoteAutoCount += rootArea->footNoteAutoCount();
-
- d->y = rootArea->bottom() + qreal(50); // (post)Layout method(s) just set this
- // 50 just to separate pages
- currentAreaNumber++;
- } while (transferedFootNoteCursor || d->layoutPosition->it != document()->rootFrame()->end());
-
- return true; // Finished layouting
-}
-
-void KoTextDocumentLayout::scheduleLayout()
-{
- // Compress multiple scheduleLayout calls into one executeScheduledLayout.
- if (d->layoutScheduled) {
- return;
- }
- d->layoutScheduled = true;
- QTimer::singleShot(0, this, SLOT(executeScheduledLayout()));
-}
-
-void KoTextDocumentLayout::executeScheduledLayout()
-{
- // Only do the actual layout if it wasn't done meanwhile by someone else.
- if (!d->layoutScheduled) {
- return;
- }
- d->layoutScheduled = false;
- if (d->isLayouting) {
- // Since we are already layouting ask for a restart to be sure to also include
- // root-areas that got dirty and are before the currently processed root-area.
- d->restartLayout = true;
- } else {
- layout();
- }
-}
-
-bool KoTextDocumentLayout::continuousLayout() const
-{
- return d->continuousLayout;
-}
-
-void KoTextDocumentLayout::setContinuousLayout(bool continuous)
-{
- d->continuousLayout = continuous;
-}
-
-void KoTextDocumentLayout::setBlockLayout(bool block)
-{
- d->layoutBlocked = block;
-}
-
-bool KoTextDocumentLayout::layoutBlocked() const
-{
- return d->layoutBlocked;
-}
-
-void KoTextDocumentLayout::setBlockChanges(bool block)
-{
- d->changesBlocked = block;
-}
-
-bool KoTextDocumentLayout::changesBlocked() const
-{
- return d->changesBlocked;
-}
-
-KoTextDocumentLayout* KoTextDocumentLayout::referencedLayout() const
-{
- return d->referencedLayout;
-}
-
-void KoTextDocumentLayout::setReferencedLayout(KoTextDocumentLayout *layout)
-{
- d->referencedLayout = layout;
-}
-
-QRectF KoTextDocumentLayout::frameBoundingRect(QTextFrame*) const
-{
- return QRectF();
-}
-
-void KoTextDocumentLayout::clearInlineObjectRegistry(const QTextBlock &block)
-{
- d->inlineObjectExtents.clear();
- d->inlineObjectOffset = block.position();
-}
-
-void KoTextDocumentLayout::registerInlineObject(const QTextInlineObject &inlineObject)
-{
- KoInlineObjectExtent pos(inlineObject.ascent(),inlineObject.descent());
- d->inlineObjectExtents.insert(d->inlineObjectOffset + inlineObject.textPosition(), pos);
-}
-
-KoInlineObjectExtent KoTextDocumentLayout::inlineObjectExtent(const QTextFragment &fragment)
-{
- if (d->inlineObjectExtents.contains(fragment.position()))
- return d->inlineObjectExtents[fragment.position()];
- return KoInlineObjectExtent();
-}
-
-void KoTextDocumentLayout::setContinuationObstruction(KoTextLayoutObstruction *continuationObstruction)
-{
- if (d->continuationObstruction) {
- delete d->continuationObstruction;
- }
- d->continuationObstruction = continuationObstruction;
-}
-
-QList<KoTextLayoutObstruction *> KoTextDocumentLayout::currentObstructions()
-{
- if (d->continuationObstruction) {
- // () is needed so we append to a local list and not anchoredObstructions
- return (d->freeObstructions + d->anchoredObstructions.values()) << d->continuationObstruction;
- } else {
- return d->freeObstructions + d->anchoredObstructions.values();
- }
-}
-
-QList<KoTextLayoutRootArea *> KoTextDocumentLayout::rootAreas() const
-{
- return d->rootAreaList;
-}
-
-void KoTextDocumentLayout::removeRootArea(KoTextLayoutRootArea *rootArea)
-{
- int indexOf = rootArea ? qMax(0, d->rootAreaList.indexOf(rootArea)) : 0;
- for(int i = d->rootAreaList.count() - 1; i >= indexOf; --i)
- d->rootAreaList.removeAt(i);
-}
-
-QList<KoShape*> KoTextDocumentLayout::shapes() const
-{
- QList<KoShape*> listOfShapes;
- foreach (KoTextLayoutRootArea *rootArea, d->rootAreaList) {
- if (rootArea->associatedShape())
- listOfShapes.append(rootArea->associatedShape());
- }
- return listOfShapes;
-}
-
-void KoTextDocumentLayout::updateProgress(const QTextFrame::iterator &it)
-{
- QTextBlock block = it.currentBlock();
- if (block.isValid()) {
- int percent = block.position() / qreal(document()->rootFrame()->lastPosition()) * 100.0;
- emit layoutProgressChanged(percent);
- } else if (it.currentFrame()) {
- int percent = it.currentFrame()->firstPosition() / qreal(document()->rootFrame()->lastPosition()) * 100.0;
- emit layoutProgressChanged(percent);
- }
-}
diff --git a/plugins/flake/textshape/textlayout/KoTextDocumentLayout.h b/plugins/flake/textshape/textlayout/KoTextDocumentLayout.h
deleted file mode 100644
index 3ed0095e56..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextDocumentLayout.h
+++ /dev/null
@@ -1,327 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2007, 2009 Thomas Zander <zander@kde.org>
- * Copyright (C) 2006, 2011 Sebastian Sauer <mail@dipe.org>
- * Copyright (C) 2011 C. Boemann <cbo@kogmbh.com>
- *
- * 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 KOTEXTDOCUMENTLAYOUT_H
-#define KOTEXTDOCUMENTLAYOUT_H
-
-#include "kritatextlayout_export.h"
-
-#include <QAbstractTextDocumentLayout>
-#include <QList>
-#include <QTextFrame>
-
-class KoShape;
-class KoStyleManager;
-class KoChangeTracker;
-class KoTextRangeManager;
-class KoInlineTextObjectManager;
-class KoViewConverter;
-class KoImageCollection;
-class KoShapeAnchor;
-class KoTextLayoutRootArea;
-class KoTextLayoutRootAreaProvider;
-class KoTextLayoutObstruction;
-
-class QRectF;
-class QSizeF;
-
-class KRITATEXTLAYOUT_EXPORT KoInlineObjectExtent
-{
-public:
- explicit KoInlineObjectExtent(qreal ascent = 0, qreal descent = 0);
- qreal m_ascent;
- qreal m_descent;
-};
-
-
-/**
- * Text layouter that allows text to flow in multiple root area and around
- * obstructions.
- */
-class KRITATEXTLAYOUT_EXPORT KoTextDocumentLayout : public QAbstractTextDocumentLayout
-{
- Q_OBJECT
-public:
- /// This struct is a helper for painting of kotext texts.
- struct PaintContext {
- PaintContext()
- : imageCollection(0)
- , showFormattingCharacters(false)
- , showSectionBounds(false)
- , showSpellChecking(false)
- , showSelections(true)
- , background(Qt::white)
- {
- }
-
- /// the QText context
- QAbstractTextDocumentLayout::PaintContext textContext;
- /// A view converter, when set, is used to find out when the zoom is so low that painting of text is unneeded
-
- KoImageCollection *imageCollection;
- bool showFormattingCharacters;
- bool showTableBorders;
- bool showSectionBounds;
- bool showSpellChecking;
- bool showSelections;
- QColor background;
- };
-
- /// constructor
- explicit KoTextDocumentLayout(QTextDocument *doc, KoTextLayoutRootAreaProvider *provider = 0);
- ~KoTextDocumentLayout() override;
-
- /// return the rootAreaProvider.
- KoTextLayoutRootAreaProvider *provider() const;
-
- /// return the currently set manager, or 0 if none is set.
- KoInlineTextObjectManager *inlineTextObjectManager() const;
- void setInlineTextObjectManager(KoInlineTextObjectManager *manager);
-
- /// return the currently set manager, or 0 if none is set.
- KoTextRangeManager *textRangeManager() const;
- void setTextRangeManager(KoTextRangeManager *manager);
-
- /// return the currently set changeTracker, or 0 if none is set.
- KoChangeTracker *changeTracker() const;
- void setChangeTracker(KoChangeTracker *tracker);
-
- /// return the currently set styleManager, or 0 if none is set.
- KoStyleManager *styleManager() const;
- void setStyleManager(KoStyleManager *manager);
-
- /// Returns the bounding rectangle of block.
- QRectF blockBoundingRect(const QTextBlock &block) const override;
- /**
- * Returns the total size of the document. This is useful to display
- * widgets since they can use to information to update their scroll bars
- * correctly
- */
- QSizeF documentSize() const override;
-
- QRectF frameBoundingRect(QTextFrame*) const override;
-
- /// the default tab size for this document
- qreal defaultTabSpacing() const;
-
- /// set default tab size for this document
- void setTabSpacing(qreal spacing);
-
- /// set if this is for a word processor (slight changes in layout may occur)
- void setWordprocessingMode();
-
- /// is it for a word processor (slight changes in layout may occur)
- bool wordprocessingMode() const;
-
- /// are the tabs relative to indent or not
- bool relativeTabs(const QTextBlock &block) const;
-
- /// visualize inline objects during paint
- void showInlineObjectVisualization(bool show);
-
- /// Calc a bounding box rect of the selection
- QRectF selectionBoundingBox(QTextCursor &cursor) const;
-
- /// Draws the layout on the given painter with the given context.
- void draw(QPainter * painter, const QAbstractTextDocumentLayout::PaintContext & context) override;
-
- /// reimplemented DO NOT CALL - USE HITTEST IN THE ROOTAREAS INSTEAD
- int hitTest(const QPointF & point, Qt::HitTestAccuracy accuracy) const override;
-
- /// reimplemented to always return 1
- int pageCount() const override;
-
- QList<KoShapeAnchor *> textAnchors() const;
-
- /**
- * Register the anchored obstruction for run around
- *
- * We have the concept of Obstructions which text has to run around in various ways.
- * We maintain two collections of obstructions. The free which are tied to just a position
- * (tied to pages), and the anchored obstructions which are each anchored to a KoShapeAnchor
- *
- * The free obstructions are collected from the KoTextLayoutRootAreaProvider during layout
- *
- * The anchored obstructions are created in the FloatingAnchorStrategy and registered using
- * this method.
- */
- void registerAnchoredObstruction(KoTextLayoutObstruction *obstruction);
-
-
- /**
- * Anchors are special InlineObjects that we detect in positionInlineObject()
- * We save those for later so we can position them during layout instead.
- * During KoTextLayoutArea::layout() we call positionAnchoredObstructions()
- */
- /// remove all anchors and associated obstructions and set up for collecting new ones
- void beginAnchorCollecting(KoTextLayoutRootArea *rootArea);
-
- /// allow positionInlineObject() to do anything (incl saving anchors)
- void allowPositionInlineObject(bool allow);
-
- /// Sets the paragraph rect that will be applied to anchorStrategies being created in
- /// positionInlineObject()
- void setAnchoringParagraphRect(const QRectF &paragraphRect);
-
- /// Sets the paragraph content rect that will be applied to anchorStrategies being created in
- /// positionInlineObject()
- void setAnchoringParagraphContentRect(const QRectF &paragraphContentRect);
-
- /// Sets the layoutEnvironment rect that will be applied to anchorStrategies being created in
- /// positionInlineObject()
- void setAnchoringLayoutEnvironmentRect(const QRectF &layoutEnvironmentRect);
-
- /// Calculates the maximum y of anchored obstructions
- qreal maxYOfAnchoredObstructions(int firstCursorPosition, int lastCursorPosition) const;
-
- int anchoringSoftBreak() const;
-
- /// Positions all anchored obstructions
- /// the paragraphRect should be in textDocument coords and not global/document coords
- void positionAnchoredObstructions();
-
- /// remove inline object
- void removeInlineObject(KoShapeAnchor *textAnchor);
-
- void clearInlineObjectRegistry(const QTextBlock& block);
-
- KoInlineObjectExtent inlineObjectExtent(const QTextFragment&);
-
- /**
- * We allow a text document to be distributed onto a sequence of KoTextLayoutRootArea;
- * which brings up the need to figure out which KoTextLayoutRootArea is used for a certain
- * text.
- * @param position the position of the character in the text document we want to locate.
- * @return the KoTextLayoutRootArea the text is laid-out in. Or 0 if there is no shape for that text character.
- */
- KoTextLayoutRootArea *rootAreaForPosition(int position) const;
-
-
- KoTextLayoutRootArea *rootAreaForPoint(const QPointF &point) const;
-
- /**
- * Remove the root-areas \p rootArea from the list of \a rootAreas() .
- * \param rootArea root-area to remove. If 0 then all root-areas are removed.
- */
- void removeRootArea(KoTextLayoutRootArea *rootArea = 0);
-
- /// reimplemented from QAbstractTextDocumentLayout
- void documentChanged(int position, int charsRemoved, int charsAdded) override;
-
- void setContinuationObstruction(KoTextLayoutObstruction *continuationObstruction);
-
- /// Return a list of obstructions intersecting current root area (during layout)
- QList<KoTextLayoutObstruction *> currentObstructions();
-
- QList<KoTextLayoutRootArea *> rootAreas() const;
- QList<KoShape*> shapes() const;
-
- /// Set should layout be continued when done with current root area
- void setContinuousLayout(bool continuous);
-
- /// Set \a layout() to be blocked (no layouting will happen)
- void setBlockLayout(bool block);
- bool layoutBlocked() const;
-
- /// Set \a documentChanged() to be blocked (changes will not result in root-areas being marked dirty)
- void setBlockChanges(bool block);
- bool changesBlocked() const;
-
- KoTextDocumentLayout* referencedLayout() const;
- void setReferencedLayout(KoTextDocumentLayout *layout);
-
- /**
- * To be called during layout by KoTextLayoutArea - similar to how qt calls positionInlineObject
- *
- * It searches for anchor text ranges in the given span
- */
- void positionAnchorTextRanges(int pos, int length, const QTextDocument *effectiveDocument);
-
-Q_SIGNALS:
- /**
- * Signal that is emitted during layouting to inform about the progress done so far.
- */
- void layoutProgressChanged(int percent);
-
- /**
- * Signal is emitted every time a layout run has completely finished (all text is positioned).
- */
- void finishedLayout();
-
- /**
- * Signal is emitted when emitLayoutIsDirty() is called which happens at
- * least when a root area is marked as dirty.
- * @see emitLayoutIsDirty
- */
- void layoutIsDirty();
-
- void foundAnnotation(KoShape *annotationShape, const QPointF &refPosition);
-
-public Q_SLOTS:
- /**
- * Does the layout of the text.
- * This method will layout the text into sections, tables and textlines,
- * chunk by chunk.
- * It may interrupt itself, @see contiuousLayout
- * calling this method when the layout is not dirty, doesn't take that much
- * time as it doesn't do much, although it does check every root area
- */
- virtual void layout();
-
- /**
- * Schedules a \a layout call for later using a QTimer::singleShot. Multiple calls
- * to this slot will be compressed into one layout-call to prevent calling layouting
- * to much. Also if meanwhile \a layout was called then the scheduled layout won't
- * be executed.
- */
- virtual void scheduleLayout();
-
- /**
- * Emits the \a layoutIsDirty signal.
- */
- void emitLayoutIsDirty();
-
-private Q_SLOTS:
- /// Called by \a scheduleLayout to start a \a layout run if not done already meanwhile.
- void executeScheduledLayout();
-
-protected:
- /// reimplemented
- void drawInlineObject(QPainter *painter, const QRectF &rect, QTextInlineObject object, int position, const QTextFormat &format) override;
- /// reimplemented
- void positionInlineObject(QTextInlineObject item, int position, const QTextFormat &format) override;
- /// reimplemented
- void resizeInlineObject(QTextInlineObject item, int position, const QTextFormat &format) override;
-
- /// should we continue layout when done with current root area
- bool continuousLayout() const;
-
- void registerInlineObject(const QTextInlineObject &inlineObject);
-
-private:
- class Private;
- Private * const d;
-
- bool doLayout();
- void updateProgress(const QTextFrame::iterator &it);
-};
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutArea.cpp b/plugins/flake/textshape/textlayout/KoTextLayoutArea.cpp
deleted file mode 100644
index 8a7460a8c4..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextLayoutArea.cpp
+++ /dev/null
@@ -1,2091 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008,2011 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2008 Roopesh Chander <roop@forwardbias.in>
- * Copyright (C) 2007-2008 Pierre Ducroquet <pinaraf@pinaraf.info>
- * Copyright (C) 2009-2011 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2009-2011 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2010 Nandita Suri <suri.nandita@gmail.com>
- * Copyright (C) 2010 Ajay Pundhir <ajay.pratap@iiitb.net>
- * Copyright (C) 2011 Lukáš Tvrdý <lukas.tvrdy@ixonos.com>
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- * Copyright (C) 2011 Stuart Dickson <stuart@furkinfantasic.net>
- *
- * 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 "KoTextLayoutArea.h"
-#include "KoTextLayoutArea_p.h"
-
-#include "TableIterator.h"
-#include "ListItemsHelper.h"
-#include "RunAroundHelper.h"
-#include "KoTextDocumentLayout.h"
-#include "FrameIterator.h"
-#include "KoPointedAt.h"
-
-#include <KoTextDocument.h>
-#include <KoParagraphStyle.h>
-#include <KoCharacterStyle.h>
-#include <KoListStyle.h>
-#include <KoTableStyle.h>
-#include <KoStyleManager.h>
-#include <KoTextBlockData.h>
-#include <KoText.h>
-#include <KoChangeTracker.h>
-#include <KoChangeTrackerElement.h>
-#include <KoInlineNote.h>
-#include <KoTextSoftPageBreak.h>
-#include <KoInlineTextObjectManager.h>
-
-#include <TextLayoutDebug.h>
-
-#include <QTextFrame>
-#include <QTextTable>
-#include <QTextList>
-#include <QStyle>
-#include <QFontMetrics>
-#include <QTextFragment>
-#include <QTextLayout>
-#include <QTextCursor>
-
-extern int qt_defaultDpiY();
-Q_DECLARE_METATYPE(QTextDocument *)
-
-#define DropCapsAdditionalFormattingId 25602902
-#define PresenterFontStretch 1.2
-
-KoTextLayoutArea::KoTextLayoutArea(KoTextLayoutArea *p, KoTextDocumentLayout *documentLayout)
- : d (new Private)
-{
- d->parent = p;
- d->documentLayout = documentLayout;
-}
-
-KoTextLayoutArea::~KoTextLayoutArea()
-{
- qDeleteAll(d->tableAreas);
- qDeleteAll(d->footNoteAreas);
- qDeleteAll(d->preregisteredFootNoteAreas);
- delete d->startOfArea;
- delete d->endOfArea;
- delete d;
-}
-
-
-KoPointedAt KoTextLayoutArea::hitTest(const QPointF &p, Qt::HitTestAccuracy accuracy) const
-{
- QPointF point = p - QPointF(0, d->verticalAlignOffset);
-
- if (d->startOfArea == 0) // We have not been layouted yet
- return KoPointedAt();
-
- KoPointedAt pointedAt;
- bool basicallyFound = false;
-
- QTextFrame::iterator it = d->startOfArea->it;
- QTextFrame::iterator stop = d->endOfArea->it;
- if (!stop.atEnd()) {
- if(!stop.currentBlock().isValid() || d->endOfArea->lineTextStart >= 0) {
- // Last thing we contain is a frame (table) or first part of a paragraph split in two
- // The stop point should be the object after that
- // However if stop is already atEnd we shouldn't increment further
- ++stop;
- }
- }
- int tableAreaIndex = 0;
- int tocIndex = 0;
- int footNoteIndex = 0;
- for (; it != stop && !it.atEnd(); ++it) {
- QTextBlock block = it.currentBlock();
- QTextTable *table = qobject_cast<QTextTable*>(it.currentFrame());
- QTextFrame *subFrame = it.currentFrame();
- QTextBlockFormat format = block.blockFormat();
-
- if (table) {
- if (tableAreaIndex >= d->tableAreas.size()) {
- continue;
- }
- if (point.y() > d->tableAreas[tableAreaIndex]->top()
- && point.y() < d->tableAreas[tableAreaIndex]->bottom()) {
- return d->tableAreas[tableAreaIndex]->hitTest(point, accuracy);
- }
- ++tableAreaIndex;
- continue;
- } else if (subFrame) {
- if (it.currentFrame()->format().intProperty(KoText::SubFrameType) == KoText::AuxillaryFrameType) {
- if (point.y() > d->endNotesArea->top()
- && point.y() < d->endNotesArea->bottom()) {
- pointedAt = d->endNotesArea->hitTest(point, accuracy);
- return pointedAt;
- }
- }
- break;
- } else {
- if (!block.isValid())
- continue;
- }
- if (block.blockFormat().hasProperty(KoParagraphStyle::GeneratedDocument)) {
- // check if p is over table of content
- if (point.y() > d->generatedDocAreas[tocIndex]->top()
- && point.y() < d->generatedDocAreas[tocIndex]->bottom()) {
- pointedAt = d->generatedDocAreas[tocIndex]->hitTest(point, accuracy);
- pointedAt.position = block.position();
- return pointedAt;
- }
- ++tocIndex;
- continue;
- }
- if (basicallyFound) // a subsequent table or lines have now had their chance
- return pointedAt;
-
- QTextLayout *layout = block.layout();
- QTextFrame::iterator next = it;
- ++next;
- if (next != stop && next.currentFrame() == 0 && point.y() > layout->boundingRect().bottom()) {
- // just skip this block.
- continue;
- }
-
- for (int i = 0; i < layout->lineCount(); i++) {
- QTextLine line = layout->lineAt(i);
- if (block == d->startOfArea->it.currentBlock() && line.textStart() < d->startOfArea->lineTextStart) {
- continue; // this line is part of a previous layoutArea
- }
- QRectF lineRect = line.naturalTextRect();
- if (point.y() > line.y() + line.height()) {
- pointedAt.position = block.position() + line.textStart() + line.textLength();
- if (block == d->endOfArea->it.currentBlock() && line.textStart() + line.textLength() >= d->endOfArea->lineTextStart) {
- pointedAt.position = block.position() + line.xToCursor(point.x());
- break; // this and following lines are part of a next layoutArea
- }
- continue;
- }
- if (accuracy == Qt::ExactHit && point.y() < line.y()) { // between lines
- return KoPointedAt();
- }
- if (accuracy == Qt::ExactHit && // left or right of line
- (point.x() < line.naturalTextRect().left() || point.x() > line.naturalTextRect().right())) {
- return KoPointedAt();
- }
- if (point.x() > lineRect.x() + lineRect.width() && layout->textOption().textDirection() == Qt::RightToLeft) {
- // totally right of RTL text means the position is the start of the text.
- //TODO how about the other side?
- pointedAt.position = block.position() + line.textStart();
- return pointedAt;
- }
- if (basicallyFound && point.y() < lineRect.y()) {
- // This was not same baseline so basicallyFound was correct
- return pointedAt;
- }
- if (point.x() > lineRect.x() + lineRect.width()) {
- // right of line
- basicallyFound = true;
- pointedAt.position = block.position() + line.textStart() + line.textLength();
- continue; // don't break as next line may be on same baseline
- }
- pointedAt.position = block.position() + line.xToCursor(point.x());
- QTextCursor tmpCursor(block);
- tmpCursor.setPosition(block.position() + line.xToCursor(point.x(), QTextLine::CursorOnCharacter) + 1);
- pointedAt.fillInLinks(tmpCursor, d->documentLayout->inlineTextObjectManager(), d->documentLayout->textRangeManager());
- return pointedAt;
- }
- }
-
- //and finally test the footnotes
- point -= QPointF(0, bottom() - d->footNotesHeight);
- while (footNoteIndex < d->footNoteAreas.length()) {
- // check if p is over foot notes area
- if (point.y() > 0 && point.y() < d->footNoteAreas[footNoteIndex]->bottom()
- - d->footNoteAreas[footNoteIndex]->top()) {
- pointedAt = d->footNoteAreas[footNoteIndex]->hitTest(point, accuracy);
- return pointedAt;
- }
- point -= QPointF(0, d->footNoteAreas[footNoteIndex]->bottom() - d->footNoteAreas[footNoteIndex]->top());
- ++footNoteIndex;
- }
- return pointedAt;
-}
-
-QRectF KoTextLayoutArea::selectionBoundingBox(QTextCursor &cursor) const
-{
- QRectF retval(-5E6, top(), 105E6, 0);
-
- if (d->startOfArea == 0) // We have not been layouted yet
- return QRectF();
- if (d->endOfArea == 0) // no end area yet
- return QRectF();
-
- QTextFrame::iterator it = d->startOfArea->it;
- QTextFrame::iterator stop = d->endOfArea->it;
- if (!stop.atEnd()) {
- if(!stop.currentBlock().isValid() || d->endOfArea->lineTextStart >= 0) {
- // Last thing we show is a frame (table) or first part of a paragraph split in two
- // The stop point should be the object after that
- // However if stop is already atEnd we shouldn't increment further
- ++stop;
- }
- }
-
- QTextFrame *subFrame;
- int footNoteIndex = 0;
- qreal offset = bottom() - d->footNotesHeight;
- while (footNoteIndex < d->footNoteAreas.length()) {
- subFrame = d->footNoteFrames[footNoteIndex];
- if (cursor.selectionStart() >= subFrame->firstPosition() && cursor.selectionEnd() <= subFrame->lastPosition()) {
- return d->footNoteAreas[footNoteIndex]->selectionBoundingBox(cursor).translated(0, offset) ;
- }
- offset += d->footNoteAreas[footNoteIndex]->bottom() - d->footNoteAreas[footNoteIndex]->top();
- ++footNoteIndex;
- }
-
- int tableAreaIndex = 0;
- int tocIndex = 0;
-
- for (; it != stop && !it.atEnd(); ++it) {
- QTextBlock block = it.currentBlock();
- QTextTable *table = qobject_cast<QTextTable*>(it.currentFrame());
- QTextFrame *subFrame = it.currentFrame();
- QTextBlockFormat format = block.blockFormat();
-
- if (table) {
- if (tableAreaIndex >= d->tableAreas.size()) {
- continue;
- }
- if (cursor.selectionEnd() < table->firstPosition()) {
- return retval.translated(0, d->verticalAlignOffset);
- }
- if (cursor.selectionStart() > table->lastPosition()) {
- ++tableAreaIndex;
- continue;
- }
- if (cursor.selectionStart() >= table->firstPosition() && cursor.selectionEnd() <= table->lastPosition()) {
- return d->tableAreas[tableAreaIndex]->selectionBoundingBox(cursor).translated(0, d->verticalAlignOffset);
- }
- if (cursor.selectionStart() >= table->firstPosition()) {
- retval = d->tableAreas[tableAreaIndex]->boundingRect();
- } else {
- retval |= d->tableAreas[tableAreaIndex]->boundingRect();
- }
- ++tableAreaIndex;
- continue;
- } else if (subFrame) {
- if (it.currentFrame()->format().intProperty(KoText::SubFrameType) == KoText::AuxillaryFrameType) {
- if (cursor.selectionEnd() < subFrame->firstPosition()) {
- return retval.translated(0, d->verticalAlignOffset);
- }
- if (cursor.selectionStart() > subFrame->lastPosition()) {
- break;
- }
- if (cursor.selectionStart() >= subFrame->firstPosition() && cursor.selectionEnd() <= subFrame->lastPosition()) {
- return d->endNotesArea->selectionBoundingBox(cursor).translated(0, d->verticalAlignOffset);
- }
- break;
- }
- } else {
- if (!block.isValid())
- continue;
- }
- if (block.blockFormat().hasProperty(KoParagraphStyle::GeneratedDocument)) {
- if (cursor.selectionStart() <= block.position()
- && cursor.selectionEnd() >= block.position()) {
- retval |= d->generatedDocAreas[tocIndex]->boundingRect();
- }
- ++tocIndex;
- continue;
- }
-
- if(cursor.selectionEnd() < block.position()) {
- return retval.translated(0, d->verticalAlignOffset);
- }
- if(cursor.selectionStart() >= block.position()
- && cursor.selectionStart() < block.position() + block.length()) {
- QTextLine line = block.layout()->lineForTextPosition(cursor.selectionStart() - block.position());
- if (line.isValid()) {
- retval.setTop(line.y());
- retval.setBottom(line.y());
- }
- }
- if(cursor.selectionEnd() >= block.position()
- && cursor.selectionEnd() < block.position() + block.length()) {
- QTextLine line = block.layout()->lineForTextPosition(cursor.selectionEnd() - block.position());
- if (line.isValid()) {
- retval.setBottom(line.y() + line.height());
- if (line.ascent()==0) {
- // Block is empty from any visible content and has as such no height
- // but in that case the block font defines line height
- retval.setBottom(line.y() + 24);
- }
-
- if (cursor.selectionStart() == cursor.selectionEnd()) {
- // We only have a caret so let's set the rect a bit more narrow
- retval.setX(line.cursorToX(cursor.position() - block.position()));
- retval.setWidth(1);
- }
- }
- }
- // if the full paragraph is selected to add it to the rect. This makes sure we get a rect for the case
- // where the end of the selection lies is a different area.
- if (cursor.selectionEnd() >= block.position() + block.length() && cursor.selectionStart() <= block.position()) {
- QTextLine line = block.layout()->lineForTextPosition(block.length()-1);
- if (line.isValid()) {
- retval.setBottom(line.y() + line.height());
- if (line.ascent()==0) {
- // Block is empty from any visible content and has as such no height
- // but in that case the block font defines line height
- retval.setBottom(line.y() + 24);
- }
- }
- }
- }
- return retval.translated(0, d->verticalAlignOffset);
-}
-
-
-bool KoTextLayoutArea::isStartingAt(FrameIterator *cursor) const
-{
- if (d->startOfArea) {
- return *d->startOfArea == *cursor;
- }
-
- return false;
-}
-
-QTextFrame::iterator KoTextLayoutArea::startTextFrameIterator() const
-{
- return d->startOfArea->it;
-}
-
-QTextFrame::iterator KoTextLayoutArea::endTextFrameIterator() const
-{
- return d->endOfArea->it;
-}
-
-void KoTextLayoutArea::backtrackKeepWithNext(FrameIterator *cursor)
-{
- QTextFrame::iterator it = cursor->it;
-
- while (!(it == d->startOfArea->it)) {
- --it;
- QTextBlock block = it.currentBlock();
- QTextTable *table = qobject_cast<QTextTable*>(it.currentFrame());
- QTextFrame *subFrame = it.currentFrame();
- bool keepWithNext = false;
- if (table) {
- keepWithNext = table->format().boolProperty(KoTableStyle::KeepWithNext);
- //setBottom(tableArea->bottom() + d->footNotesHeight);
- } else if (subFrame) {
- Q_ASSERT(false); // there should never be an aux frame before normal layouted stuff
- } else if (block.isValid()) {
- keepWithNext = block.blockFormat().boolProperty(KoParagraphStyle::KeepWithNext);
- //setBottom(d->blockRects.last()->bottom() + d->footNotesHeight);
- }
- if (!keepWithNext) {
- cursor->it = ++it;
- break;
- }
- }
-}
-
-bool KoTextLayoutArea::layout(FrameIterator *cursor)
-{
- qDeleteAll(d->tableAreas);
- d->tableAreas.clear();
- qDeleteAll(d->footNoteAreas);
- d->footNoteAreas.clear();
- qDeleteAll(d->preregisteredFootNoteAreas);
- d->preregisteredFootNoteAreas.clear();
- d->footNoteFrames.clear();
- d->preregisteredFootNoteFrames.clear();
- qDeleteAll(d->generatedDocAreas);
- d->generatedDocAreas.clear();
- d->blockRects.clear();
- delete d->endNotesArea;
- d->endNotesArea=0;
- if (d->endOfArea) {
- delete d->copyEndOfArea;
- d->copyEndOfArea = new FrameIterator(d->endOfArea);
- }
- delete d->startOfArea;
- delete d->endOfArea;
- d->dropCapsWidth = 0;
- d->dropCapsDistance = 0;
-
- d->startOfArea = new FrameIterator(cursor);
- d->endOfArea = 0;
- d->y = top();
- d->neededWidth = 0;
- setBottom(top());
- d->bottomSpacing = 0;
- d->footNoteAutoCount = 0;
- d->footNotesHeight = 0;
- d->preregisteredFootNotesHeight = 0;
- d->prevBorder = 0;
- d->prevBorderPadding = 0;
-
- if (d->footNoteCursorFromPrevious) {
- KoTextLayoutNoteArea *footNoteArea = new KoTextLayoutNoteArea(d->continuedNoteFromPrevious, this, d->documentLayout);
- d->footNoteFrames.append(d->continuedNoteFromPrevious->textFrame());
- footNoteArea->setReferenceRect(left(), right(), 0, maximumAllowedBottom());
- footNoteArea->setAsContinuedArea(true);
- footNoteArea->layout(d->footNoteCursorFromPrevious);
- d->footNotesHeight += footNoteArea->bottom() - footNoteArea->top();
- d->footNoteAreas.append(footNoteArea);
- }
- while (!cursor->it.atEnd()) {
- QTextBlock block = cursor->it.currentBlock();
- QTextTable *table = qobject_cast<QTextTable*>(cursor->it.currentFrame());
- QTextFrame *subFrame = cursor->it.currentFrame();
- if (table) {
- QString masterPageName = table->frameFormat().property(KoTableStyle::MasterPageName).toString();
- bool masterPageNameChanged = !masterPageName.isEmpty();
- if (masterPageNameChanged) {
- cursor->masterPageName = masterPageName;
- }
-
- if (!virginPage()) {
- int breaktype = table->frameFormat().intProperty(KoTableStyle::BreakBefore);
- if ((acceptsPageBreak() && (masterPageNameChanged || (breaktype == KoText::PageBreak)))
- || (acceptsColumnBreak() && (breaktype == KoText::ColumnBreak))) {
- d->endOfArea = new FrameIterator(cursor);
- setBottom(d->y + d->footNotesHeight);
- if (!d->blockRects.isEmpty()) {
- d->blockRects.last().setBottom(d->y);
- }
- return false;
- }
- }
-
- // Let's create KoTextLayoutTableArea and let that handle the table
- KoTextLayoutTableArea *tableArea = new KoTextLayoutTableArea(table, this, d->documentLayout);
- d->tableAreas.append(tableArea);
- d->y += d->bottomSpacing;
- if (!d->blockRects.isEmpty()) {
- d->blockRects.last().setBottom(d->y);
- }
- tableArea->setVirginPage(virginPage());
- tableArea->setReferenceRect(left(), right(), d->y, maximumAllowedBottom());
- if (tableArea->layoutTable(cursor->tableIterator(table)) == false) {
- d->endOfArea = new FrameIterator(cursor);
- d->y = tableArea->bottom();
- setBottom(d->y + d->footNotesHeight);
- // Expand bounding rect so if we have content outside we show it
- expandBoundingLeft(tableArea->boundingRect().left());
- expandBoundingRight(tableArea->boundingRect().right());
-
- return false;
- }
- setVirginPage(false);
- // Expand bounding rect so if we have content outside we show it
- expandBoundingLeft(tableArea->boundingRect().left());
- expandBoundingRight(tableArea->boundingRect().right());
- d->bottomSpacing = 0;
- d->y = tableArea->bottom();
- delete cursor->currentTableIterator;
- cursor->currentTableIterator = 0;
- } else if (subFrame) {
- if (subFrame->format().intProperty(KoText::SubFrameType) == KoText::AuxillaryFrameType) {
- Q_ASSERT(d->endNotesArea == 0);
- d->endNotesArea = new KoTextLayoutEndNotesArea(this, d->documentLayout);
- d->y += d->bottomSpacing;
- if (!d->blockRects.isEmpty()) {
- d->blockRects.last().setBottom(d->y);
- }
- d->endNotesArea->setVirginPage(virginPage());
- d->endNotesArea->setReferenceRect(left(), right(), d->y, maximumAllowedBottom());
- if (d->endNotesArea->layout(cursor->subFrameIterator(subFrame)) == false) {
- d->endOfArea = new FrameIterator(cursor);
- d->y = d->endNotesArea->bottom();
- setBottom(d->y + d->footNotesHeight);
- // Expand bounding rect so if we have content outside we show it
- expandBoundingLeft(d->endNotesArea->boundingRect().left());
- expandBoundingRight(d->endNotesArea->boundingRect().right());
- return false;
- }
- setVirginPage(false);
- // Expand bounding rect so if we have content outside we show it
- expandBoundingLeft(d->endNotesArea->boundingRect().left());
- expandBoundingRight(d->endNotesArea->boundingRect().right());
- d->bottomSpacing = 0;
- d->y = d->endNotesArea->bottom();
- delete cursor->currentSubFrameIterator;
- cursor->currentSubFrameIterator = 0;
-
- // we have layouted till the end of the document except for a blank block
- // which we should ignore
- ++(cursor->it);
- ++(cursor->it);
- break;
- }
- } else if (block.isValid()) {
- if (block.blockFormat().hasProperty(KoParagraphStyle::GeneratedDocument)) {
- QVariant data = block.blockFormat().property(KoParagraphStyle::GeneratedDocument);
- QTextDocument *generatedDocument = data.value<QTextDocument *>();
-
- // Let's create KoTextLayoutArea and let it handle the generated document
- KoTextLayoutArea *area = new KoTextLayoutArea(this, documentLayout());
- d->generatedDocAreas.append(area);
- d->y += d->bottomSpacing;
- if (!d->blockRects.isEmpty()) {
- d->blockRects.last().setBottom(d->y);
- }
- area->setVirginPage(virginPage());
- area->setAcceptsPageBreak(acceptsPageBreak());
- area->setAcceptsColumnBreak(acceptsColumnBreak());
- area->setReferenceRect(left(), right(), d->y, maximumAllowedBottom());
- QTextLayout *blayout = block.layout();
- blayout->beginLayout();
- QTextLine line = blayout->createLine();
- line.setNumColumns(0);
- line.setPosition(QPointF(left(), d->y));
- blayout->endLayout();
-
- if (area->layout(cursor->subFrameIterator(generatedDocument->rootFrame())) == false) {
- cursor->lineTextStart = 1; // fake we are not done
- d->endOfArea = new FrameIterator(cursor);
- d->y = area->bottom();
- setBottom(d->y + d->footNotesHeight);
- // Expand bounding rect so if we have content outside we show it
- expandBoundingLeft(area->boundingRect().left());
- expandBoundingRight(area->boundingRect().right());
- return false;
- }
- setVirginPage(false);
- // Expand bounding rect so if we have content outside we show it
- expandBoundingLeft(area->boundingRect().left());
- expandBoundingRight(area->boundingRect().right());
- d->bottomSpacing = 0;
- d->y = area->bottom();
- delete cursor->currentSubFrameIterator;
- cursor->lineTextStart = -1; // fake we are done
- cursor->currentSubFrameIterator = 0;
- } else {
- // FIXME this doesn't work for cells inside tables. We probably should make it more
- // generic to handle such cases too.
- QString masterPageName = block.blockFormat().property(KoParagraphStyle::MasterPageName).toString();
- bool masterPageNameChanged = !masterPageName.isEmpty();
- if (masterPageNameChanged) {
- cursor->masterPageName = masterPageName;
- }
-
- if (!virginPage()) {
- int breaktype = block.blockFormat().intProperty(KoParagraphStyle::BreakBefore);
- if ((acceptsPageBreak() && (masterPageNameChanged || (breaktype == KoText::PageBreak)))
- ||(acceptsColumnBreak() && (breaktype == KoText::ColumnBreak))) {
- d->endOfArea = new FrameIterator(cursor);
- setBottom(d->y + d->footNotesHeight);
- if (!d->blockRects.isEmpty()) {
- d->blockRects.last().setBottom(d->y);
- }
- return false;
- }
- }
-
- if (layoutBlock(cursor) == false) {
- if (cursor->lineTextStart == -1) {
- //Nothing was added so lets backtrack keep-with-next
- backtrackKeepWithNext(cursor);
- }
- d->endOfArea = new FrameIterator(cursor);
- setBottom(d->y + d->footNotesHeight);
- d->blockRects.last().setBottom(d->y);
- return false;
- }
- d->extraTextIndent = 0;
-
- int breaktype = block.blockFormat().intProperty(KoParagraphStyle::BreakAfter);
- if ((acceptsPageBreak() && (breaktype & KoText::PageBreak))
- || (acceptsColumnBreak() && (breaktype & KoText::ColumnBreak))) {
- Q_ASSERT(!cursor->it.atEnd());
- QTextFrame::iterator nextIt = cursor->it;
- ++nextIt;
- bool wasIncremented = !nextIt.currentFrame();
- if (wasIncremented)
- cursor->it = nextIt;
- d->endOfArea = new FrameIterator(cursor);
- if (!wasIncremented)
- ++(cursor->it);
- setBottom(d->y + d->footNotesHeight);
- d->blockRects.last().setBottom(d->y);
- return false;
- }
- }
- }
- bool atEnd = cursor->it.atEnd();
- if (!atEnd) {
- ++(cursor->it);
- }
- }
- d->endOfArea = new FrameIterator(cursor);
- d->y = qMin(maximumAllowedBottom(), d->y + d->bottomSpacing);
- setBottom(d->y + d->footNotesHeight);
- if (!d->blockRects.isEmpty()) {
- d->blockRects.last().setBottom(d->y);
- }
- if (d->maximumAllowedWidth>0) {
- d->right += d->neededWidth - d->width;
- d->maximumAllowedWidth = 0;
- setVirginPage(true);
- KoTextLayoutArea::layout(new FrameIterator(d->startOfArea));
- }
- return true; // we have layouted till the end of the frame
-}
-
-
-QTextLine KoTextLayoutArea::Private::restartLayout(QTextBlock &block, int lineTextStartOfLastKeep)
-{
- QTextLayout *layout = block.layout();
- KoTextBlockData blockData(block);
- QPointF stashedCounterPosition = blockData.counterPosition();
- QList<LineKeeper> stashedLines;
- QTextLine line;
- for(int i = 0; i < layout->lineCount(); i++) {
- QTextLine l = layout->lineAt(i);
- if (l.textStart() >= lineTextStartOfLastKeep) {
- break;
- }
- LineKeeper lk;
- lk.lineWidth = l.width();
- lk.columns = l.textLength();
- lk.position = l.position();
- stashedLines.append(lk);
- }
- layout->clearLayout();
- layout->beginLayout();
- line = layout->createLine();
-
- return recreatePartialLayout(block, stashedLines, stashedCounterPosition, line);
-}
-
-void KoTextLayoutArea::Private::stashRemainingLayout(QTextBlock &block, int lineTextStartOfFirstKeep, QList<LineKeeper> &stashedLines, QPointF &stashedCounterPosition)
-{
- QTextLayout *layout = block.layout();
- KoTextBlockData blockData(block);
- stashedCounterPosition = blockData.counterPosition();
- QTextLine line;
- for(int i = 0; i < layout->lineCount(); i++) {
- QTextLine l = layout->lineAt(i);
- if (l.textStart() < lineTextStartOfFirstKeep) {
- continue;
- }
- LineKeeper lk;
- lk.lineWidth = l.width();
- lk.columns = l.textLength();
- lk.position = l.position();
- stashedLines.append(lk);
- }
-}
-
-QTextLine KoTextLayoutArea::Private::recreatePartialLayout(QTextBlock &block, QList<LineKeeper> stashedLines, QPointF &stashedCounterPosition, QTextLine &line)
-{
- QTextLayout *layout = block.layout();
- KoTextBlockData blockData(block);
- documentLayout->allowPositionInlineObject(false);
- if (layout->lineCount() == 1) {
- blockData.setCounterPosition(stashedCounterPosition);
- }
- Q_FOREACH (const LineKeeper &lk, stashedLines) {
- line.setLineWidth(lk.lineWidth);
- if (lk.columns != line.textLength()) {
- // As setNumColumns might break differently we only use it if setLineWidth doesn't give
- // the same textLength as we had before
- line.setNumColumns(lk.columns, lk.lineWidth);
- }
- line.setPosition(lk.position);
-
- line = layout->createLine();
- if (!line.isValid())
- break;
- }
- documentLayout->allowPositionInlineObject(true);
- return line;
-}
-
-static bool compareTab(const QTextOption::Tab &tab1, const QTextOption::Tab &tab2)
-{
- return tab1.position < tab2.position;
-}
-
-// layoutBlock() method is structured like this:
-//
-// 1) Setup various helper values
-// a) related to or influenced by lists
-// b) related to or influenced by dropcaps
-// c) related to or influenced by margins
-// d) related to or influenced by tabs
-// e) related to or influenced by borders
-// f) related to or influenced by list counters
-// 2)layout each line (possibly restarting where we stopped earlier)
-// a) fit line into sub lines with as needed for text runaround
-// b) break if we encounter softbreak
-// c) make sure we keep above maximumAllowedBottom
-// d) calls addLine()
-// e) update dropcaps related variables
-bool KoTextLayoutArea::layoutBlock(FrameIterator *cursor)
-{
- QTextBlock block(cursor->it.currentBlock());
- KoTextBlockData blockData(block);
- KoParagraphStyle pStyle(block.blockFormat(), block.charFormat());
-
- int dropCapsAffectsNMoreLines = 0;
- qreal dropCapsPositionAdjust = 0.0;
- bool lastOfPreviousRun = (d->copyEndOfArea && d->copyEndOfArea->it.currentBlock() == block);
-
- KoText::Direction dir = pStyle.textProgressionDirection();
- if (dir == KoText::InheritDirection)
- dir = parentTextDirection();
- if (dir == KoText::AutoDirection)
- d->isRtl = block.text().isRightToLeft();
- else
- d->isRtl = dir == KoText::RightLeftTopBottom;
-
- // initialize list item stuff for this parag.
- QTextList *textList = block.textList();
- QTextListFormat listFormat;
- QTextCharFormat labelFormat;
- if (textList) {
- listFormat = textList->format();
-
- if (block.text().size() == 0 || d->documentLayout->wordprocessingMode()) {
- labelFormat = block.charFormat();
- } else {
- labelFormat = block.begin().fragment().charFormat();
- }
-
- if (d->documentLayout->styleManager()) {
- const int id = listFormat.intProperty(KoListStyle::CharacterStyleId);
- KoCharacterStyle *cs = d->documentLayout->styleManager()->characterStyle(id);
- if (cs) {
- cs->applyStyle(labelFormat);
- cs->ensureMinimalProperties(labelFormat);
- }
- }
-
- // fetch the text-properties of the label
- if (listFormat.hasProperty(KoListStyle::CharacterProperties)) {
- QVariant v = listFormat.property(KoListStyle::CharacterProperties);
- QSharedPointer<KoCharacterStyle> textPropertiesCharStyle = v.value< QSharedPointer<KoCharacterStyle> >();
- if (!textPropertiesCharStyle.isNull()) {
- textPropertiesCharStyle->applyStyle(labelFormat);
- textPropertiesCharStyle->ensureMinimalProperties(labelFormat);
- }
- }
-
- // Calculate the correct font point size taking into account the current
- // block format and the relative font size percent if the size is not absolute
- if (listFormat.hasProperty(KoListStyle::RelativeBulletSize)) {
- qreal percent = listFormat.property(KoListStyle::RelativeBulletSize).toDouble();
- labelFormat.setFontPointSize((percent*labelFormat.fontPointSize())/100.00);
- }
-
- QFont font(labelFormat.font(), d->documentLayout->paintDevice());
-
- if (!blockData.hasCounterData()) {
- ListItemsHelper lih(textList, font);
- lih.recalculateBlock(block);
- }
- blockData.setLabelFormat(labelFormat);
- } else { // make sure it is empty
- blockData.clearCounter();
- }
-
- QTextLayout *layout = block.layout();
- QTextOption option = layout->textOption();
- option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
-
- option.setAlignment(QStyle::visualAlignment(d->isRtl ? Qt::RightToLeft : Qt::LeftToRight, pStyle.alignment()));
- if (d->isRtl) {
- option.setTextDirection(Qt::RightToLeft);
- // For right-to-left we need to make sure that trailing spaces are included into the QTextLine naturalTextWidth
- // and naturalTextRect calculation so they are proper handled in the RunAroundHelper. For left-to-right we do
- // not like to include trailing spaces in the calculations cause else justified text would not look proper
- // justified. Seems for right-to-left we have to accept that justified text will not look proper justified then.
- // only set it for justified text as otherwise we will cut of text at the beginning of the line
- if (pStyle.alignment() == Qt::AlignJustify) {
- option.setFlags(QTextOption::IncludeTrailingSpaces);
- }
-
- } else {
- option.setFlags(0);
- option.setTextDirection(Qt::LeftToRight);
- }
-
- option.setUseDesignMetrics(true);
-
- //==========
- // Drop caps
- //==========
-
- d->dropCapsNChars = 0;
- if (cursor->lineTextStart == -1) {
- // first remove any drop-caps related formatting that's already there in the layout.
- // we'll do it all afresh now.
- QVector<QTextLayout::FormatRange> formatRanges = layout->formats();
- for (QVector< QTextLayout::FormatRange >::Iterator iter = formatRanges.begin();
- iter != formatRanges.end(); ) {
- if (iter->format.boolProperty(DropCapsAdditionalFormattingId)) {
- iter = formatRanges.erase(iter);
- } else {
- ++iter;
- }
- }
- if (formatRanges.count() != layout->formats().count())
- layout->setFormats(formatRanges);
- bool dropCaps = pStyle.dropCaps();
- int dropCapsLength = pStyle.dropCapsLength();
- int dropCapsLines = pStyle.dropCapsLines();
-
- if (dropCaps && dropCapsLines > 1 && block.length() > 1) {
- QString blockText = block.text();
- d->dropCapsDistance = pStyle.dropCapsDistance();
-
- if (dropCapsLength == 0) { // means whole word is to be dropped
- int firstNonSpace = blockText.indexOf(QRegExp("[^ ]"));
- dropCapsLength = blockText.indexOf(QRegExp("\\W"), firstNonSpace);
- } else {
- // LibreOffice skips softbreaks but not spaces. We will do the same
- QTextCursor c1(block);
- c1.setPosition(block.position());
- c1.setPosition(c1.position() + 1, QTextCursor::KeepAnchor);
-
- KoTextSoftPageBreak *softPageBreak = dynamic_cast<KoTextSoftPageBreak*>(d->documentLayout->inlineTextObjectManager()->inlineTextObject(c1));
- if (softPageBreak) {
- dropCapsLength++;
- }
- }
- dropCapsLength = qMin(dropCapsLength, blockText.length() - 1);
-
- if (dropCapsLength > 0) {
- // increase the size of the dropped chars
- QTextCursor blockStart(block);
- QTextLayout::FormatRange dropCapsFormatRange;
- dropCapsFormatRange.format = blockStart.charFormat();
-
- // find out lineHeight for this block.
- QTextBlock::iterator it = block.begin();
- QTextFragment lineRepresentative = it.fragment();
- qreal lineHeight = pStyle.lineHeightAbsolute();
- qreal dropCapsHeight = 0;
- if (lineHeight == 0) {
- lineHeight = lineRepresentative.charFormat().fontPointSize();
- qreal linespacing = pStyle.lineSpacing();
- if (linespacing == 0) { // unset
- qreal percent = pStyle.lineHeightPercent();
- if (percent != 0)
- linespacing = lineHeight * ((percent - 100) / 100.0);
- else if (linespacing == 0)
- linespacing = lineHeight * 0.2; // default
- }
- dropCapsHeight = linespacing * (dropCapsLines-1);
- }
- const qreal minimum = pStyle.minimumLineHeight();
- if (minimum > 0.0) {
- lineHeight = qMax(lineHeight, minimum);
- }
-
- dropCapsHeight += lineHeight * dropCapsLines;
-
- int dropCapsStyleId = pStyle.dropCapsTextStyleId();
- KoCharacterStyle *dropCapsCharStyle = 0;
- if (dropCapsStyleId > 0 && d->documentLayout->styleManager()) {
- dropCapsCharStyle = d->documentLayout->styleManager()->characterStyle(dropCapsStyleId);
- dropCapsCharStyle->applyStyle(dropCapsFormatRange.format);
- }
-
- QFont f(dropCapsFormatRange.format.font(), d->documentLayout->paintDevice());
- QString dropCapsText(block.text().left(dropCapsLength));
- f.setPointSizeF(dropCapsHeight);
- for (int i=0; i < 5; ++i) {
- QTextLayout tmplayout(dropCapsText, f);
- tmplayout.setTextOption(option);
- tmplayout.beginLayout();
- QTextLine tmpline = tmplayout.createLine();
- tmplayout.endLayout();
- d->dropCapsWidth = tmpline.naturalTextWidth();
-
- QFontMetricsF fm(f, documentLayout()->paintDevice());
- QRectF rect = fm.tightBoundingRect(dropCapsText);
- const qreal diff = dropCapsHeight - rect.height();
- dropCapsPositionAdjust = rect.top() + fm.ascent();
- if (qAbs(diff) < 0.5) // good enough
- break;
-
- const qreal adjustment = diff * (f.pointSizeF() / rect.height());
- // warnTextLayout << "adjusting with" << adjustment;
- f.setPointSizeF(f.pointSizeF() + adjustment);
- }
-
- dropCapsFormatRange.format.setFontPointSize(f.pointSizeF());
- dropCapsFormatRange.format.setProperty(DropCapsAdditionalFormattingId,
- (QVariant) true);
- dropCapsFormatRange.start = 0;
- dropCapsFormatRange.length = dropCapsLength;
- formatRanges.append(dropCapsFormatRange);
- layout->setFormats(formatRanges);
-
- d->dropCapsNChars = dropCapsLength;
- dropCapsAffectsNMoreLines = (d->dropCapsNChars > 0) ? dropCapsLines : 0;
- }
- }
- }
-
- //========
- // Margins
- //========
- qreal startMargin = block.blockFormat().leftMargin();
- qreal endMargin = block.blockFormat().rightMargin();
- if (d->isRtl) {
- std::swap(startMargin, endMargin);
- }
- d->indent = textIndent(block, textList, pStyle) + d->extraTextIndent;
-
- qreal labelBoxWidth = 0;
- qreal labelBoxIndent = 0;
- if (textList) {
- if (listFormat.boolProperty(KoListStyle::AlignmentMode)) {
- // according to odf 1.2 17.20 list margin should be used when paragraph margin is
- // not specified by the auto style (additionally LO/OO uses 0 as condition so we do too)
- int id = pStyle.styleId();
- bool set = false;
- if (id && d->documentLayout->styleManager()) {
- KoParagraphStyle *originalParagraphStyle = d->documentLayout->styleManager()->paragraphStyle(id);
- if (originalParagraphStyle->leftMargin() != startMargin) {
- set = (startMargin != 0);
- }
- } else {
- set = (startMargin != 0);
- }
- if (! set) {
- startMargin = listFormat.doubleProperty(KoListStyle::Margin);
- }
-
- labelBoxWidth = blockData.counterWidth();
- Qt::Alignment align = static_cast<Qt::Alignment>(listFormat.intProperty(KoListStyle::Alignment));
- if (align == 0) {
- align = Qt::AlignLeft;
- }
- if (align & Qt::AlignLeft) {
- d->indent += labelBoxWidth;
- } else if (align & Qt::AlignHCenter) {
- d->indent += labelBoxWidth/2;
- }
- labelBoxIndent = d->indent - labelBoxWidth;
- } else {
- labelBoxWidth = blockData.counterSpacing() + blockData.counterWidth();
- }
- }
-
- d->width = right() - left();
- d->width -= startMargin + endMargin;
- d->x = left() + (d->isRtl ? 0.0 : startMargin);
-
- d->documentLayout->clearInlineObjectRegistry(block);
-
- //========
- // Tabs
- //========
- QList<KoText::Tab> tabs = pStyle.tabPositions();
-
- // Handle tabs relative to startMargin
- qreal tabOffset = -d->indent;
- if (!d->documentLayout->relativeTabs(block)) {
- tabOffset -= startMargin;
- }
-
- // Make a list of tabs that Qt can use
- QList<QTextOption::Tab> qTabs;
- // Note: Converting to Qt tabs is needed as long as we use Qt for layout, but we
- // loose the possibility to do leader chars.
- foreach (const KoText::Tab &kTab, tabs) {
- qreal value = kTab.position;
- if (value == MaximumTabPos) { // MaximumTabPos is used in index generators
- // note: we subtract right margin as this is where the tab should be
- // note: we subtract indent so tab is not relative to it
- // note: we subtract left margin so tab is not relative to it
- // if rtl the above left/right reasons swap but formula stays the same
- // -tabOfset is just to cancel that we add it next
- // -2 is to avoid wrap at right edge to the next line
- value = right() - left() - startMargin - endMargin - d->indent - tabOffset - 2;
- }
-
- // conversion here is required because Qt thinks in device units and we don't
- value *= qt_defaultDpiY() / 72.0;
-
- value += tabOffset * qt_defaultDpiY() / 72.0;
-
- QTextOption::Tab tab;
- tab.position = value;
- tab.type = kTab.type;
- tab.delimiter = kTab.delimiter;
- qTabs.append(tab);
- }
-
- qreal presentationListTabValue(0.0); // for use in presentationListTabWorkaround
-
- // For some lists we need to add a special list tab according to odf 1.2 19.830
- if (textList && listFormat.intProperty(KoListStyle::LabelFollowedBy) == KoListStyle::ListTab) {
- qreal listTab = 0;
- if (listFormat.hasProperty(KoListStyle::TabStopPosition)) {
- listTab = listFormat.doubleProperty(KoListStyle::TabStopPosition);
- if (!d->documentLayout->relativeTabs(block)) {
- // How list tab is defined if fixed tabs:
- // listTab
- //|>-------------------------|
- // d->indent
- // |---------<|
- // LABEL TEXT STARTS HERE AND GOES ON
- // TO THE NEXT LINE
- //|>------------------|
- // startMargin
- listTab -= startMargin;
- } else {
- // How list tab is defined if relative tabs:
- // It's relative to startMargin - list.startMargin
- // listTab
- // |>-------------------|
- // d->indent
- // |---------<|
- // LABEL TEXT STARTS HERE AND GOES ON
- // TO THE NEXT LINE
- //|>--------------------|
- // startMargin |
- // |>-------------|
- // list.margin
- listTab -= listFormat.doubleProperty(KoListStyle::Margin);
- }
- }
- // How list tab is defined now:
- // listTab
- // |>-----|
- // d->indent
- // |---------<|
- // LABEL TEXT STARTS HERE AND GOES ON
- // TO THE NEXT LINE
- //|>------------------|
- // startMargin
- presentationListTabValue = listTab;
- listTab -= d->indent;
-
- // And now listTab is like this:
- // x()
- // | listTab
- // |>---------------|
- // d->indent
- // |---------<|
- // LABEL TEXT STARTS HERE AND GOES ON
- // TO THE NEXT LINE
- //|>------------------|
- // startMargin
-
- // conversion here is required because Qt thinks in device units and we don't
- listTab *= qt_defaultDpiY() / 72.0;
-
- QTextOption::Tab tab;
- tab.position = listTab;
- tab.type = d->isRtl ? QTextOption::RightTab : QTextOption::LeftTab;
- qTabs.append(tab);
- }
-
- // We need to sort as the MaximumTabPos may be converted to a value that really
- // should be in the middle, and listtab needs to be sorted in too
- std::sort(qTabs.begin(), qTabs.end(), compareTab);
-
- // Regular interval tabs. Since Qt doesn't handle regular interval tabs offset
- // by a fixed number we need to create the regular tabs ourselves.
- qreal tabStopDistance = pStyle.tabStopDistance() * qt_defaultDpiY() / 72.0;
- if (tabStopDistance <= 0) {
- tabStopDistance = d->documentLayout->defaultTabSpacing() * qt_defaultDpiY() / 72.0;
- }
-
- qreal regularSpacedTabPos = -d->indent * qt_defaultDpiY() / 72.0 -0.1; // first possible position
- if (!qTabs.isEmpty()) {
- regularSpacedTabPos = qTabs.last().position;
- }
-
- regularSpacedTabPos -= tabOffset * qt_defaultDpiY() / 72.0;
- if (regularSpacedTabPos < 0) {
- regularSpacedTabPos = -int(-regularSpacedTabPos / tabStopDistance) * tabStopDistance;
- } else {
- regularSpacedTabPos = (int(regularSpacedTabPos / tabStopDistance) + 1) * tabStopDistance;
- }
- regularSpacedTabPos += tabOffset * qt_defaultDpiY() / 72.0;
-
- while (regularSpacedTabPos < MaximumTabPos) {
- QTextOption::Tab tab;
- tab.position = regularSpacedTabPos;
- qTabs.append(tab);
- regularSpacedTabPos += tabStopDistance;
- }
-
- option.setTabs(qTabs);
-
- // conversion here is required because Qt thinks in device units and we don't
- option.setTabStop(tabStopDistance * qt_defaultDpiY() / 72.);
-
- layout->setTextOption(option);
-
-
- // ==============
- // Possibly store the old layout of lines in case we end up splitting the paragraph at the same position
- // ==============
- QList<LineKeeper> stashedLines;
- QPointF stashedCounterPosition;
- if (lastOfPreviousRun) {
- // we have been layouted before, and the block ended on the following page so better
- // stash the layout for later
- d->stashRemainingLayout(block, d->copyEndOfArea->lineTextStart, stashedLines, stashedCounterPosition);
- }
-
- // ==============
- // Setup line and possibly restart paragraph continuing from previous other area
- // ==============
- QTextLine line;
- if (cursor->lineTextStart == -1) {
- layout->beginLayout();
- line = layout->createLine();
- cursor->fragmentIterator = block.begin();
- } else {
- line = d->restartLayout(block, cursor->lineTextStart);
- d->indent = d->extraTextIndent;
- }
-
- if (block.blockFormat().boolProperty(KoParagraphStyle::UnnumberedListItem)) {
- // Unnumbered list items act like "following lines" in a numbered block
- d->indent = 0;
- }
-
- // ==============
- // List label/counter positioning
- // ==============
- if (textList && block.layout()->lineCount() == 1
- && ! block.blockFormat().boolProperty(KoParagraphStyle::UnnumberedListItem)) {
- // If first line in a list then set the counterposition. Following lines in the same
- // list-item have nothing to do with the counter.
- if (listFormat.boolProperty(KoListStyle::AlignmentMode) == false) {
- qreal minLabelWidth = listFormat.doubleProperty(KoListStyle::MinimumWidth);
- if (!d->isRtl) {
- d->x += listFormat.doubleProperty(KoListStyle::Indent) + minLabelWidth;
- }
- d->width -= listFormat.doubleProperty(KoListStyle::Indent) + minLabelWidth;
- d->indent += labelBoxWidth - minLabelWidth;
- blockData.setCounterPosition(QPointF(d->x + d->indent - labelBoxWidth, d->y));
- } else if (labelBoxWidth > 0.0 || blockData.counterText().length() > 0) {
- // Alignmentmode and there is a label (double check needed to account for both
- // picture bullets and non width chars)
- blockData.setCounterPosition(QPointF(d->x + labelBoxIndent, d->y));
- if (listFormat.intProperty(KoListStyle::LabelFollowedBy) == KoListStyle::ListTab
- && !presentationListTabWorkaround(textIndent(block, textList, pStyle), labelBoxWidth, presentationListTabValue)) {
- Q_FOREACH (QTextOption::Tab tab, qTabs) {
- qreal position = tab.position * 72. / qt_defaultDpiY();
- if (position > 0.0) {
- d->indent += position;
- break;
- }
- }
-
- //And finally it's like this:
- // x()
- // d->indent
- // |>-----|
- // LABEL TEXT STARTS HERE AND GOES ON
- // TO THE NEXT LINE
- //|>------------------|
- // startMargin
- } else if (listFormat.intProperty(KoListStyle::LabelFollowedBy) == KoListStyle::Space) {
- QFontMetrics fm(labelFormat.font(), d->documentLayout->paintDevice());
- d->indent += fm.width(' ');
- }
- // default needs to be no space so presentationListTabWorkaround above makes us go here
- }
- }
-
- // Whenever we relayout the markup layout becomes invalid
- blockData.setMarkupsLayoutValidity(KoTextBlockData::Misspell, false);
- blockData.setMarkupsLayoutValidity(KoTextBlockData::Grammar, false);
-
- // ==============
- // Now once we know the physical context we can work on the borders of the paragraph
- // ==============
- if (block.blockFormat().hasProperty(KoParagraphStyle::HiddenByTable)) {
- if (!d->blockRects.isEmpty()) {
- d->blockRects.last().setBottom(d->y);
- }
- d->y += d->bottomSpacing;
- d->bottomSpacing = 0;
- d->blockRects.append(QRectF(d->x, d->y, d->width, 10.0));
- } else {
- handleBordersAndSpacing(blockData, &block);
- }
-
- // Expand bounding rect so if we have content outside we show it
- expandBoundingLeft(d->blockRects.last().x());
- expandBoundingRight(d->blockRects.last().right());
-
- // ==============
- // Create the lines of this paragraph
- // ==============
- RunAroundHelper runAroundHelper;
- runAroundHelper.setObstructions(documentLayout()->currentObstructions());
- qreal maxLineHeight = 0;
- qreal y_justBelowDropCaps = 0;
- bool anyLineAdded = false;
- int numBaselineShifts = 0;
-
- while (line.isValid()) {
- runAroundHelper.setLine(this, line);
- runAroundHelper.setObstructions(documentLayout()->currentObstructions());
- QRectF anchoringRect = d->blockRects.last();
- anchoringRect.setTop(d->anchoringParagraphContentTop);
- documentLayout()->setAnchoringParagraphContentRect(anchoringRect);
- anchoringRect.setLeft(left());
- anchoringRect.setWidth(right() - left());
- anchoringRect.setTop(d->anchoringParagraphTop);
- documentLayout()->setAnchoringParagraphRect(anchoringRect);
- documentLayout()->setAnchoringLayoutEnvironmentRect(layoutEnvironmentRect());
- runAroundHelper.fit( /* resetHorizontalPosition */ false, /* rightToLeft */ d->isRtl, QPointF(x(), d->y));
-
- documentLayout()->positionAnchorTextRanges(block.position()+line.textStart(), line.textLength(), block.document());
- qreal bottomOfText = line.y() + line.height();
-
- bool softBreak = false;
- bool moreInMiddle = d->y > maximumAllowedBottom() - 150;
- if (acceptsPageBreak() && !pStyle.nonBreakableLines() && moreInMiddle) {
- int softBreakPos = -1;
- QString text = block.text();
- int pos = text.indexOf(QChar::ObjectReplacementCharacter, line.textStart());
-
- while (pos >= 0 && pos <= line.textStart() + line.textLength()) {
- QTextCursor c1(block);
- c1.setPosition(block.position() + pos);
- c1.setPosition(c1.position() + 1, QTextCursor::KeepAnchor);
-
- KoTextSoftPageBreak *softPageBreak = dynamic_cast<KoTextSoftPageBreak*>(d->documentLayout->inlineTextObjectManager()->inlineTextObject(c1));
- if (softPageBreak) {
- softBreakPos = pos;
- break;
- }
-
- pos = text.indexOf(QChar::ObjectReplacementCharacter, pos + 1);
- }
-
- if (softBreakPos >= 0 && softBreakPos < line.textStart() + line.textLength()) {
- line.setNumColumns(softBreakPos - line.textStart() + 1, line.width());
- softBreak = true;
- // if the softBreakPos is at the start of the line stop here so
- // we don't add a line here. That fixes the problem that e.g. the counter is before
- // the page break and the text is after the page break
- if (!virginPage() && softBreakPos == 0) {
- d->recreatePartialLayout(block, stashedLines, stashedCounterPosition, line);
- layout->endLayout();
- return false;
- }
- }
- }
-
- if (documentLayout()->anchoringSoftBreak() <= block.position() + line.textStart() + line.textLength()) {
- //don't add an anchor that has been moved away
- line.setNumColumns(documentLayout()->anchoringSoftBreak() - block.position() - line.textStart(), line.width());
- softBreak = true;
- // if the softBreakPos is at the start of the block stop here so
- // we don't add a line here. That fixes the problem that e.g. the counter is before
- // the page break and the text is after the page break
- if (!virginPage() && documentLayout()->anchoringSoftBreak() == block.position()) {
- d->recreatePartialLayout(block, stashedLines, stashedCounterPosition, line);
- layout->endLayout();
- return false;
- }
- }
-
- findFootNotes(block, line, bottomOfText);
- if (bottomOfText > maximumAllowedBottom()) {
- // We can not fit line within our allowed space
- // in case we resume layout on next page the line is reused later
- // but if not then we need to make sure the line becomes invisible
- // we use d->maximalAllowedBottom because we want to be below
- // footnotes too.
- if (!virginPage() && pStyle.nonBreakableLines()) {
- line.setPosition(QPointF(x(), d->maximalAllowedBottom));
- cursor->lineTextStart = -1;
- d->recreatePartialLayout(block, stashedLines, stashedCounterPosition, line);
- layout->endLayout();
- clearPreregisteredFootNotes();
- return false; //to indicate block was not done!
- }
- if (!virginPage() && pStyle.orphanThreshold() != 0
- && pStyle.orphanThreshold() > numBaselineShifts) {
- line.setPosition(QPointF(x(), d->maximalAllowedBottom));
- cursor->lineTextStart = -1;
- d->recreatePartialLayout(block, stashedLines, stashedCounterPosition, line);
- layout->endLayout();
- clearPreregisteredFootNotes();
- return false; //to indicate block was not done!
- }
- if (!virginPage() || anyLineAdded) {
- line.setPosition(QPointF(x(), d->maximalAllowedBottom));
- d->recreatePartialLayout(block, stashedLines, stashedCounterPosition, line);
- layout->endLayout();
- clearPreregisteredFootNotes();
- return false; //to indicate block was not done!
- }
- }
- confirmFootNotes();
- anyLineAdded = true;
- maxLineHeight = qMax(maxLineHeight, addLine(line, cursor, blockData));
-
- d->neededWidth = qMax(d->neededWidth, line.naturalTextWidth() + d->indent);
-
- if (!runAroundHelper.stayOnBaseline() && !(block.blockFormat().hasProperty(KoParagraphStyle::HiddenByTable)
- && block.length() <= 1)) {
- d->y += maxLineHeight;
- maxLineHeight = 0;
- d->indent = 0;
- d->extraTextIndent = 0;
- ++numBaselineShifts;
- }
-
- // drop caps
- if (d->dropCapsNChars > 0) { // we just laid out the dropped chars
- y_justBelowDropCaps = d->y; // save the y position just below the dropped characters
- d->y = line.y(); // keep the same y for the next line
- line.setPosition(line.position() - QPointF(0, dropCapsPositionAdjust));
- d->dropCapsNChars -= line.textLength();
- } else if (dropCapsAffectsNMoreLines > 0) { // we just laid out a drop-cap-affected line
- dropCapsAffectsNMoreLines--;
- if (dropCapsAffectsNMoreLines == 0) { // no more drop-cap-affected lines
- if (d->y < y_justBelowDropCaps)
- d->y = y_justBelowDropCaps; // make sure d->y is below the dropped characters
- y_justBelowDropCaps = 0;
- d->dropCapsWidth = 0;
- d->dropCapsDistance = 0;
- }
- }
- documentLayout()->positionAnchoredObstructions();
-
- // line fitted so try and do the next one
- line = layout->createLine();
- if (!line.isValid()) {
- break; // no more line means our job is done
- }
- cursor->lineTextStart = line.textStart();
-
- if (softBreak) {
- d->recreatePartialLayout(block, stashedLines, stashedCounterPosition, line);
- layout->endLayout();
- return false; // page-break means we need to start again on the next page
- }
- }
-
- d->bottomSpacing = pStyle.bottomMargin();
-
- layout->endLayout();
- setVirginPage(false);
- cursor->lineTextStart = -1; //set lineTextStart to -1 and returning true indicate new block
- block.setLineCount(layout->lineCount());
- return true;
-}
-
-bool KoTextLayoutArea::presentationListTabWorkaround(qreal indent, qreal labelBoxWidth, qreal presentationListTabValue)
-{
- if (!d->documentLayout->wordprocessingMode() && indent < 0.0) {
- // Impress / Powerpoint expects the label to be before the text
- if (indent + labelBoxWidth >= presentationListTabValue) {
- // but here is an unforseen overlap with normal text
- return true;
- }
- }
- return false;
-}
-
-qreal KoTextLayoutArea::textIndent(const QTextBlock &block, QTextList *textList, const KoParagraphStyle &pStyle) const
-{
- if (pStyle.autoTextIndent()) {
- // if auto-text-indent is set,
- // return an indent approximately 3-characters wide as per current font
- QTextCursor blockCursor(block);
- qreal guessGlyphWidth = QFontMetricsF(blockCursor.charFormat().font()).width('x');
- return guessGlyphWidth * 3;
- }
-
- qreal blockTextIndent = block.blockFormat().textIndent();
-
- if (textList && textList->format().boolProperty(KoListStyle::AlignmentMode)) {
- // according to odf 1.2 17.20 list text indent should be used when paragraph text indent is
- // not specified (additionally LO/OO uses 0 as condition so we do too)
- int id = pStyle.styleId();
- bool set = false;
- if (id && d->documentLayout->styleManager()) {
- KoParagraphStyle *originalParagraphStyle = d->documentLayout->styleManager()->paragraphStyle(id);
- if (originalParagraphStyle->textIndent() != blockTextIndent) {
- set = (blockTextIndent != 0);
- }
- } else {
- set = (blockTextIndent != 0);
- }
- if (! set) {
- return textList->format().doubleProperty(KoListStyle::TextIndent);
- }
- }
- return blockTextIndent;
-}
-
-void KoTextLayoutArea::setExtraTextIndent(qreal extraTextIndent)
-{
- d->extraTextIndent = extraTextIndent;
-}
-
-qreal KoTextLayoutArea::x() const
-{
- if (d->isRtl) {
- return d->x;
- } else {
- if (d->dropCapsNChars > 0 || d->dropCapsWidth == 0)
- return d->x + d->indent ;
- else
- return d->x + d->indent + d->dropCapsWidth + d->dropCapsDistance;
- }
-}
-
-qreal KoTextLayoutArea::width() const
-{
- if (d->dropCapsNChars > 0) {
- return d->dropCapsWidth;
- }
- qreal width = d->width;
- if (d->maximumAllowedWidth > 0) {
- // lets use that instead but remember all the indent stuff we have calculated
- width = d->width - (d->right - d->left) + d->maximumAllowedWidth;
- }
- return width - d->indent - d->dropCapsWidth - d->dropCapsDistance;
-}
-
-void KoTextLayoutArea::setAcceptsPageBreak(bool accept)
-{
- d->acceptsPageBreak = accept;
-}
-
-bool KoTextLayoutArea::acceptsPageBreak() const
-{
- return d->acceptsPageBreak;
-}
-
-void KoTextLayoutArea::setAcceptsColumnBreak(bool accept)
-{
- d->acceptsColumnBreak = accept;
-}
-
-bool KoTextLayoutArea::acceptsColumnBreak() const
-{
- return d->acceptsColumnBreak;
-}
-
-void KoTextLayoutArea::setVirginPage(bool virgin)
-{
- d->virginPage = virgin;
-}
-
-bool KoTextLayoutArea::virginPage() const
-{
- return d->virginPage;
-}
-
-void KoTextLayoutArea::setVerticalAlignOffset(qreal offset)
-{
- d->boundingRect.setTop(d->top + qMin(qreal(0.0), offset));
- d->boundingRect.setBottom(d->bottom + qMax(qreal(0.0), offset));
- Q_ASSERT_X(d->boundingRect.top() <= d->boundingRect.bottom(), __FUNCTION__, "Bounding-rect is not normalized");
- d->verticalAlignOffset = offset;
-}
-
-qreal KoTextLayoutArea::verticalAlignOffset() const
-{
- return d->verticalAlignOffset;
-}
-
-qreal KoTextLayoutArea::addLine(QTextLine &line, FrameIterator *cursor, KoTextBlockData &blockData)
-{
- QTextBlock block = cursor->it.currentBlock();
- QTextBlockFormat format = block.blockFormat();
- KoParagraphStyle style(format, block.charFormat());
-
- if (block.textList() && block.layout()->lineCount() == 1) {
- Qt::Alignment alignment = format.alignment();
- if (d->isRtl && (alignment & Qt::AlignAbsolute) == 0) {
- if (alignment & Qt::AlignLeft) {
- alignment = Qt::AlignRight;
- } else if (alignment & Qt::AlignRight) {
- alignment = Qt::AlignLeft;
- }
- }
- alignment &= Qt::AlignRight | Qt::AlignLeft | Qt::AlignHCenter;
-
- // First line, lets check where the line ended up and adjust the positioning of the counter.
- qreal newX;
- if (alignment & Qt::AlignHCenter) {
- const qreal padding = (line.width() - line.naturalTextWidth()) / 2;
- newX = blockData.counterPosition().x() + (d->isRtl ? -padding : padding);
- } else if (alignment & Qt::AlignRight) {
- const qreal padding = line.width() - line.naturalTextWidth();
- newX = blockData.counterPosition().x() + (d->isRtl ? -padding : padding);
- } else {
- newX = blockData.counterPosition().x();
- }
- if (d->isRtl) {
- newX = line.x() + line.naturalTextWidth() + line.x() + d->indent - newX;
- }
-
- blockData.setCounterPosition(QPointF(newX, blockData.counterPosition().y()));
- }
-
- qreal height = 0;
- qreal breakHeight = 0.0;
- qreal ascent = 0.0;
- qreal descent = 0.0;
- const bool useFontProperties = format.boolProperty(KoParagraphStyle::LineSpacingFromFont);
-
- if (cursor->fragmentIterator.atEnd()) {// no text in parag.
- qreal fontStretch = 1;
- QTextCharFormat charFormat = block.charFormat();
- if (block.blockFormat().hasProperty(KoParagraphStyle::EndCharStyle)) {
- QVariant v = block.blockFormat().property(KoParagraphStyle::EndCharStyle);
- QSharedPointer<KoCharacterStyle> endCharStyle = v.value< QSharedPointer<KoCharacterStyle> >();
- if (!endCharStyle.isNull()) {
- endCharStyle->applyStyle(charFormat);
- endCharStyle->ensureMinimalProperties(charFormat);
- }
- }
-
- if (useFontProperties) {
- //stretch line height to powerpoint size
- fontStretch = PresenterFontStretch;
- } else if (block.charFormat().hasProperty(KoCharacterStyle::FontYStretch)) {
- // stretch line height to ms-word size
- fontStretch = charFormat.property(KoCharacterStyle::FontYStretch).toDouble();
- }
- height = charFormat.fontPointSize() * fontStretch;
- } else {
- qreal fontStretch = 1;
- QTextFragment fragment = cursor->fragmentIterator.fragment();
- if (useFontProperties) {
- //stretch line height to powerpoint size
- fontStretch = PresenterFontStretch;
- } else if (fragment.charFormat().hasProperty(KoCharacterStyle::FontYStretch)) {
- // stretch line height to ms-word size
- fontStretch = fragment.charFormat().property(KoCharacterStyle::FontYStretch).toDouble();
- }
- // read max font height
- height = qMax(height, fragment.charFormat().fontPointSize() * fontStretch);
-
- KoInlineObjectExtent pos = d->documentLayout->inlineObjectExtent(fragment);
- ascent = qMax(ascent, pos.m_ascent);
- descent = qMax(descent, pos.m_descent);
-
- bool lineBreak = false;
- int lastCharPos = block.position() + line.textStart() + line.textLength() - 1;
- int blockLastCharWithoutPreedit = line.textStart() + line.textLength() - 1;
- if (block.layout()->preeditAreaPosition() >= block.position() + line.textStart() &&
- block.layout()->preeditAreaPosition() <= lastCharPos) {
- blockLastCharWithoutPreedit -= block.layout()->preeditAreaText().length();
- }
- if (block.text().at(blockLastCharWithoutPreedit) == QChar(0x2028)) {
- // Was a line with line-break
- if (line.textLength() != 1) { //unless empty line we should ignore the format of it
- --lastCharPos;
- }
- lineBreak = true;
- }
- while (!(fragment.contains(lastCharPos))) {
- cursor->fragmentIterator++;
- if (cursor->fragmentIterator.atEnd()) {
- break;
- }
- fragment = cursor->fragmentIterator.fragment();
- if (!d->documentLayout->changeTracker()
- || !d->documentLayout->changeTracker()->displayChanges()
- || !d->documentLayout->changeTracker()->containsInlineChanges(fragment.charFormat())
- || !d->documentLayout->changeTracker()->elementById(fragment.charFormat().property(KoCharacterStyle::ChangeTrackerId).toInt())
- || !d->documentLayout->changeTracker()->elementById(fragment.charFormat().property(KoCharacterStyle::ChangeTrackerId).toInt())->isEnabled()
- || (d->documentLayout->changeTracker()->elementById(fragment.charFormat().property(KoCharacterStyle::ChangeTrackerId).toInt())->getChangeType() != KoGenChange::DeleteChange)) {
- qreal fontStretch = 1;
- if (useFontProperties) {
- //stretch line height to powerpoint size
- fontStretch = PresenterFontStretch;
- } else if (fragment.charFormat().hasProperty(KoCharacterStyle::FontYStretch)) {
- // stretch line height to ms-word size
- fontStretch = fragment.charFormat().property(KoCharacterStyle::FontYStretch).toDouble();
- }
- // read max font height
- height = qMax(height, fragment.charFormat().fontPointSize() * fontStretch);
-
- KoInlineObjectExtent pos = d->documentLayout->inlineObjectExtent(fragment);
- ascent = qMax(ascent, pos.m_ascent);
- descent = qMax(descent, pos.m_descent);
- }
- }
-
- if (lineBreak) {
- // Was a line with line-break - the format of the line-break should not be
- // considered for the next line either. So we may have to advance the fragmentIterator.
- while (!cursor->fragmentIterator.atEnd() && lastCharPos > fragment.position() + fragment.length()-1) {
- cursor->fragmentIterator++;
- fragment = cursor->fragmentIterator.fragment();
- }
-
- qreal breakAscent = ascent;
- qreal breakDescent = descent;
- breakHeight = height;
-
- int firstPos = block.position() + line.textStart() + line.textLength();
-
- // Was a line with line-break - the format of the line-break should not be
- // considered for the next line either. So we may have to advance the fragmentIterator.
- while (!cursor->fragmentIterator.atEnd() && firstPos > fragment.position() + fragment.length()-1) {
- cursor->fragmentIterator++;
- if (!cursor->fragmentIterator.atEnd()) {
- fragment = cursor->fragmentIterator.fragment();
-
- // read max font height
- breakHeight = qMax(breakHeight, fragment.charFormat().fontPointSize() * fontStretch);
-
- KoInlineObjectExtent pos = d->documentLayout->inlineObjectExtent(fragment);
- breakAscent = qMax(breakAscent, pos.m_ascent);
- breakDescent = qMax(breakDescent, pos.m_descent);
- }
- }
- breakHeight = qMax(breakHeight, breakAscent + breakDescent);
- }
- }
-
- height = qMax(height, ascent + descent);
-
- if (height < 0.01) {
- height = 12; // default size for uninitialized styles.
- }
-
- // Calculate adjustment to the height due to line height calculated by qt which shouldn't be
- // there in reality. We will just move the line
- qreal lineAdjust = 0.0;
- if (breakHeight > height) {
- lineAdjust = height - breakHeight;
- }
-
- // Adjust the line-height according to a probably defined fixed line height,
- // a proportional (percent) line-height and/or the line-spacing. Together
- // with the line-height we maybe also need to adjust the position of the
- // line. This is for example needed if the line needs to shrink in height
- // so the line-text stays on the baseline. If the line grows in height then
- // we don't need to do anything.
- if (d->dropCapsNChars <= 0) { // linespacing rules doesn't apply to drop caps
- qreal fixedLineHeight = format.doubleProperty(KoParagraphStyle::FixedLineHeight);
- if (fixedLineHeight != 0.0) {
- qreal prevHeight = height;
- height = fixedLineHeight;
- lineAdjust += height - prevHeight;
- } else {
- qreal lineSpacing = format.doubleProperty(KoParagraphStyle::LineSpacing);
- if (lineSpacing == 0.0) { // unset
- qreal percent = format.doubleProperty(KoParagraphStyle::PercentLineHeight);
- if (percent != 0) {
- height *= percent / 100.0;
- } else {
- height *= 1.2; // default
- }
- }
- height += lineSpacing;
- }
-
- qreal minimum = style.minimumLineHeight();
- if (minimum > 0.0) {
- height = qMax(height, minimum);
- }
- } else {
- // for drop caps we just work with a basic linespacing for the dropped characters
- height *= 1.2;
- }
- //rounding problems due to Qt-scribe internally using ints.
- //also used when line was moved down because of intersections with other shapes
- if (qAbs(d->y - line.y()) >= 0.126) {
- d->y = line.y();
- }
-
- if (lineAdjust) {
- // Adjust the position of the line itself.
- line.setPosition(QPointF(line.x(), line.y() + lineAdjust));
-
- // Adjust the position of the block-rect for this line which is used later
- // to proper clip the line while drawing. If we would not adjust it here
- // then we could end with text-lines being partly cutoff.
- if (lineAdjust < 0.0) {
- d->blockRects.last().moveTop(d->blockRects.last().top() + lineAdjust);
- }
-
- if (block.textList() && block.layout()->lineCount() == 1) {
- // If this is the first line in a list (aka the first line after the list-
- // item) then we also need to adjust the counter to match to the line again.
- blockData.setCounterPosition(QPointF(blockData.counterPosition().x(), blockData.counterPosition().y() + lineAdjust));
- }
- }
-
- return height;
-}
-
-void KoTextLayoutArea::setLayoutEnvironmentResctictions(bool isLayoutEnvironment, bool actsHorizontally)
-{
- d->isLayoutEnvironment = isLayoutEnvironment;
- d->actsHorizontally = actsHorizontally;
-}
-
-QRectF KoTextLayoutArea::layoutEnvironmentRect() const
-{
- QRectF rect(-5e10, -5e10, 10e10, 10e20); // large values that never really restrict anything
-
- if (d->parent) {
- rect = d->parent->layoutEnvironmentRect();
- }
-
- if (d->isLayoutEnvironment) {
- if (d->actsHorizontally) {
- rect.setLeft(left());
- rect.setRight(right());
- }
- rect.setTop(top());
- rect.setBottom(maximumAllowedBottom());
- }
-
- return rect;
-}
-
-QRectF KoTextLayoutArea::boundingRect() const
-{
- return d->boundingRect;
-}
-
-qreal KoTextLayoutArea::maximumAllowedBottom() const
-{
- return d->maximalAllowedBottom - d->footNotesHeight
- - d->preregisteredFootNotesHeight;
-}
-
-FrameIterator *KoTextLayoutArea::footNoteCursorToNext() const
-{
- return d->footNoteCursorToNext;
-}
-
-KoInlineNote *KoTextLayoutArea::continuedNoteToNext() const
-{
- return d->continuedNoteToNext;
-}
-
-int KoTextLayoutArea::footNoteAutoCount() const
-{
- return d->footNoteAutoCount;
-}
-
-void KoTextLayoutArea::setFootNoteCountInDoc(int count)
-{
- d->footNoteCountInDoc = count;
-}
-
-void KoTextLayoutArea::setFootNoteFromPrevious(FrameIterator *footNoteCursor, KoInlineNote *note)
-{
- d->footNoteCursorFromPrevious = footNoteCursor;
- d->continuedNoteFromPrevious = note;
-}
-
-void KoTextLayoutArea::setNoWrap(qreal maximumAllowedWidth)
-{
- d->maximumAllowedWidth = maximumAllowedWidth;
-}
-
-KoText::Direction KoTextLayoutArea::parentTextDirection() const
-{
- Q_ASSERT(d->parent); //Root areas should overload this method
- return d->parent->parentTextDirection();
-}
-
-KoTextLayoutArea *KoTextLayoutArea::parent() const
-{
- return d->parent;
-}
-
-KoTextDocumentLayout *KoTextLayoutArea::documentLayout() const
-{
- return d->documentLayout;
-}
-
-void KoTextLayoutArea::setReferenceRect(qreal left, qreal right, qreal top, qreal maximumAllowedBottom)
-{
- d->left = left;
- d->right = right;
- d->top = top;
- d->boundingRect = QRectF(left, top, right - left, 0.0);
- Q_ASSERT_X(d->boundingRect.top() <= d->boundingRect.bottom() && d->boundingRect.left() <= d->boundingRect.right(), __FUNCTION__, "Bounding-rect is not normalized");
- d->maximalAllowedBottom = maximumAllowedBottom;
-}
-
-QRectF KoTextLayoutArea::referenceRect() const
-{
- return QRectF(d->left, d->top, d->right - d->left, d->bottom - d->top);
-}
-
-qreal KoTextLayoutArea::left() const
-{
- return d->left;
-}
-
-qreal KoTextLayoutArea::right() const
-{
- return d->right;
-}
-
-qreal KoTextLayoutArea::top() const
-{
- return d->top;
-}
-
-qreal KoTextLayoutArea::bottom() const
-{
- return d->bottom;
-}
-
-void KoTextLayoutArea::setBottom(qreal bottom)
-{
- d->boundingRect.setBottom(bottom + qMax(qreal(0.0), d->verticalAlignOffset));
- Q_ASSERT_X(d->boundingRect.top() <= d->boundingRect.bottom(), __FUNCTION__, "Bounding-rect is not normalized");
- d->bottom = bottom;
-}
-
-void KoTextLayoutArea::findFootNotes(const QTextBlock &block, const QTextLine &line, qreal bottomOfText)
-{
- if (d->documentLayout->inlineTextObjectManager() == 0) {
- return;
- }
- QString text = block.text();
- int pos = text.indexOf(QChar::ObjectReplacementCharacter, line.textStart());
-
- while (pos >= 0 && pos <= line.textStart() + line.textLength()) {
- QTextCursor c1(block);
- c1.setPosition(block.position() + pos);
- c1.setPosition(c1.position() + 1, QTextCursor::KeepAnchor);
-
- KoInlineNote *note = dynamic_cast<KoInlineNote*>(d->documentLayout->inlineTextObjectManager()->inlineTextObject(c1));
- if (note && note->type() == KoInlineNote::Footnote) {
- preregisterFootNote(note, bottomOfText);
- }
-
- pos = text.indexOf(QChar::ObjectReplacementCharacter, pos + 1);
- }
-}
-
-qreal KoTextLayoutArea::preregisterFootNote(KoInlineNote *note, qreal bottomOfText)
-{
- if (d->parent == 0) {
- // TODO to support footnotes at end of document this is
- // where we need to add some extra condition
- if (note->autoNumbering()) {
- KoOdfNotesConfiguration *notesConfig = d->documentLayout->styleManager()->notesConfiguration(KoOdfNotesConfiguration::Footnote);
- if (notesConfig->numberingScheme() == KoOdfNotesConfiguration::BeginAtDocument) {
- note->setAutoNumber(d->footNoteCountInDoc + (d->footNoteAutoCount++));
- } else if (notesConfig->numberingScheme() == KoOdfNotesConfiguration::BeginAtPage) {
- note->setAutoNumber(d->footNoteAutoCount++);
- }
- }
-
- if (maximumAllowedBottom() - bottomOfText > 0) {
- QTextFrame *subFrame = note->textFrame();
- d->footNoteCursorToNext = new FrameIterator(subFrame);
- KoTextLayoutNoteArea *footNoteArea = new KoTextLayoutNoteArea(note, this, d->documentLayout);
-
- d->preregisteredFootNoteFrames.append(subFrame);
- footNoteArea->setReferenceRect(left(), right(), 0, maximumAllowedBottom() - bottomOfText);
- bool contNotNeeded = footNoteArea->layout(d->footNoteCursorToNext);
- if (contNotNeeded) {
- delete d->footNoteCursorToNext;
- d->footNoteCursorToNext = 0;
- d->continuedNoteToNext = 0;
- } else {
- d->continuedNoteToNext = note;
- //layout again now it has set up a continuationObstruction
- delete d->footNoteCursorToNext;
- d->footNoteCursorToNext = new FrameIterator(subFrame);
- footNoteArea->setReferenceRect(left(), right(), 0, maximumAllowedBottom() - bottomOfText);
- footNoteArea->layout(d->footNoteCursorToNext);
- documentLayout()->setContinuationObstruction(0); // remove it again
- }
- d->preregisteredFootNotesHeight += footNoteArea->bottom() - footNoteArea->top();
- d->preregisteredFootNoteAreas.append(footNoteArea);
- return footNoteArea->bottom() - footNoteArea->top();
- }
- return 0.0;
- }
- qreal h = d->parent->preregisterFootNote(note, bottomOfText);
- d->preregisteredFootNotesHeight += h;
- return h;
-}
-
-void KoTextLayoutArea::confirmFootNotes()
-{
- d->footNotesHeight += d->preregisteredFootNotesHeight;
- d->footNoteAreas.append(d->preregisteredFootNoteAreas);
- d->footNoteFrames.append(d->preregisteredFootNoteFrames);
- d->preregisteredFootNotesHeight = 0;
- d->preregisteredFootNoteAreas.clear();
- d->preregisteredFootNoteFrames.clear();
- if (d->parent) {
- d->parent->confirmFootNotes();
- }
-}
-
-void KoTextLayoutArea::expandBoundingLeft(qreal x)
-{
- d->boundingRect.setLeft(qMin(x, d->boundingRect.x()));
-}
-
-void KoTextLayoutArea::expandBoundingRight(qreal x)
-{
- d->boundingRect.setRight(qMax(x, d->boundingRect.right()));
-}
-
-void KoTextLayoutArea::clearPreregisteredFootNotes()
-{
- d->preregisteredFootNotesHeight = 0;
- d->preregisteredFootNoteAreas.clear();
- d->preregisteredFootNoteFrames.clear();
- if (d->parent) {
- d->parent->clearPreregisteredFootNotes();
- }
-}
-
-void KoTextLayoutArea::handleBordersAndSpacing(KoTextBlockData &blockData, QTextBlock *block)
-{
- QTextBlockFormat format = block->blockFormat();
- KoParagraphStyle formatStyle(format, block->charFormat());
-
- // The AddParaTableSpacingAtStart config-item is used to be able to optionally prevent that
- // defined fo:margin-top are applied to the first paragraph. If true then the fo:margin-top
- // is applied to all except the first paragraph. If false fo:margin-top is applied to all
- // paragraphs.
- bool paraTableSpacingAtStart = KoTextDocument(d->documentLayout->document()).paraTableSpacingAtStart();
- bool paddingExpandsBorders = false;//KoTextDocument(d->documentLayout->document()).paddingExpandsBorders();
-
- qreal topMargin = 0;
- if (paraTableSpacingAtStart || block->previous().isValid()) {
- topMargin = formatStyle.topMargin();
- }
- qreal spacing = qMax(d->bottomSpacing, topMargin);
- qreal dx = 0.0;
- qreal x = d->x;
- qreal width = d->width;
- if (d->indent < 0) {
- x += d->indent;
- width -= d->indent;
- }
- if (blockData.hasCounterData() && blockData.counterPosition().x() < x) {
- width += x - blockData.counterPosition().x();
- x = blockData.counterPosition().x();
- }
-
- KoTextBlockBorderData border(QRectF(x, d->y, width, 1));
- border.setEdge(border.Left, format, KoParagraphStyle::LeftBorderStyle,
- KoParagraphStyle::LeftBorderWidth, KoParagraphStyle::LeftBorderColor,
- KoParagraphStyle::LeftBorderSpacing, KoParagraphStyle::LeftInnerBorderWidth);
- border.setEdge(border.Right, format, KoParagraphStyle::RightBorderStyle,
- KoParagraphStyle::RightBorderWidth, KoParagraphStyle::RightBorderColor,
- KoParagraphStyle::RightBorderSpacing, KoParagraphStyle::RightInnerBorderWidth);
- border.setEdge(border.Top, format, KoParagraphStyle::TopBorderStyle,
- KoParagraphStyle::TopBorderWidth, KoParagraphStyle::TopBorderColor,
- KoParagraphStyle::TopBorderSpacing, KoParagraphStyle::TopInnerBorderWidth);
- border.setEdge(border.Bottom, format, KoParagraphStyle::BottomBorderStyle,
- KoParagraphStyle::BottomBorderWidth, KoParagraphStyle::BottomBorderColor,
- KoParagraphStyle::BottomBorderSpacing, KoParagraphStyle::BottomInnerBorderWidth);
- border.setMergeWithNext(formatStyle.joinBorder());
-
- if (border.hasBorders()) {
- // check if we can merge with the previous parags border.
- if (d->prevBorder && d->prevBorder->equals(border)) {
- blockData.setBorder(d->prevBorder);
- // Merged mean we don't have inserts inbetween the blocks
- d->anchoringParagraphTop = d->y;
- if (d->bottomSpacing + topMargin) {
- d->anchoringParagraphTop += spacing * d->bottomSpacing / (d->bottomSpacing + topMargin);
- }
- if (!d->blockRects.isEmpty()) {
- d->blockRects.last().setBottom(d->anchoringParagraphTop);
- }
- d->anchoringParagraphTop = d->y;
- d->y += spacing;
- d->blockRects.append(QRectF(x, d->anchoringParagraphTop, width, 1.0));
- } else {
- // can't merge; then these are our new borders.
- KoTextBlockBorderData *newBorder = new KoTextBlockBorderData(border);
- blockData.setBorder(newBorder);
- if (d->prevBorder) {
- d->y += d->prevBorderPadding;
- d->y += d->prevBorder->inset(KoTextBlockBorderData::Bottom);
- }
- if (!d->blockRects.isEmpty()) {
- d->blockRects.last().setBottom(d->y);
- }
- d->anchoringParagraphTop = d->y;
- if (d->bottomSpacing + topMargin) {
- d->anchoringParagraphTop += spacing * d->bottomSpacing / (d->bottomSpacing + topMargin);
- }
- d->y += spacing;
- if (paddingExpandsBorders) {
- d->blockRects.append(QRectF(x - format.doubleProperty(KoParagraphStyle::LeftPadding), d->y,
- width + format.doubleProperty(KoParagraphStyle::LeftPadding) + format.doubleProperty(KoParagraphStyle::RightPadding), 1.0));
- } else {
- d->blockRects.append(QRectF(x, d->y, width, 1.0));
- }
- d->y += newBorder->inset(KoTextBlockBorderData::Top);
- d->y += format.doubleProperty(KoParagraphStyle::TopPadding);
- }
-
- // finally, horizontal components of the borders
- dx = border.inset(KoTextBlockBorderData::Left);
- d->x += dx;
- d->width -= border.inset(KoTextBlockBorderData::Left);
- d->width -= border.inset(KoTextBlockBorderData::Right);
- } else { // this parag has no border.
- if (d->prevBorder) {
- d->y += d->prevBorderPadding;
- d->y += d->prevBorder->inset(KoTextBlockBorderData::Bottom);
- }
- blockData.setBorder(0); // remove an old one, if there was one.
- if (!d->blockRects.isEmpty()) {
- d->blockRects.last().setBottom(d->y);
- }
- d->anchoringParagraphTop = d->y;
- if (d->bottomSpacing + topMargin) {
- d->anchoringParagraphTop += spacing * d->bottomSpacing / (d->bottomSpacing + topMargin);
- }
- d->y += spacing;
- d->blockRects.append(QRectF(x, d->y, width, 1.0));
- }
- if (!paddingExpandsBorders) {
- // add padding inside the border
- dx += format.doubleProperty(KoParagraphStyle::LeftPadding);
- d->x += format.doubleProperty(KoParagraphStyle::LeftPadding);
- d->width -= format.doubleProperty(KoParagraphStyle::LeftPadding);
- d->width -= format.doubleProperty(KoParagraphStyle::RightPadding);
- }
- if (block->layout()->lineCount() == 1 && blockData.hasCounterData()) {
- blockData.setCounterPosition(QPointF(blockData.counterPosition().x() + dx, d->y));
- }
- d->prevBorder = blockData.border();
- d->prevBorderPadding = format.doubleProperty(KoParagraphStyle::BottomPadding);
- d->anchoringParagraphContentTop = d->y;
-}
diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutArea.h b/plugins/flake/textshape/textlayout/KoTextLayoutArea.h
deleted file mode 100644
index 142bf51916..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextLayoutArea.h
+++ /dev/null
@@ -1,231 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 C. Boemann <cbo@kogmbh.com>
- *
- * 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 KOTEXTLAYOUTAREA_H
-#define KOTEXTLAYOUTAREA_H
-
-#include "kritatextlayout_export.h"
-
-#include <KoText.h>
-#include <KoTextDocumentLayout.h>
-
-class KoTextBlockData;
-class KoInlineNote;
-class KoPointedAt;
-class KoParagraphStyle;
-
-class FrameIterator;
-
-class QTextList;
-class QRectF;
-
-/**
- * When layouting text the text is chopped up into physical area of space.
- *
- * Examples of such areas are:
- * <ul>
- * <li>RootArea (corresponds to a text shape, or a spreadsheet cell)
- * <li>TableArea (the kind of table that appears in text documents)
- * <li>SectionArea, that splits text into columns
- * </ul>
- *
- * Each of these are implemented through subclasses, and this is just the interface.
- *
- * Layout happens until maximalAllowedY() is reached. That maximum may be set by
- * the RootArea, but it may also be set by, for example, a row in a table with
- * fixed height.
- */
-class KRITATEXTLAYOUT_EXPORT KoTextLayoutArea
-{
-public:
- /// constructor
- explicit KoTextLayoutArea(KoTextLayoutArea *parent, KoTextDocumentLayout *documentLayout);
- virtual ~KoTextLayoutArea();
-
- /// Returns true if the area starts at the cursor position
- bool isStartingAt(FrameIterator *cursor) const;
-
- /**
- * These methods are deprecated since they lead to wrong assumptions.
- * Only use these methods after discussing with boemann. The problem
- * is related to tables (and paragraphs) split over more than one page,
- * in which case these methods just don't give correct or enough information.
- */
- Q_DECL_DEPRECATED QTextFrame::iterator startTextFrameIterator() const;
- Q_DECL_DEPRECATED QTextFrame::iterator endTextFrameIterator() const;
-
- /// Layouts as much as we can
- bool layout(FrameIterator *cursor);
-
- /// Returns the bounding rectangle in textdocument coordinates.
- QRectF boundingRect() const;
-
- virtual KoText::Direction parentTextDirection() const;
-
- KoTextLayoutArea *parent() const;
- KoTextDocumentLayout *documentLayout() const;
-
- /// Sets the left,right and top coordinate of the reference rect we place ourselves within
- /// The content may be smaller or bigger than that depending on our margins
- void setReferenceRect(qreal left, qreal right, qreal top, qreal maximumAllowedBottom);
-
- /// Returns the left,right,top and bottom coordinate of the reference rect.
- QRectF referenceRect() const;
-
- /// The left coordinate of the reference rect we place ourselves within
- /// The content may be smaller or bigger than that depending on our margins
- qreal left() const;
-
- /// The right coordinate of the reference rect we place ourselves within
- /// The content may be smaller or bigger than that depending on our margins
- qreal right() const;
-
- /// The top coordinate of the reference rect we place ourselves within
- /// The content may be smaller or bigger than that depending on our margins
- qreal top() const;
-
- /// The bottom coordinate of the reference rect we place ourselves within
- /// The content may be smaller or bigger than that depending on our margins
- /// bottom() can be used to place contents following this area
- qreal bottom() const;
-
- /// The maximum allowed bottom coordinate of the reference rect we place ourselves within
- /// The real bottom will be determined during layout
- qreal maximumAllowedBottom() const;
-
- FrameIterator *footNoteCursorToNext() const;
-
- KoInlineNote *continuedNoteToNext() const;
-
- int footNoteAutoCount() const;
-
- void setFootNoteCountInDoc(int count);
-
- void setFootNoteFromPrevious(FrameIterator *footNoteCursor, KoInlineNote *note);
-
- /// Sets the maximum allowed width before wrapping text.
- /// Setting this also indicates that we don't want wrapping.
- /// 0 means wrapping is allowed
- /// This has to be set before each layout(), and the layout() will change the reference rect
- /// right value to fit snugly (minimum the old right value) and so that no wrapping occurs up
- /// to maximumAllowedWidth
- void setNoWrap(qreal maximumAllowedWidth);
-
- /// Set if and how this area acts as a layout environment
- void setLayoutEnvironmentResctictions(bool isLayoutEnvironment, bool actsHorizontally);
-
- /// Returns the rect of the layout environment (see odf style:flow-with-text).
- QRectF layoutEnvironmentRect() const;
-
- qreal textIndent(const QTextBlock &block, QTextList *textList, const KoParagraphStyle &pStyle) const;
- void setExtraTextIndent(qreal extraTextIndent);
- qreal x() const;
- qreal width() const;
-
- /// Set if Area accepts page breaks, default is false;
- void setAcceptsPageBreak(bool accept);
-
- /// Areas that accept page breaks return true, default is false;
- bool acceptsPageBreak() const;
-
- /// Set if Area accepts column breaks, default is false;
- void setAcceptsColumnBreak(bool accept);
-
- /// Areas that accept column breaks return true, default is false;
- bool acceptsColumnBreak() const;
-
- /// Should be set to true when first starting layouting page
- /// Should be set to false when we add anything during layout
- void setVirginPage(bool virgin);
-
- /// returns true if we have not yet added anything to the page
- bool virginPage() const;
-
- /// Sets the amount the content should be vertically offset due to any outside induced
- /// vertical alignment
- void setVerticalAlignOffset(qreal offset);
- qreal verticalAlignOffset() const;
-
- void paint(QPainter *painter, const KoTextDocumentLayout::PaintContext &context);
-
- KoPointedAt hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const;
-
- /// Calc a bounding box rect of the selection
- /// or invalid if not
- QRectF selectionBoundingBox(QTextCursor &cursor) const;
-
- static const int MaximumTabPos = 10000;
-
-protected:
- void setBottom(qreal bottom);
-
- /// If this area has the responsibility to show footnotes then store
- /// it so it can later be in the m_pregisteredFootnotes
- /// returns the height of the foot note
- virtual qreal preregisterFootNote(KoInlineNote *note, qreal bottomOfText);
-
- /// Takes all preregistered footnotes and create Areas out of them
- void confirmFootNotes();
-
- /// Set the Left of the boundingRect to the min of what it was and x
- void expandBoundingLeft(qreal x);
-
- /// Set the Right of the boundingRect to the max of what it was and x
- void expandBoundingRight(qreal x);
-
-private:
- /// remove tables and paragraphs that are keep-with-next
- void backtrackKeepWithNext(FrameIterator *cursor);
-
- bool layoutBlock(FrameIterator *cursor);
-
- bool presentationListTabWorkaround(qreal indent, qreal labelBoxWidth, qreal presentationListTabValue);
-
- /// Returns vertical height of line
- qreal addLine(QTextLine &line, FrameIterator *cursor, KoTextBlockData &blockData);
-
- /// looks for footnotes and preregisters them
- void findFootNotes(const QTextBlock &block, const QTextLine &line, qreal bottomOfText);
-
- void clearPreregisteredFootNotes();
-
- void drawListItem(QPainter *painter, QTextBlock &block);
-
- void decorateParagraph(QPainter *painter, QTextBlock &block, bool showFormattingCharacter, bool showSpellChecking);
-
- void drawStrikeOuts(QPainter *painter, const QTextCharFormat &currentCharFormat, const QString &text, const QTextLine &line, qreal x1, qreal x2, const int startOfFragmentInBlock, const int fragmentToLineOffset) const;
-
- void drawOverlines(QPainter *painter, const QTextCharFormat &currentCharFormat, const QString &text, const QTextLine &line, qreal x1, qreal x2, const int startOfFragmentInBlock, const int fragmentToLineOffset) const;
-
- void drawUnderlines(QPainter *painter, const QTextCharFormat &currentCharFormat, const QString &text, const QTextLine &line, qreal x1, qreal x2, const int startOfFragmentInBlock, const int fragmentToLineOffset) const;
-
- int decorateTabsAndFormatting(QPainter *painter, const QTextFragment& currentFragment, const QTextLine &line, const int startOfFragmentInBlock, const QVariantList& tabList, int currentTabStop, bool showFormattingCharacter);
-
- void decorateListLabel(QPainter *painter, const KoTextBlockData &blockData, const QTextLine &listLabelLine, const QTextBlock &listItem);
-
- void handleBordersAndSpacing(KoTextBlockData &blockData, QTextBlock *block);
-
- void decorateParagraphSections(QPainter* painter, QTextBlock& block);
-
-private:
- class Private;
- Private * const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutArea_p.h b/plugins/flake/textshape/textlayout/KoTextLayoutArea_p.h
deleted file mode 100644
index dc1f295b1f..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextLayoutArea_p.h
+++ /dev/null
@@ -1,149 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008,2011 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2008 Roopesh Chander <roop@forwardbias.in>
- * Copyright (C) 2007-2008 Pierre Ducroquet <pinaraf@pinaraf.info>
- * Copyright (C) 2009-2011 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2009-2011 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2010 Nandita Suri <suri.nandita@gmail.com>
- * Copyright (C) 2010 Ajay Pundhir <ajay.pratap@iiitb.net>
- * Copyright (C) 2011 Lukáš Tvrdý <lukas.tvrdy@ixonos.com>
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- * Copyright (C) 2011 Stuart Dickson <stuart@furkinfantasic.net>
- *
- * 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 KOTEXTLAYOUTAREA_P_H
-#define KOTEXTLAYOUTAREA_P_H
-
-#include "KoTextLayoutTableArea.h"
-#include "KoTextLayoutEndNotesArea.h"
-#include "KoTextLayoutNoteArea.h"
-
-#include <KoTextBlockBorderData.h>
-
-//local type for temporary use in restartLayout
-struct LineKeeper
-{
- int columns;
- qreal lineWidth;
- QPointF position;
-};
-
-
-class Q_DECL_HIDDEN KoTextLayoutArea::Private
-{
-public:
- Private()
- : left(0.0)
- , right(0.0)
- , top(0.0)
- , bottom(0.0)
- , maximalAllowedBottom(0.0)
- , maximumAllowedWidth(0.0)
- , neededWidth(0.0)
- , isLayoutEnvironment(false)
- , actsHorizontally(false)
- , dropCapsWidth(0)
- , dropCapsDistance(0)
- , startOfArea(0)
- , endOfArea(0)
- , copyEndOfArea(0)
- , footNoteCursorToNext(0)
- , footNoteCursorFromPrevious(0)
- , continuedNoteToNext(0)
- , continuedNoteFromPrevious(0)
- , footNoteCountInDoc(0)
- , acceptsPageBreak(false)
- , acceptsColumnBreak(false)
- , virginPage(true)
- , verticalAlignOffset(0)
- , preregisteredFootNotesHeight(0)
- , footNotesHeight(0)
- , footNoteAutoCount(0)
- , extraTextIndent(0)
- , endNotesArea(0)
- {
- }
-
- KoTextLayoutArea *parent; // A pointer to the parent
-
- KoTextDocumentLayout *documentLayout;
-
- qreal left; // reference area left
- qreal right; // reference area right
- qreal top; // reference area top
- qreal bottom; // reference area top
- qreal maximalAllowedBottom;
- qreal maximumAllowedWidth; // 0 indicates wrapping is allowed
- qreal neededWidth; // used in conjuntion with grow-text-width
- QRectF boundingRect;
- bool isLayoutEnvironment;
- bool actsHorizontally;
- KoTextBlockBorderData *prevBorder;
- qreal prevBorderPadding;
-
- qreal x; // text area starts here as defined by margins (so not == left)
- qreal y;
- qreal width; // of text area as defined by margins (so not == right - left)
- qreal indent;
- qreal dropCapsWidth;
- qreal dropCapsDistance;
- int dropCapsNChars;
- bool isRtl;
- qreal bottomSpacing;
- QList<KoTextLayoutTableArea *> tableAreas;
- FrameIterator *startOfArea;
- FrameIterator *endOfArea;
- FrameIterator *copyEndOfArea;
- FrameIterator *footNoteCursorToNext;
- FrameIterator *footNoteCursorFromPrevious;
- KoInlineNote *continuedNoteToNext;
- KoInlineNote *continuedNoteFromPrevious;
- int footNoteCountInDoc;
-
- bool acceptsPageBreak;
- bool acceptsColumnBreak;
- bool virginPage;
- qreal verticalAlignOffset;
- QList<QRectF> blockRects;
- qreal anchoringParagraphTop;
- qreal anchoringParagraphContentTop;
-
- qreal preregisteredFootNotesHeight;
- qreal footNotesHeight;
- int footNoteAutoCount;
- qreal extraTextIndent;
- QList<KoTextLayoutNoteArea *> preregisteredFootNoteAreas;
- QList<KoTextLayoutNoteArea *> footNoteAreas;
- QList<QTextFrame *> preregisteredFootNoteFrames;
- QList<QTextFrame *> footNoteFrames;
- KoTextLayoutEndNotesArea *endNotesArea;
- QList<KoTextLayoutArea *> generatedDocAreas;
-
- /// utility method to restart layout of a block
- QTextLine restartLayout(QTextBlock &block, int lineTextStartOfLastKeep);
- /// utility method to store remaining layout of a split block
- void stashRemainingLayout(QTextBlock &block, int lineTextStartOfFirstKeep, QList<LineKeeper> &stashedLines, QPointF &stashedCounterPosition);
- /// utility method to recreate partial layout of a split block
- QTextLine recreatePartialLayout(QTextBlock &block, QList<LineKeeper> stashedLines, QPointF &stashedCounterPosition, QTextLine &line);
-
-
-};
-
-#endif // KOTEXTLAYOUTAREA_P_H
diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutArea_paint.cpp b/plugins/flake/textshape/textlayout/KoTextLayoutArea_paint.cpp
deleted file mode 100644
index e569fc12da..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextLayoutArea_paint.cpp
+++ /dev/null
@@ -1,1200 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2008 Roopesh Chander <roop@forwardbias.in>
- * Copyright (C) 2007-2008 Pierre Ducroquet <pinaraf@pinaraf.info>
- * Copyright (C) 2009-2011 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2009-2012 C. Boemann <cbo@boemann.dk>
- * Copyright (C) 2010 Nandita Suri <suri.nandita@gmail.com>
- * Copyright (C) 2010 Ajay Pundhir <ajay.pratap@iiitb.net>
- * Copyright (C) 2011 Lukáš Tvrdý <lukas.tvrdy@ixonos.com>
- * Copyright (C) 2011 Gopalakrishna Bhat A <gopalakbhat@gmail.com>
- * Copyright (C) 2011 Stuart Dickson <stuart@furkinfantasic.net>
- * Copyright (C) 2014 Denis Kuplyakov <dener.kup@gmail.com>
- *
- * 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 "KoTextLayoutArea.h"
-
-#include "KoTextLayoutEndNotesArea.h"
-#include "KoTextLayoutTableArea.h"
-#include "KoTextLayoutNoteArea.h"
-#include "TableIterator.h"
-#include "ListItemsHelper.h"
-#include "RunAroundHelper.h"
-#include "KoTextDocumentLayout.h"
-#include "FrameIterator.h"
-
-#include <KoParagraphStyle.h>
-#include <KoCharacterStyle.h>
-#include <KoListStyle.h>
-#include <KoStyleManager.h>
-#include <KoTextBlockData.h>
-#include <KoTextBlockBorderData.h>
-#include <KoTextBlockPaintStrategyBase.h>
-#include <KoText.h>
-#include <KoChangeTracker.h>
-#include <KoChangeTrackerElement.h>
-#include <KoImageData.h>
-
-#include <TextLayoutDebug.h>
-#include <KoSection.h>
-#include <KoSectionEnd.h>
-#include <KoSectionUtils.h>
-
-#include <QPainter>
-#include <QTextTable>
-#include <QTextList>
-#include <QFontMetrics>
-#include <QTextFragment>
-#include <QTextLayout>
-#include <QTextCursor>
-#include <QTime>
-#include "kis_painting_tweaks.h"
-
-extern int qt_defaultDpiY();
-Q_DECLARE_METATYPE(QTextDocument *)
-
-#define DropCapsAdditionalFormattingId 25602902
-
-#include "KoTextLayoutArea_p.h"
-
-void KoTextLayoutArea::paint(QPainter *painter, const KoTextDocumentLayout::PaintContext &context)
-{
- if (d->startOfArea == 0 || d->endOfArea == 0) // We have not been layouted yet
- return;
-
- /*
- struct Timer {
- QTime d->time;
- Timer() { d->time.start(); }
- ~Timer() { warnTextLayout << "elapsed=" << d->time.elapsed(); }
- };
- Timer timer;
- */
-
- painter->save();
- painter->translate(0, d->verticalAlignOffset);
-
- painter->setPen(context.textContext.palette.color(QPalette::Text)); // for text that has no color.
- const QRegion clipRegion = KisPaintingTweaks::safeClipRegion(*painter); // fetch after painter->translate so the clipRegion is correct
- KoTextBlockBorderData *lastBorder = 0;
- QRectF lastBorderRect;
-
- QTextFrame::iterator it = d->startOfArea->it;
- QTextFrame::iterator stop = d->endOfArea->it;
- if (!stop.atEnd()) {
- if (!stop.currentBlock().isValid() || d->endOfArea->lineTextStart >= 0) {
- // Last thing we show is a frame (table) or first part of a paragraph split in two
- // The stop point should be the object after that
- // However if stop is already atEnd we shouldn't increment further
- ++stop;
- }
- }
-
- int tableAreaIndex = 0;
- int blockIndex = 0;
- int tocIndex = 0;
- for (; it != stop && !it.atEnd(); ++it) {
- QTextBlock block = it.currentBlock();
- QTextTable *table = qobject_cast<QTextTable*>(it.currentFrame());
- QTextFrame *subFrame = it.currentFrame();
- QTextBlockFormat format = block.blockFormat();
-
- if (!block.isValid()) {
- if (lastBorder) { // draw previous block's border
- lastBorder->paint(*painter, lastBorderRect);
- lastBorder = 0;
- }
- }
-
- if (table) {
- if (tableAreaIndex >= d->tableAreas.size()) {
- continue;
- }
- d->tableAreas[tableAreaIndex]->paint(painter, context);
- ++tableAreaIndex;
- continue;
- } else if (subFrame) {
- if (subFrame->format().intProperty(KoText::SubFrameType) == KoText::AuxillaryFrameType) {
- d->endNotesArea->paint(painter, context);
- }
- continue;
- } else {
- if (!block.isValid()) {
- continue;
- }
- }
-
- if (block.blockFormat().hasProperty(KoParagraphStyle::GeneratedDocument)) {
- // Possibly paint the selection of the entire Table of Contents
- // but since it's a secondary document we need to create a fake selection
- QVariant data = block.blockFormat().property(KoParagraphStyle::GeneratedDocument);
- QTextDocument *generatedDocument = data.value<QTextDocument *>();
-
- KoTextDocumentLayout::PaintContext tocContext = context;
- tocContext.textContext.selections = QVector<QAbstractTextDocumentLayout::Selection>();
-
- bool pure = true;
- Q_FOREACH (const QAbstractTextDocumentLayout::Selection &selection, context.textContext.selections) {
- if (selection.cursor.selectionStart() <= block.position()
- && selection.cursor.selectionEnd() >= block.position()) {
- painter->fillRect(d->generatedDocAreas[tocIndex]->boundingRect(), selection.format.background());
- if (pure) {
- tocContext.textContext.selections.append(QAbstractTextDocumentLayout::Selection());
- tocContext.textContext.selections[0].cursor = QTextCursor(generatedDocument);
- tocContext.textContext.selections[0].cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
- tocContext.textContext.selections[0].format = selection.format;
- pure = false;
- }
- }
- }
- d->generatedDocAreas[tocIndex]->paint(painter, tocContext);
- ++tocIndex;
- continue;
- }
-
- QTextLayout *layout = block.layout();
- KoTextBlockBorderData *border = 0;
-
- if (blockIndex >= d->blockRects.count())
- break;
- QRectF br = d->blockRects[blockIndex];
- ++blockIndex;
-
- if (!painter->hasClipping() || clipRegion.intersects(br.toRect())) {
- KoTextBlockData blockData(block);
- border = blockData.border();
- KoTextBlockPaintStrategyBase *paintStrategy = blockData.paintStrategy();
-
- KoTextBlockPaintStrategyBase dummyPaintStrategy;
- if (paintStrategy == 0) {
- paintStrategy = &dummyPaintStrategy;
- }
- if (!paintStrategy->isVisible()) {
- if (lastBorder) { // draw previous block's border
- lastBorder->paint(*painter, lastBorderRect);
- lastBorder = 0;
- }
- continue; // this paragraph shouldn't be shown so just skip it
- }
-
- // Check and update border drawing code
- if (lastBorder == 0) {
- lastBorderRect = br;
- } else if (lastBorder != border
- || lastBorderRect.width() != br.width()
- || lastBorderRect.x() != br.x()) {
- lastBorder->paint(*painter, lastBorderRect);
- lastBorderRect = br;
- } else {
- lastBorderRect = lastBorderRect.united(br);
- }
- lastBorder = border;
-
- painter->save();
-
- QBrush bg = paintStrategy->background(block.blockFormat().background());
- if (bg != Qt::NoBrush ) {
- painter->fillRect(br, bg);
- } else {
- bg = context.background;
- }
-
- paintStrategy->applyStrategy(painter);
- painter->save();
- drawListItem(painter, block);
- painter->restore();
-
- QVector<QTextLayout::FormatRange> selections;
- if (context.showSelections) {
- Q_FOREACH (const QAbstractTextDocumentLayout::Selection & selection, context.textContext.selections) {
- QTextCursor cursor = selection.cursor;
- int begin = cursor.position();
- int end = cursor.anchor();
- if (begin > end)
- std::swap(begin, end);
-
- if (end < block.position() || begin > block.position() + block.length())
- continue; // selection does not intersect this block.
- if (selection.cursor.hasComplexSelection()) {
- continue; // selections of several table cells are covered by the within drawBorders above.
- }
- if (d->documentLayout->changeTracker()
- && !d->documentLayout->changeTracker()->displayChanges()
- && d->documentLayout->changeTracker()->containsInlineChanges(selection.format)
- && d->documentLayout->changeTracker()->elementById(selection.format.property(KoCharacterStyle::ChangeTrackerId).toInt())->isEnabled()
- && d->documentLayout->changeTracker()->elementById(selection.format.property(KoCharacterStyle::ChangeTrackerId).toInt())->getChangeType() == KoGenChange::DeleteChange) {
- continue; // Deletions should not be shown.
- }
- QTextLayout::FormatRange fr;
- fr.start = begin - block.position();
- fr.length = end - begin;
- fr.format = selection.format;
- selections.append(fr);
- }
- }
- // this is a workaround to fix text getting cut of when format ranges are used. There
- // is a bug in Qt that can hit when text lines overlap each other. In case a format range
- // is used for formatting it can clip the lines above/below as Qt creates a clip rect for
- // the places it already painted for the format range which results in clippling. So use
- // the format range always to paint the text.
- QVector<QTextLayout::FormatRange> workaroundFormatRanges;
- for (QTextBlock::iterator it = block.begin(); !(it.atEnd()); ++it) {
- QTextFragment currentFragment = it.fragment();
- if (currentFragment.isValid()) {
- bool formatChanged = false;
-
- QTextCharFormat format = currentFragment.charFormat();
- int changeId = format.intProperty(KoCharacterStyle::ChangeTrackerId);
- if (changeId && d->documentLayout->changeTracker() && d->documentLayout->changeTracker()->displayChanges()) {
- KoChangeTrackerElement *changeElement = d->documentLayout->changeTracker()->elementById(changeId);
- switch(changeElement->getChangeType()) {
- case (KoGenChange::InsertChange):
- format.setBackground(QBrush(d->documentLayout->changeTracker()->getInsertionBgColor()));
- break;
- case (KoGenChange::FormatChange):
- format.setBackground(QBrush(d->documentLayout->changeTracker()->getFormatChangeBgColor()));
- break;
- case (KoGenChange::DeleteChange):
- format.setBackground(QBrush(d->documentLayout->changeTracker()->getDeletionBgColor()));
- break;
- case (KoGenChange::UNKNOWN):
- break;
- }
- formatChanged = true;
- }
-
- if (format.isAnchor()) {
- if (!format.hasProperty(KoCharacterStyle::UnderlineStyle))
- format.setFontUnderline(true);
- if (!format.hasProperty(QTextFormat::ForegroundBrush))
- format.setForeground(Qt::blue);
- formatChanged = true;
- }
-
- if (format.boolProperty(KoCharacterStyle::UseWindowFontColor)) {
- QBrush backbrush = bg;
- if (format.background() != Qt::NoBrush) {
- backbrush = format.background();
- }
-
- QBrush frontBrush;
- frontBrush.setStyle(Qt::SolidPattern);
- // use the same luma calculation and threshold as msoffice
- // see https://social.msdn.microsoft.com/Forums/en-US/os_binaryfile/thread/a02a9a24-efb6-4ba0-a187-0e3d2704882b
- int luma = ((5036060/2) * backbrush.color().red()
- + (9886846/2) * backbrush.color().green()
- + (1920103/2) * backbrush.color().blue()) >> 23;
- if (luma > 60) {
- frontBrush.setColor(QColor(Qt::black));
- } else {
- frontBrush.setColor(QColor(Qt::white));
- }
- format.setForeground(frontBrush);
-
- formatChanged = true;
- }
- if (formatChanged) {
- QTextLayout::FormatRange fr;
- fr.start = currentFragment.position() - block.position();
- fr.length = currentFragment.length();
- if (!format.hasProperty(KoCharacterStyle::InlineInstanceId)) {
- if (format.background().style() == Qt::NoBrush) {
- format.setBackground(QBrush(QColor(0, 0, 0, 0)));
- }
- if (format.foreground().style() == Qt::NoBrush) {
- format.setForeground(QBrush(QColor(0, 0, 0)));
- }
- }
- fr.format = format;
- // the prepend is done so the selections are at the end.
- selections.prepend(fr);
- }
- else {
- if (!format.hasProperty(KoCharacterStyle::InlineInstanceId)) {
- QTextLayout::FormatRange fr;
- fr.start = currentFragment.position() - block.position();
- fr.length = currentFragment.length();
- QTextCharFormat f;
- if (format.background().style() == Qt::NoBrush) {
- f.setBackground(QBrush(QColor(0, 0, 0, 0)));
- }
- else {
- f.setBackground(format.background());
- }
- if (format.foreground().style() == Qt::NoBrush) {
- f.setForeground(QBrush(QColor(0, 0, 0)));
- }
- else {
- f.setForeground(format.foreground());
- }
- fr.format = f;
- workaroundFormatRanges.append(fr);
- }
- }
- }
- }
-
- if (!selections.isEmpty()) {
- selections = workaroundFormatRanges + selections;
- }
-
- //We set clip because layout-draw doesn't clip text to it correctly after all
- //and adjust to make sure we don't clip edges of glyphs. The clipping is
- //important for paragraph split across two pages.
- //20pt enlargement seems safe as pages is split by 50pt and this helps unwanted
- //glyph cutting
- painter->setClipRect(br.adjusted(-20,-20,20,20), Qt::IntersectClip);
-
- layout->draw(painter, QPointF(0, 0), selections);
-
- if (context.showSectionBounds) {
- decorateParagraphSections(painter, block);
- }
- decorateParagraph(painter, block, context.showFormattingCharacters, context.showSpellChecking);
-
- painter->restore();
- } else {
- if (lastBorder) {
- lastBorder->paint(*painter, lastBorderRect);
- lastBorder = 0;
- }
- }
- }
- if (lastBorder) {
- lastBorder->paint(*painter, lastBorderRect);
- }
-
- painter->translate(0, -d->verticalAlignOffset);
- painter->translate(0, bottom() - d->footNotesHeight);
- Q_FOREACH (KoTextLayoutNoteArea *footerArea, d->footNoteAreas) {
- footerArea->paint(painter, context);
- painter->translate(0, footerArea->bottom() - footerArea->top());
- }
- painter->restore();
-}
-
-void KoTextLayoutArea::drawListItem(QPainter *painter, QTextBlock &block)
-{
- KoTextBlockData blockData(block);
-
- QTextList *list = block.textList();
- if (list && blockData.hasCounterData()) {
- QTextListFormat listFormat = list->format();
- if (! blockData.counterText().isEmpty()) {
- QFont font(blockData.labelFormat().font(), d->documentLayout->paintDevice());
-
- KoListStyle::Style listStyle = static_cast<KoListStyle::Style>(listFormat.style());
- QString result = blockData.counterText();
-
- QTextLayout layout(result, font, d->documentLayout->paintDevice());
-
- QList<QTextLayout::FormatRange> layouts;
- QTextLayout::FormatRange format;
- format.start = 0;
- format.length = blockData.counterText().length();
- format.format = blockData.labelFormat();
-
- layouts.append(format);
- layout.setAdditionalFormats(layouts);
-
- Qt::Alignment alignment = static_cast<Qt::Alignment>(listFormat.intProperty(KoListStyle::Alignment));
-
- if (alignment == 0) {
- alignment = Qt::AlignLeft | Qt::AlignAbsolute;
- }
- if (d->isRtl && (alignment & Qt::AlignAbsolute) == 0) {
- if (alignment & Qt::AlignLeft) {
- alignment = Qt::AlignRight;
- } else if (alignment & Qt::AlignRight) {
- alignment = Qt::AlignLeft;
- }
- }
- alignment |= Qt::AlignAbsolute;
-
- QTextOption option(alignment);
- option.setTextDirection(block.layout()->textOption().textDirection());
-/*
- if (option.textDirection() == Qt::RightToLeft || blockData.counterText().isRightToLeft()) {
- option.setAlignment(Qt::AlignRight);
- }
-*/
- layout.setTextOption(option);
-
- layout.beginLayout();
-
- QTextLine line = layout.createLine();
- line.setLineWidth(blockData.counterWidth());
- layout.endLayout();
-
- QPointF counterPosition = blockData.counterPosition();
-
- if (block.layout()->lineCount() > 0) {
- // if there is text, then baseline align the counter.
- QTextLine firstParagLine = block.layout()->lineAt(0);
- if (KoListStyle::isNumberingStyle(listStyle)) {
- //if numbered list baseline align
- counterPosition += QPointF(0, firstParagLine.ascent() - layout.lineAt(0).ascent());
- } else {
- //for unnumbered list center align
- counterPosition += QPointF(0, (firstParagLine.height() - layout.lineAt(0).height())/2.0);
- }
- }
- layout.draw(painter, counterPosition);
-
- //decorate the list label iff it is a numbered list
- if (KoListStyle::isNumberingStyle(listStyle)) {
- painter->save();
- decorateListLabel(painter, blockData, layout.lineAt(0), block);
- painter->restore();
- }
- }
-
- KoListStyle::Style listStyle = static_cast<KoListStyle::Style>(listFormat.style());
- if (listStyle == KoListStyle::ImageItem) {
- QFontMetricsF fm(blockData.labelFormat().font(), d->documentLayout->paintDevice());
- qreal x = qMax(qreal(1), blockData.counterPosition().x());
- qreal width = qMax(listFormat.doubleProperty(KoListStyle::Width), (qreal)1.0);
- qreal height = qMax(listFormat.doubleProperty(KoListStyle::Height), (qreal)1.0);
- qreal y = blockData.counterPosition().y() + fm.ascent() - fm.xHeight()/2 - height/2; // centered
- KoImageData *idata = listFormat.property(KoListStyle::BulletImage).value<KoImageData *>();
- if (idata) {
- painter->drawPixmap(x, y, width, height, idata->pixmap());
- }
- }
- }
-}
-
-void KoTextLayoutArea::decorateListLabel(QPainter *painter, const KoTextBlockData &blockData, const QTextLine &listLabelLine, const QTextBlock &listItem)
-{
- const QTextCharFormat listLabelCharFormat = blockData.labelFormat();
- painter->setFont(listLabelCharFormat.font());
-
- int startOfFragmentInBlock = 0;
- Q_ASSERT_X(listLabelLine.isValid(), __FUNCTION__, QString("Invalid list label").toLocal8Bit());
- if (!listLabelLine.isValid()) {
- return;
- }
-
- int fragmentToLineOffset = 0;
-
- qreal x1 = blockData.counterPosition().x();
- qreal x2 = listItem.layout()->lineAt(0).x();
-
- if (x2 != x1) {
- drawStrikeOuts(painter, listLabelCharFormat, blockData.counterText(), listItem.layout()->lineAt(0), x1, x2, startOfFragmentInBlock, fragmentToLineOffset);
- drawOverlines(painter, listLabelCharFormat, blockData.counterText(), listItem.layout()->lineAt(0), x1, x2, startOfFragmentInBlock, fragmentToLineOffset);
- drawUnderlines(painter, listLabelCharFormat, blockData.counterText(), listItem.layout()->lineAt(0), x1, x2, startOfFragmentInBlock, fragmentToLineOffset);
- }
-}
-
-/**
- * Draw a line. Typically meant to underline text or similar.
- * @param painter the painter to paint on.
- * @param color the pen color to for the decoration line
- * @param type The type
- * @param style the type of line to draw.
- * @param width The thickness of the line, in pixels (the painter will be prescaled to points coordinate system).
- * @param x1 we are always drawing horizontal lines, this is the start point.
- * @param x2 we are always drawing horizontal lines, this is the end point.
- * @param y the y-offset to paint on.
- */
-static void drawDecorationLine(QPainter *painter, const QColor &color, KoCharacterStyle::LineType type, KoCharacterStyle::LineStyle style, qreal width, const qreal x1, const qreal x2, const qreal y)
-{
- QPen penBackup = painter->pen();
- QPen pen = painter->pen();
- pen.setColor(color);
- pen.setWidthF(width);
- if (style == KoCharacterStyle::WaveLine) {
- // Ok, try the waves :)
- pen.setStyle(Qt::SolidLine);
- painter->setPen(pen);
- qreal x = x1;
- const qreal halfWaveWidth = 0.5 * width;
- const qreal halfWaveLength = 2 * width;
- const int startAngle = 0 * 16;
- const int middleAngle = 180 * 16;
- const int endAngle = 180 * 16;
- while (x < x2) {
- QRectF rectangle1(x, y, halfWaveLength, 2*halfWaveWidth);
- if (type == KoCharacterStyle::DoubleLine) {
- painter->translate(0, -pen.width());
- painter->drawArc(rectangle1, startAngle, middleAngle);
- painter->translate(0, 2*pen.width());
- painter->drawArc(rectangle1, startAngle, middleAngle);
- painter->translate(0, -pen.width());
- } else {
- painter->drawArc(rectangle1, startAngle, middleAngle);
- }
- if (x + halfWaveLength > x2)
- break;
- QRectF rectangle2(x + halfWaveLength, y, halfWaveLength, 2*halfWaveWidth);
- if (type == KoCharacterStyle::DoubleLine) {
- painter->translate(0, -pen.width());
- painter->drawArc(rectangle2, middleAngle, endAngle);
- painter->translate(0, 2*pen.width());
- painter->drawArc(rectangle2, middleAngle, endAngle);
- painter->translate(0, -pen.width());
- } else {
- painter->drawArc(rectangle2, middleAngle, endAngle);
- }
- x = x + 2 * halfWaveLength;
- }
- } else {
- if (style == KoCharacterStyle::LongDashLine) {
- QVector<qreal> dashes;
- dashes << 12 << 2;
- pen.setDashPattern(dashes);
- } else {
- pen.setStyle((Qt::PenStyle)style);
- }
- painter->setPen(pen);
- if (type == KoCharacterStyle::DoubleLine) {
- painter->translate(0, -pen.width());
- painter->drawLine(QPointF(x1, y), QPointF(x2, y));
- painter->translate(0, 2*pen.width());
- painter->drawLine(QPointF(x1, y), QPointF(x2, y));
- painter->translate(0, -pen.width());
- } else {
- painter->drawLine(QPointF(x1, y), QPointF(x2, y));
- }
- }
- painter->setPen(penBackup);
-}
-
-static void drawDecorationText(QPainter *painter, const QTextLine &line, const QColor &color, const QString& decorText, qreal x1, qreal x2)
-{
- qreal y = line.position().y();
- QPen oldPen = painter->pen();
- painter->setPen(QPen(color));
- do {
- QRectF br;
- painter->drawText(QRectF(QPointF(x1, y), QPointF(x2, y + line.height())), Qt::AlignLeft | Qt::AlignVCenter, decorText, &br);
- x1 = br.right();
- } while (x1 <= x2);
- painter->setPen(oldPen);
-}
-
-static void drawDecorationWords(QPainter *painter, const QTextLine &line, const QString &text, const QColor &color, KoCharacterStyle::LineType type, KoCharacterStyle::LineStyle style, const QString& decorText, qreal width, const qreal y, const int fragmentToLineOffset, const int startOfFragmentInBlock)
-{
- qreal wordBeginX = -1;
- int j = line.textStart()+fragmentToLineOffset;
- while (j < line.textLength() + line.textStart() && j-startOfFragmentInBlock<text.size()) {
- if (text[j-startOfFragmentInBlock].isSpace()) {
- if (wordBeginX != -1) {
- if (decorText.isEmpty())
- drawDecorationLine(painter, color, type, style, width, wordBeginX, line.cursorToX(j), y);
- else
- drawDecorationText(painter, line, color, decorText, wordBeginX, line.cursorToX(j));
- }
- wordBeginX = -1;
- } else if (wordBeginX == -1) {
- wordBeginX = line.cursorToX(j);
- }
- ++j;
- }
- if (wordBeginX != -1) {
- if (decorText.isEmpty())
- drawDecorationLine(painter, color, type, style, width, wordBeginX, line.cursorToX(j), y);
- else
- drawDecorationText(painter, line, color, decorText, wordBeginX, line.cursorToX(j));
- }
-}
-
-static qreal computeWidth(KoCharacterStyle::LineWeight weight, qreal width, const QFont& font)
-{
- switch (weight) {
- case KoCharacterStyle::AutoLineWeight:
- case KoCharacterStyle::NormalLineWeight:
- case KoCharacterStyle::MediumLineWeight:
- case KoCharacterStyle::DashLineWeight:
- return QFontMetricsF(font).lineWidth();
- case KoCharacterStyle::BoldLineWeight:
- case KoCharacterStyle::ThickLineWeight:
- return QFontMetricsF(font).lineWidth() * 1.5;
- case KoCharacterStyle::ThinLineWeight:
- return QFontMetricsF(font).lineWidth() * 0.7;
- case KoCharacterStyle::PercentLineWeight:
- return QFontInfo(font).pointSizeF() * width / 100;
- case KoCharacterStyle::LengthLineWeight:
- return width;
- }
- Q_ASSERT(0); // illegal weight passed
- return 0;
-}
-
-void KoTextLayoutArea::decorateParagraphSections(QPainter *painter, QTextBlock &block)
-{
- QTextLayout *layout = block.layout();
- QTextBlockFormat bf = block.blockFormat();
-
- QPen penBackup = painter->pen();
- QPen pen = painter->pen();
-
- pen.setWidth(1);
- pen.setColor(Qt::gray);
- painter->setPen(pen);
-
- qreal xl = layout->boundingRect().left();
- qreal xr = qMax(layout->boundingRect().right(), layout->boundingRect().left() + width());
- qreal yu = layout->boundingRect().top();
- qreal yd = layout->boundingRect().bottom();
-
- qreal bracketSize = painter->fontMetrics().height() / 2;
-
- const qreal levelShift = 3;
-
- QList<KoSection *> openList = KoSectionUtils::sectionStartings(bf);
- for (int i = 0; i < openList.size(); i++) {
- int sectionLevel = openList[i]->level();
- if (i == 0) {
- painter->drawLine(xl + sectionLevel * levelShift, yu,
- xr - sectionLevel * levelShift, yu);
- }
- painter->drawLine(xl + sectionLevel * levelShift, yu,
- xl + sectionLevel * levelShift, yu + bracketSize);
-
- painter->drawLine(xr - sectionLevel * levelShift, yu,
- xr - sectionLevel * levelShift, yu + bracketSize);
- }
-
- QList<KoSectionEnd *> closeList = KoSectionUtils::sectionEndings(bf);
- for (int i = 0; i < closeList.size(); i++) {
- int sectionLevel = closeList[i]->correspondingSection()->level();
- if (i == closeList.count() - 1) {
- painter->drawLine(xl + sectionLevel * levelShift, yd,
- xr - sectionLevel * levelShift, yd);
- }
- painter->drawLine(xl + sectionLevel * levelShift, yd,
- xl + sectionLevel * levelShift, yd - bracketSize);
-
- painter->drawLine(xr - sectionLevel * levelShift, yd,
- xr - sectionLevel * levelShift, yd - bracketSize);
- }
-
- painter->setPen(penBackup);
-}
-
-void KoTextLayoutArea::decorateParagraph(QPainter *painter, QTextBlock &block, bool showFormattingCharacters, bool showSpellChecking)
-{
- QTextLayout *layout = block.layout();
-
- QTextBlockFormat bf = block.blockFormat();
- QVariantList tabList = bf.property(KoParagraphStyle::TabPositions).toList();
- QFont oldFont = painter->font();
-
- QTextBlock::iterator it;
- int startOfBlock = -1;
- int currentTabStop = 0;
-
-// qDebug() << "\n-------------------"
-// << "\nGoing to decorate block\n"
-// << block.text()
-// << "\n-------------------";
-
- // loop over text fragments in this paragraph and draw the underline and line through.
- for (it = block.begin(); !it.atEnd(); ++it) {
- QTextFragment currentFragment = it.fragment();
- if (currentFragment.isValid()) {
-
-// qDebug() << "\tGoing to layout fragment:" << currentFragment.text();
-
- QTextCharFormat fmt = currentFragment.charFormat();
- painter->setFont(fmt.font());
-
- // a block doesn't have a real start position, so use our own counter. Initialize
- // it with the position of the first text fragment in the block.
- if (startOfBlock == -1) {
- startOfBlock = currentFragment.position(); // start of this block w.r.t. the document
- }
-
- // the start of our fragment in the block is the absolute position of the fragment
- // in the document minus the start of the block in the document.
- int startOfFragmentInBlock = currentFragment.position() - startOfBlock;
-
- // a fragment can span multiple lines, but we paint the decorations per line.
- int firstLine = layout->lineForTextPosition(currentFragment.position() - startOfBlock).lineNumber();
- int lastLine = layout->lineForTextPosition(currentFragment.position() + currentFragment.length()
- - startOfBlock).lineNumber();
-
-// qDebug() << "\tfirst line:" << firstLine << "last line:" << lastLine;
-
- for (int i = firstLine ; i <= lastLine ; ++i) {
- QTextLine line = layout->lineAt(i);
-// qDebug() << "\n\t\tcurrent line:" << i
-// << "\n\t\tline length:" << line.textLength() << "width:"<< line.width() << "natural width" << line.naturalTextWidth()
-// << "\n\t\tvalid:" << layout->isValidCursorPosition(currentFragment.position() - startOfBlock)
-// << "\n\t\tcurrentFragment.position:" << currentFragment.position()
-// << "\n\t\tstartOfBlock:" << startOfBlock
-// << "\n\t\tstartOfFragmentInBlock:" << startOfFragmentInBlock;
-
- if (layout->isValidCursorPosition(currentFragment.position() - startOfBlock)) {
-
- // the start position for painting the decoration is the position of the fragment
- // inside, but after the first line, the decoration always starts at the beginning
- // of the line. See bug: 264471
- int p1 = startOfFragmentInBlock;
- if (i > firstLine) {
- p1 = line.textStart();
- }
-
-// qDebug() << "\n\t\tblock.text.length:" << block.text().length() << "p1" << p1;
-
- if (block.text().length() > p1 && block.text().at(p1) != QChar::ObjectReplacementCharacter) {
- Q_ASSERT_X(line.isValid(), __FUNCTION__, QString("Invalid line=%1 first=%2 last=%3").arg(i).arg(firstLine).arg(lastLine).toLocal8Bit()); // see bug 278682
- if (!line.isValid())
- continue;
-
- // end position: note that x2 can be smaller than x1 when we are handling RTL
- int p2 = startOfFragmentInBlock + currentFragment.length();
- int lineEndWithoutPreedit = line.textStart() + line.textLength();
- if (block.layout()->preeditAreaPosition() >= block.position() + line.textStart() &&
- block.layout()->preeditAreaPosition() <= block.position() + line.textStart() + line.textLength()) {
- lineEndWithoutPreedit -= block.layout()->preeditAreaText().length();
- }
- while (lineEndWithoutPreedit > line.textStart() && block.text().at(lineEndWithoutPreedit - 1) == ' ') {
- --lineEndWithoutPreedit;
- }
- if (lineEndWithoutPreedit < p2) { //line caps
- p2 = lineEndWithoutPreedit;
- }
- int fragmentToLineOffset = qMax(startOfFragmentInBlock - line.textStart(), 0);
-
- qreal x1 = line.cursorToX(p1);
- qreal x2 = line.cursorToX(p2);
-
- //qDebug() << "\n\t\t\tp1:" << p1 << "x1:" << x1
- // << "\n\t\t\tp2:" << p2 << "x2:" << x2
- // << "\n\t\t\tlineEndWithoutPreedit" << lineEndWithoutPreedit;
-
- if (x1 != x2) {
- drawStrikeOuts(painter, fmt, currentFragment.text(), line, x1, x2, startOfFragmentInBlock, fragmentToLineOffset);
- drawOverlines(painter, fmt, currentFragment.text(), line, x1, x2, startOfFragmentInBlock, fragmentToLineOffset);
- drawUnderlines(painter, fmt, currentFragment.text(), line, x1, x2, startOfFragmentInBlock, fragmentToLineOffset);
- }
- decorateTabsAndFormatting(painter, currentFragment, line, startOfFragmentInBlock, tabList, currentTabStop, showFormattingCharacters);
-
- // underline preedit strings
- if (layout->preeditAreaPosition() > -1) {
- int start = block.layout()->preeditAreaPosition();
- int end = block.layout()->preeditAreaPosition() + block.layout()->preeditAreaText().length();
-
- QTextCharFormat underline;
- underline.setFontUnderline(true);
- underline.setUnderlineStyle(QTextCharFormat::DashUnderline);
-
- //qDebug() << "underline style" << underline.underlineStyle();
- //qDebug() << "line start: " << block.position() << line.textStart();
- qreal z1 = 0;
- qreal z2 = 0;
-
- // preedit start in this line, end in this line
- if ( start >= block.position() + line.textStart() &&
- end <= block.position() + line.textStart() + line.textLength() ) {
- z1 = line.cursorToX(start);
- z2 = line.cursorToX(end);
- }
- // preedit start in this line, end after this line
- if ( start >= block.position() + line.textStart() &&
- end > block.position() + line.textStart() + line.textLength() ) {
- z1 = line.cursorToX(start);
- z2 = line.cursorToX(block.position() + line.textStart() + line.textLength());
- }
- // preedit start before this line, end in this line
- if ( start < block.position() + line.textStart() &&
- end <= block.position() + line.textStart() + line.textLength() ) {
- z1 = line.cursorToX(block.position() + line.textStart());
- z2 = line.cursorToX(end);
- }
- // preedit start before this line, end after this line
- if ( start < block.position() + line.textStart() &&
- end > block.position() + line.textStart() + line.textLength() ) {
- z1 = line.cursorToX(block.position() + line.textStart());
- z2 = line.cursorToX(block.position() + line.textStart() + line.textLength());
- }
- if (z2 > z1) {
- //qDebug() << "z1: " << z1 << "z2: " << z2;
- KoCharacterStyle::LineStyle fontUnderLineStyle = KoCharacterStyle::DashLine;
- KoCharacterStyle::LineType fontUnderLineType = KoCharacterStyle::SingleLine;
- QTextCharFormat::VerticalAlignment valign = fmt.verticalAlignment();
-
- QFont font(fmt.font());
- if (valign == QTextCharFormat::AlignSubScript
- || valign == QTextCharFormat::AlignSuperScript)
- font.setPointSize(font.pointSize() * 2 / 3);
- QFontMetricsF metrics(font, d->documentLayout->paintDevice());
-
- qreal y = line.position().y();
- if (valign == QTextCharFormat::AlignSubScript)
- y += line.height() - metrics.descent() + metrics.underlinePos();
- else if (valign == QTextCharFormat::AlignSuperScript)
- y += metrics.ascent() + metrics.underlinePos();
- else
- y += line.ascent() + metrics.underlinePos();
-
- QColor color = fmt.foreground().color();
- qreal width = computeWidth( // line thickness
- (KoCharacterStyle::LineWeight) underline.intProperty(KoCharacterStyle::UnderlineWeight),
- underline.doubleProperty(KoCharacterStyle::UnderlineWidth),
- font);
- if (valign == QTextCharFormat::AlignSubScript
- || valign == QTextCharFormat::AlignSuperScript) // adjust size.
- width = width * 2 / 3;
-
- drawDecorationLine(painter, color, fontUnderLineType, fontUnderLineStyle, width, z1, z2, y);
- }
- }
- }
- }
- }
- }
- }
-
- if (showFormattingCharacters) {
- QTextLine line = layout->lineForTextPosition(block.length()-1);
- qreal y = line.position().y() + line.ascent();
- qreal x = line.cursorToX(block.length()-1);
- painter->drawText(QPointF(x, y), QChar((ushort)0x00B6));
- }
-
- if (showSpellChecking) {
- // Finally let's paint our own spelling markings
- // TODO Should we make this optional at this point (right on/off handled by the plugin)
- // also we might want to provide alternative ways of drawing it
- KoTextBlockData blockData(block);
- QPen penBackup = painter->pen();
- QPen pen;
- pen.setColor(QColor(Qt::red));
- pen.setWidthF(1.5);
- QVector<qreal> pattern;
- pattern << 1 << 2;
- pen.setDashPattern(pattern);
- painter->setPen(pen);
-
- QList<KoTextBlockData::MarkupRange>::Iterator markIt = blockData.markupsBegin(KoTextBlockData::Misspell);
- QList<KoTextBlockData::MarkupRange>::Iterator markEnd = blockData.markupsEnd(KoTextBlockData::Misspell);
- for (int i = 0 ; i < layout->lineCount(); ++i) {
- if (markIt == markEnd) {
- break;
- }
- QTextLine line = layout->lineAt(i);
- // the y position is placed half way between baseline and descent of the line
- // this is fast and sufficient
- qreal y = line.position().y() + line.ascent() + 0.5 * line.descent();
-
- // first handle all those marking ranges that end on this line
- while (markIt != markEnd && markIt->lastChar < line.textStart() + line.textLength()
- && line.textStart() + line.textLength() <= block.length()) {
- if (!blockData.isMarkupsLayoutValid(KoTextBlockData::Misspell)) {
- if (markIt->firstChar > line.textStart()) {
- markIt->startX = line.cursorToX(markIt->firstChar);
- }
- markIt->endX = line.cursorToX(qMin(markIt->lastChar, block.length()));
- }
- qreal x1 = (markIt->firstChar > line.textStart()) ? markIt->startX : line.cursorToX(0);
-
- painter->drawLine(QPointF(x1, y), QPointF(markIt->endX, y));
-
- ++markIt;
- }
-
- // there may be a markup range on this line that extends to the next line
- if (markIt != markEnd && markIt->firstChar < line.textStart() + line.textLength()
- && line.textStart() + line.textLength() <= block.length()) {
- if (!blockData.isMarkupsLayoutValid(KoTextBlockData::Misspell)) {
- if (markIt->firstChar > line.textStart()) {
- markIt->startX = line.cursorToX(markIt->firstChar);
- }
- }
- qreal x1 = (markIt->firstChar > line.textStart()) ? markIt->startX : line.cursorToX(0);
-
- painter->drawLine(QPointF(x1, y), QPointF(line.cursorToX(line.textStart() + line.textLength()), y));
-
- // since it extends to next line we don't increment the iterator
- }
- }
- blockData.setMarkupsLayoutValidity(KoTextBlockData::Misspell, true);
-
- painter->setPen(penBackup);
- }
- painter->setFont(oldFont);
-}
-
-void KoTextLayoutArea::drawStrikeOuts(QPainter *painter, const QTextCharFormat &currentCharFormat, const QString &text, const QTextLine &line, qreal x1, qreal x2, const int startOfFragmentInBlock, const int fragmentToLineOffset) const
-{
- KoCharacterStyle::LineStyle strikeOutStyle = (KoCharacterStyle::LineStyle)
- currentCharFormat.intProperty(KoCharacterStyle::StrikeOutStyle);
- KoCharacterStyle::LineType strikeOutType = (KoCharacterStyle::LineType)
- currentCharFormat.intProperty(KoCharacterStyle::StrikeOutType);
- if ((strikeOutStyle != KoCharacterStyle::NoLineStyle) &&
- (strikeOutType != KoCharacterStyle::NoLineType)) {
- QTextCharFormat::VerticalAlignment valign = currentCharFormat.verticalAlignment();
-
- QFont font(currentCharFormat.font());
- if (valign == QTextCharFormat::AlignSubScript
- || valign == QTextCharFormat::AlignSuperScript)
- font.setPointSize(qRound(font.pointSize() * 2 / 3.));
- QFontMetricsF metrics(font, d->documentLayout->paintDevice());
-
- qreal y = line.position().y();
- if (valign == QTextCharFormat::AlignSubScript)
- y += line.height() - metrics.descent() - metrics.strikeOutPos();
- else if (valign == QTextCharFormat::AlignSuperScript)
- y += metrics.ascent() - metrics.strikeOutPos();
- else
- y += line.ascent() - metrics.strikeOutPos();
-
- QColor color = currentCharFormat.colorProperty(KoCharacterStyle::StrikeOutColor);
- if (!color.isValid())
- color = currentCharFormat.foreground().color();
- KoCharacterStyle::LineMode strikeOutMode =
- (KoCharacterStyle::LineMode) currentCharFormat.intProperty(KoCharacterStyle::StrikeOutMode);
-
- QString strikeOutText = currentCharFormat.stringProperty(KoCharacterStyle::StrikeOutText);
- qreal width = 0; // line thickness
- if (strikeOutText.isEmpty()) {
- width = computeWidth(
- (KoCharacterStyle::LineWeight) currentCharFormat.intProperty(KoCharacterStyle::StrikeOutWeight),
- currentCharFormat.doubleProperty(KoCharacterStyle::StrikeOutWidth),
- font);
- }
- if (valign == QTextCharFormat::AlignSubScript
- || valign == QTextCharFormat::AlignSuperScript) // adjust size.
- width = width * 2 / 3;
-
- if (strikeOutMode == KoCharacterStyle::SkipWhiteSpaceLineMode) {
- drawDecorationWords(painter, line, text, color, strikeOutType,
- strikeOutStyle, strikeOutText, width, y, fragmentToLineOffset,
- startOfFragmentInBlock);
- } else {
- if (strikeOutText.isEmpty())
- drawDecorationLine(painter, color, strikeOutType, strikeOutStyle, width, x1, x2, y);
- else
- drawDecorationText(painter, line, color, strikeOutText, x1, x2);
- }
- }
-}
-
-void KoTextLayoutArea::drawOverlines(QPainter *painter, const QTextCharFormat &currentCharFormat, const QString &text, const QTextLine &line, qreal x1, qreal x2, const int startOfFragmentInBlock, const int fragmentToLineOffset) const
-{
- KoCharacterStyle::LineStyle fontOverLineStyle = (KoCharacterStyle::LineStyle) currentCharFormat.intProperty(KoCharacterStyle::OverlineStyle);
- KoCharacterStyle::LineType fontOverLineType = (KoCharacterStyle::LineType) currentCharFormat.intProperty(KoCharacterStyle::OverlineType);
- if ((fontOverLineStyle != KoCharacterStyle::NoLineStyle) &&
- (fontOverLineType != KoCharacterStyle::NoLineType)) {
- QTextCharFormat::VerticalAlignment valign = currentCharFormat.verticalAlignment();
-
- QFont font(currentCharFormat.font());
- if (valign == QTextCharFormat::AlignSubScript
- || valign == QTextCharFormat::AlignSuperScript)
- font.setPointSize(font.pointSize() * 2 / 3);
- QFontMetricsF metrics(font, d->documentLayout->paintDevice());
-
- qreal y = line.position().y();
- if (valign == QTextCharFormat::AlignSubScript)
- y += line.height() - metrics.descent() - metrics.overlinePos();
- else if (valign == QTextCharFormat::AlignSuperScript)
- y += metrics.ascent() - metrics.overlinePos();
- else
- y += line.ascent() - metrics.overlinePos();
-
- QColor color = currentCharFormat.colorProperty(KoCharacterStyle::OverlineColor);
- if (!color.isValid())
- color = currentCharFormat.foreground().color();
- KoCharacterStyle::LineMode overlineMode =
- (KoCharacterStyle::LineMode) currentCharFormat.intProperty(KoCharacterStyle::OverlineMode);
- qreal width = computeWidth( // line thickness
- (KoCharacterStyle::LineWeight) currentCharFormat.intProperty(KoCharacterStyle::OverlineWeight),
- currentCharFormat.doubleProperty(KoCharacterStyle::OverlineWidth),
- font);
- if (valign == QTextCharFormat::AlignSubScript
- || valign == QTextCharFormat::AlignSuperScript) // adjust size.
- width = width * 2 / 3;
-
- if (overlineMode == KoCharacterStyle::SkipWhiteSpaceLineMode) {
- drawDecorationWords(painter, line, text, color, fontOverLineType,
- fontOverLineStyle, QString(), width, y, fragmentToLineOffset, startOfFragmentInBlock);
- } else {
- drawDecorationLine(painter, color, fontOverLineType, fontOverLineStyle, width, x1, x2, y);
- }
- }
-}
-
-void KoTextLayoutArea::drawUnderlines(QPainter *painter, const QTextCharFormat &currentCharFormat,const QString &text, const QTextLine &line, qreal x1, qreal x2, const int startOfFragmentInBlock, const int fragmentToLineOffset) const
-{
- KoCharacterStyle::LineStyle fontUnderLineStyle = (KoCharacterStyle::LineStyle) currentCharFormat.intProperty(KoCharacterStyle::UnderlineStyle);
- KoCharacterStyle::LineType fontUnderLineType = (KoCharacterStyle::LineType) currentCharFormat.intProperty(KoCharacterStyle::UnderlineType);
- if ((fontUnderLineStyle != KoCharacterStyle::NoLineStyle) &&
- (fontUnderLineType != KoCharacterStyle::NoLineType)) {
- QTextCharFormat::VerticalAlignment valign = currentCharFormat.verticalAlignment();
-
- QFont font(currentCharFormat.font());
- if (valign == QTextCharFormat::AlignSubScript
- || valign == QTextCharFormat::AlignSuperScript)
- font.setPointSize(font.pointSize() * 2 / 3);
- QFontMetricsF metrics(font, d->documentLayout->paintDevice());
-
- qreal y = line.position().y();
- if (valign == QTextCharFormat::AlignSubScript)
- y += line.height() - metrics.descent() + metrics.underlinePos();
- else if (valign == QTextCharFormat::AlignSuperScript)
- y += metrics.ascent() + metrics.underlinePos();
- else
- y += line.ascent() + metrics.underlinePos();
-
- QColor color = currentCharFormat.underlineColor();
- if (!color.isValid())
- color = currentCharFormat.foreground().color();
- KoCharacterStyle::LineMode underlineMode =
- (KoCharacterStyle::LineMode) currentCharFormat.intProperty(KoCharacterStyle::UnderlineMode);
- qreal width = computeWidth( // line thickness
- (KoCharacterStyle::LineWeight) currentCharFormat.intProperty(KoCharacterStyle::UnderlineWeight),
- currentCharFormat.doubleProperty(KoCharacterStyle::UnderlineWidth),
- font);
- if (valign == QTextCharFormat::AlignSubScript
- || valign == QTextCharFormat::AlignSuperScript) // adjust size.
- width = width * 2 / 3;
-
- if (underlineMode == KoCharacterStyle::SkipWhiteSpaceLineMode) {
- drawDecorationWords(painter, line, text, color, fontUnderLineType,
- fontUnderLineStyle, QString(), width, y, fragmentToLineOffset, startOfFragmentInBlock);
- } else {
- drawDecorationLine(painter, color, fontUnderLineType, fontUnderLineStyle, width, x1, x2, y);
- }
- }
-}
-
-// Decorate any tabs ('\t's) in 'currentFragment' and laid out in 'line'.
-int KoTextLayoutArea::decorateTabsAndFormatting(QPainter *painter, const QTextFragment& currentFragment, const QTextLine &line, const int startOfFragmentInBlock, const QVariantList& tabList, int currentTabStop, bool showFormattingCharacters)
-{
- // If a line in the layout represent multiple text fragments, this function will
- // be called multiple times on the same line, with different fragments.
- // Likewise, if a fragment spans two lines, then this function will be called twice
- // on the same fragment, once for each line.
-
- QString fragText = currentFragment.text();
-
- QFontMetricsF fm(currentFragment.charFormat().font(), d->documentLayout->paintDevice());
- qreal tabStyleLineMargin = fm.averageCharWidth() / 4; // leave some margin for the tab decoration line
-
- // currentFragment.position() : start of this fragment w.r.t. the document
- // startOfFragmentInBlock : start of this fragment w.r.t. the block
- // line.textStart() : start of this line w.r.t. the block
-
- int searchForCharFrom; // search for \t from this point onwards in fragText
- int searchForCharTill; // search for \t till this point in fragText
-
- if (line.textStart() >= startOfFragmentInBlock) { // fragment starts at or before the start of line
- // we are concerned with only that part of the fragment displayed in this line
- searchForCharFrom = line.textStart() - startOfFragmentInBlock;
- // It's a new line. So we should look at the first tab-stop properties for the next \t.
- currentTabStop = 0;
- } else { // fragment starts in the middle of the line
- searchForCharFrom = 0;
- }
- if (line.textStart() + line.textLength() > startOfFragmentInBlock + currentFragment.length()) {
- // fragment ends before the end of line. need to see only till the end of the fragment.
- searchForCharTill = currentFragment.length();
- } else {
- // line ends before the fragment ends. need to see only till the end of this line.
- // but then, we need to convert the end of line to an index into fragText
- searchForCharTill = line.textLength() + line.textStart() - startOfFragmentInBlock;
- }
- for (int i = searchForCharFrom ; i < searchForCharTill; i++) {
- if (currentTabStop >= tabList.size() && !showFormattingCharacters) // no more decorations
- break;
-
- if (fragText[i] == '\t') {
- qreal x1(0.0);
- qreal x2(0.0);
-
- if (showFormattingCharacters) {
- x1 = line.cursorToX(startOfFragmentInBlock + i);
- x2 = line.cursorToX(startOfFragmentInBlock + i + 1);
- qreal y = line.position().y() + line.ascent() - fm.xHeight()/2.0;
- qreal arrowDim = fm.xHeight()/2.0;
- QPen penBackup = painter->pen();
- QPen pen = painter->pen();
- pen.setWidthF(fm.ascent()/10.0);
- pen.setStyle(Qt::SolidLine);
- painter->setPen(pen);
- painter->drawLine(QPointF(x1, y), QPointF(x2, y));
- painter->drawLine(QPointF(x2 - arrowDim, y - arrowDim), QPointF(x2, y));
- painter->drawLine(QPointF(x2 - arrowDim, y + arrowDim), QPointF(x2, y));
- painter->setPen(penBackup);
- }
- if (currentTabStop < tabList.size()) { // still tabsstops worth examining
- if (!showFormattingCharacters) {
- // only then was it not calculated
- x1 = line.cursorToX(startOfFragmentInBlock + i);
- }
- // find a tab-stop decoration for this tab position
- // for eg., if there's a tab-stop at 1in, but the text before \t already spans 1.2in,
- // we should look at the next tab-stop
- KoText::Tab tab;
- do {
- tab = qvariant_cast<KoText::Tab>(tabList[currentTabStop]);
- currentTabStop++;
- // comparing with x1 should work for all of left/right/center/char tabs
- } while (tab.position <= x1 && currentTabStop < tabList.size());
-
- if (tab.position > x1) {
- if (!showFormattingCharacters) {
- // only then was it not calculated
- x2 = line.cursorToX(startOfFragmentInBlock + i + 1);
- }
- qreal tabStyleLeftLineMargin = tabStyleLineMargin;
- qreal tabStyleRightLineMargin = tabStyleLineMargin;
- // no margin if its adjacent char is also a tab
- if (i > searchForCharFrom && fragText[i-1] == '\t')
- tabStyleLeftLineMargin = 0;
- if (i < (searchForCharTill - 1) && fragText[i+1] == '\t')
- tabStyleRightLineMargin = 0;
-
- qreal y = line.position().y() + line.ascent() - 1;
- x1 += tabStyleLeftLineMargin;
- x2 -= tabStyleRightLineMargin;
- QColor tabDecorColor = currentFragment.charFormat().foreground().color();
- if (tab.leaderColor.isValid())
- tabDecorColor = tab.leaderColor;
- qreal width = computeWidth(tab.leaderWeight, tab.leaderWidth, painter->font());
- if (x1 < x2) {
- if (tab.leaderText.isEmpty()) {
- drawDecorationLine(painter, tabDecorColor, tab.leaderType, tab.leaderStyle, width, x1, x2, y);
- } else {
- drawDecorationText(painter, line, tabDecorColor, tab.leaderText, x1, x2);
- }
- }
- }
- }
- } else if (showFormattingCharacters) {
- if (fragText[i] == ' ' || fragText[i] == QChar::Nbsp) {
- qreal x = line.cursorToX(startOfFragmentInBlock + i);
- qreal y = line.position().y() + line.ascent();
-
- painter->drawText(QPointF(x, y), QChar((ushort)0xb7));
- } else if (fragText[i] == QChar::LineSeparator){
- qreal x = line.cursorToX(startOfFragmentInBlock + i);
- qreal y = line.position().y() + line.ascent();
-
- painter->drawText(QPointF(x, y), QChar((ushort)0x21B5));
- }
- }
- }
- return currentTabStop;
-}
diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutCellHelper.cpp b/plugins/flake/textshape/textlayout/KoTextLayoutCellHelper.cpp
deleted file mode 100644
index 595f5f7d1e..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextLayoutCellHelper.cpp
+++ /dev/null
@@ -1,465 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Roopesh Chander <roop@forwardbias.in>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
- *
- * 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 "KoTextLayoutCellHelper.h"
-
-#include <KoTableCellStyle.h>
-#include <QPainter>
-
-KoTextLayoutCellHelper::KoTextLayoutCellHelper(const KoTableCellStyle &cellStyle, QObject *parent)
- : QObject(parent), m_cellStyle(cellStyle)
-{
-
-}
-
-bool isSpeciallyDrawn(KoBorder::BorderStyle style)
-{
- if (style == KoBorder::BorderWave)
- return true;
- if (style == KoBorder::BorderDoubleWave)
- return true;
- if (style == KoBorder::BorderSlash)
- return true;
- return false;
-}
-
-void KoTextLayoutCellHelper::drawHorizontalWave(KoBorder::BorderStyle style, QPainter &painter, qreal x, qreal w, qreal t) const
-{
- QPen pen = painter.pen();
- const qreal linewidth = pen.widthF();
- const qreal penwidth = linewidth/6;
- pen.setWidth(penwidth);
- painter.setPen(pen);
- if (style == KoBorder::BorderSlash) {
- for (qreal sx=x; sx<x+w-linewidth; sx+=linewidth*0.5) {
- painter.drawLine(QLineF(sx, t-penwidth*2, sx+linewidth, t+penwidth*2));
- }
- } else {
- for (qreal sx=x; sx<x+w-2*linewidth; sx+=linewidth) {
- painter.drawLine(QLineF(sx, t-penwidth*2, sx+linewidth, t+penwidth*2));
- sx+=linewidth;
- painter.drawLine(QLineF(sx, t+penwidth*2, sx+linewidth, t-penwidth*2));
- }
- }
-}
-
-void KoTextLayoutCellHelper::drawVerticalWave(KoBorder::BorderStyle style, QPainter &painter, qreal y, qreal h, qreal t) const
-{
- QPen pen = painter.pen();
- const qreal linewidth = pen.width();
- const qreal penwidth = linewidth/6;
- pen.setWidth(penwidth);
- painter.setPen(pen);
- if (style == KoBorder::BorderSlash) {
- for (qreal sy=y; sy<y+h-linewidth; sy+=linewidth*0.5) {
- painter.drawLine(QLineF(t-penwidth*2, sy, t+penwidth*2, sy+linewidth));
- }
- } else {
- for (qreal sy=y; sy<y+h-2*linewidth; sy+=linewidth) {
- painter.drawLine(QLineF(t-penwidth*2, sy, t+penwidth*2, sy+linewidth));
- sy+=linewidth;
- painter.drawLine(QLineF(t+penwidth*2, sy, t-penwidth*2, sy+linewidth));
- }
- }
-}
-
-
-void KoTextLayoutCellHelper::paintBorders(QPainter &painter, const QRectF &bounds, QVector<QLineF> *accumulatedBlankBorders) const
-{
- QRectF innerBounds = bounds;
-
- // outer lines
- QPen topOuterPen = m_cellStyle.getEdge(KoBorder::TopBorder).outerPen;
- QPen bottomOuterPen = m_cellStyle.getEdge(KoBorder::BottomBorder).outerPen;
- QPen leftOuterPen = m_cellStyle.getEdge(KoBorder::LeftBorder).outerPen;
- QPen rightOuterPen = m_cellStyle.getEdge(KoBorder::RightBorder).outerPen;
-
- if (topOuterPen.widthF() > 0) {
- painter.setPen(topOuterPen);
- const qreal t = bounds.top() + topOuterPen.widthF() / 2.0;
- innerBounds.setTop(bounds.top() + m_cellStyle.getEdge(KoBorder::TopBorder).spacing + topOuterPen.widthF());
- painter.drawLine(QLineF(bounds.left(), t, bounds.right(), t));
- } else if (accumulatedBlankBorders) {
- // No border but we'd like to draw one for user convenience when on screen
- accumulatedBlankBorders->append(QLineF(bounds.left() + leftOuterPen.widthF() + m_cellStyle.getEdge(KoBorder::LeftBorder).spacing,
- bounds.top() + topOuterPen.widthF() + m_cellStyle.getEdge(KoBorder::TopBorder).spacing,
- bounds.right() - rightOuterPen.widthF() - m_cellStyle.getEdge(KoBorder::RightBorder).spacing,
- bounds.top() + topOuterPen.widthF() + m_cellStyle.getEdge(KoBorder::TopBorder).spacing));
- }
-
- if (bottomOuterPen.widthF() > 0) {
- painter.setPen(bottomOuterPen);
- const qreal b = bounds.bottom() - bottomOuterPen.widthF() / 2.0;
- innerBounds.setBottom(bounds.bottom() - m_cellStyle.getEdge(KoBorder::BottomBorder).spacing - bottomOuterPen.widthF());
- painter.drawLine(QLineF(bounds.left(), b, bounds.right(), b));
- } else if (accumulatedBlankBorders) {
- // No border but we'd like to draw one for user convenience when on screen
- accumulatedBlankBorders->append(QLineF(bounds.left() + leftOuterPen.widthF() + m_cellStyle.getEdge(KoBorder::LeftBorder).spacing,
- bounds.bottom() - bottomOuterPen.widthF() - m_cellStyle.getEdge(KoBorder::BottomBorder).spacing,
- bounds.right() - rightOuterPen.widthF() - m_cellStyle.getEdge(KoBorder::RightBorder).spacing,
- bounds.bottom() - bottomOuterPen.widthF() - m_cellStyle.getEdge(KoBorder::BottomBorder).spacing));
- }
-
- if (leftOuterPen.widthF() > 0) {
- painter.setPen(leftOuterPen);
- const qreal l = bounds.left() + leftOuterPen.widthF() / 2.0;
- innerBounds.setLeft(bounds.left() + m_cellStyle.getEdge(KoBorder::LeftBorder).spacing + leftOuterPen.widthF());
- painter.drawLine(QLineF(l, bounds.top() + m_cellStyle.getEdge(KoBorder::TopBorder).outerPen.widthF(), l, bounds.bottom() - m_cellStyle.getEdge(KoBorder::BottomBorder).outerPen.widthF()));
- } else if (accumulatedBlankBorders) {
- // No border but we'd like to draw one for user convenience when on screen
- accumulatedBlankBorders->append(QLineF(bounds.left() + leftOuterPen.widthF() + m_cellStyle.getEdge(KoBorder::LeftBorder).spacing,
- bounds.top() + topOuterPen.widthF() + m_cellStyle.getEdge(KoBorder::TopBorder).spacing,
- bounds.left() + leftOuterPen.widthF() + m_cellStyle.getEdge(KoBorder::LeftBorder).spacing,
- bounds.bottom() - bottomOuterPen.widthF() - m_cellStyle.getEdge(KoBorder::BottomBorder).spacing));
- }
-
- if (m_cellStyle.getEdge(KoBorder::RightBorder).outerPen.widthF() > 0) {
- painter.setPen(rightOuterPen);
- const qreal r = bounds.right() - rightOuterPen.widthF() / 2.0;
- innerBounds.setRight(bounds.right() - m_cellStyle.getEdge(KoBorder::RightBorder).spacing - rightOuterPen.widthF());
- painter.drawLine(QLineF(r, bounds.top() + m_cellStyle.getEdge(KoBorder::TopBorder).outerPen.widthF(), r, bounds.bottom() - bottomOuterPen.widthF()));
- } else if (accumulatedBlankBorders) {
- // No border but we'd like to draw one for user convenience when on screen
- accumulatedBlankBorders->append(QLineF(bounds.right() - rightOuterPen.widthF() - m_cellStyle.getEdge(KoBorder::RightBorder).spacing,
- bounds.top() + topOuterPen.widthF() + m_cellStyle.getEdge(KoBorder::TopBorder).spacing,
- bounds.right() - rightOuterPen.widthF() - m_cellStyle.getEdge(KoBorder::RightBorder).spacing,
- bounds.bottom() - bottomOuterPen.widthF() - m_cellStyle.getEdge(KoBorder::BottomBorder).spacing));
- }
-
- paintDiagonalBorders(painter, bounds);
-
- // inner lines
- if (m_cellStyle.getEdge(KoBorder::TopBorder).innerPen.widthF() > 0) {
- QPen pen = m_cellStyle.getEdge(KoBorder::TopBorder).innerPen;
- painter.setPen(pen);
- const qreal t = innerBounds.top() + pen.widthF() / 2.0;
- painter.drawLine(QLineF(innerBounds.left(), t, innerBounds.right(), t));
- }
- if (m_cellStyle.getEdge(KoBorder::BottomBorder).innerPen.widthF() > 0) {
- QPen pen = m_cellStyle.getEdge(KoBorder::BottomBorder).innerPen;
- painter.setPen(pen);
- const qreal b = innerBounds.bottom() - pen.widthF() / 2.0;
- painter.drawLine(QLineF(innerBounds.left(), b, innerBounds.right(), b));
- }
- if (m_cellStyle.getEdge(KoBorder::LeftBorder).innerPen.widthF() > 0) {
- QPen pen = m_cellStyle.getEdge(KoBorder::LeftBorder).innerPen;
- painter.setPen(pen);
- const qreal l = innerBounds.left() + pen.widthF() / 2.0;
- painter.drawLine(QLineF(l, innerBounds.top() + m_cellStyle.getEdge(KoBorder::TopBorder).innerPen.widthF(), l, innerBounds.bottom() - m_cellStyle.getEdge(KoBorder::BottomBorder).innerPen.widthF()));
- }
- if (m_cellStyle.getEdge(KoBorder::RightBorder).innerPen.widthF() > 0) {
- QPen pen = m_cellStyle.getEdge(KoBorder::RightBorder).innerPen;
- painter.setPen(pen);
- const qreal r = innerBounds.right() - pen.widthF() / 2.0;
- painter.drawLine(QLineF(r, innerBounds.top() + m_cellStyle.getEdge(KoBorder::TopBorder).innerPen.widthF(), r, innerBounds.bottom() - m_cellStyle.getEdge(KoBorder::BottomBorder).innerPen.widthF()));
- }
-}
-
-void KoTextLayoutCellHelper::paintDiagonalBorders(QPainter &painter, const QRectF &bounds) const
-{
- if (m_cellStyle.getEdge(KoBorder::TlbrBorder).outerPen.widthF() > 0) {
- QPen diagonalPen = m_cellStyle.getEdge(KoBorder::TlbrBorder).outerPen;
- painter.setPen(diagonalPen);
-
- QPen topPen = m_cellStyle.getEdge(KoBorder::TopBorder).outerPen;
- const qreal top = bounds.top() + topPen.widthF() / 2.0;
- QPen leftPen = m_cellStyle.getEdge(KoBorder::LeftBorder).outerPen;
- const qreal left = bounds.left() + leftPen.widthF() / 2.0;
- QPen bottomPen = m_cellStyle.getEdge(KoBorder::BottomBorder).outerPen;
- const qreal bottom = bounds.bottom() - bottomPen.widthF() / 2.0;
- QPen rightPen = m_cellStyle.getEdge(KoBorder::RightBorder).outerPen;
- const qreal right = bounds.right() - rightPen.widthF() / 2.0;
-
- painter.drawLine(QLineF(left, top, right, bottom));
- }
- if (m_cellStyle.getEdge(KoBorder::BltrBorder).outerPen.widthF() > 0) {
- QPen pen = m_cellStyle.getEdge(KoBorder::BltrBorder).outerPen;
- painter.setPen(pen);
-
- QPen topPen = m_cellStyle.getEdge(KoBorder::TopBorder).outerPen;
- const qreal top = bounds.top() + topPen.widthF() / 2.0;
- QPen leftPen = m_cellStyle.getEdge(KoBorder::LeftBorder).outerPen;
- const qreal left = bounds.left() + leftPen.widthF() / 2.0;
- QPen bottomPen = m_cellStyle.getEdge(KoBorder::BottomBorder).outerPen;
- const qreal bottom = bounds.bottom() - bottomPen.widthF() / 2.0;
- QPen rightPen = m_cellStyle.getEdge(KoBorder::RightBorder).outerPen;
- const qreal right = bounds.right() - rightPen.widthF() / 2.0;
-
- painter.drawLine(QLineF(left, bottom, right, top));
- }
-}
-
-void KoTextLayoutCellHelper::drawTopHorizontalBorder(QPainter &painter, qreal x, qreal y, qreal w, QVector<QLineF> *accumulatedBlankBorders) const
-{
- qreal t=y;
- if (m_cellStyle.getEdge(KoBorder::TopBorder).outerPen.widthF() > 0) {
- QPen pen = m_cellStyle.getEdge(KoBorder::TopBorder).outerPen;
-
- painter.setPen(pen);
- t += pen.widthF() / 2.0;
- if(isSpeciallyDrawn(m_cellStyle.getBorderStyle(KoBorder::TopBorder))) {
- drawHorizontalWave(m_cellStyle.getBorderStyle(KoBorder::TopBorder), painter,x,w,t);
- } else {
- painter.drawLine(QLineF(x, t, x+w, t));
- }
- t = y + m_cellStyle.getEdge(KoBorder::TopBorder).spacing + pen.widthF();
- } else if (accumulatedBlankBorders) {
- // No border but we'd like to draw one for user convenience when on screen
- accumulatedBlankBorders->append(QLineF(x, t, x+w, t));
- }
-
- // inner line
- if (m_cellStyle.getEdge(KoBorder::TopBorder).innerPen.widthF() > 0) {
- QPen pen = m_cellStyle.getEdge(KoBorder::TopBorder).innerPen;
- painter.setPen(pen);
- t += pen.widthF() / 2.0;
- if(isSpeciallyDrawn(m_cellStyle.getBorderStyle(KoBorder::TopBorder))) {
- drawHorizontalWave(m_cellStyle.getBorderStyle(KoBorder::TopBorder), painter,x,w,t);
- } else {
- painter.drawLine(QLineF(x, t, x+w, t));
- }
- }
-}
-
-void KoTextLayoutCellHelper::drawSharedHorizontalBorder(QPainter &painter, const KoTableCellStyle &styleBelow, qreal x, qreal y, qreal w, QVector<QLineF> *accumulatedBlankBorders) const
-{
- bool paintThis = true;
- if (m_cellStyle.getBorderStyle(KoBorder::BottomBorder) == KoBorder::BorderNone) {
- if (styleBelow.getBorderStyle(KoBorder::TopBorder) == KoBorder::BorderNone) {
- if (accumulatedBlankBorders) {
- accumulatedBlankBorders->append(QLineF(x, y, x+w, y));
- }
- return;
- }
- paintThis = false;
- }
- else {
- if (styleBelow.getBorderStyle(KoBorder::TopBorder) != KoBorder::BorderNone) {
- qreal thisWidth = m_cellStyle.getEdge(KoBorder::BottomBorder).outerPen.widthF() + m_cellStyle.getEdge(KoBorder::BottomBorder).spacing + m_cellStyle.getEdge(KoBorder::BottomBorder).innerPen.widthF();
- qreal thatWidth = styleBelow.getEdge(KoBorder::TopBorder).outerPen.widthF() + styleBelow.getEdge(KoBorder::TopBorder).spacing
- + styleBelow.getEdge(KoBorder::TopBorder).innerPen.widthF();
- paintThis = thisWidth >= thatWidth;
- }
- }
-
- const KoBorder::BorderData &edge = paintThis ? m_cellStyle.getEdge(KoBorder::BottomBorder) : styleBelow.getEdge(KoBorder::TopBorder);
- const KoBorder::BorderStyle borderStyle = paintThis ? m_cellStyle.getBorderStyle(KoBorder::BottomBorder): styleBelow.getBorderStyle(KoBorder::TopBorder);
- qreal t=y;
-
- if (edge.outerPen.widthF() > 0) {
- QPen pen = edge.outerPen;
- const qreal linewidth = pen.widthF();
-
- painter.setPen(pen);
- t += linewidth / 2.0;
- if(isSpeciallyDrawn(borderStyle)) {
- drawHorizontalWave(borderStyle, painter,x,w,t);
- } else {
- painter.drawLine(QLineF(x, t, x+w, t));
- }
- t = y + edge.spacing + linewidth;
- }
- // inner line
- if (edge.innerPen.widthF() > 0) {
- QPen pen = edge.innerPen;
- painter.setPen(pen);
- t += pen.widthF() / 2.0;
- if(isSpeciallyDrawn(borderStyle)) {
- drawHorizontalWave(borderStyle, painter,x,w,t);
- } else {
- painter.drawLine(QLineF(x, t, x+w, t));
- }
- }
-}
-
-void KoTextLayoutCellHelper::drawBottomHorizontalBorder(QPainter &painter, qreal x, qreal y, qreal w, QVector<QLineF> *accumulatedBlankBorders) const
-{
- qreal t=y;
- if (m_cellStyle.getEdge(KoBorder::BottomBorder).outerPen.widthF() > 0) {
- QPen pen = m_cellStyle.getEdge(KoBorder::BottomBorder).outerPen;
-
- painter.setPen(pen);
- t += pen.widthF() / 2.0;
- if(isSpeciallyDrawn(m_cellStyle.getBorderStyle(KoBorder::BottomBorder))) {
- drawHorizontalWave(m_cellStyle.getBorderStyle(KoBorder::BottomBorder), painter,x,w,t);
- } else {
- painter.drawLine(QLineF(x, t, x+w, t));
- }
- t = y + m_cellStyle.getEdge(KoBorder::BottomBorder).spacing + pen.widthF();
- } else if (accumulatedBlankBorders) {
- // No border but we'd like to draw one for user convenience when on screen
- accumulatedBlankBorders->append(QLineF(x, t, x+w, t));
-
- }
-
- // inner line
- if (m_cellStyle.getEdge(KoBorder::BottomBorder).innerPen.widthF() > 0) {
- QPen pen = m_cellStyle.getEdge(KoBorder::BottomBorder).innerPen;
- painter.setPen(pen);
- t += pen.widthF() / 2.0;
- if(isSpeciallyDrawn(m_cellStyle.getBorderStyle(KoBorder::BottomBorder))) {
- drawHorizontalWave(m_cellStyle.getBorderStyle(KoBorder::BottomBorder), painter,x,w,t);
- } else {
- painter.drawLine(QLineF(x, t, x+w, t));
- }
- }
-}
-
-void KoTextLayoutCellHelper::drawLeftmostVerticalBorder(QPainter &painter, qreal x, qreal y, qreal h, QVector<QLineF> *accumulatedBlankBorders) const
-{
- qreal thisWidth = m_cellStyle.getEdge(KoBorder::LeftBorder).outerPen.widthF() + m_cellStyle.getEdge(KoBorder::LeftBorder).spacing + m_cellStyle.getEdge(KoBorder::LeftBorder).innerPen.widthF();
- qreal l = x - thisWidth / 2.0;
-
- if (m_cellStyle.getEdge(KoBorder::LeftBorder).outerPen.widthF() > 0) {
- QPen pen = m_cellStyle.getEdge(KoBorder::LeftBorder).outerPen;
-
- painter.setPen(pen);
- l += pen.widthF() / 2.0;
- if(isSpeciallyDrawn(m_cellStyle.getBorderStyle(KoBorder::LeftBorder))) {
- drawVerticalWave(m_cellStyle.getBorderStyle(KoBorder::LeftBorder), painter,y,h,l);
- } else {
- painter.drawLine(QLineF(l, y, l, y+h));
- }
- l += m_cellStyle.getEdge(KoBorder::LeftBorder).spacing + pen.widthF() / 2.0;
- } else if (accumulatedBlankBorders) {
- // No border but we'd like to draw one for user convenience when on screen
- accumulatedBlankBorders->append(QLineF(l, y, l, y+h));
-
- }
-
- // inner line
- if (m_cellStyle.getEdge(KoBorder::LeftBorder).innerPen.widthF() > 0) {
- QPen pen = m_cellStyle.getEdge(KoBorder::LeftBorder).innerPen;
- painter.setPen(pen);
- l += pen.widthF() / 2.0;
- if(isSpeciallyDrawn(m_cellStyle.getBorderStyle(KoBorder::LeftBorder))) {
- drawVerticalWave(m_cellStyle.getBorderStyle(KoBorder::LeftBorder), painter,y,h,l);
- } else {
- painter.drawLine(QLineF(l, y, l, y+h));
- }
- }
-}
-
-void KoTextLayoutCellHelper::drawSharedVerticalBorder(QPainter &painter, const KoTableCellStyle &styleRight, qreal x, qreal y, qreal h, QVector<QLineF> *accumulatedBlankBorders) const
-{
- // First determine which style "wins" by comparing total width
- qreal thisWidth = m_cellStyle.getEdge(KoBorder::RightBorder).outerPen.widthF() + m_cellStyle.getEdge(KoBorder::RightBorder).spacing + m_cellStyle.getEdge(KoBorder::RightBorder).innerPen.widthF();
- qreal thatWidth = styleRight.getEdge(KoBorder::LeftBorder).outerPen.widthF() + styleRight.getEdge(KoBorder::LeftBorder).spacing
- + styleRight.getEdge(KoBorder::LeftBorder).innerPen.widthF();
-
- qreal l=x;
-
- if(thisWidth >= thatWidth) {
- // left style wins
- l -= thisWidth / 2.0;
- if (m_cellStyle.getEdge(KoBorder::RightBorder).outerPen.widthF() > 0) {
- QPen pen = m_cellStyle.getEdge(KoBorder::RightBorder).outerPen;
-
- painter.setPen(pen);
- l += pen.widthF() / 2.0;
- if(isSpeciallyDrawn(m_cellStyle.getBorderStyle(KoBorder::RightBorder))) {
- drawVerticalWave(m_cellStyle.getBorderStyle(KoBorder::RightBorder), painter,y,h,l);
- } else {
- painter.drawLine(QLineF(l, y, l, y+h));
- }
- l += m_cellStyle.getEdge(KoBorder::RightBorder).spacing + pen.widthF() / 2.0;
- } else if (accumulatedBlankBorders) {
- // No border but we'd like to draw one for user convenience when on screen
- accumulatedBlankBorders->append(QLineF(l, y, l, y+h));
-
- }
-
- // inner line
- if (m_cellStyle.getEdge(KoBorder::RightBorder).innerPen.widthF() > 0) {
- QPen pen = m_cellStyle.getEdge(KoBorder::RightBorder).innerPen;
- painter.setPen(pen);
- l += pen.widthF() / 2.0;
- if(isSpeciallyDrawn(m_cellStyle.getBorderStyle(KoBorder::RightBorder))) {
- drawVerticalWave(m_cellStyle.getBorderStyle(KoBorder::RightBorder), painter,y,h,l);
- } else {
- painter.drawLine(QLineF(l, y, l, y+h));
- }
- }
- } else {
- // right style wins
- l -= thatWidth/2.0;
- if (styleRight.getEdge(KoBorder::LeftBorder).outerPen.widthF() > 0) {
- QPen pen = styleRight.getEdge(KoBorder::LeftBorder).outerPen;
-
- painter.setPen(pen);
- l += pen.widthF() / 2.0;
- if(isSpeciallyDrawn(styleRight.getBorderStyle(KoBorder::LeftBorder))) {
- drawVerticalWave(styleRight.getBorderStyle(KoBorder::LeftBorder), painter,y,h,l);
- } else {
- painter.drawLine(QLineF(l, y, l, y+h));
- }
- l += styleRight.getEdge(KoBorder::LeftBorder).spacing + pen.widthF() / 2.0;
- }
- // inner line
- if (styleRight.getEdge(KoBorder::LeftBorder).innerPen.widthF() > 0) {
- QPen pen = styleRight.getEdge(KoBorder::LeftBorder).innerPen;
- painter.setPen(pen);
- l += pen.widthF() / 2.0;
- if(isSpeciallyDrawn(styleRight.getBorderStyle(KoBorder::LeftBorder))) {
- drawVerticalWave(styleRight.getBorderStyle(KoBorder::LeftBorder), painter,y,h,l);
- } else {
- painter.drawLine(QLineF(l, y, l, y+h));
- }
- }
- }
-}
-
-void KoTextLayoutCellHelper::drawRightmostVerticalBorder(QPainter &painter, qreal x, qreal y, qreal h, QVector<QLineF> *accumulatedBlankBorders) const
-{
- qreal thisWidth = m_cellStyle.getEdge(KoBorder::RightBorder).outerPen.widthF() + m_cellStyle.getEdge(KoBorder::RightBorder).spacing + m_cellStyle.getEdge(KoBorder::RightBorder).innerPen.widthF();
- qreal l = x - thisWidth / 2.0;
-
- if (m_cellStyle.getEdge(KoBorder::RightBorder).outerPen.widthF() > 0) {
- QPen pen = m_cellStyle.getEdge(KoBorder::RightBorder).outerPen;
-
- painter.setPen(pen);
- l += pen.widthF() / 2.0;
- if(isSpeciallyDrawn(m_cellStyle.getBorderStyle(KoBorder::RightBorder))) {
- drawVerticalWave(m_cellStyle.getBorderStyle(KoBorder::RightBorder), painter,y,h,l);
- } else {
- painter.drawLine(QLineF(l, y, l, y+h));
- }
- l += m_cellStyle.getEdge(KoBorder::RightBorder).spacing + pen.widthF() / 2.0;
- } else if (accumulatedBlankBorders) {
- // No border but we'd like to draw one for user convenience when on screen
- accumulatedBlankBorders->append(QLineF(l, y, l, y+h));
- }
-
- // inner line
- if (m_cellStyle.getEdge(KoBorder::RightBorder).innerPen.widthF() > 0) {
- QPen pen = m_cellStyle.getEdge(KoBorder::RightBorder).innerPen;
- painter.setPen(pen);
- l += pen.widthF() / 2.0;
- if(isSpeciallyDrawn(m_cellStyle.getBorderStyle(KoBorder::RightBorder))) {
- drawVerticalWave(m_cellStyle.getBorderStyle(KoBorder::RightBorder), painter,y,h,l);
- } else {
- painter.drawLine(QLineF(l, y, l, y+h));
- }
- }
-}
diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutCellHelper.h b/plugins/flake/textshape/textlayout/KoTextLayoutCellHelper.h
deleted file mode 100644
index 839ab3cf31..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextLayoutCellHelper.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Roopesh Chander <roop@forwardbias.in>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
- * Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
- *
- * 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 KOTEXTLAYOUTCELLHELPER_H
-#define KOTEXTLAYOUTCELLHELPER_H
-
-#include "kritatextlayout_export.h"
-
-#include <KoBorder.h>
-
-#include <QObject>
-
-class KoTableCellStyle;
-class QPainter;
-
-class KRITATEXTLAYOUT_EXPORT KoTextLayoutCellHelper : public QObject
-{
- Q_OBJECT
-public:
- explicit KoTextLayoutCellHelper(const KoTableCellStyle &cellStyle, QObject *parent = 0);
-
- /// draws a horizontal wave line
- void drawHorizontalWave(KoBorder::BorderStyle style, QPainter &painter, qreal x, qreal w, qreal t) const;
-
- /// draws a vertical wave line
- void drawVerticalWave(KoBorder::BorderStyle style, QPainter &painter, qreal y, qreal h, qreal t) const;
-
- /**
- * Paint the borders.
- *
- * @param painter the painter to draw with.
- * @param bounds the bounding rectangle to draw.
- * @param blanks a painterpath where blank borders should be added to.
- */
- void paintBorders(QPainter &painter, const QRectF &bounds, QVector<QLineF> *blanks) const;
-
- /**
- * Paint the diagonal borders.
- *
- * @param painter the painter to draw with.
- * @param bounds the bounding rectangle to draw.
- */
- void paintDiagonalBorders(QPainter &painter, const QRectF &bounds) const;
-
- /**
- * Paint the top border.
- *
- * @param painter the painter to draw with.
- * @param x the x position.
- * @param y the y position.
- * @param w the width.
- * @param blanks a painterpath where blank borders should be added to.
- */
- void drawTopHorizontalBorder(QPainter &painter, qreal x, qreal y, qreal w, QVector<QLineF> *blanks = 0) const;
-
- /**
- * Paint the border that is shared.
- * It only draws the thickest and it always draws it below the y position.
- *
- * @param painter the painter to draw with.
- * @param styleBelow the table cell style.
- * @param x the x position.
- * @param y the y position.
- * @param w the width.
- * @param blanks a painterpath where blank borders should be added to.
- */
- void drawSharedHorizontalBorder(QPainter &painter, const KoTableCellStyle &styleBelow, qreal x, qreal y, qreal w, QVector<QLineF> *blanks = 0) const;
-
- /**
- * Paint the bottom border.
- *
- * @param painter the painter to draw with.
- * @param x the x position.
- * @param y the y position.
- * @param w the width.
- * @param blanks a painterpath where blank borders should be added to.
- */
- void drawBottomHorizontalBorder(QPainter &painter, qreal x, qreal y, qreal w, QVector<QLineF> *blanks = 0) const;
-
- /**
- * Paint the leftmost border.
- *
- * @param painter the painter to draw with.
- * @param x the x position.
- * @param y the y position.
- * @param h the height.
- * @param blanks a painterpath where blank borders should be added to.
- */
- void drawLeftmostVerticalBorder(QPainter &painter, qreal x, qreal y, qreal h, QVector<QLineF> *blanks = 0) const;
-
- /**
- * Paint the border that is shared.
- * It only draws the thickest and it always draws it to the right of the x position.
- *
- * @param painter the painter to draw with.
- * @param styleRight the table cell style.
- * @param x the x position.
- * @param y the y position.
- * @param h the height.
- * @param blanks a painterpath where blank borders should be added to.
- */
- void drawSharedVerticalBorder(QPainter &painter, const KoTableCellStyle &styleRight, qreal x, qreal y, qreal h, QVector<QLineF> *blanks = 0) const;
-
- /**
- * Paint the rightmost border.
- *
- * @param painter the painter to draw with.
- * @param x the x position.
- * @param y the y position.
- * @param h the height.
- * @param blanks a painterpath where blank borders should be added to.
- */
- void drawRightmostVerticalBorder(QPainter &painter, qreal x, qreal y, qreal h, QVector<QLineF> *blanks = 0) const;
-
-private:
- const KoTableCellStyle &m_cellStyle;
-};
-
-#endif // KOTEXTLAYOUTCELLHELPER_H
diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutEndNotesArea.cpp b/plugins/flake/textshape/textlayout/KoTextLayoutEndNotesArea.cpp
deleted file mode 100644
index 2e3b3f496f..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextLayoutEndNotesArea.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 C. Boemann <cbo@kogmbh.com>
- *
- * 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 "KoTextLayoutEndNotesArea.h"
-
-#include "KoTextLayoutNoteArea.h"
-#include "KoInlineTextObjectManager.h"
-#include "KoInlineNote.h"
-#include "KoPointedAt.h"
-#include "FrameIterator.h"
-
-#include <KoTextDocument.h>
-
-#include <QPainter>
-
-static bool beforeThan(KoInlineNote *note1, KoInlineNote *note2)
-{
- return (note1->getPosInDocument() < note2->getPosInDocument());
-}
-
-class Q_DECL_HIDDEN KoTextLayoutEndNotesArea::Private
-{
-public:
- Private()
- : startOfArea(0)
- {
- }
- QList<KoTextLayoutNoteArea *> endNoteAreas;
- QList<QTextFrame *> endNoteFrames;
- FrameIterator *startOfArea;
- FrameIterator *endOfArea;
- int endNoteAutoCount;
-};
-
-KoTextLayoutEndNotesArea::KoTextLayoutEndNotesArea(KoTextLayoutArea *parent, KoTextDocumentLayout *documentLayout)
- : KoTextLayoutArea(parent, documentLayout)
- , d(new Private)
-{
- d->endNoteAutoCount = 0;
-}
-
-KoTextLayoutEndNotesArea::~KoTextLayoutEndNotesArea()
-{
- qDeleteAll(d->endNoteAreas);
- delete d;
-}
-
-bool KoTextLayoutEndNotesArea::layout(FrameIterator *cursor)
-{
- qDeleteAll(d->endNoteAreas);
- d->endNoteAreas.clear();
- d->endNoteFrames.clear();
-
- d->startOfArea = new FrameIterator(cursor);
- d->endOfArea = 0;
- int shiftDown = 15;
- qreal y = top() + shiftDown;
- setBottom(y);
-
- KoInlineTextObjectManager *manager = KoTextDocument(documentLayout()->document()).inlineTextObjectManager();
- QList<KoInlineNote *> list = QList<KoInlineNote *>(manager->endNotes());
- std::sort(list.begin(), list.end(), beforeThan); //making a list of endnotes in the order they appear
- while (cursor->endNoteIndex < list.length())
- {
- KoInlineNote *note = list[cursor->endNoteIndex];
- if (note->autoNumbering()) {
- note->setAutoNumber(d->endNoteAutoCount++);
- }
- QTextFrame *subFrame = note->textFrame();
- KoTextLayoutNoteArea *noteArea = new KoTextLayoutNoteArea(note, this, documentLayout());
- d->endNoteAreas.append(noteArea);
- d->endNoteFrames.append(subFrame);
- noteArea->setReferenceRect(left(), right(), y, maximumAllowedBottom());
- if (noteArea->layout(cursor->subFrameIterator(subFrame)) == false) {
- d->endOfArea = new FrameIterator(cursor);
- setBottom(noteArea->bottom());
- return false;
- }
- y = noteArea->bottom();
- setBottom(y);
- delete cursor->currentSubFrameIterator;
- cursor->currentSubFrameIterator = 0;
- cursor->endNoteIndex++;
- }
- if (cursor->endNoteIndex == 0) {
- setBottom(top() + shiftDown);
- }
- d->endOfArea = new FrameIterator(cursor);
- return true;
-}
-KoPointedAt KoTextLayoutEndNotesArea::hitTest(const QPointF &p, Qt::HitTestAccuracy accuracy) const
-{
- KoPointedAt pointedAt;
- int endNoteIndex = 0;
- while (endNoteIndex < d->endNoteAreas.length()) {
- // check if p is over end notes area
- if (p.y() > d->endNoteAreas[endNoteIndex]->top()
- && p.y() < d->endNoteAreas[endNoteIndex]->bottom()) {
- pointedAt = d->endNoteAreas[endNoteIndex]->hitTest(p, accuracy);
- return pointedAt;
- }
- ++endNoteIndex;
- }
- return KoPointedAt();
-}
-
-QRectF KoTextLayoutEndNotesArea::selectionBoundingBox(QTextCursor &cursor) const
-{
- QTextFrame *subFrame;
- int endNoteIndex = 0;
- while (endNoteIndex < d->endNoteFrames.length()) {
- subFrame = d->endNoteFrames[endNoteIndex];
- if (subFrame != 0) {
- if (cursor.selectionStart() >= subFrame->firstPosition() && cursor.selectionEnd() <= subFrame->lastPosition()) {
- return d->endNoteAreas[endNoteIndex]->selectionBoundingBox(cursor);
- }
- ++endNoteIndex;
- }
- }
- return QRectF();
-}
-
-void KoTextLayoutEndNotesArea::paint(QPainter *painter, const KoTextDocumentLayout::PaintContext &context)
-{
- if (d->startOfArea == 0) // We have not been layouted yet
- return;
-
- if (!d->endNoteAreas.isEmpty()) {
- int left = 2;
- int right = 150;
- int shiftDown = 10;
- painter->drawLine(left, top()+shiftDown, right, top()+shiftDown);
- }
- Q_FOREACH (KoTextLayoutNoteArea *area, d->endNoteAreas) {
- area->paint(painter, context);
- }
-}
diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutEndNotesArea.h b/plugins/flake/textshape/textlayout/KoTextLayoutEndNotesArea.h
deleted file mode 100644
index 667793ceb1..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextLayoutEndNotesArea.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 C. Boemann <cbo@kogmbh.com>
- *
- * 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 KOTEXTLAYOUTENDNOTESAREA_H
-#define KOTEXTLAYOUTENDNOTESAREA_H
-
-#include "kritatextlayout_export.h"
-
-#include "KoTextLayoutArea.h"
-
-class QRectF;
-
-
-/**
- * When laying out text it happens in areas that can occupy space of various size.
- */
-class KRITATEXTLAYOUT_EXPORT KoTextLayoutEndNotesArea : public KoTextLayoutArea
-{
-public:
- /// constructor
- explicit KoTextLayoutEndNotesArea(KoTextLayoutArea *parent, KoTextDocumentLayout *documentLayout);
- ~KoTextLayoutEndNotesArea() override;
-
- /// Layouts as much as it can
- /// Returns true if it has reached the end of the frame
- bool layout(FrameIterator *cursor);
-
- KoPointedAt hitTest(const QPointF &p, Qt::HitTestAccuracy accuracy) const;
-
- QRectF selectionBoundingBox(QTextCursor &cursor) const;
-
- void paint(QPainter *painter, const KoTextDocumentLayout::PaintContext &context);
-
-private:
- class Private;
- Private * const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutNoteArea.cpp b/plugins/flake/textshape/textlayout/KoTextLayoutNoteArea.cpp
deleted file mode 100644
index eb2e3ca715..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextLayoutNoteArea.cpp
+++ /dev/null
@@ -1,196 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Brijesh Patel <brijesh3105@gmail.com>
- *
- * 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 "KoTextLayoutNoteArea.h"
-
-#include "FrameIterator.h"
-#include "KoStyleManager.h"
-#include "KoParagraphStyle.h"
-#include "KoTextLayoutObstruction.h"
-#include "KoPointedAt.h"
-#include <KoOdfNumberDefinition.h>
-#include <KoInlineNote.h>
-#include <KoTextDocument.h>
-
-#include <QPainter>
-
-#define OVERLAPPREVENTION 1000
-
-class Q_DECL_HIDDEN KoTextLayoutNoteArea::Private
-{
-public:
- Private()
- {
- }
- KoInlineNote *note;
- QTextLayout *textLayout;
- QTextLayout *postLayout;
- qreal labelIndent;
- bool isContinuedArea;
- qreal labelWidth;
- qreal labelHeight;
- qreal labelYOffset;
-};
-
-KoTextLayoutNoteArea::KoTextLayoutNoteArea(KoInlineNote *note, KoTextLayoutArea *parent, KoTextDocumentLayout *documentLayout)
- : KoTextLayoutArea(parent, documentLayout)
- , d(new Private)
-{
- Q_ASSERT(note);
- Q_ASSERT(parent);
-
- d->note = note;
- d->isContinuedArea = false;
- d->postLayout = 0;
-}
-
-KoTextLayoutNoteArea::~KoTextLayoutNoteArea()
-{
- delete d;
-}
-
-void KoTextLayoutNoteArea::paint(QPainter *painter, const KoTextDocumentLayout::PaintContext &context)
-{
- painter->save();
- if (d->isContinuedArea) {
- painter->translate(0, -OVERLAPPREVENTION);
- }
-
- KoTextLayoutArea::paint(painter, context);
- if (d->postLayout) {
- d->postLayout->draw(painter, QPointF(left() + d->labelIndent, top() + d->labelYOffset));
- }
- d->textLayout->draw(painter, QPointF(left() + d->labelIndent, top() + d->labelYOffset));
- painter->restore();
-}
-
-bool KoTextLayoutNoteArea::layout(FrameIterator *cursor)
-{
- KoOdfNotesConfiguration *notesConfig = 0;
- if (d->note->type() == KoInlineNote::Footnote) {
- notesConfig = KoTextDocument(d->note->textFrame()->document()).styleManager()->notesConfiguration(KoOdfNotesConfiguration::Footnote);
- } else if (d->note->type() == KoInlineNote::Endnote) {
- notesConfig = KoTextDocument(d->note->textFrame()->document()).styleManager()->notesConfiguration(KoOdfNotesConfiguration::Endnote);
- }
-
- QString label;
- if (d->isContinuedArea) {
- if (! notesConfig->footnoteContinuationBackward().isEmpty()) {
- label = notesConfig->footnoteContinuationBackward() + " " + d->note->label();
- }
- setReferenceRect(left(), right(), top() + OVERLAPPREVENTION
- , maximumAllowedBottom() + OVERLAPPREVENTION);
- } else {
- label = d->note->label();
- }
- label.prepend(notesConfig->numberFormat().prefix());
- label.append(notesConfig->numberFormat().suffix());
- QPaintDevice *pd = documentLayout()->paintDevice();
- QTextBlock block = cursor->it.currentBlock();
- QTextCharFormat format = block.charFormat();
- KoCharacterStyle *style = static_cast<KoCharacterStyle *>(notesConfig->citationTextStyle());
- if (style) {
- style->applyStyle(format);
- }
- QFont font(format.font(), pd);
- d->textLayout = new QTextLayout(label, font, pd);
- QList<QTextLayout::FormatRange> layouts;
- QTextLayout::FormatRange range;
- range.start = 0;
- range.length = label.length();
- range.format = format;
- layouts.append(range);
- d->textLayout->setAdditionalFormats(layouts);
-
- QTextOption option(Qt::AlignLeft | Qt::AlignAbsolute);
- d->textLayout->setTextOption(option);
- d->textLayout->beginLayout();
- QTextLine line = d->textLayout->createLine();
- d->textLayout->endLayout();
-
- KoParagraphStyle pStyle(block.blockFormat(), QTextCharFormat());
- d->labelIndent = textIndent(d->note->textFrame()->begin().currentBlock(), 0, pStyle);
- if (line.naturalTextWidth() > -d->labelIndent) {
- KoTextLayoutArea::setExtraTextIndent(line.naturalTextWidth());
- } else {
- KoTextLayoutArea::setExtraTextIndent(-d->labelIndent);
- }
- d->labelIndent += pStyle.leftMargin();
- d->labelWidth = line.naturalTextWidth();
- d->labelHeight = line.naturalTextRect().bottom() - line.naturalTextRect().top();
- d->labelYOffset = -line.ascent();
-
- bool contNotNeeded = KoTextLayoutArea::layout(cursor);
-
- d->labelYOffset += block.layout()->lineAt(0).ascent();
-
- if (!contNotNeeded) {
- QString contNote = notesConfig->footnoteContinuationForward();
- font.setBold(true);
- d->postLayout = new QTextLayout(contNote, font, pd);
- QList<QTextLayout::FormatRange> contTextLayouts;
- QTextLayout::FormatRange contTextRange;
- contTextRange.start = 0;
- contTextRange.length = contNote.length();
- contTextRange.format = block.charFormat();
- contTextLayouts.append(contTextRange);
- d->postLayout->setAdditionalFormats(contTextLayouts);
-
- QTextOption contTextOption(Qt::AlignLeft | Qt::AlignAbsolute);
- //option.setTextDirection();
- d->postLayout->setTextOption(contTextOption);
- d->postLayout->beginLayout();
- QTextLine contTextLine = d->postLayout->createLine();
- d->postLayout->endLayout();
- contTextLine.setPosition(QPointF(right() - contTextLine.naturalTextWidth(), bottom() - contTextLine.height()));
-
- documentLayout()->setContinuationObstruction(new
- KoTextLayoutObstruction(contTextLine.naturalTextRect(), false));
- }
- return contNotNeeded;
-}
-
-void KoTextLayoutNoteArea::setAsContinuedArea(bool isContinuedArea)
-{
- d->isContinuedArea = isContinuedArea;
-}
-
-KoPointedAt KoTextLayoutNoteArea::hitTest(const QPointF &p, Qt::HitTestAccuracy accuracy) const
-{
- KoPointedAt pointedAt;
- pointedAt.noteReference = -1;
- QPointF tmpP(p.x(), p.y() + (d->isContinuedArea ? OVERLAPPREVENTION : 0));
-
- pointedAt = KoTextLayoutArea::hitTest(tmpP, accuracy);
-
- if (tmpP.x() > left() && tmpP.x() < d->labelWidth && tmpP.y() < top() + d->labelYOffset + d->labelHeight)
- {
- pointedAt.noteReference = d->note->getPosInDocument();
- pointedAt.position = tmpP.x();
- }
-
- return pointedAt;
-}
-
-QRectF KoTextLayoutNoteArea::selectionBoundingBox(QTextCursor &cursor) const
-{
- return KoTextLayoutArea::selectionBoundingBox(cursor).translated(0
- , d->isContinuedArea ? -OVERLAPPREVENTION : 0);
-
-}
diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutNoteArea.h b/plugins/flake/textshape/textlayout/KoTextLayoutNoteArea.h
deleted file mode 100644
index 13d9c86fdd..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextLayoutNoteArea.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 Brijesh Patel <brijesh3105@gmail.com>
- *
- * 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 KOTEXTLAYOUTNOTEAREA_H
-#define KOTEXTLAYOUTNOTEAREA_H
-
-#include "KoTextLayoutArea.h"
-
-#include <KoTextDocumentLayout.h>
-
-class KoInlineNote;
-
-class KRITATEXTLAYOUT_EXPORT KoTextLayoutNoteArea : public KoTextLayoutArea
-{
-public:
- explicit KoTextLayoutNoteArea(KoInlineNote *note, KoTextLayoutArea *parent, KoTextDocumentLayout *documentLayout);
- ~KoTextLayoutNoteArea() override;
-
- void paint(QPainter *painter, const KoTextDocumentLayout::PaintContext &context);
-
- bool layout(FrameIterator *cursor);
-
- void setAsContinuedArea(bool isContinuedArea);
-
- KoPointedAt hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const;
-
- QRectF selectionBoundingBox(QTextCursor &cursor) const;
-
-private:
- class Private;
- Private * const d;
-};
-
-#endif // KOTEXTLAYOUTNOTEAREA_H
diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutObstruction.cpp b/plugins/flake/textshape/textlayout/KoTextLayoutObstruction.cpp
deleted file mode 100644
index 6860673ad1..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextLayoutObstruction.cpp
+++ /dev/null
@@ -1,321 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2007, 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2010 Ko Gmbh <cbo@kogmbh.com>
- *
- * 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 "KoTextLayoutObstruction.h"
-
-#include <KoShapeStrokeModel.h>
-#include <KoShapeShadow.h>
-#include <KoShapeGroup.h>
-#include <KoClipPath.h>
-#include <KoInsets.h>
-
-#include <QTransform>
-#include <QPainterPath>
-
-KoTextLayoutObstruction::KoTextLayoutObstruction(KoShape *shape, const QTransform &matrix)
- : m_side(None),
- m_polygon(QPolygonF()),
- m_line(QRectF()),
- m_shape(shape),
- m_runAroundThreshold(0)
-{
- qreal borderHalfWidth;
- QPainterPath path = decoratedOutline(m_shape, borderHalfWidth);
-
- //TODO check if path is convex. otherwise do triangulation and create more convex obstructions
- init(matrix, path, shape->textRunAroundDistanceLeft(), shape->textRunAroundDistanceTop(), shape->textRunAroundDistanceRight(), shape->textRunAroundDistanceBottom(), borderHalfWidth);
-
- if (shape->textRunAroundSide() == KoShape::NoRunAround) {
- // make the shape take the full width of the text area
- m_side = Empty;
- } else if (shape->textRunAroundSide() == KoShape::RunThrough) {
- m_distanceLeft = 0;
- m_distanceTop = 0;
- m_distanceRight = 0;
- m_distanceBottom = 0;
- // We don't exist.
- return;
- } else if (shape->textRunAroundSide() == KoShape::LeftRunAroundSide) {
- m_side = Left;
- } else if (shape->textRunAroundSide() == KoShape::RightRunAroundSide) {
- m_side = Right;
- } else if (shape->textRunAroundSide() == KoShape::BothRunAroundSide) {
- m_side = Both;
- } else if (shape->textRunAroundSide() == KoShape::BiggestRunAroundSide) {
- m_side = Bigger;
- } else if (shape->textRunAroundSide() == KoShape::EnoughRunAroundSide) {
- m_side = Enough;
- m_runAroundThreshold = shape->textRunAroundThreshold();
- }
-}
-
-KoTextLayoutObstruction::KoTextLayoutObstruction(const QRectF &rect, bool rtl)
- : m_side(None),
- m_polygon(QPolygonF()),
- m_line(QRectF()),
- m_shape(0),
- m_runAroundThreshold(0)
-{
- qreal borderHalfWidth = 0;
- qreal textRunAroundDistance = 1;
-
- QPainterPath path;
- path.addRect(rect);
-
- init(QTransform(), path, textRunAroundDistance, 0.0, textRunAroundDistance, 0.0, borderHalfWidth);
- if (rtl) {
- m_side = Right;
- } else {
- m_side = Left;
- }
-}
-
-QPainterPath KoTextLayoutObstruction::decoratedOutline(const KoShape *shape, qreal &borderHalfWidth) const
-{
- const KoShapeGroup *shapeGroup = dynamic_cast<const KoShapeGroup *>(shape);
- if (shapeGroup) {
- QPainterPath groupPath;
-
- foreach (const KoShape *child, shapeGroup->shapes()) {
- groupPath += decoratedOutline(child, borderHalfWidth);
- }
- return groupPath;
- }
-
- QPainterPath path;
- if (shape->textRunAroundContour() != KoShape::ContourBox) {
- KoClipPath *clipPath = shape->clipPath();
- if (clipPath) {
- path = clipPath->pathForSize(shape->size());
- } else {
- path = shape->outline();
- }
- } else {
- path.addRect(shape->outlineRect());
- }
-
- QRectF bb = shape->outlineRect();
- borderHalfWidth = 0;
-
- if (shape->stroke()) {
- KoInsets insets;
- shape->stroke()->strokeInsets(shape, insets);
- /*
- bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
- path = QPainterPath();
- path.addRect(bb);
- */
- borderHalfWidth = qMax(qMax(insets.left, insets.top),qMax(insets.right, insets.bottom));
- }
-
- if (shape->shadow() && shape->shadow()->isVisible()) {
- QTransform transform = shape->absoluteTransformation();
- bb = transform.mapRect(bb);
- KoInsets insets;
- shape->shadow()->insets(insets);
- bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
- path = QPainterPath();
- path.addRect(bb);
- path = transform.inverted().map(path);
- }
-
- return path;
-}
-
-void KoTextLayoutObstruction::init(const QTransform &matrix, const QPainterPath &obstruction, qreal distanceLeft, qreal distanceTop, qreal distanceRight, qreal distanceBottom, qreal borderHalfWidth)
-{
- m_distanceLeft = distanceLeft;
- m_distanceTop = distanceTop;
- m_distanceRight = distanceRight;
- m_distanceBottom = distanceBottom;
- QPainterPath path = matrix.map(obstruction);
- distanceLeft += borderHalfWidth;
- distanceTop += borderHalfWidth;
- distanceRight += borderHalfWidth;
- distanceBottom += borderHalfWidth;
-
- qreal extraWidth = distanceLeft + distanceRight;
- qreal extraHeight = distanceTop + distanceBottom;
- if (extraWidth != 0.0 || extraHeight != 0.0) {
- // Let's extend the outline with at least the border half width in all directions.
- // However since the distance can be express in 4 directions and QPainterPathStroker only
- // handles a penWidth we do some tricks to get it working.
- //
- // Explanation in one dimension only: we sum the distances top and below and use that as the
- // penWidth. Afterwards we translate the result so it is distributed correctly by top and bottom.
- // Now by doing that we would also implicitly set the left+right size of the pen which is no good,
- // so in order to set that to a minimal value (we choose 1, as 0 would give division by 0) we do
- // the following:. We scale the original path by sumX, stroke the path with penwidth=sumY, then
- // scale it back. Effectively we have now stroked with a pen sized 1 x sumY.
- //
- // The math to do both x an y in one go becomes a little more complex, but only a little.
- extraWidth = qMax(qreal(0.1), extraWidth);
- extraHeight = qMax(qreal(0.1), extraHeight);
-
- QPainterPathStroker stroker;
- stroker.setWidth(extraWidth);
- stroker.setJoinStyle(Qt::MiterJoin);
- stroker.setCapStyle(Qt::SquareCap);
- QPainterPath bigPath = stroker.createStroke(QTransform().scale(1.0, extraWidth / extraHeight).map(path));
- bigPath = QTransform().scale(1.0, extraHeight / extraWidth). map(bigPath);
- path += bigPath.translated(extraWidth / 2 - distanceLeft, extraHeight / 2 - distanceTop);
- }
-
- m_bounds = path.boundingRect();
-
- // Now we need to change the path into a polygon for easier handling later on
- m_polygon = path.toFillPolygon();
- QPointF prev = *(m_polygon.begin());
- foreach (const QPointF &vtx, m_polygon) { //initialized edges
- if (vtx.x() == prev.x() && vtx.y() == prev.y())
- continue;
- QLineF line;
- if (prev.y() < vtx.y()) // Make sure the vector lines all point downwards.
- line = QLineF(prev, vtx);
- else
- line = QLineF(vtx, prev);
- m_edges.insert(line.y1(), line);
- prev = vtx;
- }
-}
-
-qreal KoTextLayoutObstruction::xAtY(const QLineF &line, qreal y)
-{
- if (line.dx() == 0)
- return line.x1();
- return line.x1() + (y - line.y1()) / line.dy() * line.dx();
-}
-
-void KoTextLayoutObstruction::changeMatrix(const QTransform &matrix)
-{
- m_edges.clear();
-
- qreal borderHalfWidth;
- QPainterPath path = decoratedOutline(m_shape, borderHalfWidth);
-
- init(matrix, path, m_distanceLeft, m_distanceTop, m_distanceRight, m_distanceBottom, borderHalfWidth);
-}
-
-QRectF KoTextLayoutObstruction::cropToLine(const QRectF &lineRect)
-{
- if (m_bounds.intersects(lineRect)) {
- m_line = lineRect;
- bool untilFirst = true;
- //check inner points
- foreach (const QPointF &point, m_polygon) {
- if (lineRect.contains(point)) {
- if (untilFirst) {
- m_line.setLeft(point.x());
- m_line.setRight(point.x());
- untilFirst = false;
- } else {
- if (point.x() < m_line.left()) {
- m_line.setLeft(point.x());
- } else if (point.x() > m_line.right()) {
- m_line.setRight(point.x());
- }
- }
- }
- }
- //check edges
- qreal points[2] = { lineRect.top(), lineRect.bottom() };
- for (int i = 0; i < 2; i++) {
- const qreal y = points[i];
- QMap<qreal, QLineF>::const_iterator iter = m_edges.constBegin();
- for (;iter != m_edges.constEnd(); ++iter) {
- QLineF line = iter.value();
- if (line.y2() < y) // not a section that will intersect with ou Y yet
- continue;
- if (line.y1() > y) // section is below our Y, so abort loop
- //break;
- continue;
- if (qAbs(line.dy()) < 1E-10) // horizontal lines don't concern us.
- continue;
-
- qreal intersect = xAtY(iter.value(), y);
- if (untilFirst) {
- m_line.setLeft(intersect);
- m_line.setRight(intersect);
- untilFirst = false;
- } else {
- if (intersect < m_line.left()) {
- m_line.setLeft(intersect);
- } else if (intersect > m_line.right()) {
- m_line.setRight(intersect);
- }
- }
- }
- }
- } else {
- m_line = QRectF();
- }
- return m_line;
-}
-
-QRectF KoTextLayoutObstruction::getLeftLinePart(const QRectF &lineRect) const
-{
- QRectF leftLinePart = lineRect;
- leftLinePart.setRight(m_line.left());
- return leftLinePart;
-}
-
-QRectF KoTextLayoutObstruction::getRightLinePart(const QRectF &lineRect) const
-{
- QRectF rightLinePart = lineRect;
- if (m_line.right() > rightLinePart.left()) {
- rightLinePart.setLeft(m_line.right());
- }
- return rightLinePart;
-}
-
-bool KoTextLayoutObstruction::textOnLeft() const
-{
- return m_side == Left;
-}
-
-bool KoTextLayoutObstruction::textOnRight() const
-{
- return m_side == Right;
-}
-
-bool KoTextLayoutObstruction::textOnBiggerSide() const
-{
- return m_side == Bigger;
-}
-
-bool KoTextLayoutObstruction::textOnEnoughSides() const
-{
- return m_side == Enough;
-}
-
-qreal KoTextLayoutObstruction::runAroundThreshold() const
-{
- return m_runAroundThreshold;
-}
-
-bool KoTextLayoutObstruction::noTextAround() const
-{
- return m_side == Empty;
-}
-
-bool KoTextLayoutObstruction::compareRectLeft(KoTextLayoutObstruction *o1, KoTextLayoutObstruction *o2)
-{
- return o1->m_line.left() < o2->m_line.left();
-}
diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutObstruction.h b/plugins/flake/textshape/textlayout/KoTextLayoutObstruction.h
deleted file mode 100644
index cabd1a542d..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextLayoutObstruction.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2007, 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2010 Ko Gmbh <cbo@kogmbh.com>
- *
- * 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 KOTEXTLAYOUTOBSTRUCTION_H
-#define KOTEXTLAYOUTOBSTRUCTION_H
-
-#include "kritatextlayout_export.h"
-
-#include <QMultiMap>
-#include <QPolygonF>
-#include <QRectF>
-#include <QLineF>
-
-class KoShape;
-class QTransform;
-class QPainterPath;
-
-/// Class that allows us with the runaround of QPainterPaths
-class KRITATEXTLAYOUT_EXPORT KoTextLayoutObstruction
-{
-public:
- KoTextLayoutObstruction(KoShape *shape, const QTransform &matrix);
-
- KoTextLayoutObstruction(const QRectF &rect, bool rtl);
-
- void init(const QTransform &matrix, const QPainterPath &obstruction, qreal distanceLeft, qreal distanceTop, qreal distanceRight, qreal distanceBottom, qreal borderHalfWidth);
-
- QRectF limit(const QRectF &content);
-
- KoShape *shape() const { return m_shape; }
-
- static qreal xAtY(const QLineF &line, qreal y);
-
- void changeMatrix(const QTransform &matrix);
-
- //-------------------------------------------------------------------------------
-
- QRectF cropToLine(const QRectF &lineRect);
-
- QRectF getLeftLinePart(const QRectF &lineRect) const;
-
- QRectF getRightLinePart(const QRectF &lineRect) const;
-
- bool textOnLeft() const;
-
- bool textOnRight() const;
-
- bool textOnBiggerSide() const;
-
- bool textOnEnoughSides() const;
-
- bool noTextAround() const;
-
- // Don't run around unless available space is > than this when m_side == Enough.
- qreal runAroundThreshold() const;
-
- static bool compareRectLeft(KoTextLayoutObstruction *o1, KoTextLayoutObstruction *o2);
-private:
- QPainterPath decoratedOutline(const KoShape *shape, qreal &borderHalfWidth) const;
-
- enum Side { None, Left, Right, Empty, Both, Bigger, Enough };
- Side m_side;
- QRectF m_bounds;
- QPolygonF m_polygon;
- public:
- QRectF m_line;
- QMultiMap<qreal, QLineF> m_edges; //sorted with y-coord
- KoShape *m_shape;
- QRectF m_rect;
- qreal m_distanceLeft;
- qreal m_distanceTop;
- qreal m_distanceRight;
- qreal m_distanceBottom;
- qreal m_borderHalfWidth;
- qreal m_runAroundThreshold;
-};
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutRootArea.cpp b/plugins/flake/textshape/textlayout/KoTextLayoutRootArea.cpp
deleted file mode 100644
index 6dae718f80..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextLayoutRootArea.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 C. Boemann <cbo@kogmbh.com>
- *
- * 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 "KoTextLayoutRootArea.h"
-
-#include "FrameIterator.h"
-
-#include <KoShapeContainer.h>
-#include <KoTextShapeData.h>
-#include <KoTextPage.h>
-
-class Q_DECL_HIDDEN KoTextLayoutRootArea::Private
-{
-public:
- Private()
- : shape(0)
- , dirty(true)
- , textpage(0)
- , nextStartOfArea(0)
- {
- }
- KoShape *shape;
- bool dirty;
- KoTextPage *textpage;
- FrameIterator *nextStartOfArea;
-};
-
-KoTextLayoutRootArea::KoTextLayoutRootArea(KoTextDocumentLayout *documentLayout)
- : KoTextLayoutArea(0, documentLayout)
- , d(new Private)
-{
-}
-
-KoTextLayoutRootArea::~KoTextLayoutRootArea()
-{
- if (d->shape)
- {
- KoTextShapeData *data = qobject_cast<KoTextShapeData*>(d->shape->userData());
- if (data)
- data->setRootArea(0);
- }
- delete d->nextStartOfArea;
- delete d->textpage;
- delete d;
-}
-
-bool KoTextLayoutRootArea::layoutRoot(FrameIterator *cursor)
-{
- d->dirty = false;
-
- setVirginPage(true);
-
- bool retval = KoTextLayoutArea::layout(cursor);
-
- delete d->nextStartOfArea;
- d->nextStartOfArea = new FrameIterator(cursor);
- return retval;
-}
-
-void KoTextLayoutRootArea::setAssociatedShape(KoShape *shape)
-{
- d->shape = shape;
-}
-
-KoShape *KoTextLayoutRootArea::associatedShape() const
-{
- return d->shape;
-}
-
-void KoTextLayoutRootArea::setPage(KoTextPage *textpage)
-{
- delete d->textpage;
- d->textpage = textpage;
-}
-
-KoTextPage* KoTextLayoutRootArea::page() const
-{
- if (d->textpage) {
- return d->textpage;
- }
- // If this root area has no KoTextPage then walk up the shape-hierarchy and look if we
- // have a textshape-parent that has a valid KoTextPage. This handles the in Words valid
- // case that the associatedShape is nested in another shape.
- KoTextPage *p = 0;
- for(KoShape *shape = associatedShape() ? associatedShape()->parent() : 0; shape; shape = shape->parent()) {
- if (KoTextShapeData *data = qobject_cast<KoTextShapeData*>(shape->userData())) {
- if (KoTextLayoutRootArea *r = data->rootArea())
- p = r->page();
- break;
- }
- }
- return p;
-}
-
-void KoTextLayoutRootArea::setDirty()
-{
- d->dirty = true;
- documentLayout()->emitLayoutIsDirty();
-}
-
-bool KoTextLayoutRootArea::isDirty() const
-{
- return d->dirty;
-}
-
-FrameIterator *KoTextLayoutRootArea::nextStartOfArea() const
-{
- return d->nextStartOfArea;
-}
-
-
-KoText::Direction KoTextLayoutRootArea::parentTextDirection() const
-{
- return KoText::LeftRightTopBottom;
-}
-
-void KoTextLayoutRootArea::setBottom(qreal b)
-{
- KoTextLayoutArea::setBottom(b);
-}
diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutRootArea.h b/plugins/flake/textshape/textlayout/KoTextLayoutRootArea.h
deleted file mode 100644
index fe319e68c6..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextLayoutRootArea.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 C. Boemann <cbo@kogmbh.com>
- *
- * 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 KOTEXTLAYOUTROOTAREA_H
-#define KOTEXTLAYOUTROOTAREA_H
-
-#include "kritatextlayout_export.h"
-
-#include "KoTextLayoutArea.h"
-
-class KoShape;
-class KoTextPage;
-
-/**
- * When laying out text it happens in areas that can occupy space of various size.
- */
-class KRITATEXTLAYOUT_EXPORT KoTextLayoutRootArea : public KoTextLayoutArea
-{
-public:
- /// constructor
- explicit KoTextLayoutRootArea(KoTextDocumentLayout *documentLayout);
- ~KoTextLayoutRootArea() override;
-
- /// Layouts as much as it can
- /// Returns true if it has reached the end of the frame
- bool layoutRoot(FrameIterator *cursor);
-
- /// Sets an associated shape which can be retrieved with associatedShape()
- /// KoTextLayoutRootArea doesn't use it for anything.
- void setAssociatedShape(KoShape *shape);
-
- /// Retruns the shape set with setAssociatedShape()
- KoShape *associatedShape() const;
-
- /**
- * Set the \p page this root area is on.
- *
- * The root-area takes over the ownership of the KoTextPage and will take
- * care to delete the KoTextPage if not needed any longer.
- */
- void setPage(KoTextPage *textpage);
-
- /// Returns the page this root area is on.
- KoTextPage *page() const;
-
- void setDirty();
-
- bool isDirty() const;
-
- /// Returns the cursor position of the following root frame
- FrameIterator *nextStartOfArea() const;
-
- KoText::Direction parentTextDirection() const override;
-
- void setBottom(qreal b);
-
-private:
- class Private;
- Private * const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutRootAreaProvider.cpp b/plugins/flake/textshape/textlayout/KoTextLayoutRootAreaProvider.cpp
deleted file mode 100644
index 7d27944df4..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextLayoutRootAreaProvider.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 C. Boemann <cbo@kogmbh.com>
- *
- * 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 "KoTextLayoutRootAreaProvider.h"
-
-KoTextLayoutRootAreaProvider::KoTextLayoutRootAreaProvider()
-{
-}
-
-KoTextLayoutRootAreaProvider::~KoTextLayoutRootAreaProvider()
-{
-}
diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutRootAreaProvider.h b/plugins/flake/textshape/textlayout/KoTextLayoutRootAreaProvider.h
deleted file mode 100644
index 871311366b..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextLayoutRootAreaProvider.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 C. Boemann <cbo@kogmbh.com>
- *
- * 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 KOTEXTLAYOUTROOTAREAPROVIDER_H
-#define KOTEXTLAYOUTROOTAREAPROVIDER_H
-
-#include "kritatextlayout_export.h"
-
-#include <QList>
-#include <QString>
-
-class KoTextLayoutRootArea;
-class KoTextDocumentLayout;
-class KoTextLayoutObstruction;
-class QRectF;
-
-/**
- * Represents the contract that a root area requested by the layout system
- * has to respect. For simple layout situations (like a single text shape),
- * it's fine to ignore the contract since pages do not exist.
- */
-struct RootAreaConstraint {
- QString masterPageName;
- int visiblePageNumber;
- bool newPageForced;
-};
-
-/**
- * When laying out text we need an area where upon the text will be placed.
- * A KoTextLayoutRootAreaProvider provides the layout process with such areas
- */
-class KRITATEXTLAYOUT_EXPORT KoTextLayoutRootAreaProvider
-{
-public:
- /// constructor
- explicit KoTextLayoutRootAreaProvider();
- virtual ~KoTextLayoutRootAreaProvider();
-
- /**
- * Provides a new root area for the layout
- *
- * @param documentLayout the current document layouter
- * @param constraints the rules the new area has to respect (page style, visible page number...)
- * @param requestedPosition the position of the new area in the text flow
- * @param isNewArea will contain a boolean to tell whether this is a new area or a recycled one
- */
- virtual KoTextLayoutRootArea *provide(KoTextDocumentLayout *documentLayout, const RootAreaConstraint &constraints, int requestedPosition, bool *isNewArea) = 0;
-
- /// Release all root areas that are after the "afterThis" root area
- /// If afterThis == 0 all should be released
- virtual void releaseAllAfter(KoTextLayoutRootArea *afterThis) = 0;
-
- /// This method allows the provider to do any post processing like
- /// - painting it
- /// - changing it's size
- /// - do other things to other structures (eg resizing the textshape)
- virtual void doPostLayout(KoTextLayoutRootArea *rootArea, bool isNewRootArea) = 0;
-
- /// Makes all canvases redraw the shapes maintained by this provider
- /// use with care - it eats a lot of processing for no real gain
- virtual void updateAll() = 0;
-
- /// Returns a suggested offset and size for the root area
- virtual QRectF suggestRect(KoTextLayoutRootArea *rootArea) = 0;
-
- /// Return a list of obstructions intersecting root area
- virtual QList<KoTextLayoutObstruction *> relevantObstructions(KoTextLayoutRootArea *rootArea) = 0;
-};
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutTableArea.cpp b/plugins/flake/textshape/textlayout/KoTextLayoutTableArea.cpp
deleted file mode 100644
index 3827e76bea..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextLayoutTableArea.cpp
+++ /dev/null
@@ -1,1125 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2009 Elvis Stansvik <elvstone@gmail.org>
- * Copyright (C) 2011 C. Boemann <cbo@kogmbh.com>
- *
- * 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 "KoTextLayoutTableArea.h"
-
-#include "KoTextLayoutCellHelper.h"
-#include "TableIterator.h"
-#include "KoPointedAt.h"
-
-#include <KoTableColumnAndRowStyleManager.h>
-#include <KoTableColumnStyle.h>
-#include <KoTableRowStyle.h>
-#include <KoTableCellStyle.h>
-#include <KoTableStyle.h>
-#include <KoStyleManager.h>
-#include <KoTextTableTemplate.h>
-
-#include <QTextTable>
-#include <QTextTableFormat>
-#include <QPainter>
-#include <QRectF>
-#include <QPair>
-
-#include "FrameIterator.h"
-
-class Q_DECL_HIDDEN KoTextLayoutTableArea::Private
-{
-public:
- Private()
- : startOfArea(0)
- {
- }
- QVector<QVector<KoTextLayoutArea *> > cellAreas;
- TableIterator *startOfArea;
- TableIterator *endOfArea;
- bool lastRowHasSomething;
- QTextTable *table;
- int headerRows;
- qreal headerOffsetX;
- qreal headerOffsetY;
- KoTableColumnAndRowStyleManager carsManager;
- qreal tableWidth;
- QVector<qreal> headerRowPositions; // we will only fill those that this area covers
- QVector<qreal> rowPositions; // we will only fill those that this area covers
- QVector<qreal> columnWidths;
- QVector<qreal> columnPositions;
- bool collapsing;
- bool totalMisFit;
- KoTextDocumentLayout *documentLayout;
-
- KoTableCellStyle effectiveCellStyle(const QTextTableCell &tableCell);
-};
-
-KoTableCellStyle KoTextLayoutTableArea::Private::effectiveCellStyle(const QTextTableCell &tableCell)
-{
- QTextTableFormat tableFormat = table->format();
- KoTableCellStyle cellStyle(tableCell.format().toTableCellFormat());
- if (documentLayout->styleManager() && table->format().hasProperty(KoTableStyle::TableTemplate)) {
- if (KoTextTableTemplate *tableTemplate = documentLayout->styleManager()->tableTemplate(table->format().intProperty(KoTableStyle::TableTemplate))) {
- //priorities according to ODF 1.2, 16.18 - table:table-template
- if (tableCell.column() == 0 && tableTemplate->firstColumn()
- && tableFormat.boolProperty(KoTableStyle::UseFirstColumnStyles)) {
- cellStyle = *(documentLayout->styleManager()->tableCellStyle(tableTemplate->firstColumn()));
- return cellStyle;
- }
-
- if (tableCell.column() == (table->columns() - 1) && tableTemplate->lastColumn()
- && tableFormat.boolProperty(KoTableStyle::UseLastColumnStyles)) {
- cellStyle = *(documentLayout->styleManager()->tableCellStyle(tableTemplate->lastColumn()));
- return cellStyle;
- }
-
- if (tableCell.row() == 0 && tableTemplate->firstRow()
- && tableFormat.boolProperty(KoTableStyle::UseFirstRowStyles)) {
- cellStyle = *(documentLayout->styleManager()->tableCellStyle(tableTemplate->firstRow()));
- return cellStyle;
- }
-
- if (tableCell.row() == (table->rows() - 1) && tableTemplate->lastRow()
- && tableFormat.boolProperty(KoTableStyle::UseLastRowStyles)) {
- cellStyle = *(documentLayout->styleManager()->tableCellStyle(tableTemplate->lastRow()));
- return cellStyle;
- }
-
- if (((tableCell.row() + 1) % 2) == 0 && tableTemplate->evenRows()
- && tableFormat.boolProperty(KoTableStyle::UseBandingRowStyles)) {
- cellStyle = *(documentLayout->styleManager()->tableCellStyle(tableTemplate->evenRows()));
- return cellStyle;
- }
-
- if (((tableCell.row() + 1) % 2) != 0 && tableTemplate->oddRows()
- && tableFormat.boolProperty(KoTableStyle::UseBandingRowStyles)) {
- cellStyle = *(documentLayout->styleManager()->tableCellStyle(tableTemplate->oddRows()));
- return cellStyle;
- }
-
- if (((tableCell.column() + 1) % 2) == 0 && tableTemplate->evenColumns()
- && tableFormat.boolProperty(KoTableStyle::UseBandingColumnStyles)) {
- cellStyle = *(documentLayout->styleManager()->tableCellStyle(tableTemplate->evenColumns()));
- return cellStyle;
- }
-
- if (((tableCell.column() + 1) % 2) != 0 && tableTemplate->oddColumns()
- && tableFormat.boolProperty(KoTableStyle::UseBandingColumnStyles)) {
- cellStyle = *(documentLayout->styleManager()->tableCellStyle(tableTemplate->oddColumns()));
- return cellStyle;
- }
-
- if (tableTemplate->body()) {
- cellStyle = *(documentLayout->styleManager()->tableCellStyle(tableTemplate->body()));
- }
- }
- }
-
- return cellStyle;
-}
-
-
-KoTextLayoutTableArea::KoTextLayoutTableArea(QTextTable *table, KoTextLayoutArea *parent, KoTextDocumentLayout *documentLayout)
- : KoTextLayoutArea(parent, documentLayout)
- , d(new Private)
-{
- Q_ASSERT(table);
- Q_ASSERT(parent);
-
- d->table = table;
- d->documentLayout = documentLayout;
- d->carsManager = KoTableColumnAndRowStyleManager::getManager(table);
-
- // Resize geometry vectors for the table.
- d->rowPositions.resize(table->rows() + 1);
- d->headerRowPositions.resize(table->rows() + 1);
- d->cellAreas.resize(table->rows());
- for (int row = 0; row < table->rows(); ++row) {
- d->cellAreas[row].resize(table->columns());
- }
- KoTableStyle tableStyle(d->table->format());
- d->collapsing = tableStyle.collapsingBorderModel();
-}
-
-KoTextLayoutTableArea::~KoTextLayoutTableArea()
-{
- for (int row = d->startOfArea->row; row < d->cellAreas.size(); ++row) {
- for (int col = 0; col < d->cellAreas[row].size(); ++col) {
- delete d->cellAreas[row][col];
- }
- }
- delete d->startOfArea;
- delete d->endOfArea;
- delete d;
-}
-
-KoPointedAt KoTextLayoutTableArea::hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const
-{
- int firstRow = qMax(d->startOfArea->row, d->headerRows);
- int lastRow = d->endOfArea->row;
-
- if (d->lastRowHasSomething == false) {
- --lastRow;
- }
-
- if (lastRow < d->startOfArea->row) {
- return KoPointedAt(); // empty
- }
-
- // Test normal cells.
- if (point.y() > d->rowPositions[firstRow] - 3.0 && point.y() < d->rowPositions[lastRow + 1] + 3.0) {
- QVector<qreal>::const_iterator start = d->rowPositions.constBegin() + firstRow;
- QVector<qreal>::const_iterator end = d->rowPositions.constBegin() + lastRow + 1;
- int row = std::lower_bound(start, end, point.y()) - d->rowPositions.constBegin() - 1;
- int column = std::lower_bound(d->columnPositions.begin(), d->columnPositions.end(), point.x()) - d->columnPositions.constBegin() - 1;
- if (point.y() < d->rowPositions[firstRow]) {
- ++row;
- }
- column = qBound(0, column, d->table->columns() - 1);
- KoPointedAt pointedAt;
- if (qAbs(d->columnPositions[column] - point.x()) < 3.0) {
- pointedAt.tableHit = KoPointedAt::ColumnDivider;
- } else if (qAbs(d->columnPositions[column+1] - point.x()) < 3.0) {
- pointedAt.tableHit = KoPointedAt::ColumnDivider;
- ++column;
- } else if (d->columnPositions[0] < point.x()
- && point.x() < d->columnPositions[d->table->columns()]
- && qAbs(d->rowPositions[row] - point.y()) < 3.0) {
- pointedAt.tableHit = KoPointedAt::RowDivider;
- } else if (d->columnPositions[0] < point.x()
- && point.x() < d->columnPositions[d->table->columns()]
- && qAbs(d->rowPositions[row+1] - point.y()) < 3.0) {
- pointedAt.tableHit = KoPointedAt::RowDivider;
- ++row;
- } else {
- QTextTableCell cell = d->table->cellAt(row, column);
- pointedAt = d->cellAreas[cell.row()][cell.column()]->hitTest(point, accuracy);
- }
-
- if (pointedAt.tableHit == KoPointedAt::ColumnDivider) {
- if (column > 0) {
- pointedAt.tableLeadSize = d->columnPositions[column] - d->columnPositions[column-1];
- }
- if (column < d->table->columns()) {
- pointedAt.tableTrailSize = d->columnPositions[column+1] - d->columnPositions[column];
- }
- } else if (pointedAt.tableHit == KoPointedAt::RowDivider) {
- if (row > 0) {
- pointedAt.tableLeadSize = d->rowPositions[row] - d->rowPositions[row-1];
- }
- if (row < d->table->rows()) {
- pointedAt.tableTrailSize = d->rowPositions[row+1] - d->rowPositions[row];
- }
- }
- pointedAt.table = d->table;
- pointedAt.tableRowDivider = row;
- pointedAt.tableColumnDivider = column;
- pointedAt.tableDividerPos = QPointF(d->columnPositions[column],d->rowPositions[row]);
- return pointedAt;
- }
-
- // Test header row cells.
- QPointF headerPoint = point - QPointF(d->headerOffsetX, d->headerOffsetY);
- if (headerPoint.y() > d->headerRowPositions.first() && headerPoint.y() < d->headerRowPositions[d->headerRows]) {
- QVector<qreal>::const_iterator start = d->headerRowPositions.constBegin();
- QVector<qreal>::const_iterator end = d->headerRowPositions.constBegin() + d->headerRows;
- int row = std::lower_bound(start, end, headerPoint.y()) - d->headerRowPositions.constBegin() - 1;
- int column = std::lower_bound(d->columnPositions.begin(), d->columnPositions.end(), headerPoint.x()) - d->columnPositions.constBegin() - 1;
- column = qBound(0, column, d->table->columns() - 1);
- KoPointedAt pointedAt;
- if (qAbs(d->columnPositions[column] - headerPoint.x()) < 3.0) {
- pointedAt.tableHit = KoPointedAt::ColumnDivider;
- } else if (qAbs(d->columnPositions[column+1] - headerPoint.x()) < 3.0) {
- pointedAt.tableHit = KoPointedAt::ColumnDivider;
- ++column;
- } else {
- QTextTableCell cell = d->table->cellAt(row, column);
- pointedAt = d->cellAreas[cell.row()][cell.column()]->hitTest(headerPoint, accuracy);
- }
- if (pointedAt.tableHit == KoPointedAt::ColumnDivider) {
- if (column > 0) {
- pointedAt.tableLeadSize = d->columnPositions[column] - d->columnPositions[column-1];
- }
- if (column < d->table->columns()) {
- pointedAt.tableTrailSize = d->columnPositions[column+1] - d->columnPositions[column];
- }
- }
- pointedAt.table = d->table;
- pointedAt.tableRowDivider = row;
- pointedAt.tableColumnDivider = column;
- pointedAt.tableDividerPos = QPointF(d->columnPositions[column],d->rowPositions[row]);
- return pointedAt;
- }
-
- return KoPointedAt();
-}
-
-QRectF KoTextLayoutTableArea::selectionBoundingBox(QTextCursor &cursor) const
-{
- int lastRow = d->endOfArea->row;
- if (d->lastRowHasSomething == false) {
- --lastRow;
- }
- if (lastRow < d->startOfArea->row) {
- return QRectF(); // empty
- }
-
- int firstRow = qMax(d->startOfArea->row, d->headerRows);
- QTextTableCell startTableCell = d->table->cellAt(cursor.selectionStart());
- QTextTableCell endTableCell = d->table->cellAt(cursor.selectionEnd());
-
- if (startTableCell == endTableCell) {
- if (startTableCell.row() < d->startOfArea->row || startTableCell.row() > lastRow) {
- return QRectF(); // cell is not in this area
- }
- KoTextLayoutArea *area = d->cellAreas[startTableCell.row()][startTableCell.column()];
- Q_ASSERT(area);
- return area->selectionBoundingBox(cursor);
- } else {
- int selectionRow;
- int selectionColumn;
- int selectionRowSpan;
- int selectionColumnSpan;
- cursor.selectedTableCells(&selectionRow, &selectionRowSpan, &selectionColumn, &selectionColumnSpan);
-
- qreal top, bottom;
-
- if (selectionRow < d->headerRows) {
- top = d->headerRowPositions[selectionRow] + d->headerOffsetY;
- } else {
- top = d->rowPositions[qMin(qMax(firstRow, selectionRow), lastRow)];
- }
-
- if (selectionRow + selectionRowSpan < d->headerRows) {
- bottom = d->headerRowPositions[selectionRow + selectionRowSpan] + d->headerOffsetY;
- } else {
- bottom = d->rowPositions[d->headerRows] + d->headerOffsetY;
- if (selectionRow + selectionRowSpan >= firstRow) {
- bottom = d->rowPositions[qMin(selectionRow + selectionRowSpan, lastRow + 1)];
- }
- }
-
- return QRectF(d->columnPositions[selectionColumn], top,
- d->columnPositions[selectionColumn + selectionColumnSpan] - d->columnPositions[selectionColumn], bottom - top);
- }
-}
-
-bool KoTextLayoutTableArea::layoutTable(TableIterator *cursor)
-{
- d->startOfArea = new TableIterator(cursor);
- d->headerRows = cursor->headerRows;
- d->totalMisFit = false;
-
- // If table is done we create an empty area and return true
- if (cursor->row == d->table->rows()) {
- setBottom(top());
- d->endOfArea = new TableIterator(cursor);
- return true;
- }
- layoutColumns();
-
- bool first = cursor->row == 0 && (d->cellAreas[0][0] == 0);
- if (first) { // are we at the beginning of the table
- cursor->row = 0;
- d->rowPositions[0] = top() + d->table->format().topMargin();
- d->headerOffsetX = 0;
- d->headerOffsetY = 0;
- } else {
- for (int row = 0; row < d->headerRows; ++row) {
- // Copy header rows
- d->headerRowPositions[row] = cursor->headerRowPositions[row];
- for (int col = 0; col < d->table->columns(); ++col) {
- d->cellAreas[row][col] = cursor->headerCellAreas[row][col];
- }
- }
-
- if (d->headerRows) {
- // Also set the position of the border below headers
- d->headerRowPositions[d->headerRows] = cursor->headerRowPositions[d->headerRows];
- }
-
- // If headerRows == 0 then the following reduces to: d->rowPositions[cursor->row] = top()
- d->headerOffsetY = top() - d->headerRowPositions[0];
- d->rowPositions[cursor->row] = d->headerRowPositions[d->headerRows] + d->headerOffsetY;
-
- // headerOffsetX should also be set
- d->headerOffsetX = d->columnPositions[0] - cursor->headerPositionX;
- }
-
- bool complete = first;
- qreal topBorderWidth = 0;
- qreal bottomBorderWidth = 0;
- qreal dummyWidth = 0;
-
- collectBorderThicknesss(cursor->row - 1, dummyWidth, topBorderWidth);
- collectBorderThicknesss(cursor->row, topBorderWidth, bottomBorderWidth);
- do {
- qreal nextBottomBorderWidth = 0;
- collectBorderThicknesss(cursor->row+1, bottomBorderWidth, nextBottomBorderWidth);
-
- d->lastRowHasSomething = false;
-
- complete = layoutRow(cursor, topBorderWidth, bottomBorderWidth);
-
- setBottom(d->rowPositions[cursor->row + 1] + bottomBorderWidth);
- topBorderWidth = bottomBorderWidth;
- bottomBorderWidth = nextBottomBorderWidth;
-
-
- if (complete) {
- setVirginPage(false);
- cursor->row++;
- }
- } while (complete && cursor->row < d->table->rows());
-
- if (cursor->row == d->table->rows()) {
- d->lastRowHasSomething = false;
- }
-
-
- if (first) { // were we at the beginning of the table
- for (int row = 0; row < d->headerRows; ++row) {
- // Copy header rows
- cursor->headerRowPositions[row] = d->rowPositions[row];
- d->headerRowPositions[row] = d->rowPositions[row];
- for (int col = 0; col < d->table->columns(); ++col) {
- cursor->headerCellAreas[row][col] = d->cellAreas[row][col];
- }
- }
- if (d->headerRows) {
- // Also set the position of the border below headers
- cursor->headerRowPositions[d->headerRows] = d->rowPositions[d->headerRows];
- d->headerRowPositions[d->headerRows] = d->rowPositions[d->headerRows];
- }
- cursor->headerPositionX = d->columnPositions[0];
-
- if (!virginPage() && d->totalMisFit) {
- //if we couldn't fit the header rows plus some then don't even try
- cursor->row = 0;
- nukeRow(cursor);
- }
- }
-
- d->endOfArea = new TableIterator(cursor);
-
- return complete;
-}
-
-
-void KoTextLayoutTableArea::layoutColumns()
-{
- QTextTableFormat tableFormat = d->table->format();
-
- d->columnPositions.resize(d->table->columns() + 1);
- d->columnWidths.resize(d->table->columns() + 1);
-
- // Table width.
- d->tableWidth = 0;
- qreal parentWidth = right() - left();
- if (tableFormat.width().rawValue() == 0 || tableFormat.alignment() == Qt::AlignJustify) {
- // We got a zero width value or alignment is justify, so use 100% of parent.
- d->tableWidth = parentWidth - tableFormat.leftMargin() - tableFormat.rightMargin();
- } else {
- if (tableFormat.width().type() == QTextLength::FixedLength) {
- // Fixed length value, so use the raw value directly.
- d->tableWidth = tableFormat.width().rawValue();
- } else if (tableFormat.width().type() == QTextLength::PercentageLength) {
- // Percentage length value, so use a percentage of parent width.
- d->tableWidth = tableFormat.width().rawValue() * (parentWidth / 100)
- - tableFormat.leftMargin() - tableFormat.rightMargin();
- } else {
- // Unknown length type, so use 100% of parent.
- d->tableWidth = parentWidth - tableFormat.leftMargin() - tableFormat.rightMargin();
- }
- }
-
- // Column widths.
- qreal availableWidth = d->tableWidth; // Width available for columns.
- QList<int> fixedWidthColumns; // List of fixed width columns.
- QList<int> relativeWidthColumns; // List of relative width columns.
- qreal relativeWidthSum = 0; // Sum of relative column width values.
- int numNonStyleColumns = 0;
- for (int col = 0; col < d->table->columns(); ++col) {
- KoTableColumnStyle columnStyle = d->carsManager.columnStyle(col);
-
- if (columnStyle.hasProperty(KoTableColumnStyle::RelativeColumnWidth)) {
- // Relative width specified. Will be handled in the next loop.
- d->columnWidths[col] = 0.0;
- relativeWidthColumns.append(col);
- relativeWidthSum += columnStyle.relativeColumnWidth();
- } else if (columnStyle.hasProperty(KoTableColumnStyle::ColumnWidth)) {
- // Only width specified, so use it.
- d->columnWidths[col] = columnStyle.columnWidth();
- fixedWidthColumns.append(col);
- availableWidth -= columnStyle.columnWidth();
- } else {
- // Neither width nor relative width specified.
- d->columnWidths[col] = 0.0;
- relativeWidthColumns.append(col); // handle it as a relative width column without asking for anything
- ++numNonStyleColumns;
- }
- }
-
- // Handle the case that the fixed size columns are larger then the defined table width
- if (availableWidth < 0.0) {
- if (tableFormat.width().rawValue() == 0 && fixedWidthColumns.count() > 0) {
- // If not table width was defined then we need to scale down the fixed size columns so they match
- // into the width of the table.
- qreal diff = (-availableWidth) / qreal(fixedWidthColumns.count());
- Q_FOREACH (int col, fixedWidthColumns) {
- d->columnWidths[col] = qMax(qreal(0.0), d->columnWidths[col] - diff);
- }
- }
- availableWidth = 0.0;
- }
-
- // Calculate width to those columns that don't actually request it
- qreal widthForNonWidthColumn = ((1.0 - qMin<qreal>(relativeWidthSum, 1.0)) * availableWidth);
- availableWidth -= widthForNonWidthColumn; // might as well do this calc before dividing by numNonStyleColumns
- if (numNonStyleColumns > 0 && widthForNonWidthColumn > 0.0) {
- widthForNonWidthColumn /= numNonStyleColumns;
- }
-
- // Relative column widths have now been summed up and can be distributed.
- foreach (int col, relativeWidthColumns) {
- KoTableColumnStyle columnStyle = d->carsManager.columnStyle(col);
- if (columnStyle.hasProperty(KoTableColumnStyle::RelativeColumnWidth) || columnStyle.hasProperty(KoTableColumnStyle::ColumnWidth)) {
- d->columnWidths[col] = qMax<qreal>(columnStyle.relativeColumnWidth() * availableWidth / relativeWidthSum, 0.0);
- } else {
- d->columnWidths[col] = widthForNonWidthColumn;
- }
- }
-
- // Column positions.
- qreal columnPosition = left();
- qreal columnOffset = tableFormat.leftMargin();
- if (tableFormat.alignment() == Qt::AlignRight) {
- // Table is right-aligned, so add all of the remaining space.
- columnOffset += parentWidth - d->tableWidth;
- }
- if (tableFormat.alignment() == Qt::AlignHCenter) {
- // Table is centered, so add half of the remaining space.
- columnOffset += (parentWidth - d->tableWidth) / 2;
- }
- for (int col = 0; col < d->columnPositions.size(); ++col) {
- d->columnPositions[col] = columnPosition + columnOffset;
- // Increment by this column's width.
- columnPosition += d->columnWidths[col];
- }
-
- // Borders can be outside of the cell (outer-borders) in which case it's need
- // to take them into account to not cut content off.
- qreal leftBorder = 0.0;
- qreal rightBorder = 0.0;
- for (int row = 0; row < d->table->rows(); ++row) {
- QTextTableCell leftCell = d->table->cellAt(row, 0);
- KoTableCellStyle leftCellStyle = d->effectiveCellStyle(leftCell);
- leftBorder = qMax(leftBorder, leftCellStyle.leftOuterBorderWidth());
-
- QTextTableCell rightCell = d->table->cellAt(row, d->table->columns() - 1);
- KoTableCellStyle rightCellStyle = d->effectiveCellStyle(rightCell);
- rightBorder = qMax(rightBorder, rightCellStyle.rightOuterBorderWidth());
- }
-
- expandBoundingLeft(d->columnPositions[0] - leftBorder);
- expandBoundingRight(d->columnPositions[d->table->columns()] + rightBorder + leftBorder);
-}
-
-void KoTextLayoutTableArea::collectBorderThicknesss(int row, qreal &topBorderWidth, qreal &bottomBorderWidth)
-{
- int col = 0;
-
- if (d->collapsing && row >= 0 && row < d->table->rows()) {
- // let's collect the border info
- while (col < d->table->columns()) {
- QTextTableCell cell = d->table->cellAt(row, col);
-
- if (row == cell.row() + cell.rowSpan() - 1) {
- /*
- * This cell ends vertically in this row, and hence should
- * contribute to the bottom border.
- */
- KoTableCellStyle cellStyle = d->effectiveCellStyle(cell);
-
- topBorderWidth = qMax(cellStyle.topBorderWidth(), topBorderWidth);
- bottomBorderWidth = qMax(cellStyle.bottomBorderWidth(), bottomBorderWidth);
- }
- col += cell.columnSpan(); // Skip across column spans.
- }
- }
-}
-
-void KoTextLayoutTableArea::nukeRow(TableIterator *cursor)
-{
- for (int column = 0; column < d->table->columns(); ++column) {
- delete d->cellAreas[cursor->row][column];
- d->cellAreas[cursor->row][column] = 0;
- delete cursor->frameIterators[column];
- cursor->frameIterators[column] = 0;
- }
- d->lastRowHasSomething = false;
-}
-
-bool KoTextLayoutTableArea::layoutRow(TableIterator *cursor, qreal topBorderWidth, qreal bottomBorderWidth)
-{
- int row = cursor->row;
-
- Q_ASSERT(row >= 0);
- Q_ASSERT(row < d->table->rows());
-
- QTextTableFormat tableFormat = d->table->format();
-
- /*
- * Implementation Note:
- *
- * An undocumented behavior of QTextTable::cellAt is that requesting a
- * cell that is covered by a spanning cell will return the cell that
- * spans over the requested cell. Example:
- *
- * +------------+------------+
- * | | |
- * | | |
- * | +------------+
- * | | |
- * | | |
- * +------------+------------+
- *
- * table.cellAt(1, 0).row() // Will return 0.
- *
- * In the code below, we rely on this behavior to determine whether
- * a cell "vertically" ends in the current row, as those are the only
- * cells that should contribute to the row height.
- */
-
- KoTableRowStyle rowStyle = d->carsManager.rowStyle(row);
- qreal rowHeight = rowStyle.rowHeight();
- bool rowHasExactHeight = rowStyle.hasProperty(KoTableRowStyle::RowHeight);
- qreal rowBottom;
- if (rowHasExactHeight) {
- rowBottom = d->rowPositions[row] + rowHeight;
- } else {
- rowBottom = d->rowPositions[row] + rowStyle.minimumRowHeight();
- }
-
- if (rowBottom > maximumAllowedBottom()) {
- d->rowPositions[row+1] = d->rowPositions[row];
- if (cursor->row > d->startOfArea->row) {
- cursor->row--;
- layoutMergedCellsNotEnding(cursor, topBorderWidth, bottomBorderWidth, rowBottom);
- cursor->row++;
- }
- return false; // we can't honour minimum or fixed height so don't even try
- }
-
- bool allCellsFullyDone = true;
- bool anyCellTried = false;
- bool noCellsFitted = true;
- int col = 0;
- while (col < d->table->columns()) {
- // Get the cell format.
- QTextTableCell cell = d->table->cellAt(row, col);
-
- if (row == cell.row() + cell.rowSpan() - 1) {
- /*
- * This cell ends vertically in this row, and hence should
- * contribute to the row height.
- */
- bool ignoreMisFittingCell = false;
- KoTableCellStyle cellStyle = d->effectiveCellStyle(cell);
- anyCellTried = true;
-
- qreal maxBottom = maximumAllowedBottom();
-
- qreal requiredRowHeight = cellStyle.bottomPadding() + cellStyle.bottomPadding();
-
- if (rowHasExactHeight) {
- maxBottom = qMin(d->rowPositions[row] + rowHeight, maxBottom);
- }
- maxBottom -= cellStyle.bottomPadding();
-
- qreal areaTop = d->rowPositions[qMax(cell.row(), d->startOfArea->row)] + cellStyle.topPadding();
-
- if (d->collapsing) {
- areaTop += topBorderWidth;
- maxBottom -= bottomBorderWidth;
- requiredRowHeight += bottomBorderWidth + topBorderWidth;
- } else {
- areaTop += cellStyle.topBorderWidth();
- maxBottom -= cellStyle.bottomBorderWidth();
- requiredRowHeight += cellStyle.bottomBorderWidth() + cellStyle.topBorderWidth();
- }
-
- if (rowHasExactHeight && (rowHeight < requiredRowHeight))
- {
- ignoreMisFittingCell = true;
- }
-
- if (maxBottom < areaTop && !ignoreMisFittingCell) {
- d->rowPositions[row+1] = d->rowPositions[row];
- nukeRow(cursor);
- if (cursor->row > d->startOfArea->row) {
- cursor->row--;
- layoutMergedCellsNotEnding(cursor, topBorderWidth, bottomBorderWidth, rowBottom);
- cursor->row++;
- }
- return false; // we can't honour the borders so give up doing row
- }
-
- KoTextLayoutArea *cellArea = new KoTextLayoutArea(this, documentLayout());
- d->cellAreas[cell.row()][cell.column()] = cellArea;
-
- qreal left = d->columnPositions[col] + cellStyle.leftPadding() + cellStyle.leftInnerBorderWidth();
- qreal right = qMax(left, d->columnPositions[col+cell.columnSpan()] - cellStyle.rightPadding() - cellStyle.rightInnerBorderWidth());
-
- cellArea->setReferenceRect(
- left,
- right,
- areaTop,
- maxBottom);
-
- cellArea->setVirginPage(virginPage());
- cellArea->setLayoutEnvironmentResctictions(true, true);
-
- FrameIterator *cellCursor = cursor->frameIterator(col);
-
- bool cellFully = cellArea->layout(cellCursor);
- allCellsFullyDone = allCellsFullyDone && (cellFully || rowHasExactHeight);
-
- noCellsFitted = noCellsFitted && (cellArea->top() >= cellArea->bottom()) && !ignoreMisFittingCell;
-
- if (!rowHasExactHeight) {
- /*
- * Now we know how much height this cell contributes to the row,
- * and can determine whether the row height will grow.
- */
- if (d->collapsing) {
- rowBottom = qMax(cellArea->bottom() + cellStyle.bottomPadding(), rowBottom);
- } else {
- rowBottom = qMax(cellArea->bottom() + cellStyle.bottomPadding() + cellStyle.bottomBorderWidth(), rowBottom);
- }
- rowBottom = qMax(rowBottom, documentLayout()->maxYOfAnchoredObstructions(cell.firstCursorPosition().position(), cell.lastCursorPosition().position()));
- }
-
-
- d->lastRowHasSomething = true; // last row contains something (even if empty)
- }
-
- col += cell.columnSpan(); // Skip across column spans.
-
- }
-
- if (allCellsFullyDone) {
- for (col = 0; col < d->table->columns(); ++col) {
- QTextTableCell cell = d->table->cellAt(row, col);
-
- if (row == cell.row() + cell.rowSpan() - 1) {
- delete cursor->frameIterators[col];
- cursor->frameIterators[col] = 0;
- }
- }
- }
-
- if (noCellsFitted && row <= d->headerRows) {
- d->totalMisFit = true;
- }
-
- if (anyCellTried && noCellsFitted && !rowHasExactHeight && !allCellsFullyDone) {
- d->rowPositions[row+1] = d->rowPositions[row];
- nukeRow(cursor);
- if (cursor->row > d->startOfArea->row) {
- cursor->row--;
- layoutMergedCellsNotEnding(cursor, topBorderWidth, bottomBorderWidth, rowBottom);
- cursor->row++;
- }
- return false; // we can't honour the anything inside so give up doing row
- }
-
- if (!allCellsFullyDone) {
- layoutMergedCellsNotEnding(cursor, topBorderWidth, bottomBorderWidth, rowBottom);
- } else {
- // Cells all ended naturally, so we can now do vertical alignment
- // Stop! Other odf implementors also only do it if all cells are fully done
- col = 0;
- while (col < d->table->columns()) {
- QTextTableCell cell = d->table->cellAt(row, col);
-
- if (row == cell.row() + cell.rowSpan() - 1) {
- // cell ended in this row
- KoTextLayoutArea *cellArea = d->cellAreas[cell.row()][cell.column()];
- KoTableCellStyle cellStyle = d->effectiveCellStyle(cell);
-
- if (cellStyle.alignment() & Qt::AlignBottom) {
- if (true /*FIXME test no page based shapes interfering*/) {
- cellArea->setVerticalAlignOffset(rowBottom - cellArea->bottom());
- }
- }
- if (cellStyle.alignment() & Qt::AlignVCenter) {
- if (true /*FIXME test no page based shapes interfering*/) {
- cellArea->setVerticalAlignOffset((rowBottom - cellArea->bottom()) / 2);
- }
- }
- }
- col += cell.columnSpan(); // Skip across column spans.
- }
- }
-
- // Adjust Y position of NEXT row.
- // This is nice since the outside layout routine relies on the next row having a correct y position
- // the first row y position is set in layout()
- d->rowPositions[row+1] = rowBottom;
-
- return allCellsFullyDone;
-}
-
-bool KoTextLayoutTableArea::layoutMergedCellsNotEnding(TableIterator *cursor, qreal topBorderWidth, qreal bottomBorderWidth, qreal rowBottom)
-{
- Q_UNUSED(topBorderWidth)
- Q_UNUSED(bottomBorderWidth)
-
- // Let's make sure all merged cells in this row, that don't end in this row gets a layout
- int row = cursor->row;
- int col = 0;
- while (col < d->table->columns()) {
- QTextTableCell cell = d->table->cellAt(row, col);
- if (row != cell.row() + cell.rowSpan() - 1) {
- // TODO do all of the following like in layoutRow()
- KoTableCellStyle cellStyle = d->effectiveCellStyle(cell);
-
- KoTextLayoutArea *cellArea = new KoTextLayoutArea(this, documentLayout());
-
- d->cellAreas[cell.row()][cell.column()] = cellArea;
-
- qreal left = d->columnPositions[col] + cellStyle.leftPadding() + cellStyle.leftInnerBorderWidth();
- qreal right = qMax(left, d->columnPositions[col+cell.columnSpan()] - cellStyle.rightPadding() - cellStyle.rightInnerBorderWidth());
-
- cellArea->setReferenceRect(
- left,
- right,
- d->rowPositions[qMax(cell.row(), d->startOfArea->row)] + cellStyle.topPadding() + cellStyle.topBorderWidth(),
- rowBottom - cellStyle.bottomPadding() - cellStyle.bottomBorderWidth());
-
- cellArea->setVirginPage(virginPage());
- cellArea->setLayoutEnvironmentResctictions(true, true);
-
- FrameIterator *cellCursor = cursor->frameIterator(col);
-
- cellArea->layout(cellCursor);
- if (cellArea->top() < cellArea->bottom() && row == d->headerRows) {
- d->totalMisFit = false;
- }
- }
- col += cell.columnSpan(); // Skip across column spans.
- }
- return true;
-}
-
-void KoTextLayoutTableArea::paint(QPainter *painter, const KoTextDocumentLayout::PaintContext &context)
-{
- if (d->startOfArea == 0) // We have not been layouted yet
- return;
-
- int lastRow = d->endOfArea->row;
- if (d->lastRowHasSomething == false) {
- --lastRow;
- }
- if (lastRow < d->startOfArea->row) {
- return; // empty
- }
-
- int firstRow = qMax(d->startOfArea->row, d->headerRows);
-
- // Draw table background
- qreal topY = d->headerRows ? d->rowPositions[0] : d->rowPositions[firstRow];
- QRectF tableRect(d->columnPositions[0], topY, d->tableWidth,
- d->headerRowPositions[d->headerRows] - d->headerRowPositions[0]
- + d->rowPositions[lastRow+1] - d->rowPositions[firstRow]);
-
- painter->fillRect(tableRect, d->table->format().background());
-
- KoTextDocumentLayout::PaintContext cellContext = context;
- QColor tableBackground = context.background;
- if (d->table->format().hasProperty(QTextFormat::BackgroundBrush)) {
- tableBackground = d->table->format().background().color();
- }
-
- // Draw header row backgrounds
- for (int row = 0; row < d->headerRows; ++row) {
- QRectF rowRect(d->columnPositions[0], d->headerRowPositions[row], d->tableWidth, d->headerRowPositions[row+1] - d->headerRowPositions[row]);
-
- KoTableRowStyle rowStyle = d->carsManager.rowStyle(row);
-
- rowRect.translate(0, d->headerOffsetY);
-
- painter->fillRect(rowRect, rowStyle.background());
- }
-
- // Draw plain row backgrounds
- for (int row = firstRow; row <= lastRow; ++row) {
- QRectF rowRect(d->columnPositions[0], d->rowPositions[row], d->tableWidth, d->rowPositions[row+1] - d->rowPositions[row]);
-
- KoTableRowStyle rowStyle = d->carsManager.rowStyle(row);
-
- painter->fillRect(rowRect, rowStyle.background());
- }
-
- QSet<QPair<int, int> > visitedCells;
- // Draw cell backgrounds and contents.
- for (int row = firstRow; row <= lastRow; ++row) {
- for (int column = 0; column < d->table->columns(); ++column) {
- QTextTableCell tableCell = d->table->cellAt(row, column);
-
- int testRow = (row == firstRow ? tableCell.row() : row);
- if (d->cellAreas[testRow][column] && !visitedCells.contains(QPair<int, int>(testRow, column))) {
- cellContext.background = tableBackground;
- QBrush bgBrush = d->effectiveCellStyle(tableCell).background();
- if (bgBrush != Qt::NoBrush) {
- cellContext.background = bgBrush.color();
- }
- paintCell(painter, cellContext, tableCell, d->cellAreas[testRow][column]);
- visitedCells.insert(QPair<int, int>(testRow, column));
- }
- }
- }
-
- painter->translate(0, d->headerOffsetY);
-
- QVector<QLineF> accuBlankBorders;
-
- bool hasAntialiasing = painter->testRenderHint(QPainter::Antialiasing);
-
- // Draw header row cell backgrounds and contents.
- for (int row = 0; row < d->headerRows; ++row) {
- for (int column = 0; column < d->table->columns(); ++column) {
- QTextTableCell tableCell = d->table->cellAt(row, column);
-
- int testRow = row == firstRow ? tableCell.row() : row;
- if (d->cellAreas[testRow][column]) {
- cellContext.background = tableBackground;
- QBrush bgBrush = d->effectiveCellStyle(tableCell).background();
- if (bgBrush != Qt::NoBrush) {
- cellContext.background = bgBrush.color();
- }
- paintCell(painter, cellContext, tableCell, d->cellAreas[testRow][column]);
- }
- }
- }
- // Draw header row cell borders.(need to be second step so nabour cells don't overwrite)
- for (int row = 0; row < d->headerRows; ++row) {
- for (int column = 0; column < d->table->columns(); ++column) {
- QTextTableCell tableCell = d->table->cellAt(row, column);
-
- int testRow = row == firstRow ? tableCell.row() : row;
- if (d->cellAreas[testRow][column]) {
- painter->setRenderHint(QPainter::Antialiasing, true);
- paintCellBorders(painter, context, tableCell, false, lastRow, &accuBlankBorders);
- painter->setRenderHint(QPainter::Antialiasing, hasAntialiasing);
- }
- }
- }
- for (int i = 0; i < accuBlankBorders.size(); ++i) {
- accuBlankBorders[i].translate(0, d->headerOffsetY);
- }
-
- painter->translate(0, -d->headerOffsetY);
-
- // Draw cell borders.
- bool topRow = !d->headerRows && firstRow != 0; // are we top row in this area
-
- painter->setRenderHint(QPainter::Antialiasing, true);
- visitedCells.clear();
- for (int row = firstRow; row <= lastRow; ++row) {
- for (int column = 0; column < d->table->columns(); ++column) {
- QTextTableCell tableCell = d->table->cellAt(row, column);
-
- int testRow = row == firstRow ? tableCell.row() : row;
- if (d->cellAreas[testRow][column] && !visitedCells.contains(QPair<int, int>(testRow, column))) {
- paintCellBorders(painter, context, tableCell, topRow, lastRow, &accuBlankBorders);
- visitedCells.insert(QPair<int, int>(testRow, column));
- }
- }
- topRow = false;
- }
-
- painter->setRenderHint(QPainter::Antialiasing, hasAntialiasing);
-
- if (context.showTableBorders) {
- QPen pen(painter->pen());
- painter->setPen(QPen(QColor(0,0,0,96)));
- painter->drawLines(accuBlankBorders);
- painter->setPen(pen);
- }
-}
-
-void KoTextLayoutTableArea::paintCell(QPainter *painter, const KoTextDocumentLayout::PaintContext &context, const QTextTableCell &tableCell, KoTextLayoutArea *frameArea)
-{
- int row = tableCell.row();
- int column = tableCell.column();
-
- // This is an actual cell we want to draw, and not a covered one.
- QRectF bRect(cellBoundingRect(tableCell));
-
- painter->save();
- painter->setClipRect(bRect, Qt::IntersectClip);
-
- // Possibly paint the background of the cell
- QBrush background(d->effectiveCellStyle(tableCell).background());
- if (background != Qt::NoBrush) {
- painter->fillRect(bRect, background);
- }
-
- // Possibly paint the selection of the entire cell
- if (context.showSelections) {
- Q_FOREACH (const QAbstractTextDocumentLayout::Selection & selection, context.textContext.selections) {
- QTextTableCell startTableCell = d->table->cellAt(selection.cursor.selectionStart());
- QTextTableCell endTableCell = d->table->cellAt(selection.cursor.selectionEnd());
-
- if (startTableCell.isValid() && startTableCell != endTableCell) {
- int selectionRow;
- int selectionColumn;
- int selectionRowSpan;
- int selectionColumnSpan;
- selection.cursor.selectedTableCells(&selectionRow, &selectionRowSpan, &selectionColumn, &selectionColumnSpan);
- if (row >= selectionRow && column>=selectionColumn
- && row < selectionRow + selectionRowSpan
- && column < selectionColumn + selectionColumnSpan) {
- painter->fillRect(bRect, selection.format.background());
- }
- } else if (selection.cursor.selectionStart() < d->table->firstPosition()
- && selection.cursor.selectionEnd() > d->table->lastPosition()) {
- painter->fillRect(bRect, selection.format.background());
- }
- }
- }
-
- if (row < d->headerRows) {
- painter->translate(d->headerOffsetX, 0);
- }
-
- // Paint the content of the cellArea
- frameArea->paint(painter, context);
-
- painter->restore();
-}
-
-void KoTextLayoutTableArea::paintCellBorders(QPainter *painter, const KoTextDocumentLayout::PaintContext &context, const QTextTableCell &tableCell, bool topRow, int lastRow, QVector<QLineF> *accuBlankBorders)
-{
- Q_UNUSED(context);
-
- int row = tableCell.row();
- int column = tableCell.column();
-
- // This is an actual cell we want to draw, and not a covered one.
- KoTableCellStyle cellStyle = d->effectiveCellStyle(tableCell);
- KoTextLayoutCellHelper cellStyleHelper(cellStyle);
-
- QRectF bRect = cellBoundingRect(tableCell);
-
- if (d->collapsing) {
- // First the horizontal borders
- if (row == 0) {
- cellStyleHelper.drawTopHorizontalBorder(*painter, bRect.x(), bRect.y(), bRect.width(), accuBlankBorders);
- }
- if (topRow && row != 0) {
- // in collapsing mode we need to also paint the top border of the area
- int c = column;
- while (c < column + tableCell.columnSpan()) {
- QTextTableCell tableCellAbove = d->table->cellAt(row - 1, c);
- QRectF aboveBRect = cellBoundingRect(tableCellAbove);
- qreal x = qMax(bRect.x(), aboveBRect.x());
- qreal x2 = qMin(bRect.right(), aboveBRect.right());
- KoTableCellStyle cellAboveStyle = d->effectiveCellStyle(tableCellAbove);
- KoTextLayoutCellHelper cellAboveStyleHelper(cellAboveStyle);
- cellAboveStyleHelper.drawSharedHorizontalBorder(*painter, cellStyle, x, bRect.y(), x2 - x, accuBlankBorders);
- c = tableCellAbove.column() + tableCellAbove.columnSpan();
- }
- }
- if (row + tableCell.rowSpan() == d->table->rows()) {
- // we hit the bottom of the table so just draw the bottom border
- cellStyleHelper.drawBottomHorizontalBorder(*painter, bRect.x(), bRect.bottom(), bRect.width(), accuBlankBorders);
- } else {
- int c = column;
- while (c < column + tableCell.columnSpan()) {
- QTextTableCell tableCellBelow = d->table->cellAt(row == d->headerRows - 1 ?
- d->startOfArea->row : row + tableCell.rowSpan(), c);
- QRectF belowBRect = cellBoundingRect(tableCellBelow);
- qreal x = qMax(bRect.x(), belowBRect.x());
- qreal x2 = qMin(bRect.right(), belowBRect.right());
- KoTableCellStyle cellBelowStyle = d->effectiveCellStyle(tableCellBelow);
- cellStyleHelper.drawSharedHorizontalBorder(*painter, cellBelowStyle, x, bRect.bottom(), x2 - x, accuBlankBorders);
- c = tableCellBelow.column() + tableCellBelow.columnSpan();
- }
- }
-
- // And then the same treatment for vertical borders
- if (column == 0) {
- cellStyleHelper.drawLeftmostVerticalBorder(*painter, bRect.x(), bRect.y(), bRect.height() + cellStyle.bottomOuterBorderWidth(), accuBlankBorders);
- }
- if (column + tableCell.columnSpan() == d->table->columns()) {
- // we hit the rightmost edge of the table so draw the rightmost border
- cellStyleHelper.drawRightmostVerticalBorder(*painter, bRect.right(), bRect.y(), bRect.height() + cellStyle.bottomOuterBorderWidth(), accuBlankBorders);
- } else {
- // we have cells to the right so draw sharedborders
- int r = row;
- while (r < row + tableCell.rowSpan() && r <= lastRow) {
- QTextTableCell tableCellRight = d->table->cellAt(r, column + tableCell.columnSpan());
- KoTableCellStyle cellRightStyle = d->effectiveCellStyle(tableCellRight);
- QRectF rightBRect = cellBoundingRect(tableCellRight);
- qreal y = qMax(bRect.y(), rightBRect.y());
- qreal y2 = qMin(bRect.bottom() + cellStyle.bottomOuterBorderWidth(), rightBRect.bottom() + cellRightStyle.bottomOuterBorderWidth());
- cellStyleHelper.drawSharedVerticalBorder(*painter, cellRightStyle, bRect.right(), y, y2-y, accuBlankBorders);
- r = tableCellRight.row() + tableCellRight.rowSpan();
- }
- }
-
- // Paint diagonal borders for current cell
- cellStyleHelper.paintDiagonalBorders(*painter, bRect);
- } else { // separating border model
- cellStyleHelper.paintBorders(*painter, bRect, accuBlankBorders);
- }
-}
-
-QRectF KoTextLayoutTableArea::cellBoundingRect(const QTextTableCell &cell) const
-{
- int row = cell.row();
- int rowSpan = cell.rowSpan();
- const int column = cell.column();
- const int columnSpan = cell.columnSpan();
- const qreal width = d->columnPositions[column + columnSpan] - d->columnPositions[column];
-
- if (row >= d->headerRows) {
- int lastRow = d->endOfArea->row;
- if (d->lastRowHasSomething == false) {
- --lastRow;
- }
- if (lastRow < d->startOfArea->row) {
- return QRectF(); // empty
- }
-
- // Limit cell to within the area
- if (row < d->startOfArea->row) {
- rowSpan -= d->startOfArea->row - row;
- row += d->startOfArea->row - row;
- }
- if (row + rowSpan - 1 > lastRow) {
- rowSpan = lastRow - row + 1;
- }
- const qreal height = d->rowPositions[row + rowSpan] - d->rowPositions[row];
- return QRectF(d->columnPositions[column], d->rowPositions[row], width, height);
- } else {
- return QRectF(d->columnPositions[column], d->headerRowPositions[row], width, d->headerRowPositions[row + rowSpan] - d->headerRowPositions[row]);
- }
-}
diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutTableArea.h b/plugins/flake/textshape/textlayout/KoTextLayoutTableArea.h
deleted file mode 100644
index d376804cbc..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextLayoutTableArea.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 C. Boemann <cbo@kogmbh.com>
- *
- * 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 KOTEXTLAYOUTTABLEAREA_H
-#define KOTEXTLAYOUTTABLEAREA_H
-
-#include "kritatextlayout_export.h"
-
-#include "KoTextLayoutArea.h"
-
-#include <QVector>
-
-class KoPointedAt;
-class TableIterator;
-class QTextTableCell;
-class QLineF;
-
-/**
- * This class represent a (full width) piece of a table
- */
-class KRITATEXTLAYOUT_EXPORT KoTextLayoutTableArea : public KoTextLayoutArea
-{
-public:
- /// constructor
- explicit KoTextLayoutTableArea(QTextTable *table, KoTextLayoutArea *parent, KoTextDocumentLayout *documentLayout);
- ~KoTextLayoutTableArea() override;
-
- /// Layouts as much as it can
- /// Returns true if it has reached the end of the table
- bool layoutTable(TableIterator *cursor);
-
- void paint(QPainter *painter, const KoTextDocumentLayout::PaintContext &context);
-
- KoPointedAt hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const;
-
- /// Calc a bounding box rect of the selection
- QRectF selectionBoundingBox(QTextCursor &cursor) const;
-
-private:
- void layoutColumns();
- void collectBorderThicknesss(int row, qreal &topBorderWidth, qreal &bottomBorderWidth);
- void nukeRow(TableIterator *cursor);
- bool layoutRow(TableIterator *cursor, qreal topBorderWidth, qreal bottomBorderWidth);
- bool layoutMergedCellsNotEnding(TableIterator *cursor, qreal topBorderWidth, qreal bottomBorderWidth, qreal rowBottom);
- QRectF cellBoundingRect(const QTextTableCell &cell) const;
- void paintCell(QPainter *painter, const KoTextDocumentLayout::PaintContext &context, const QTextTableCell &tableCell, KoTextLayoutArea *frameArea);
- void paintCellBorders(QPainter *painter, const KoTextDocumentLayout::PaintContext &context, const QTextTableCell &tableCell, bool topRow, int maxRow, QVector<QLineF> *accuBlankBorders);
-
- class Private;
- Private * const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/KoTextShapeContainerModel.cpp b/plugins/flake/textshape/textlayout/KoTextShapeContainerModel.cpp
deleted file mode 100644
index 43fc529794..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextShapeContainerModel.cpp
+++ /dev/null
@@ -1,240 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007,2009,2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2010 C. Boemann <cbo@kogmbh.com>
- *
- * 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 "KoTextShapeContainerModel.h"
-
-#include "KoAnchorInlineObject.h"
-#include "KoTextShapeData.h"
-#include "KoShapeContainer.h"
-
-#include <QTextBlock>
-#include <QTextLayout>
-#include <QTextLine>
-#include <QTextDocument>
-
-#include <TextLayoutDebug.h>
-
-struct Relation
-{
- Relation(KoShape *shape = 0)
- : child(shape),
- anchor(0),
- nested(false),
- inheritsTransform(false)
- {
- }
- KoShape *child;
- KoShapeAnchor *anchor;
- uint nested : 1;
- uint inheritsTransform :1;
-};
-
-class Q_DECL_HIDDEN KoTextShapeContainerModel::Private
-{
-public:
- QHash<const KoShape*, Relation> children;
- QList<KoShapeAnchor *> shapeRemovedAnchors;
-};
-
-KoTextShapeContainerModel::KoTextShapeContainerModel()
- : d(new Private())
-{
-}
-
-KoTextShapeContainerModel::~KoTextShapeContainerModel()
-{
- delete d;
-}
-
-void KoTextShapeContainerModel::add(KoShape *child)
-{
- if (d->children.contains(child))
- return;
- Relation relation(child);
- d->children.insert(child, relation);
-
- KoShapeAnchor *toBeAddedAnchor = 0;
- foreach (KoShapeAnchor *anchor, d->shapeRemovedAnchors) {
- if (child == anchor->shape()) {
- toBeAddedAnchor = anchor;
- break;
- }
- }
-
- if (toBeAddedAnchor) {
- addAnchor(toBeAddedAnchor);
- d->shapeRemovedAnchors.removeAll(toBeAddedAnchor);
- }
-}
-
-void KoTextShapeContainerModel::remove(KoShape *child)
-{
- Relation relation = d->children.value(child);
- d->children.remove(child);
- if (relation.anchor) {
- relation.anchor->placementStrategy()->detachFromModel();
- d->shapeRemovedAnchors.append(relation.anchor);
- }
-}
-
-void KoTextShapeContainerModel::setClipped(const KoShape *child, bool clipping)
-{
- Q_ASSERT(d->children.contains(child));
- d->children[child].nested = clipping;
-}
-
-bool KoTextShapeContainerModel::isClipped(const KoShape *child) const
-{
- Q_ASSERT(d->children.contains(child));
- return d->children[child].nested;
-}
-
-void KoTextShapeContainerModel::setInheritsTransform(const KoShape *shape, bool inherit)
-{
- Q_ASSERT(d->children.contains(shape));
- d->children[shape].inheritsTransform = inherit;
-}
-
-bool KoTextShapeContainerModel::inheritsTransform(const KoShape *shape) const
-{
- Q_ASSERT(d->children.contains(shape));
- return d->children[shape].inheritsTransform;
-}
-
-
-int KoTextShapeContainerModel::count() const
-{
- return d->children.count();
-}
-
-QList<KoShape*> KoTextShapeContainerModel::shapes() const
-{
- QList<KoShape*> answer;
- answer.reserve(d->children.count());
- foreach (const Relation &relation, d->children) {
- answer << relation.child;
- }
- return answer;
-}
-
-void KoTextShapeContainerModel::containerChanged(KoShapeContainer *container, KoShape::ChangeType type)
-{
- Q_UNUSED(container);
- Q_UNUSED(type);
-}
-
-void KoTextShapeContainerModel::childChanged(KoShape *child, KoShape::ChangeType type)
-{
- if (((type == KoShape::RotationChanged ||
- type == KoShape::ScaleChanged ||
- type == KoShape::ShearChanged ||
- type == KoShape::ClipPathChanged ||
- type == KoShape::ClipMaskChanged ||
- type == KoShape::PositionChanged ||
- type == KoShape::SizeChanged) && child->textRunAroundSide() != KoShape::RunThrough) ||
- type == KoShape::TextRunAroundChanged) {
-
- relayoutInlineObject(child);
- }
- KoShapeContainerModel::childChanged( child, type );
-}
-
-void KoTextShapeContainerModel::addAnchor(KoShapeAnchor *anchor)
-{
- Q_ASSERT(anchor);
- Q_ASSERT(anchor->shape());
- Q_ASSERT(d->children.contains(anchor->shape()));
- d->children[anchor->shape()].anchor = anchor;
-}
-
-void KoTextShapeContainerModel::removeAnchor(KoShapeAnchor *anchor)
-{
- if (d->children.contains(anchor->shape())) {
- d->children[anchor->shape()].anchor = 0;
- d->shapeRemovedAnchors.removeAll(anchor);
- }
-}
-
-void KoTextShapeContainerModel::proposeMove(KoShape *child, QPointF &move)
-{
- if (!d->children.contains(child))
- return;
- Relation relation = d->children.value(child);
- if (relation.anchor == 0)
- return;
-
- QPointF newPosition = child->position() + move/* + relation.anchor->offset()*/;
- const QRectF parentShapeRect(QPointF(0, 0), child->parent()->size());
-//warnTextLayout <<"proposeMove:" /*<< move <<" |"*/ << newPosition <<" |" << parentShapeRect;
-
- QTextLayout *layout = 0;
- int anchorPosInParag = -1;
-
- if (relation.anchor->anchorType() == KoShapeAnchor::AnchorAsCharacter) {
- int posInDocument = relation.anchor->textLocation()->position();
- const QTextDocument *document = relation.anchor->textLocation()->document();
- QTextBlock block = document->findBlock(posInDocument);
- layout = block.layout();
- anchorPosInParag = posInDocument - block.position();
- if (layout) {
- QTextLine tl = layout->lineForTextPosition(anchorPosInParag);
- Q_ASSERT(tl.isValid());
- relation.anchor->setOffset(QPointF(newPosition.x() - tl.cursorToX(anchorPosInParag)
- + tl.x(), 0));
- relayoutInlineObject(child);
- }
-
- // the rest of the code uses the shape baseline, at this time the bottom. So adjust
- newPosition.setY(newPosition.y() + child->size().height());
- if (layout == 0) {
- QTextBlock block = document->findBlock(posInDocument);
- layout = block.layout();
- anchorPosInParag = posInDocument - block.position();
- }
- if (layout->lineCount() > 0) {
- KoTextShapeData *data = qobject_cast<KoTextShapeData*>(child->parent()->userData());
- Q_ASSERT(data);
- QTextLine tl = layout->lineForTextPosition(anchorPosInParag);
- Q_ASSERT(tl.isValid());
- qreal y = tl.y() - data->documentOffset() - newPosition.y() + child->size().height();
- relation.anchor->setOffset(QPointF(relation.anchor->offset().x(), -y));
- relayoutInlineObject(child);
- }
- } else {
- //TODO pavolk: handle position type change: absolute to relative, etc ..
- child->setPosition(newPosition);
- relation.anchor->setOffset(relation.anchor->offset() + move);
- relayoutInlineObject(child);
- }
-
- move.setX(0); // let the text layout move it.
- move.setY(0);
-}
-
-void KoTextShapeContainerModel::relayoutInlineObject(KoShape *child)
-{
- if (child == 0) {
- return;
- }
- KoTextShapeData *data = qobject_cast<KoTextShapeData*>(child->parent()->userData());
- Q_ASSERT(data);
- data->setDirty();
-}
-
diff --git a/plugins/flake/textshape/textlayout/KoTextShapeContainerModel.h b/plugins/flake/textshape/textlayout/KoTextShapeContainerModel.h
deleted file mode 100644
index 99ec92c35a..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextShapeContainerModel.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2007 Thomas Zander <zander@kde.org>
- *
- * 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 KOTEXTSHAPECONTAINERMODEL_H
-#define KOTEXTSHAPECONTAINERMODEL_H
-
-#include <KoShapeContainerModel.h>
-
-#include "kritatextlayout_export.h"
-
-class KoShapeAnchor;
-class KoShapeContainer;
-
-/**
- * A model to position children of the text shape.
- * All anchored frames are children of the text shape, and they get positioned
- * by the text layouter.
- */
-class KRITATEXTLAYOUT_EXPORT KoTextShapeContainerModel : public KoShapeContainerModel
-{
-public:
- /// constructor
- KoTextShapeContainerModel();
- ~KoTextShapeContainerModel() override;
-
- /// reimplemented from KoShapeContainerModel
- void add(KoShape *child) override;
- /// reimplemented from KoShapeContainerModel
- void remove(KoShape *child) override;
- /// reimplemented from KoShapeContainerModel
- void setClipped(const KoShape *child, bool clipping) override;
- /// reimplemented from KoShapeContainerModel
- bool isClipped(const KoShape *child) const override;
- /// reimplemented from KoShapeContainerModel
- int count() const override;
- /// reimplemented from KoShapeContainerModel
- QList<KoShape*> shapes() const override;
- /// reimplemented from KoShapeContainerModel
- void containerChanged(KoShapeContainer *container, KoShape::ChangeType type) override;
- /// reimplemented from KoShapeContainerModel
- void proposeMove(KoShape *child, QPointF &move) override;
- /// reimplemented from KoShapeContainerModel
- void childChanged(KoShape *child, KoShape::ChangeType type) override;
- /// reimplemented from KoShapeContainerModel
- void setInheritsTransform(const KoShape *shape, bool inherit) override;
- /// reimplemented from KoShapeContainerModel
- bool inheritsTransform(const KoShape *shape) const override;
-
- /// each child that is added due to being anchored in the text has an anchor; register it for rules based placement.
- void addAnchor(KoShapeAnchor *anchor);
- /// When a shape is removed or stops being anchored, remove it.
- void removeAnchor(KoShapeAnchor *anchor);
-
-private:
- // reset child position and relayout shape to which this shape is linked
- void relayoutInlineObject(KoShape *child);
-
- class Private;
- Private * const d;
-};
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/KoTextShapeData.cpp b/plugins/flake/textshape/textlayout/KoTextShapeData.cpp
deleted file mode 100644
index 83858fc6b7..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextShapeData.cpp
+++ /dev/null
@@ -1,406 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006, 2009-2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- * Copyright (C) 2011 C. Boemann <cbo@boemann.dk>
- *
- * 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 "KoTextShapeData.h"
-
-#include <KoTextShapeDataBase.h>
-#include <KoTextShapeDataBase_p.h>
-#include "KoTextDocument.h"
-#include <KoTextEditor.h>
-#include "styles/KoStyleManager.h"
-#include "styles/KoParagraphStyle.h"
-
-#include <KoTextLayoutRootArea.h>
-
-#include <QTextDocument>
-#include <QTextBlock>
-#include <QTextCursor>
-
-#include <KoGenStyle.h>
-#include <KoOdfLoadingContext.h>
-#include <KoOdfStylesReader.h>
-#include <KoShapeLoadingContext.h>
-#include <KoShapeSavingContext.h>
-#include <KoDocumentRdfBase.h>
-#include <KoStyleStack.h>
-#include <KoShape.h>
-#include <KoUnit.h>
-
-#include <KoXmlNS.h>
-
-#include "KoTextPage.h"
-
-#include "opendocument/KoTextLoader.h"
-#include "opendocument/KoTextWriter.h"
-
-#include <TextLayoutDebug.h>
-
-class KoTextShapeDataPrivate : public KoTextShapeDataBasePrivate
-{
-public:
- KoTextShapeDataPrivate()
- : topPadding(0)
- , leftPadding(0)
- , rightPadding(0)
- , bottomPadding(0)
- , direction(KoText::AutoDirection)
- , rootArea(0)
- {
- }
-
- KoTextShapeDataPrivate(const KoTextShapeDataPrivate &rhs)
- : KoTextShapeDataBasePrivate(rhs),
- topPadding(rhs.topPadding),
- leftPadding(rhs.leftPadding),
- rightPadding(rhs.rightPadding),
- bottomPadding(rhs.bottomPadding),
- direction(rhs.direction),
- rootArea(0), // root area will be reset manually by the provider
- paragraphStyle(rhs.paragraphStyle->clone())
- {
- }
-
- ~KoTextShapeDataPrivate() override
- {
- }
-
- qreal topPadding;
- qreal leftPadding;
- qreal rightPadding;
- qreal bottomPadding;
- KoText::Direction direction;
- KoTextLayoutRootArea *rootArea;
- QScopedPointer<KoParagraphStyle> paragraphStyle; // the paragraph style of the shape (part of the graphic style)
-};
-
-
-KoTextShapeData::KoTextShapeData()
- : KoTextShapeDataBase(new KoTextShapeDataPrivate())
-{
- setDocument(new QTextDocument);
-}
-
-KoTextShapeData::KoTextShapeData(KoTextShapeDataPrivate *dd)
- : KoTextShapeDataBase(dd)
-{
- if (dd->document) {
- setDocument(dd->document.data());
- }
-
-}
-
-KoTextShapeData::~KoTextShapeData()
-{
-}
-
-KoShapeUserData *KoTextShapeData::clone() const
-{
- Q_D(const KoTextShapeData);
- return new KoTextShapeData(new KoTextShapeDataPrivate(*d));
-}
-
-void KoTextShapeData::setDocument(QTextDocument *document)
-{
- Q_D(KoTextShapeData);
- Q_ASSERT(document);
-
- // The following avoids the normal case where the glyph metrices are rounded to integers and
- // hinted to the screen by freetype, which you of course don't want for WYSIWYG
- if (! document->useDesignMetrics())
- document->setUseDesignMetrics(true);
-
- KoTextDocument kodoc(document);
-
- if (document->isEmpty() && !document->firstBlock().blockFormat().hasProperty(KoParagraphStyle::StyleId)) { // apply app default style for first parag
- KoStyleManager *sm = kodoc.styleManager();
- if (sm) {
- KoParagraphStyle *defaultStyle = sm->defaultParagraphStyle();
- if (defaultStyle) {
- QTextBlock block = document->begin();
- defaultStyle->applyStyle(block);
- }
- }
- }
-
- // After setting the document (even if not changing it) we need to explicitly set the root area
- // to 0. Otherwise crashes may occur when inserting textshape in words (or resetting document)
- d->rootArea = 0;
-
- if (d->document.data() != document) {
- d->document.reset(document);
-
- if (kodoc.textEditor() == 0) {
- kodoc.setTextEditor(new KoTextEditor(d->document.data()));
- }
- }
-}
-
-qreal KoTextShapeData::documentOffset() const
-{
- Q_D(const KoTextShapeData);
- if (d->rootArea) {
- KoBorder *border = d->rootArea->associatedShape()->border();
- if (border) {
- return d->rootArea->top() - topPadding() - border->borderWidth(KoBorder::TopBorder);
- } else {
- return d->rootArea->top() - topPadding();
- }
- } else {
- return 0.0;
- }
-}
-
-void KoTextShapeData::setDirty()
-{
- Q_D(KoTextShapeData);
- if (d->rootArea) {
- d->rootArea->setDirty();
- }
-}
-
-
-bool KoTextShapeData::isDirty() const
-{
- Q_D(const KoTextShapeData);
- if (d->rootArea) {
- return d->rootArea->isDirty();
- }
- return true;
-}
-
-void KoTextShapeData::setPageDirection(KoText::Direction direction)
-{
- Q_D(KoTextShapeData);
- d->direction = direction;
-}
-
-KoText::Direction KoTextShapeData::pageDirection() const
-{
- Q_D(const KoTextShapeData);
- return d->direction;
-}
-
-void KoTextShapeData::setRootArea(KoTextLayoutRootArea *rootArea)
-{
- Q_D(KoTextShapeData);
- d->rootArea = rootArea;
-}
-
-KoTextLayoutRootArea *KoTextShapeData::rootArea()
-{
- Q_D(const KoTextShapeData);
- return d->rootArea;
-}
-
-void KoTextShapeData::setLeftPadding(qreal padding)
-{
- Q_D(KoTextShapeData);
- d->leftPadding = padding;
-}
-
-qreal KoTextShapeData::leftPadding() const
-{
- Q_D(const KoTextShapeData);
- return d->leftPadding;
-}
-
-void KoTextShapeData::setTopPadding(qreal padding)
-{
- Q_D(KoTextShapeData);
- d->topPadding = padding;
-}
-
-qreal KoTextShapeData::topPadding() const
-{
- Q_D(const KoTextShapeData);
- return d->topPadding;
-}
-
-void KoTextShapeData::setRightPadding(qreal padding)
-{
- Q_D(KoTextShapeData);
- d->rightPadding = padding;
-}
-
-qreal KoTextShapeData::rightPadding() const
-{
- Q_D(const KoTextShapeData);
- return d->rightPadding;
-}
-
-void KoTextShapeData::setBottomPadding(qreal padding)
-{
- Q_D(KoTextShapeData);
- d->bottomPadding = padding;
-}
-
-qreal KoTextShapeData::bottomPadding() const
-{
- Q_D(const KoTextShapeData);
- return d->bottomPadding;
-}
-
-void KoTextShapeData::setPadding(qreal padding)
-{
- setLeftPadding(padding);
- setTopPadding(padding);
- setRightPadding(padding);
- setBottomPadding(padding);
-}
-
-bool KoTextShapeData::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context, KoDocumentRdfBase *rdfData, KoShape *shape)
-{
- Q_UNUSED(rdfData);
- KoTextLoader loader(context, shape);
-
- QTextCursor cursor(document());
- loader.loadBody(element, cursor); // now let's load the body from the ODF KoXmlElement.
- KoTextEditor *editor = KoTextDocument(document()).textEditor();
- if (editor) { // at one point we have to get the position from the odf doc instead.
- editor->setPosition(0);
- }
-
- return true;
-}
-
-void KoTextShapeData::saveOdf(KoShapeSavingContext &context, KoDocumentRdfBase *rdfData, int from, int to) const
-{
- Q_D(const KoTextShapeData);
-
- KoTextWriter::saveOdf(context, rdfData, d->document.data(), from, to);
-}
-
-void KoTextShapeData::loadStyle(const KoXmlElement &element, KoShapeLoadingContext &context)
-{
- Q_D(KoTextShapeData);
- // load the (text) style of the frame
- const KoXmlElement *style = 0;
- if (element.hasAttributeNS(KoXmlNS::draw, "style-name")) {
- style = context.odfLoadingContext().stylesReader().findStyle(
- element.attributeNS(KoXmlNS::draw, "style-name"), "graphic",
- context.odfLoadingContext().useStylesAutoStyles());
- if (!style) {
- warnTextLayout << "graphic style not found:" << element.attributeNS(KoXmlNS::draw, "style-name");
- }
- }
- if (element.hasAttributeNS(KoXmlNS::presentation, "style-name")) {
- style = context.odfLoadingContext().stylesReader().findStyle(
- element.attributeNS(KoXmlNS::presentation, "style-name"), "presentation",
- context.odfLoadingContext().useStylesAutoStyles());
- if (!style) {
- warnTextLayout << "presentation style not found:" << element.attributeNS(KoXmlNS::presentation, "style-name");
- }
- }
-
-
- if (style) {
- KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
- styleStack.save();
- context.odfLoadingContext().addStyles(style, style->attributeNS(KoXmlNS::style, "family", "graphic").toLocal8Bit().constData()); // Load all parents
- styleStack.setTypeProperties("graphic");
- // Spacing (padding)
- const QString paddingLeft(styleStack.property(KoXmlNS::fo, "padding-left" ));
- if (!paddingLeft.isEmpty()) {
- setLeftPadding(KoUnit::parseValue(paddingLeft));
- }
- const QString paddingRight(styleStack.property(KoXmlNS::fo, "padding-right" ));
- if (!paddingRight.isEmpty()) {
- setRightPadding(KoUnit::parseValue(paddingRight));
- }
- const QString paddingTop(styleStack.property(KoXmlNS::fo, "padding-top" ));
- if (!paddingTop.isEmpty()) {
- setTopPadding(KoUnit::parseValue(paddingTop));
- }
- const QString paddingBottom(styleStack.property(KoXmlNS::fo, "padding-bottom" ));
- if (!paddingBottom.isEmpty()) {
- setBottomPadding(KoUnit::parseValue(paddingBottom));
- }
- const QString padding(styleStack.property(KoXmlNS::fo, "padding"));
- if (!padding.isEmpty()) {
- setPadding(KoUnit::parseValue(padding));
- }
- styleStack.restore();
-
- QString family = style->attributeNS(KoXmlNS::style, "family", "graphic");
- KoParagraphStyle *defaultStyle = 0;
- const KoXmlElement *dstyle = context.odfLoadingContext().stylesReader().defaultStyle(family);
- if (dstyle) {
- defaultStyle = new KoParagraphStyle();
- defaultStyle->loadOdf(dstyle, context);
- }
- // graphic styles don't support inheritance yet therefore some additional work is needed here.
- QList<KoParagraphStyle *> paragraphStyles;
- while (style) {
- KoParagraphStyle *pStyle = new KoParagraphStyle();
- pStyle->loadOdf(style, context);
- if (!paragraphStyles.isEmpty()) {
- paragraphStyles.last()->setParentStyle(pStyle);
- }
- paragraphStyles.append(pStyle);
- QString family = style->attributeNS(KoXmlNS::style, "family", "graphic");
- style = context.odfLoadingContext().stylesReader().findStyle(
- style->attributeNS(KoXmlNS::style, "parent-style-name"), family.toLocal8Bit().constData(),
- context.odfLoadingContext().useStylesAutoStyles());
- }
- // rather than setting default style and apply to block we just set a final parent
- paragraphStyles.last()->setParentStyle(defaultStyle);
-
- QTextDocument *document = this->document();
- QTextCursor cursor(document);
- QTextBlockFormat format;
- paragraphStyles.first()->applyStyle(format);
- cursor.setBlockFormat(format);
- QTextCharFormat cformat;
- paragraphStyles.first()->KoCharacterStyle::applyStyle(cformat);
- cursor.setCharFormat(cformat);
- cursor.setBlockCharFormat(cformat);
-
- d->paragraphStyle.reset(new KoParagraphStyle(format, cformat));
- qDeleteAll(paragraphStyles);
- delete defaultStyle;
- }
-}
-
-void KoTextShapeData::saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const
-{
- if ((leftPadding() == rightPadding()) && (topPadding() == bottomPadding()) && (rightPadding() == topPadding())) {
- style.addPropertyPt("fo:padding", leftPadding(), KoGenStyle::GraphicType);
- } else {
- if (leftPadding()) {
- style.addPropertyPt("fo:padding-left", leftPadding(), KoGenStyle::GraphicType);
- }
- if (rightPadding()) {
- style.addPropertyPt("fo:padding-right", rightPadding(), KoGenStyle::GraphicType);
- }
- if (topPadding()) {
- style.addPropertyPt("fo:padding-top", topPadding(), KoGenStyle::GraphicType);
- }
- if (bottomPadding()) {
- style.addPropertyPt("fo:padding-bottom", bottomPadding(), KoGenStyle::GraphicType);
- }
- }
-
- Q_D(const KoTextShapeData);
- if (d->paragraphStyle) {
- d->paragraphStyle->saveOdf(style, context);
- }
-}
diff --git a/plugins/flake/textshape/textlayout/KoTextShapeData.h b/plugins/flake/textshape/textlayout/KoTextShapeData.h
deleted file mode 100644
index 35edead9f5..0000000000
--- a/plugins/flake/textshape/textlayout/KoTextShapeData.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006, 2009-2010 Thomas Zander <zander@kde.org>
- *
- * 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 KOTEXTSHAPEDATA_H
-#define KOTEXTSHAPEDATA_H
-
-#include "KoText.h"
-#include "kritatextlayout_export.h"
-
-#include <KoTextShapeDataBase.h>
-#include <KoXmlReaderForward.h>
-
-class QTextDocument;
-class KoShapeLoadingContext;
-class KoShapeSavingContext;
-class KoTextShapeDataPrivate;
-class KoDocumentRdfBase;
-class KoTextLayoutRootArea;
-
-/**
- * The data store that is held by each TextShape instance.
- * This is a separate object to allow Words proper to use this class' API and
- * access the internals of the text shape.
- *
- * This class holds a QTextDocument pointer and is built so multiple shapes (and thus
- * multiple instances of this shape data) can share one QTextDocument by providing a
- * different view on (a different part of) the QTextDocument.
- */
-class KRITATEXTLAYOUT_EXPORT KoTextShapeData : public KoTextShapeDataBase
-{
- Q_OBJECT
-public:
- /// constructor
- KoTextShapeData();
- ~KoTextShapeData() override;
-
- KoShapeUserData* clone() const override;
-
- /**
- * Replace the QTextDocument this shape will render.
- * @param document the new document. If there was an old document owned, it will be deleted.
- */
- void setDocument(QTextDocument *document);
-
- /**
- * return the amount of points into the document (y) this shape will display.
- */
- qreal documentOffset() const;
-
- /// mark shape as dirty triggering a re-layout of its text.
- void setDirty();
-
- /// return if the shape is marked dirty and its text content needs to be relayout
- bool isDirty() const;
-
- /// Set the rootArea that is associated to the textshape
- void setRootArea(KoTextLayoutRootArea *rootArea);
-
- /// the rootArea that is associated to the textshape
- KoTextLayoutRootArea *rootArea();
-
- void setLeftPadding(qreal padding);
- qreal leftPadding() const;
- void setTopPadding(qreal padding);
- qreal topPadding() const;
- void setRightPadding(qreal padding);
- qreal rightPadding() const;
- void setBottomPadding(qreal padding);
- qreal bottomPadding() const;
- void setPadding(qreal padding);
-
- /**
- * Load the TextShape from ODF.
- *
- * @see the @a TextShape::loadOdf() method which calls this method.
- * @see the @a KoTextLoader::loadBody() method which got called by this method
- * to load the ODF.
- */
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context, KoDocumentRdfBase *rdfData, KoShape *shape = 0);
-
- /**
- * Load the TextShape from ODF.
- * Overloaded method provided for your convenience.
- */
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override {
- return loadOdf(element, context, 0);
- }
-
- /**
- * Store the TextShape data as ODF.
- * @see TextShape::saveOdf()
- */
- void saveOdf(KoShapeSavingContext &context, KoDocumentRdfBase *rdfData, int from = 0, int to = -1) const;
-
- /**
- * Store the TextShape data as ODF.
- * Overloaded method provided for your convenience.
- */
- void saveOdf(KoShapeSavingContext &context, int from = 0, int to = -1) const override {
- saveOdf(context, 0, from, to);
- }
-
- // reimplemented
- void loadStyle(const KoXmlElement &element, KoShapeLoadingContext &context) override;
-
- // reimplemented
- void saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const override;
-
- /**
- * Set the page direction.
- * The page direction will determine behavior on the insertion of new text and those
- * new paragraphs default direction.
- */
- void setPageDirection(KoText::Direction direction);
- /**
- * Return the direction set on the page.
- * The page direction will determine behavior on the insertion of new text and those
- * new paragraphs default direction.
- */
- KoText::Direction pageDirection() const;
-
-private:
- KoTextShapeData(KoTextShapeDataPrivate *dd);
-
-private:
- Q_DECLARE_PRIVATE(KoTextShapeData)
-};
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/ListItemsHelper.cpp b/plugins/flake/textshape/textlayout/ListItemsHelper.cpp
deleted file mode 100644
index d3b2709dd3..0000000000
--- a/plugins/flake/textshape/textlayout/ListItemsHelper.cpp
+++ /dev/null
@@ -1,503 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2007, 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
- *
- * 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 "ListItemsHelper.h"
-
-#include <KoTextBlockData.h>
-#include <KoParagraphStyle.h>
-#include <KoTextDocument.h>
-#include <KoList.h>
-
-#include <TextLayoutDebug.h>
-#include <klocalizedstring.h>
-#include <QTextList>
-
-using namespace Lists;
-
-QString Lists::intToRoman(int n)
-{
- static const QString RNUnits[] = {"", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix"};
- static const QString RNTens[] = {"", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc"};
- static const QString RNHundreds[] = {"", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm"};
- static const QString RNThousands[] = {"", "m", "mm", "mmm", "mmmm", "mmmmm", "mmmmmm", "mmmmmmm", "mmmmmmmm", "mmmmmmmmm"};
-
- if (n <= 0) {
- warnTextLayout << "intToRoman called with negative number: n=" << n;
- return QString::number(n);
- }
-
- return RNThousands[(n / 1000)] +
- RNHundreds[(n / 100) % 10 ] +
- RNTens[(n / 10) % 10 ] +
- RNUnits[(n) % 10 ];
-}
-
-QString Lists::intToAlpha(int n, Capitalisation caps, bool letterSynchronization)
-{
- const char offset = caps == Uppercase ? 'A' : 'a';
- QString answer;
- if (letterSynchronization) {
- int digits = 1;
- for (; n > 26; n -= 26)
- digits += 1;
- for (int i = 0; i < digits; i++)
- answer.prepend(QChar(offset + n - 1));
- return answer;
- } else {
- char bottomDigit;
- while (n > 26) {
- bottomDigit = (n - 1) % 26;
- n = (n - 1) / 26;
- answer.prepend(QChar(offset + bottomDigit));
- }
- }
- answer.prepend(QChar(offset + n - 1));
- return answer;
-}
-
-QString Lists::intToScript(int n, KoListStyle::Style type)
-{
- // 10-base
- static const int bengali = 0x9e6;
- static const int gujarati = 0xae6;
- static const int gurumukhi = 0xa66;
- static const int kannada = 0xce6;
- static const int malayalam = 0xd66;
- static const int oriya = 0xb66;
- static const int tamil = 0x0be6;
- static const int telugu = 0xc66;
- static const int tibetan = 0xf20;
- static const int thai = 0xe50;
-
- int offset;
- switch (type) {
- case KoListStyle::Bengali:
- offset = bengali;
- break;
- case KoListStyle::Gujarati:
- offset = gujarati;
- break;
- case KoListStyle::Gurumukhi:
- offset = gurumukhi;
- break;
- case KoListStyle::Kannada:
- offset = kannada;
- break;
- case KoListStyle::Malayalam:
- offset = malayalam;
- break;
- case KoListStyle::Oriya:
- offset = oriya;
- break;
- case KoListStyle::Tamil:
- offset = tamil;
- break;
- case KoListStyle::Telugu:
- offset = telugu;
- break;
- case KoListStyle::Tibetan:
- offset = tibetan;
- break;
- case KoListStyle::Thai:
- offset = thai;
- break;
- default:
- return QString::number(n);
- }
- QString answer;
- while (n > 0) {
- answer.prepend(QChar(offset + n % 10));
- n = n / 10;
- }
- return answer;
-}
-
-QString Lists::intToScriptList(int n, KoListStyle::Style type)
-{
- // 1 time Sequences
- // note; the leading X is to make these 1 based.
- static const char* const Abjad[] = { "أ", "ب", "ج", "د", "ﻫ", "و", "ز", "ح", "ط", "ي", "ك", "ل", "م",
- "ن", "س", "ع", "ف", "ص", "ق", "ر", "ش", "ت", "ث", "خ", "ذ", "ض", "ظ", "غ"
- };
- static const char* const Abjad2[] = { "ﺃ", "ﺏ", "ﺝ", "ﺩ", "ﻫ", "ﻭ", "ﺯ", "ﺡ", "ﻁ", "ﻱ", "ﻙ", "ﻝ", "ﻡ",
- "ﻥ", "ﺹ", "ﻉ", "ﻑ", "ﺽ", "ﻕ", "ﺭ", "ﺱ", "ﺕ", "ﺙ", "ﺥ", "ﺫ", "ﻅ", "ﻍ", "ﺵ"
- };
- static const char* const ArabicAlphabet[] = {"ا", "ب", "ت", "ث", "ج", "ح", "خ", "د", "ذ", "ر", "ز",
- "س", "ش", "ص", "ض", "ط", "ظ", "ع", "غ", "ف", "ق", "ك", "ل", "م", "ن", "ه", "و", "ي"
- };
-
- /*
- // see this page for the 10, 100, 1000 etc http://en.wikipedia.org/wiki/Chinese_numerals
- static const char* const chinese1[] = { '零','壹','貳','叄','肆','伍','陸','柒','捌','玖' };
- static const char* const chinese2[] = { '〇','一','二','三','四','五','六','七','八','九' };
-
- TODO: https://en.wikipedia.org/wiki/Korean_numerals
- https://en.wikipedia.org/wiki/Japanese_numerals
- 'https://en.wikipedia.org/wiki/Hebrew_numerals'
- 'https://en.wikipedia.org/wiki/Armenian_numerals'
- 'https://en.wikipedia.org/wiki/Greek_numerals'
- 'https://en.wikipedia.org/wiki/Cyrillic_numerals'
- 'https://en.wikipedia.org/wiki/Sanskrit_numerals'
- 'https://en.wikipedia.org/wiki/Ge%27ez_alphabet#Numerals'
- 'https://en.wikipedia.org/wiki/Abjad_numerals'
- */
-
- switch (type) {
- case KoListStyle::Abjad:
- if (n > 22) return "*";
- return QString::fromUtf8(Abjad[n-1]);
- case KoListStyle::AbjadMinor:
- if (n > 22) return "*";
- return QString::fromUtf8(Abjad2[n-1]);
- case KoListStyle::ArabicAlphabet:
- if (n > 28) return "*";
- return QString::fromUtf8(ArabicAlphabet[n-1]);
- default:
- return QString::number(n);
- }
-}
-
-QString Lists::intToNumberingStyle(int index, KoListStyle::Style listStyle, bool letterSynchronization)
-{
- QString counterText;
- switch(listStyle) {
- case KoListStyle::DecimalItem:
- counterText = QString::number(index);
- break;
- case KoListStyle::AlphaLowerItem:
- counterText = intToAlpha(index, Lowercase, letterSynchronization);
- break;
- case KoListStyle::UpperAlphaItem:
- counterText = intToAlpha(index, Uppercase, letterSynchronization);
- break;
- case KoListStyle::RomanLowerItem:
- counterText = intToRoman(index);
- break;
- case KoListStyle::UpperRomanItem:
- counterText = intToRoman(index).toUpper();
- break;
- case KoListStyle::Bengali:
- case KoListStyle::Gujarati:
- case KoListStyle::Gurumukhi:
- case KoListStyle::Kannada:
- case KoListStyle::Malayalam:
- case KoListStyle::Oriya:
- case KoListStyle::Tamil:
- case KoListStyle::Telugu:
- case KoListStyle::Tibetan:
- case KoListStyle::Thai:
- counterText = intToScript(index, listStyle);
- break;
- case KoListStyle::Abjad:
- case KoListStyle::ArabicAlphabet:
- case KoListStyle::AbjadMinor:
- counterText = intToScriptList(index, listStyle);
- break;
- default:
- counterText = QString::number(index);
- }
-
- return counterText;
-}
-
-QList<ListStyleItem> Lists::genericListStyleItems()
-{
- QList<ListStyleItem> answer;
- answer.append(ListStyleItem(i18nc("Text list-style", "None"), KoListStyle::None));
- answer.append(ListStyleItem(i18n("Small Bullet"), KoListStyle::Bullet));
- answer.append(ListStyleItem(i18n("Circle Bullet"), KoListStyle::CircleItem));
- answer.append(ListStyleItem(i18n("Square Bullet"), KoListStyle::SquareItem));
- answer.append(ListStyleItem(i18n("Rhombus Bullet"), KoListStyle::RhombusItem));
- answer.append(ListStyleItem(i18n("Check Mark Bullet"), KoListStyle::HeavyCheckMarkItem));
- answer.append(ListStyleItem(i18n("Rightwards Arrow Bullet"), KoListStyle::RightArrowItem));
- answer.append(ListStyleItem(i18n("Arabic"), KoListStyle::DecimalItem));
- answer.append(ListStyleItem(i18n("Lower Alphabetical"), KoListStyle::AlphaLowerItem));
- answer.append(ListStyleItem(i18n("Upper Alphabetical"), KoListStyle::UpperAlphaItem));
- answer.append(ListStyleItem(i18n("Lower Roman"), KoListStyle::RomanLowerItem));
- answer.append(ListStyleItem(i18n("Upper Roman"), KoListStyle::UpperRomanItem));
- return answer;
-}
-
-QList<ListStyleItem> Lists::otherListStyleItems()
-{
- QList<ListStyleItem> answer;
- answer.append(ListStyleItem(i18n("Large Bullet"), KoListStyle::BlackCircle));
- answer.append(ListStyleItem(i18n("Ballot X Bullet"), KoListStyle::BallotXItem));
- answer.append(ListStyleItem(i18n("Rightwards Arrow Head Bullet"), KoListStyle::RightArrowHeadItem));
- answer.append(ListStyleItem(i18n("Bengali"), KoListStyle::Bengali));
- answer.append(ListStyleItem(i18n("Gujarati"), KoListStyle::Gujarati));
- answer.append(ListStyleItem(i18n("Gurumukhi"), KoListStyle::Gurumukhi));
- answer.append(ListStyleItem(i18n("Kannada"), KoListStyle::Kannada));
- answer.append(ListStyleItem(i18n("Malayalam"), KoListStyle::Malayalam));
- answer.append(ListStyleItem(i18n("Oriya"), KoListStyle::Oriya));
- answer.append(ListStyleItem(i18n("Tamil"), KoListStyle::Tamil));
- answer.append(ListStyleItem(i18n("Telugu"), KoListStyle::Telugu));
- answer.append(ListStyleItem(i18n("Tibetan"), KoListStyle::Tibetan));
- answer.append(ListStyleItem(i18n("Thai"), KoListStyle::Thai));
- answer.append(ListStyleItem(i18n("Abjad"), KoListStyle::Abjad));
- answer.append(ListStyleItem(i18n("AbjadMinor"), KoListStyle::AbjadMinor));
- answer.append(ListStyleItem(i18n("ArabicAlphabet"), KoListStyle::ArabicAlphabet));
- answer.append(ListStyleItem(i18n("Image"), KoListStyle::ImageItem));
- return answer;
-}
-
-// ------------------- ListItemsHelper ------------
-/// \internal helper class for calculating text-lists prefixes and indents
-ListItemsHelper::ListItemsHelper(QTextList *textList, const QFont &font)
- : m_textList(textList)
- , m_fm(font, textList->document()->documentLayout()->paintDevice())
-{
-}
-
-void ListItemsHelper::recalculateBlock(QTextBlock &block)
-{
- //warnTextLayout;
- const QTextListFormat format = m_textList->format();
- const KoListStyle::Style listStyle = static_cast<KoListStyle::Style>(format.style());
-
- const QString prefix = format.stringProperty(KoListStyle::ListItemPrefix);
- const QString suffix = format.stringProperty(KoListStyle::ListItemSuffix);
- const int level = format.intProperty(KoListStyle::Level);
- int dp = format.intProperty(KoListStyle::DisplayLevel);
- if (dp > level)
- dp = level;
- const int displayLevel = dp ? dp : 1;
-
- QTextBlockFormat blockFormat = block.blockFormat();
-
- // Look if we have a block that is inside a header. We need to special case them cause header-lists are
- // different from any other kind of list and they do build up there own global list (table of content).
- bool isOutline = blockFormat.intProperty(KoParagraphStyle::OutlineLevel) > 0;
-
- int startValue = 1;
- if (format.hasProperty(KoListStyle::StartValue))
- startValue = format.intProperty(KoListStyle::StartValue);
-
- int index = startValue;
- bool fixed = false;
- if (blockFormat.boolProperty(KoParagraphStyle::RestartListNumbering)) {
- index = format.intProperty(KoListStyle::StartValue);
- fixed = true;
- }
- const int paragIndex = blockFormat.intProperty(KoParagraphStyle::ListStartValue);
- if (paragIndex > 0) {
- index = paragIndex;
- fixed = true;
- }
-
- if (!fixed) {
- //if this is the first item then find if the list has to be continued from any other list
- KoList *listContinued = 0;
- if (m_textList->itemNumber(block) == 0 && KoTextDocument(m_textList->document()).list(m_textList) && (listContinued = KoTextDocument(m_textList->document()).list(m_textList)->listContinuedFrom())) {
- //find the previous list of the same level
- QTextList *previousTextList = listContinued->textLists().at(level - 1).data();
- if (previousTextList) {
- QTextBlock textBlock = previousTextList->item(previousTextList->count() - 1);
- if (textBlock.isValid()) {
- index = KoTextBlockData(textBlock).counterIndex() + 1; //resume the previous list count
- }
- }
- } else if (m_textList->itemNumber(block) > 0) {
- QTextBlock textBlock = m_textList->item(m_textList->itemNumber(block) - 1);
- if (textBlock.isValid()) {
- index = KoTextBlockData(textBlock).counterIndex() + 1; //resume the previous list count
- }
- }
- }
-
- qreal width = 0.0;
- KoTextBlockData blockData(block);
-
- if (blockFormat.boolProperty(KoParagraphStyle::UnnumberedListItem)
- || blockFormat.boolProperty(KoParagraphStyle::IsListHeader)) {
- blockData.setCounterPlainText(QString());
- blockData.setCounterPrefix(QString());
- blockData.setCounterSuffix(QString());
- blockData.setPartialCounterText(QString());
- // set the counter for the current un-numbered list to the counter index of the previous list item.
- // index-1 because the list counter would have already incremented by one
- blockData.setCounterIndex(index - 1);
- if (blockFormat.boolProperty(KoParagraphStyle::IsListHeader)) {
- blockData.setCounterWidth(format.doubleProperty(KoListStyle::MinimumWidth));
- blockData.setCounterSpacing(0);
- }
- return;
- }
-
- QString item;
- if (displayLevel > 1) {
- int checkLevel = level;
- int tmpDisplayLevel = displayLevel;
- bool counterResetRequired = true;
- for (QTextBlock b = block.previous(); tmpDisplayLevel > 1 && b.isValid(); b = b.previous()) {
- if (b.textList() == 0)
- continue;
- QTextListFormat lf = b.textList()->format();
- if (lf.property(KoListStyle::StyleId) != format.property(KoListStyle::StyleId))
- continue; // uninteresting for us
- if (isOutline != bool(b.blockFormat().intProperty(KoParagraphStyle::OutlineLevel)))
- continue; // also uninteresting cause the one is an outline-listitem while the other is not
-
- if (! KoListStyle::isNumberingStyle(static_cast<KoListStyle::Style>(lf.style()))) {
- continue;
- }
-
- if (b.blockFormat().boolProperty(KoParagraphStyle::UnnumberedListItem)) {
- continue; //unnumbered listItems are irrelevant
- }
-
- const int otherLevel = lf.intProperty(KoListStyle::Level);
- if (isOutline && checkLevel == otherLevel) {
- counterResetRequired = false;
- }
-
- if (checkLevel <= otherLevel)
- continue;
-
- KoTextBlockData otherData(b);
- if (!otherData.hasCounterData()) {
- continue;
- }
- if (tmpDisplayLevel - 1 < otherLevel) { // can't just copy it fully since we are
- // displaying less then the full counter
- item += otherData.partialCounterText();
- tmpDisplayLevel--;
- checkLevel--;
- for (int i = otherLevel + 1; i < level; i++) {
- tmpDisplayLevel--;
- item += "." + intToNumberingStyle(index, listStyle,
- m_textList->format().boolProperty(KoListStyle::LetterSynchronization)); // add missing counters.
- }
- } else { // just copy previous counter as prefix
- QString otherPrefix = lf.stringProperty(KoListStyle::ListItemPrefix);
- QString otherSuffix = lf.stringProperty(KoListStyle::ListItemSuffix);
- QString pureCounter = otherData.counterText().mid(otherPrefix.size());
- pureCounter = pureCounter.left(pureCounter.size() - otherSuffix.size());
- item += pureCounter;
- for (int i = otherLevel + 1; i < level; i++)
- item += "." + intToNumberingStyle(index, listStyle,
- m_textList->format().boolProperty(KoListStyle::LetterSynchronization)); // add missing counters.
- tmpDisplayLevel = 0;
- if (isOutline && counterResetRequired) {
- index = 1;
- }
- break;
- }
- }
- for (int i = 1; i < tmpDisplayLevel; i++)
- item = intToNumberingStyle(index, listStyle,
- m_textList->format().boolProperty(KoListStyle::LetterSynchronization))
- + "." + item; // add missing counters.
- }
-
- if ((listStyle == KoListStyle::DecimalItem || listStyle == KoListStyle::AlphaLowerItem ||
- listStyle == KoListStyle::UpperAlphaItem ||
- listStyle == KoListStyle::RomanLowerItem ||
- listStyle == KoListStyle::UpperRomanItem) &&
- !(item.isEmpty() || item.endsWith('.') || item.endsWith(' '))) {
- item += '.';
- }
- bool calcWidth = true;
- QString partialCounterText;
- if (KoListStyle::isNumberingStyle(listStyle)) {
- partialCounterText = intToNumberingStyle(index, listStyle,
- m_textList->format().boolProperty(KoListStyle::LetterSynchronization));
- } else {
- switch (listStyle) {
- case KoListStyle::SquareItem:
- case KoListStyle::Bullet:
- case KoListStyle::BlackCircle:
- case KoListStyle::DiscItem:
- case KoListStyle::CircleItem:
- case KoListStyle::HeavyCheckMarkItem:
- case KoListStyle::BallotXItem:
- case KoListStyle::RightArrowItem:
- case KoListStyle::RightArrowHeadItem:
- case KoListStyle::RhombusItem:
- case KoListStyle::BoxItem: {
- calcWidth = false;
- if (format.intProperty(KoListStyle::BulletCharacter))
- item = QString(QChar(format.intProperty(KoListStyle::BulletCharacter)));
- width = m_fm.width(item);
- int percent = format.intProperty(KoListStyle::RelativeBulletSize);
- if (percent > 0)
- width = width * (percent / 100.0);
- break;
- }
- case KoListStyle::CustomCharItem:
- calcWidth = false;
- if (format.intProperty(KoListStyle::BulletCharacter))
- item = QString(QChar(format.intProperty(KoListStyle::BulletCharacter)));
- width = m_fm.width(item);
- break;
- case KoListStyle::None:
- calcWidth = false;
- width = 0.0;
- break;
- case KoListStyle::ImageItem:
- calcWidth = false;
- width = qMax(format.doubleProperty(KoListStyle::Width), (qreal)1.0);
- break;
- default: // others we ignore.
- calcWidth = false;
- }
- }
-
- blockData.setCounterIsImage(listStyle == KoListStyle::ImageItem);
- blockData.setPartialCounterText(partialCounterText);
- blockData.setCounterIndex(index);
- item += partialCounterText;
- blockData.setCounterPlainText(item);
- blockData.setCounterPrefix(prefix);
- blockData.setCounterSuffix(suffix);
- if (calcWidth)
- width = m_fm.width(item);
- index++;
-
- width += m_fm.width(prefix + suffix);
-
- qreal counterSpacing = 0;
- if (format.boolProperty(KoListStyle::AlignmentMode)) {
- // for AlignmentMode spacing should be 0
- counterSpacing = 0;
- } else {
- if (listStyle != KoListStyle::None) {
- // see ODF spec 1.2 item 20.422
- counterSpacing = format.doubleProperty(KoListStyle::MinimumDistance);
- if (width < format.doubleProperty(KoListStyle::MinimumWidth)) {
- counterSpacing -= format.doubleProperty(KoListStyle::MinimumWidth) - width;
- }
- counterSpacing = qMax(counterSpacing, qreal(0.0));
- }
- width = qMax(width, format.doubleProperty(KoListStyle::MinimumWidth));
- }
- blockData.setCounterWidth(width);
- blockData.setCounterSpacing(counterSpacing);
- //warnTextLayout;
-}
-
-// static
-bool ListItemsHelper::needsRecalc(QTextList *textList)
-{
- Q_ASSERT(textList);
- QTextBlock tb = textList->item(0);
- KoTextBlockData blockData(tb);
- return !blockData.hasCounterData();
-}
diff --git a/plugins/flake/textshape/textlayout/ListItemsHelper.h b/plugins/flake/textshape/textlayout/ListItemsHelper.h
deleted file mode 100644
index 478bde1b62..0000000000
--- a/plugins/flake/textshape/textlayout/ListItemsHelper.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
- *
- * 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 LISTITEMSHELPER_H
-#define LISTITEMSHELPER_H
-
-#include "kritatextlayout_export.h"
-
-#include <KoListStyle.h>
-
-#include <QFontMetricsF>
-
-class QTextList;
-class QFont;
-
-namespace Lists
-{
-enum Capitalisation { Lowercase, Uppercase };
-struct ListStyleItem {
- ListStyleItem(const QString &name_, KoListStyle::Style style_) {
- name = name_;
- style = style_;
- }
- KoListStyle::Style style;
- QString name;
-};
-
-KRITATEXTLAYOUT_EXPORT QString intToRoman(int n);
-KRITATEXTLAYOUT_EXPORT QString intToAlpha(int n, Capitalisation caps, bool letterSynchronization);
-KRITATEXTLAYOUT_EXPORT QString intToScript(int n, KoListStyle::Style type);
-KRITATEXTLAYOUT_EXPORT QString intToScriptList(int n, KoListStyle::Style type);
-KRITATEXTLAYOUT_EXPORT QString intToNumberingStyle(int index, KoListStyle::Style listStyle, bool letterSynchronizations);
-
-/// return international list items (bullets/arabic/roman)
-KRITATEXTLAYOUT_EXPORT QList<ListStyleItem> genericListStyleItems();
-/// return non-latin list items (bullets/arabic/roman)
-KRITATEXTLAYOUT_EXPORT QList<ListStyleItem> otherListStyleItems(); // we may want to split this method up into different world regions.
-}
-
-/// \internal helper class for calculating text-lists prefixes and indents
-class ListItemsHelper
-{
-public:
- ListItemsHelper(QTextList *textList, const QFont &font);
- ~ListItemsHelper() {}
- /// is meant to take a QTextList and set the indent plus the string to render on each listitem
- void recalculateBlock(QTextBlock &block);
- static bool needsRecalc(QTextList *textList);
-
-private:
- QTextList *m_textList;
- QFontMetricsF m_fm;
-};
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/Mainpage.dox b/plugins/flake/textshape/textlayout/Mainpage.dox
deleted file mode 100644
index 9563c9ce8b..0000000000
--- a/plugins/flake/textshape/textlayout/Mainpage.dox
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * \mainpage
- *
- * KoText is a library for general use that extends the QText framework
- * (codenamed scribe) with an enhanced text-layout which adds features
- * required by ODF and general word-processing applications.
- *
- * You can use KoText at all places where you would normally use a
- * QTextDocument as the main text layout class in scribe can be replaced
- * on any QTextDocument instance using QTextDocument::setDocumentLayout().
- * This means you can use the Qt API as normal, but you will be
- * able to use extra features like the plugins, the variables and the
- * ODF loading and saving for all the ODF text-layout features.
- *
- * TextShape Flake-Plugin
- *
- * Closely coupled with the kotext library is the text plugin that is
- * build on flake technology. All the user interaction dialogs and code
- * will reside in that plugin, and the actual heavy lifting of the
- * layout also is present only in that plugin. In other words; this
- * library will supply you with the APIs but without having the text
- * shape plugin loaded you can't show or layout the text. The goal is
- * to keep it cheap to link to this library and only provide the bare
- * minimum of functionality is the way to get there. The feature-
- * package will be completed by the optional text-plugin.
- *
- * QTextDocument compatibility
- *
- * The actual content is stored in the QTextDocument, as mentioned before.
- * In KoText we support a lot more features than Qt does in its layout
- * and this library will allow you to enrich your document with those
- * features. The core design goal is that you can use an externally
- * created QTextDocument with KoText. This has the implication that all
- * the extra content is stored inside the document. We add QTextFormat
- * based properties for that as can be seen in the styles (see
- * KoParagraphStyle::Properties for instance), and we allow managers to
- * be stored on the document too. So for example a KoStyleManager will
- * be stored as a property on the QTextDocument and you can access that
- * using the KoTextDocument API. Note that you can use the
- * KoTextDocument class while using only a QTextDocument instance.
- *
- * Plugins
- *
- * There are various plugins for KoText that make it possible for 3rd
- * parties to extend the KoText functionality, see the techbase page;
- * http://techbase.kde.org/Development/Tutorials/Calligra_Overview#Text_Plugins
- *
- * ODF compatibility
- *
- * Loading and saving of documents can be done to and from ODF using the
- * open document classes.
- *
- * Important classes;
- *
- * KoTextDocumentLayout the main layout class to be set on the QTextDocument.
- *
- * KoInlineTextObject plugin base for inline objects (and variables)
- *
- * KoTextEditingPlugin plugin base for text editing plugins.
- *
- * KoText namespace.
- */
-
-// DOXYGEN_SET_PROJECT_NAME = KritaTextLayout
-// DOXYGEN_SET_IGNORE_PREFIX = Ko K
diff --git a/plugins/flake/textshape/textlayout/RunAroundHelper.cpp b/plugins/flake/textshape/textlayout/RunAroundHelper.cpp
deleted file mode 100644
index 4120fedd45..0000000000
--- a/plugins/flake/textshape/textlayout/RunAroundHelper.cpp
+++ /dev/null
@@ -1,312 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2007, 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2010-2011 KO Gmbh <cbo@kogmbh.com>
- *
- * 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 "RunAroundHelper.h"
-
-#include "KoTextLayoutObstruction.h"
-
-#include "KoTextLayoutArea.h"
-
-const qreal RIDICULOUSLY_LARGE_NEGATIVE_INDENT = -5E6;
-#define MIN_WIDTH 0.01f
-
-RunAroundHelper::RunAroundHelper()
-{
- m_lineRect = QRectF();
- m_updateValidObstructions = false;
- m_horizontalPosition = RIDICULOUSLY_LARGE_NEGATIVE_INDENT;
- m_stayOnBaseline = false;
-}
-
-void RunAroundHelper::setLine(KoTextLayoutArea *area, const QTextLine &l) {
- m_area = area;
- line = l;
-}
-
-void RunAroundHelper::setObstructions(const QList<KoTextLayoutObstruction*> &obstructions)
-{
- m_obstructions = obstructions;
-}
-
-bool RunAroundHelper::stayOnBaseline() const
-{
- return m_stayOnBaseline;
-}
-
-void RunAroundHelper::updateObstruction(KoTextLayoutObstruction *obstruction)
-{
- QRectF obstructionLineRect = obstruction->cropToLine(m_lineRect);
- if (obstructionLineRect.isValid()) {
- m_updateValidObstructions = true;
- }
-}
-
-bool RunAroundHelper::fit(const bool resetHorizontalPosition, bool isRightToLeft, const QPointF &position)
-{
- Q_ASSERT(line.isValid());
- if (resetHorizontalPosition) {
- m_horizontalPosition = RIDICULOUSLY_LARGE_NEGATIVE_INDENT;
- m_stayOnBaseline = false;
- }
- const qreal maxLineWidth = m_area->width();
- // Make sure at least some text is fitted if the basic width (page, table cell, column)
- // is too small
- if (maxLineWidth <= 0.) {
- // we need to make sure that something like "line.setLineWidth(0.0);" is called here to prevent
- // the QTextLine from being removed again and leading at a later point to crashes. It seems
- // following if-condition including the setNumColumns call was added to do exactly that. But
- // it's not clear for what the if-condition was added. In any case that condition is wrong or
- // incompleted cause things can still crash with m_state->layout->text().length() == 0 (see the
- // document attached to bug 244411).
-
- //if (m_state->layout->lineCount() > 1 || m_state->layout->text().length() > 0)
- line.setNumColumns(1);
-
- line.setPosition(position);
- return false;
- }
-
- // Too little width because of wrapping is handled in the remainder of this method
- line.setLineWidth(maxLineWidth);
- const qreal maxLineHeight = line.height();
- const qreal maxNaturalTextWidth = line.naturalTextWidth();
- QRectF lineRect(position, QSizeF(maxLineWidth, maxLineHeight));
- QRectF lineRectPart;
- qreal movedDown = 10;
-
- while (!lineRectPart.isValid()) {
- // The line rect could be split into no further linerectpart, so we have
- // to move the lineRect down a bit and try again
- // No line rect part was enough big, to fit the line. Recreate line rect further down
- // (and that is divided into new line parts). Line rect is at different position to
- // obstructions, so new parts are completely different. if there are no obstructions, then we
- // have only one line part which is full line rect
-
- lineRectPart = getLineRect(lineRect, maxNaturalTextWidth);
- if (!lineRectPart.isValid()) {
- m_horizontalPosition = RIDICULOUSLY_LARGE_NEGATIVE_INDENT;
- lineRect = QRectF(position, QSizeF(maxLineWidth, maxLineHeight));
- lineRect.setY(lineRect.y() + movedDown);
- movedDown += 10;
- }
- }
-
- if (isRightToLeft && line.naturalTextWidth() > m_textWidth) {
- // This can happen if spaces are added at the end of a line. Those spaces will not result in a
- // line-break. On left-to-right everything is fine and the spaces at the end are just not visible
- // but on right-to-left we need to adjust the position cause spaces at the end are displayed at
- // the beginning and we need to make sure that doesn't result in us cutting of text at the right side.
- qreal diff = line.naturalTextWidth() - m_textWidth;
- lineRectPart.setX(lineRectPart.x() - diff);
- }
-
- line.setLineWidth(m_textWidth);
- line.setPosition(QPointF(lineRectPart.x(), lineRectPart.y()));
- checkEndOfLine(lineRectPart, maxNaturalTextWidth);
- return true;
-}
-
-void RunAroundHelper::validateObstructions()
-{
- m_validObstructions.clear();
- foreach (KoTextLayoutObstruction *obstruction, m_obstructions) {
- validateObstruction(obstruction);
- }
-}
-
-void RunAroundHelper::validateObstruction(KoTextLayoutObstruction *obstruction)
-{
- QRectF obstructionLineRect = obstruction->cropToLine(m_lineRect);
- if (obstructionLineRect.isValid()) {
- m_validObstructions.append(obstruction);
- }
-}
-
-void RunAroundHelper::createLineParts()
-{
- m_lineParts.clear();
- if (m_validObstructions.isEmpty()) {
- // Add whole line rect
- m_lineParts.append(m_lineRect);
- } else {
- QList<QRectF> lineParts;
- QRectF rightLineRect = m_lineRect;
- bool lastRightRectValid = false;
- std::sort(m_validObstructions.begin(), m_validObstructions.end(), KoTextLayoutObstruction::compareRectLeft);
- // Divide rect to parts, part can be invalid when obstructions are not disjunct.
- foreach (KoTextLayoutObstruction *validObstruction, m_validObstructions) {
- QRectF leftLineRect = validObstruction->getLeftLinePart(rightLineRect);
- lineParts.append(leftLineRect);
- QRectF lineRect = validObstruction->getRightLinePart(rightLineRect);
- if (lineRect.isValid()) {
- rightLineRect = lineRect;
- lastRightRectValid = true;
- } else {
- lastRightRectValid = false;
- }
- }
- if (lastRightRectValid) {
- lineParts.append(rightLineRect);
- }
- else {
- lineParts.append(QRect());
- }
- Q_ASSERT(m_validObstructions.size() + 1 == lineParts.size());
- // Select invalid parts because of wrap.
- for (int i = 0; i < m_validObstructions.size(); i++) {
- KoTextLayoutObstruction *obstruction = m_validObstructions.at(i);
- if (obstruction->noTextAround()) {
- lineParts.replace(i, QRectF());
- lineParts.replace(i + 1, QRect());
- } else if (obstruction->textOnLeft()) {
- lineParts.replace(i + 1, QRect());
- } else if (obstruction->textOnRight()) {
- lineParts.replace(i, QRectF());
- } else if (obstruction->textOnEnoughSides()) {
- QRectF leftRect = obstruction->getLeftLinePart(m_lineRect);
- QRectF rightRect = obstruction->getRightLinePart(m_lineRect);
- if (leftRect.width() < obstruction->runAroundThreshold()) {
- lineParts.replace(i, QRectF());
- }
- if (rightRect.width() < obstruction->runAroundThreshold()) {
- lineParts.replace(i + 1, QRectF());
- }
- } else if (obstruction->textOnBiggerSide()) {
- QRectF leftRect = obstruction->getLeftLinePart(m_lineRect);
- QRectF rightRect = obstruction->getRightLinePart(m_lineRect);
- if (leftRect.width() < rightRect.width()) {
- lineParts.replace(i, QRectF());
- } else {
- lineParts.replace(i + 1, QRectF());
- }
- }
- }
- // Filter invalid parts.
- foreach (const QRectF &rect, lineParts) {
- if (rect.isValid()) {
- m_lineParts.append(rect);
- }
- }
- }
-}
-
-QRectF RunAroundHelper::minimizeHeightToLeastNeeded(const QRectF &lineRect)
-{
- Q_ASSERT(line.isValid());
- QRectF lineRectBase = lineRect;
- // Get width of one char or shape (as-char).
- m_textWidth = line.cursorToX(line.textStart() + 1) - line.cursorToX(line.textStart());
- // Make sure width is not wider than the area allows.
- if (m_textWidth > m_area->width()) {
- m_textWidth = m_area->width();
- }
- line.setLineWidth(m_textWidth);
- // Base linerect height on the width calculated above.
- lineRectBase.setHeight(line.height());
- return lineRectBase;
-}
-
-void RunAroundHelper::updateLineParts(const QRectF &lineRect)
-{
- if (m_lineRect != lineRect || m_updateValidObstructions) {
- m_lineRect = lineRect;
- m_updateValidObstructions = false;
- validateObstructions();
- createLineParts();
- }
-}
-
-QRectF RunAroundHelper::getLineRectPart()
-{
- QRectF retVal;
- foreach (const QRectF &lineRectPart, m_lineParts) {
- if (m_horizontalPosition <= lineRectPart.left() && m_textWidth <= lineRectPart.width()) {
- retVal = lineRectPart;
- break;
- }
- }
- return retVal;
-}
-
-void RunAroundHelper::setMaxTextWidth(const QRectF &minLineRectPart, const qreal leftIndent, const qreal maxNaturalTextWidth)
-{
- Q_ASSERT(line.isValid());
- qreal width = m_textWidth;
- qreal maxWidth = minLineRectPart.width() - leftIndent;
- qreal height;
- qreal maxHeight = minLineRectPart.height();
- qreal widthDiff = maxWidth - width;
-
- widthDiff /= 2;
- while (width <= maxWidth && width <= maxNaturalTextWidth && widthDiff > MIN_WIDTH) {
- qreal linewidth = width + widthDiff;
- line.setLineWidth(linewidth);
- height = line.height();
- if (height <= maxHeight) {
- width = linewidth;
- m_textWidth = width;
- }
- widthDiff /= 2;
- }
-}
-
-QRectF RunAroundHelper::getLineRect(const QRectF &lineRect, const qreal maxNaturalTextWidth)
-{
- Q_ASSERT(line.isValid());
-
- const qreal leftIndent = lineRect.left();
- QRectF minLineRect = minimizeHeightToLeastNeeded(lineRect);
- updateLineParts(minLineRect);
-
- // Get appropriate line rect part, to fit line,
- // using horizontal position, minimal height and width of line.
- QRectF lineRectPart = getLineRectPart();
- if (lineRectPart.isValid()) {
- qreal x = lineRectPart.x();
- qreal width = lineRectPart.width();
-
- // Limit moved the left edge, keep the indent.
- if (leftIndent < x) {
- x += leftIndent;
- width -= leftIndent;
- }
- line.setLineWidth(width);
-
- // Check if line rect is big enough to fit line.
- // Otherwise find shorter width, what means also shorter height of line.
- // Condition is reverted.
- if (line.height() > lineRectPart.height()) {
- setMaxTextWidth(lineRectPart, leftIndent, maxNaturalTextWidth);
- } else {
- m_textWidth = width;
- }
- }
- return lineRectPart;
-}
-
-void RunAroundHelper::checkEndOfLine(const QRectF &lineRectPart, const qreal maxNaturalTextWidth)
-{
- if (lineRectPart == m_lineParts.last() || maxNaturalTextWidth <= lineRectPart.width()) {
- m_horizontalPosition = RIDICULOUSLY_LARGE_NEGATIVE_INDENT;
- m_stayOnBaseline = false;
- } else {
- m_horizontalPosition = lineRectPart.right();
- m_stayOnBaseline = true;
- }
-}
diff --git a/plugins/flake/textshape/textlayout/RunAroundHelper.h b/plugins/flake/textshape/textlayout/RunAroundHelper.h
deleted file mode 100644
index f4a3e3c3d9..0000000000
--- a/plugins/flake/textshape/textlayout/RunAroundHelper.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2006-2007, 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2010 Ko Gmbh <cbo@kogmbh.com>
- *
- * 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 RUNAROUNDHELPER_H
-#define RUNAROUNDHELPER_H
-
-#include <QList>
-#include <QTextLine>
-#include <QRectF>
-
-class KoTextLayoutArea;
-class KoTextLayoutObstruction;
-
-class RunAroundHelper
-{
-public:
- RunAroundHelper();
- void setLine(KoTextLayoutArea *area, const QTextLine &l);
- void setObstructions(const QList<KoTextLayoutObstruction *> &obstructions);
- bool stayOnBaseline() const;
- void updateObstruction(KoTextLayoutObstruction *obstruction);
- bool fit(bool resetHorizontalPosition, bool isRightToLeft, const QPointF &position);
- QTextLine line;
-private:
- KoTextLayoutArea *m_area;
- QList<KoTextLayoutObstruction*> m_obstructions;
- QList<KoTextLayoutObstruction*> m_validObstructions;
- QList<QRectF> m_lineParts;
- QRectF m_lineRect;
- qreal m_horizontalPosition;
- bool m_updateValidObstructions;
- bool m_stayOnBaseline;
- qreal m_textWidth;
- void validateObstructions();
- void validateObstruction(KoTextLayoutObstruction *obstruction);
- void createLineParts();
- QRectF minimizeHeightToLeastNeeded(const QRectF &lineRect);
- void updateLineParts(const QRectF &lineRect);
- QRectF getLineRectPart();
- void setMaxTextWidth(const QRectF &minLineRectPart, const qreal leftIndent, const qreal maxNaturalTextWidth);
- QRectF getLineRect(const QRectF &lineRect, const qreal maxNaturalTextWidth);
- void checkEndOfLine(const QRectF &lineRectPart, const qreal maxNaturalTextWidth);
-};
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/TableIterator.cpp b/plugins/flake/textshape/textlayout/TableIterator.cpp
deleted file mode 100644
index 5a9dd53918..0000000000
--- a/plugins/flake/textshape/textlayout/TableIterator.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 C. Boemann, KO GmbH <cbo@kogmbh.com>
- *
- * 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 "TableIterator.h"
-
-#include "FrameIterator.h"
-
-#include <KoTableStyle.h>
-
-#include <QTextTable>
-
-TableIterator::TableIterator(QTextTable *t)
-{
- table = t;
- frameIterators.resize(table->columns());
- for (int col = 0; col < table->columns(); ++col) {
- frameIterators[col] = 0;
- }
- row = 0;
- headerRows = table->format().property(KoTableStyle::NumberHeadingRows).toInt();
- headerRowPositions.resize(headerRows + 1);
- headerCellAreas.resize(headerRows);
- for (int row = 0; row < headerRows; ++row) {
- headerCellAreas[row].resize(table->columns());
- for (int col = 0; col < table->columns(); ++col) {
- headerCellAreas[row][col] = 0;
- }
- }
-}
-
-TableIterator::TableIterator(TableIterator *other)
-{
- table = other->table;
- frameIterators.resize(table->columns());
- for (int col = 0; col < table->columns(); ++col) {
- if (other->frameIterators[col]) {
- frameIterators[col] = new FrameIterator(other->frameIterators[col]);
- } else {
- frameIterators[col] = 0;
- }
- }
- row = other->row;
- headerRows = other->headerRows;
- headerPositionX = other->headerPositionX;
- headerRowPositions.resize(headerRows + 1);
- headerCellAreas.resize(headerRows);
- for (int row = 0; row < headerRows; ++row) {
- headerCellAreas[row].resize(table->columns());
- for (int col = 0; col < table->columns(); ++col) {
- headerCellAreas[row][col] = other->headerCellAreas[row][col];
- }
- headerRowPositions[row] = other->headerRowPositions[row];
- }
- headerRowPositions[headerRows] = other->headerRowPositions[headerRows];
-}
-
-
-TableIterator::~TableIterator()
-{
- for (int col = 0; col < frameIterators.size(); ++col) {
- delete frameIterators[col];
- }
-}
-
-bool TableIterator::operator ==(const TableIterator &other) const
-{
- if (table != other.table)
- return false;
-
- if (row != other.row)
- return false;
-
- if (headerRows != other.headerRows)
- return false;
-
- for (int row = 0; row < headerRows; ++row) {
- for (int col = 0; col < table->columns(); ++col) {
- if (headerCellAreas[row][col] != other.headerCellAreas[row][col])
- return false;
- }
- }
-
- for (int col = 0; col < table->columns(); ++col) {
- if (frameIterators[col] && other.frameIterators[col]) {
- if (!(*frameIterators[col] ==
- *(other.frameIterators[col])))
- return false;
- }
- }
-
- return true;
-}
-
-FrameIterator *TableIterator::frameIterator(int column)
-{
- FrameIterator *it = 0;
- if (row == table->rows()) {
- delete frameIterators[column];
- frameIterators[column] = it;
- } else if (frameIterators[column] == 0) {
- it = new FrameIterator(table->cellAt(row, column));
- it->masterPageName = masterPageName;
- frameIterators[column] = it;
- } else {
- it = frameIterators[column];
- }
- return it;
-}
diff --git a/plugins/flake/textshape/textlayout/TableIterator.h b/plugins/flake/textshape/textlayout/TableIterator.h
deleted file mode 100644
index ef451686b8..0000000000
--- a/plugins/flake/textshape/textlayout/TableIterator.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2011 C. Boemann, KO GmbH <cbo@kogmbh.com>
- *
- * 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 TABLEITERATOR_H
-#define TABLEITERATOR_H
-
-#include <QVector>
-#include <QString>
-
-class FrameIterator;
-class KoTextLayoutArea;
-class QTextTable;
-
-/**
- * Convenience cursor class used during table layout.
- *
- * The class holds information about a table and the current row. Can also
- * provide a FrameIterator for a given column in the table.
- */
-class TableIterator
-{
-public:
- /**
- * Constructs a new iterator for the given table.
- *
- * @param table table to use.
- */
- explicit TableIterator(QTextTable *table);
-
- /**
- * Constructs a new iterator initialized from another.
- *
- * @param other iterator to initialize the iterator from.
- */
- explicit TableIterator(TableIterator *other);
-
- /// Destructor.
- ~TableIterator();
-
- /// Compare this iterator to another.
- bool operator ==(const TableIterator &other) const;
-
- /**
- * Returns a frame iterator that iterates over the frames in a given column.
- *
- * @param column column for which and iterator should be returned.
- */
- FrameIterator *frameIterator(int column);
-
- /// Table being iterated over.
- QTextTable *table;
- /// Current row.
- int row;
- /// Number of header rows.
- int headerRows;
- /// X position of header.
- qreal headerPositionX;
- /// Frame iterators, one for each column.
- QVector<FrameIterator *> frameIterators;
- /// Header row positions.
- QVector<qreal> headerRowPositions; // we will only fill those of header rows
- /// Rows of header cell areas.
- QVector<QVector<KoTextLayoutArea *> > headerCellAreas;
- /// The name of the master-page that is used for this table.
- QString masterPageName;
-};
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/TextLayoutDebug.cpp b/plugins/flake/textshape/textlayout/TextLayoutDebug.cpp
deleted file mode 100644
index 95a95c04f3..0000000000
--- a/plugins/flake/textshape/textlayout/TextLayoutDebug.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2015 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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 "TextLayoutDebug.h"
-
-const QLoggingCategory &TEXT_LAYOUT_LOG() \
-{
- static const QLoggingCategory category("krita.lib.textlayout", QtInfoMsg);
- return category;
-}
-
-
diff --git a/plugins/flake/textshape/textlayout/TextLayoutDebug.h b/plugins/flake/textshape/textlayout/TextLayoutDebug.h
deleted file mode 100644
index 4f58f02e25..0000000000
--- a/plugins/flake/textshape/textlayout/TextLayoutDebug.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2015 Boudewijn Rempt <boud@valdyas.org>
- *
- * 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 TEXT_LAYOUT_DEBUG_H_
-#define TEXT_LAYOUT_DEBUG_H_
-
-#include <QDebug>
-#include <QLoggingCategory>
-#include <kritatextlayout_export.h>
-
-extern const KRITATEXTLAYOUT_EXPORT QLoggingCategory &TEXT_LAYOUT_LOG();
-
-#define debugTextLayout qCDebug(TEXT_LAYOUT_LOG)
-#define warnTextLayout qCWarning(TEXT_LAYOUT_LOG)
-#define errorTextLayout qCCritical(TEXT_LAYOUT_LOG)
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/ToCGenerator.cpp b/plugins/flake/textshape/textlayout/ToCGenerator.cpp
deleted file mode 100644
index 055112082b..0000000000
--- a/plugins/flake/textshape/textlayout/ToCGenerator.cpp
+++ /dev/null
@@ -1,334 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2010 Jean Nicolas Artaud <jean.nicolas.artaud@kogmbh.com>
- * Copyright (C) 2011 Pavol Korinek <pavol.korinek@ixonos.com>
- * Copyright (C) 2011 Lukáš Tvrdý <lukas.tvrdy@ixonos.com>
- * Copyright (C) 2011 Ko GmbH <cbo@kogmbh.com>
- *
- * 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 "ToCGenerator.h"
-
-#include <klocalizedstring.h>
-
-#include "KoTextDocumentLayout.h"
-#include "KoTextLayoutRootArea.h"
-#include "DummyDocumentLayout.h"
-
-#include <KoParagraphStyle.h>
-#include <KoTextPage.h>
-#include <KoTextDocument.h>
-#include <KoTextBlockData.h>
-#include <KoStyleManager.h>
-#include <KoTableOfContentsGeneratorInfo.h>
-
-#include <QTextDocument>
-#include <TextLayoutDebug.h>
-#include <KoBookmark.h>
-#include <KoTextRangeManager.h>
-
-static const QString INVALID_HREF_TARGET = "INVALID_HREF";
-
-ToCGenerator::ToCGenerator(QTextDocument *tocDocument, KoTableOfContentsGeneratorInfo *tocInfo)
- : QObject(tocDocument)
- , m_ToCDocument(tocDocument)
- , m_ToCInfo(tocInfo)
- , m_document(0)
- , m_documentLayout(0)
-{
- Q_ASSERT(tocDocument);
- Q_ASSERT(tocInfo);
-
- tocDocument->setUndoRedoEnabled(false);
- tocDocument->setDocumentLayout(new DummyDocumentLayout(tocDocument));
- KoTextDocument(tocDocument).setRelativeTabs(tocInfo->m_relativeTabStopPosition);
-}
-
-ToCGenerator::~ToCGenerator()
-{
- delete m_ToCInfo;
-}
-
-void ToCGenerator::setBlock(const QTextBlock &block)
-{
- m_block = block;
- m_documentLayout = static_cast<KoTextDocumentLayout *>(m_block.document()->documentLayout());
- m_document = m_documentLayout->document();
-}
-
-QString ToCGenerator::fetchBookmarkRef(const QTextBlock &block, KoTextRangeManager *textRangeManager)
-{
- QHash<int, KoTextRange *> ranges = textRangeManager->textRangesChangingWithin(block.document(), block.position(), block.position() + block.length(), block.position(), block.position() + block.length());
-
- foreach (KoTextRange *range, ranges) {
- KoBookmark *bookmark = dynamic_cast<KoBookmark *>(range);
- if (bookmark) {
- return bookmark->name();
- }
- }
- return QString();
-}
-
-
-static QString removeWhitespacePrefix(const QString& text)
-{
- int firstNonWhitespaceCharIndex = 0;
- const int length = text.length();
- while (firstNonWhitespaceCharIndex < length && text.at(firstNonWhitespaceCharIndex).isSpace()) {
- firstNonWhitespaceCharIndex++;
- }
- return text.right(length - firstNonWhitespaceCharIndex);
-}
-
-
-bool ToCGenerator::generate()
-{
- if (!m_ToCInfo)
- return true;
-
- m_preservePagebreak = m_ToCDocument->begin().blockFormat().intProperty(KoParagraphStyle::BreakBefore) & KoText::PageBreak;
-
- m_success = true;
-
- QTextCursor cursor = m_ToCDocument->rootFrame()->lastCursorPosition();
- cursor.setPosition(m_ToCDocument->rootFrame()->firstPosition(), QTextCursor::KeepAnchor);
- cursor.beginEditBlock();
- cursor.insertBlock(QTextBlockFormat(), QTextCharFormat());
-
- KoStyleManager *styleManager = KoTextDocument(m_document).styleManager();
-
- if (!m_ToCInfo->m_indexTitleTemplate.text.isEmpty()) {
- KoParagraphStyle *titleStyle = styleManager->paragraphStyle(m_ToCInfo->m_indexTitleTemplate.styleId);
-
- // titleStyle == 0? then it might be in unused styles
- if (!titleStyle) {
- titleStyle = styleManager->unusedStyle(m_ToCInfo->m_indexTitleTemplate.styleId); // this should return true only for ToC template preview
- }
-
- if (!titleStyle) {
- titleStyle = styleManager->defaultTableOfcontentsTitleStyle();
- }
-
- QTextBlock titleTextBlock = cursor.block();
- titleStyle->applyStyle(titleTextBlock);
-
- cursor.insertText(m_ToCInfo->m_indexTitleTemplate.text);
- if (m_preservePagebreak) {
- QTextBlockFormat blockFormat;
- blockFormat.setProperty(KoParagraphStyle::BreakBefore, KoText::PageBreak);
- cursor.mergeBlockFormat(blockFormat);
- m_preservePagebreak = false;
- }
- cursor.insertBlock(QTextBlockFormat(), QTextCharFormat());
- }
-
- // Add TOC
- // Iterate through all blocks to generate TOC
- QTextBlock block = m_document->rootFrame()->firstCursorPosition().block();
- int blockId = 0;
- for (; block.isValid(); block = block.next()) {
- // Choose only TOC blocks
- if (m_ToCInfo->m_useOutlineLevel) {
- if (block.blockFormat().hasProperty(KoParagraphStyle::OutlineLevel)) {
- int level = block.blockFormat().intProperty(KoParagraphStyle::OutlineLevel);
- generateEntry(level, cursor, block, blockId);
- continue;
- }
- }
-
- if (m_ToCInfo->m_useIndexSourceStyles) {
- bool inserted = false;
- foreach (const IndexSourceStyles &indexSourceStyles, m_ToCInfo->m_indexSourceStyles) {
- foreach (const IndexSourceStyle &indexStyle, indexSourceStyles.styles) {
- if (indexStyle.styleId == block.blockFormat().intProperty(KoParagraphStyle::StyleId)) {
- generateEntry(indexSourceStyles.outlineLevel, cursor, block, blockId);
- inserted = true;
- break;
- }
- }
- if (inserted)
- break;
- }
- if (inserted)
- continue;
- }
-
- if (m_ToCInfo->m_useIndexMarks) {
- if (false) {
- generateEntry(1, cursor, block, blockId);
- continue;
- }
- }
- }
- cursor.endEditBlock();
-
- m_documentLayout->documentChanged(m_block.position(),1,1);
- return m_success;
-}
-
-static bool compareTab(const QVariant &tab1, const QVariant &tab2)
-{
- return tab1.value<KoText::Tab>().position < tab2.value<KoText::Tab>().position;
-}
-
-
-void ToCGenerator::generateEntry(int outlineLevel, QTextCursor &cursor, QTextBlock &block, int &blockId)
-{
- KoStyleManager *styleManager = KoTextDocument(m_document).styleManager();
-
- QString tocEntryText = block.text();
- tocEntryText.remove(QChar::ObjectReplacementCharacter);
- // some headings contain tabs, replace all occurrences with spaces
- tocEntryText.replace('\t',' ').remove(0x200B);
- tocEntryText = removeWhitespacePrefix(tocEntryText);
-
- // Add only blocks with text
- if (!tocEntryText.isEmpty()) {
- KoParagraphStyle *tocTemplateStyle = 0;
-
- if (outlineLevel >= 1 && (outlineLevel-1) < m_ToCInfo->m_entryTemplate.size()
- && outlineLevel <= m_ToCInfo->m_outlineLevel) {
- // List's index starts with 0, outline level starts with 0
- const TocEntryTemplate *tocEntryTemplate = &m_ToCInfo->m_entryTemplate.at(outlineLevel - 1);
-
- // ensure that we fetched correct entry template
- Q_ASSERT(tocEntryTemplate->outlineLevel == outlineLevel);
- if (tocEntryTemplate->outlineLevel != outlineLevel) {
- qDebug() << "TOC outline level not found correctly " << outlineLevel;
- }
-
- tocTemplateStyle = styleManager->paragraphStyle(tocEntryTemplate->styleId);
- if (tocTemplateStyle == 0) {
- tocTemplateStyle = styleManager->defaultTableOfContentsEntryStyle(outlineLevel);
- }
-
- QTextBlockFormat blockFormat;
- if (m_preservePagebreak) {
- blockFormat.setProperty(KoParagraphStyle::BreakBefore, KoText::PageBreak);
- m_preservePagebreak = false;
- }
- cursor.insertBlock(blockFormat, QTextCharFormat());
-
- QTextBlock tocEntryTextBlock = cursor.block();
- tocTemplateStyle->applyStyle( tocEntryTextBlock );
-
- KoTextBlockData bd(block);
-
- // save the current style due to hyperlinks
- QTextCharFormat savedCharFormat = cursor.charFormat();
- foreach (IndexEntry * entry, tocEntryTemplate->indexEntries) {
- switch(entry->name) {
- case IndexEntry::LINK_START: {
- //IndexEntryLinkStart *linkStart = static_cast<IndexEntryLinkStart*>(entry);
-
- QString target = fetchBookmarkRef(block, m_documentLayout->textRangeManager());
-
- if (target.isNull()) {
- // generate unique name for the bookmark
- target = tocEntryText + "|outline" + QString::number(blockId);
- blockId++;
-
- // insert new KoBookmark
- QTextCursor blockCursor(block);
- KoBookmark *bookmark = new KoBookmark(blockCursor);
- bookmark->setName(target);
- m_documentLayout->textRangeManager()->insert(bookmark);
- }
-
- if (!target.isNull()) {
- // copy it to alter subset of properties
- QTextCharFormat linkCf(savedCharFormat);
- linkCf.setAnchor(true);
- linkCf.setProperty(KoCharacterStyle::AnchorType, KoCharacterStyle::Anchor);
- linkCf.setAnchorHref('#'+ target);
-
- QBrush foreground = linkCf.foreground();
- foreground.setColor(Qt::blue);
-
- linkCf.setForeground(foreground);
- linkCf.setProperty(KoCharacterStyle::UnderlineStyle, KoCharacterStyle::SolidLine);
- linkCf.setProperty(KoCharacterStyle::UnderlineType, KoCharacterStyle::SingleLine);
- cursor.setCharFormat(linkCf);
- }
- break;
- }
- case IndexEntry::CHAPTER: {
- //IndexEntryChapter *chapter = static_cast<IndexEntryChapter*>(entry);
- cursor.insertText(bd.counterText());
- break;
- }
- case IndexEntry::SPAN: {
- IndexEntrySpan *span = static_cast<IndexEntrySpan*>(entry);
- cursor.insertText(span->text);
- break;
- }
- case IndexEntry::TEXT: {
- //IndexEntryText *text = static_cast<IndexEntryText*>(entry);
- cursor.insertText(tocEntryText);
- break;
- }
- case IndexEntry::TAB_STOP: {
- IndexEntryTabStop *tabEntry = static_cast<IndexEntryTabStop*>(entry);
-
- cursor.insertText("\t");
-
- QTextBlockFormat blockFormat = cursor.blockFormat();
- QList<QVariant> tabList = (blockFormat.property(KoParagraphStyle::TabPositions)).value<QList<QVariant> >();
-
- if (tabEntry->m_position.isEmpty()) {
- tabEntry->tab.position = KoTextLayoutArea::MaximumTabPos;
- } // else the position is already parsed into tab.position
- tabList.append(QVariant::fromValue<KoText::Tab>(tabEntry->tab));
- std::sort(tabList.begin(), tabList.end(), compareTab);
- blockFormat.setProperty(KoParagraphStyle::TabPositions, QVariant::fromValue<QList<QVariant> >(tabList));
- cursor.setBlockFormat(blockFormat);
- break;
- }
- case IndexEntry::PAGE_NUMBER: {
- //IndexEntryPageNumber *pageNumber = static_cast<IndexEntryPageNumber*>(entry);
- cursor.insertText(resolvePageNumber(block));
- break;
- }
- case IndexEntry::LINK_END: {
- //IndexEntryLinkEnd *linkEnd = static_cast<IndexEntryLinkEnd*>(entry);
- cursor.setCharFormat(savedCharFormat);
- break;
- }
- default:{
- qDebug() << "New or unknown index entry";
- break;
- }
- }
- }// foreach
- cursor.setCharFormat(savedCharFormat); // restore the cursor char format
- }
- }
-}
-
-QString ToCGenerator::resolvePageNumber(const QTextBlock &headingBlock)
-{
- KoTextDocumentLayout *layout = qobject_cast<KoTextDocumentLayout*>(m_document->documentLayout());
- KoTextLayoutRootArea *rootArea = layout->rootAreaForPosition(headingBlock.position());
- if (rootArea) {
- if (rootArea->page()) {
- return QString::number(rootArea->page()->visiblePageNumber());
- }
- else qDebug()<<"had root but no page";
- }
- m_success = false;
- return "###";
-}
diff --git a/plugins/flake/textshape/textlayout/ToCGenerator.h b/plugins/flake/textshape/textlayout/ToCGenerator.h
deleted file mode 100644
index 5634288935..0000000000
--- a/plugins/flake/textshape/textlayout/ToCGenerator.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* This file is part of the KDE project
- * Copyright (C) 2010 Thomas Zander <zander@kde.org>
- * Copyright (C) 2011 Pavol Korinek <pavol.korinek@ixonos.com>
- * Copyright (C) 2011 Lukáš Tvrdý <lukas.tvrdy@ixonos.com>
- * Copyright (C) 2011 Ko GmbH <cbo@kogmbh.com>
- *
- * 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 TOCGENERATOR_H
-#define TOCGENERATOR_H
-
-#include <QTextBlock>
-#include <QObject>
-
-class KoTextRangeManager;
-class KoTextDocumentLayout;
-class KoTableOfContentsGeneratorInfo;
-
-class QTextDocument;
-
-class ToCGenerator : public QObject
-{
- Q_OBJECT
-public:
- explicit ToCGenerator(QTextDocument *tocDocument, KoTableOfContentsGeneratorInfo *tocInfo);
- ~ToCGenerator() override;
-
- virtual void setBlock(const QTextBlock &block);
-
- bool generate();
-
-private:
- QString resolvePageNumber(const QTextBlock &headingBlock);
- void generateEntry(int outlineLevel, QTextCursor &cursor, QTextBlock &block, int &blockId);
-
- QTextDocument *m_ToCDocument;
- KoTableOfContentsGeneratorInfo *m_ToCInfo;
- QTextBlock m_block;
- QTextDocument *m_document;
- KoTextDocumentLayout *m_documentLayout;
- bool m_success;
- bool m_preservePagebreak;
-
- // Return the ref (name) of the first KoBookmark in the block, if KoBookmark not found, null QString is returned
- QString fetchBookmarkRef(const QTextBlock &block, KoTextRangeManager *textRangeManager);
-};
-
-#endif
diff --git a/plugins/flake/textshape/textlayout/documentation/list_alignment_mode.txt b/plugins/flake/textshape/textlayout/documentation/list_alignment_mode.txt
deleted file mode 100644
index 1a52255a5d..0000000000
--- a/plugins/flake/textshape/textlayout/documentation/list_alignment_mode.txt
+++ /dev/null
@@ -1,98 +0,0 @@
-label-width-and-position mode
-=============================
-
- min- min-
- label- label-
- width distance
- |------|--------|
- LABELBOX TEXT STARTS HERE AND GOES ON
- | TO THE NEXT LINE
-|>------------------| |----|
- space-before text-indent
- + margin-left
-
-Inside LABELBOX the label can be aligned and prepended by spacing:
-
-left:
- LABELBOX
- 11.2
-
-center:
- LABELBOX
- 11.2
-
-right:
- LABELBOX
- 11.2
-
-
-label-alignment mode
-====================
-
-How list tab is defined if fixed tabs:
-
- text-indent
- |---------<|
- LABEL TEXT STARTS HERE AND GOES ON
- TO THE|NEXT LINE
-|>--------------------| |
- margin |
- |
-|>--------------------------|
- tab-position
-
-
-
-How list tab is defined if relative tabs:
-
- text-indent
- |---------<|
- LABEL TEXT STARTS HERE AND GOES ON
- TO THE|NEXT LINE
-|>--------------------| |
- margin | |
- | |
- |>-------------| |
- |list:margin-left |
- | |
- |>-------------------|
- tab-position
-
-text-indent is equal to list:text-indent unless paragraph:text-indent is defined and not zero
-margin is equal to list:margin-left unless paragraph:margin-left is defined and not zero
-
-
-LABEL was shown above center aligned. to illustrate the alignment the LABEL box and a sample label is shown below in all of the three alignments and how it relates to the position defined by text-indent:
-
-left:
- text-indent
- |---------<|
- LABEL
- 1.2
-center:
- text-indent
- |---------<|
- LABEL
- 1.2
-right:
- text-indent
- |---------<|
- LABEL
- 1.2
-
-
-Font determination in calligra
-==============================
-
-In presentations the order of text properties is:
--------------------------------------------------
-paragraph textproperties
-first fragment of the text's textproperties
-liststyle referenced named characterstyle (but LO/OO doesn't)
-liststyle text-properties
-
-In odt the order is:
---------------------
-paragraph textproperties
-liststyle referenced named characterstyle
-liststyle text-properties (but LO/OO doesn't)
diff --git a/plugins/flake/textshape/textshape.qrc b/plugins/flake/textshape/textshape.qrc
deleted file mode 100644
index 3c27331676..0000000000
--- a/plugins/flake/textshape/textshape.qrc
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE RCC>
-<RCC version="1.0">
- <qresource>
- <file alias="edit-table-cell-merge.png">pics/22-actions-edit-table-cell-merge.png</file>
- <file alias="table-cell-split.png">pics/22-actions-edit-table-cell-split.png</file>
- <file alias="tool_references.png">pics/22-actions-tool_references.png</file>
- <file alias="tool_review.png">pics/22-actions-tool_review.png</file>
- <file alias="tool-text.png">pics/22-actions-tool-text.png</file>
- <file alias="settings-icon1_1.png">pics/settings-icon1_1.png</file>
- <file alias="tool_references.svg">pics/tool_references.svg</file>
- <file alias="tool_review.svg">pics/tool_review.svg</file>
- <file alias="tool-text.svg">pics/tool-text.svg</file>
- </qresource>
-</RCC>
diff --git a/plugins/impex/libkra/kis_kra_load_visitor.cpp b/plugins/impex/libkra/kis_kra_load_visitor.cpp
index b33f3fc0ee..455acc28e8 100644
--- a/plugins/impex/libkra/kis_kra_load_visitor.cpp
+++ b/plugins/impex/libkra/kis_kra_load_visitor.cpp
@@ -1,803 +1,803 @@
/*
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
* Copyright (c) 2005 C. Boemann <cbo@boemann.dk>
*
* 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_kra_load_visitor.h"
#include "kis_kra_tags.h"
#include "flake/kis_shape_layer.h"
#include "flake/KisReferenceImagesLayer.h"
#include "KisReferenceImage.h"
#include <KisImportExportManager.h>
#include <QRect>
#include <QBuffer>
#include <QByteArray>
#include <QMessageBox>
#include <KoMD5Generator.h>
#include <KoColorSpaceRegistry.h>
#include <KoColorProfile.h>
#include <KoFileDialog.h>
#include <KoStore.h>
#include <KoColorSpace.h>
#include <KoShapeControllerBase.h>
#include <KisGlobalResourcesInterface.h>
// kritaimage
#include <kis_meta_data_io_backend.h>
#include <kis_meta_data_store.h>
#include <kis_types.h>
#include <kis_node_visitor.h>
#include <kis_image.h>
#include <kis_selection.h>
#include <kis_layer.h>
#include <kis_paint_layer.h>
#include <kis_group_layer.h>
#include <kis_adjustment_layer.h>
#include <filter/kis_filter_configuration.h>
#include <kis_datamanager.h>
#include <generator/kis_generator_layer.h>
#include <kis_pixel_selection.h>
#include <kis_clone_layer.h>
#include <kis_filter_mask.h>
#include <kis_transform_mask.h>
#include <kis_transform_mask_params_interface.h>
#include "kis_transform_mask_params_factory_registry.h"
#include <kis_transparency_mask.h>
#include <kis_selection_mask.h>
#include <lazybrush/kis_colorize_mask.h>
#include <lazybrush/kis_lazy_fill_tools.h>
#include "kis_shape_selection.h"
#include "kis_colorize_dom_utils.h"
#include "kis_dom_utils.h"
#include "kis_raster_keyframe_channel.h"
#include "kis_paint_device_frames_interface.h"
#include "kis_filter_registry.h"
#include "kis_generator_registry.h"
using namespace KRA;
QString expandEncodedDirectory(const QString& _intern)
{
QString intern = _intern;
QString result;
int pos;
while ((pos = intern.indexOf('/')) != -1) {
if (QChar(intern.at(0)).isDigit())
result += "part";
result += intern.left(pos + 1); // copy numbers (or "pictures") + "/"
intern = intern.mid(pos + 1); // remove the dir we just processed
}
if (!intern.isEmpty() && QChar(intern.at(0)).isDigit())
result += "part";
result += intern;
return result;
}
KisKraLoadVisitor::KisKraLoadVisitor(KisImageSP image,
KoStore *store,
KoShapeControllerBase *shapeController,
QMap<KisNode *, QString> &layerFilenames,
QMap<KisNode *, QString> &keyframeFilenames,
const QString & name,
int syntaxVersion)
: KisNodeVisitor()
, m_image(image)
, m_store(store)
, m_external(false)
, m_layerFilenames(layerFilenames)
, m_keyframeFilenames(keyframeFilenames)
, m_name(name)
, m_shapeController(shapeController)
{
m_store->pushDirectory();
if (!m_store->enterDirectory(m_name)) {
QStringList directories = m_store->directoryList();
dbgKrita << directories;
if (directories.size() > 0) {
dbgFile << "Could not locate the directory, maybe some encoding issue? Grab the first directory, that'll be the image one." << m_name << directories;
m_name = directories.first();
}
else {
dbgFile << "Could not enter directory" << m_name << ", probably an old-style file with 'part' added.";
m_name = expandEncodedDirectory(m_name);
}
}
else {
m_store->popDirectory();
}
m_syntaxVersion = syntaxVersion;
}
void KisKraLoadVisitor::setExternalUri(const QString &uri)
{
m_external = true;
m_uri = uri;
}
bool KisKraLoadVisitor::visit(KisExternalLayer * layer)
{
bool result = false;
if (auto *referencesLayer = dynamic_cast<KisReferenceImagesLayer*>(layer)) {
Q_FOREACH(KoShape *shape, referencesLayer->shapes()) {
auto *reference = dynamic_cast<KisReferenceImage*>(shape);
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(reference, false);
while (!reference->loadImage(m_store)) {
if (reference->embed()) {
m_errorMessages << i18n("Could not load embedded reference image %1 ", reference->internalFile());
break;
} else {
QString msg = i18nc(
"@info",
"A reference image linked to an external file could not be loaded.\n\n"
"Path: %1\n\n"
"Do you want to select another location?", reference->filename());
int locateManually = QMessageBox::warning(0, i18nc("@title:window", "File not found"), msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
QString url;
if (locateManually == QMessageBox::Yes) {
KoFileDialog dialog(0, KoFileDialog::OpenFile, "OpenDocument");
dialog.setMimeTypeFilters(KisImportExportManager::supportedMimeTypes(KisImportExportManager::Import));
url = dialog.filename();
}
if (url.isEmpty()) {
break;
} else {
reference->setFilename(url);
}
}
}
}
} else if (KisShapeLayer *shapeLayer = dynamic_cast<KisShapeLayer*>(layer)) {
if (!loadMetaData(layer)) {
return false;
}
m_store->pushDirectory();
m_store->enterDirectory(getLocation(layer, DOT_SHAPE_LAYER)) ;
result = shapeLayer->loadLayer(m_store);
m_store->popDirectory();
}
result = visitAll(layer) && result;
return result;
}
bool KisKraLoadVisitor::visit(KisPaintLayer *layer)
{
loadNodeKeyframes(layer);
if (!loadPaintDevice(layer->paintDevice(), getLocation(layer))) {
return false;
}
if (!loadProfile(layer->paintDevice(), getLocation(layer, DOT_ICC))) {
return false;
}
if (!loadMetaData(layer)) {
return false;
}
if (m_syntaxVersion == 1) {
// Check whether there is a file with a .mask extension in the
// layer directory, if so, it's an old-style transparency mask
// that should be converted.
QString location = getLocation(layer, ".mask");
if (m_store->open(location)) {
KisSelectionSP selection = KisSelectionSP(new KisSelection());
KisPixelSelectionSP pixelSelection = selection->pixelSelection();
if (!pixelSelection->read(m_store->device())) {
pixelSelection->disconnect();
} else {
KisTransparencyMask* mask = new KisTransparencyMask();
mask->setSelection(selection);
m_image->addNode(mask, layer, layer->firstChild());
}
m_store->close();
}
}
bool result = visitAll(layer);
return result;
}
bool KisKraLoadVisitor::visit(KisGroupLayer *layer)
{
if (*layer->colorSpace() != *m_image->colorSpace()) {
layer->resetCache(m_image->colorSpace());
}
if (!loadMetaData(layer)) {
return false;
}
bool result = visitAll(layer);
return result;
}
bool KisKraLoadVisitor::visit(KisAdjustmentLayer* layer)
{
loadNodeKeyframes(layer);
// Adjustmentlayers are tricky: there's the 1.x style and the 2.x
// style, which has selections with selection components
bool result = true;
if (m_syntaxVersion == 1) {
KisSelectionSP selection = new KisSelection();
KisPixelSelectionSP pixelSelection = selection->pixelSelection();
result = loadPaintDevice(pixelSelection, getLocation(layer, ".selection"));
layer->setInternalSelection(selection);
} else if (m_syntaxVersion == 2) {
result = loadSelection(getLocation(layer), layer->internalSelection());
} else {
// We use the default, empty selection
}
if (!loadMetaData(layer)) {
return false;
}
KisFilterSP filter = KisFilterRegistry::instance()->value(layer->filter()->name());
KisFilterConfigurationSP kfc = filter->factoryConfiguration(KisGlobalResourcesInterface::instance());
loadFilterConfiguration(kfc, getLocation(layer, DOT_FILTERCONFIG));
fixOldFilterConfigurations(kfc);
kfc->createLocalResourcesSnapshot();
layer->setFilter(kfc);
result = visitAll(layer);
return result;
}
bool KisKraLoadVisitor::visit(KisGeneratorLayer *layer)
{
if (!loadMetaData(layer)) {
return false;
}
bool result = true;
loadNodeKeyframes(layer);
result = loadSelection(getLocation(layer), layer->internalSelection());
KisGeneratorSP filter = KisGeneratorRegistry::instance()->value(layer->filter()->name());
KisFilterConfigurationSP kfc = filter->factoryConfiguration(KisGlobalResourcesInterface::instance());
result = loadFilterConfiguration(kfc, getLocation(layer, DOT_FILTERCONFIG));
kfc->createLocalResourcesSnapshot();
layer->setFilter(kfc);
result = visitAll(layer);
return result;
}
bool KisKraLoadVisitor::visit(KisCloneLayer *layer)
{
if (!loadMetaData(layer)) {
return false;
}
// the layer might have already been lazily initialized
// from the mask loading code
if (layer->copyFrom()) {
return true;
}
KisNodeSP srcNode = layer->copyFromInfo().findNode(m_image->rootLayer());
if (!srcNode.isNull()) {
KisLayerSP srcLayer = qobject_cast<KisLayer*>(srcNode.data());
Q_ASSERT(srcLayer);
layer->setCopyFrom(srcLayer);
} else {
m_warningMessages.append(i18nc("Loading a .kra file", "The file contains a clone layer that has an incorrect source node id. "
"This layer will be converted into a paint layer."));
}
// Clone layers have no data except for their masks
bool result = visitAll(layer);
return result;
}
void KisKraLoadVisitor::initSelectionForMask(KisMask *mask)
{
KisLayer *cloneLayer = dynamic_cast<KisCloneLayer*>(mask->parent().data());
if (cloneLayer) {
// the clone layers should be initialized out of order
// and lazily, because their original() is still not
// initialized
cloneLayer->accept(*this);
}
KisLayer *parentLayer = qobject_cast<KisLayer*>(mask->parent().data());
// the KisKraLoader must have already set the parent for us
Q_ASSERT(parentLayer);
mask->initSelection(parentLayer);
}
bool KisKraLoadVisitor::visit(KisFilterMask *mask)
{
initSelectionForMask(mask);
loadNodeKeyframes(mask);
bool result = true;
result = loadSelection(getLocation(mask), mask->selection());
KisFilterSP filter = KisFilterRegistry::instance()->value(mask->filter()->name());
KisFilterConfigurationSP kfc = filter->factoryConfiguration(KisGlobalResourcesInterface::instance());
result = loadFilterConfiguration(kfc, getLocation(mask, DOT_FILTERCONFIG));
fixOldFilterConfigurations(kfc);
kfc->createLocalResourcesSnapshot();
mask->setFilter(kfc);
return result;
}
bool KisKraLoadVisitor::visit(KisTransformMask *mask)
{
QString location = getLocation(mask, DOT_TRANSFORMCONFIG);
if (m_store->hasFile(location)) {
QByteArray data;
m_store->open(location);
data = m_store->read(m_store->size());
m_store->close();
if (!data.isEmpty()) {
QDomDocument doc;
doc.setContent(data);
QDomElement rootElement = doc.documentElement();
QDomElement main;
if (!KisDomUtils::findOnlyElement(rootElement, "main", &main/*, &m_errorMessages*/)) {
return false;
}
QString id = main.attribute("id", "not-valid");
if (id == "not-valid") {
m_errorMessages << i18n("Could not load \"id\" of the transform mask");
return false;
}
QDomElement data;
if (!KisDomUtils::findOnlyElement(rootElement, "data", &data, &m_errorMessages)) {
return false;
}
KisTransformMaskParamsInterfaceSP params =
KisTransformMaskParamsFactoryRegistry::instance()->createParams(id, data);
if (!params) {
m_errorMessages << i18n("Could not create transform mask params");
return false;
}
mask->setTransformParams(params);
loadNodeKeyframes(mask);
params->clearChangedFlag();
return true;
}
}
return false;
}
bool KisKraLoadVisitor::visit(KisTransparencyMask *mask)
{
initSelectionForMask(mask);
loadNodeKeyframes(mask);
return loadSelection(getLocation(mask), mask->selection());
}
bool KisKraLoadVisitor::visit(KisSelectionMask *mask)
{
initSelectionForMask(mask);
return loadSelection(getLocation(mask), mask->selection());
}
bool KisKraLoadVisitor::visit(KisColorizeMask *mask)
{
m_store->pushDirectory();
QString location = getLocation(mask, DOT_COLORIZE_MASK);
m_store->enterDirectory(location) ;
QByteArray data;
if (!m_store->extractFile("content.xml", data))
return false;
QDomDocument doc;
if (!doc.setContent(data))
return false;
QVector<KisLazyFillTools::KeyStroke> strokes;
if (!KisDomUtils::loadValue(doc.documentElement(), COLORIZE_KEYSTROKES_SECTION, &strokes, mask->colorSpace()))
return false;
int i = 0;
Q_FOREACH (const KisLazyFillTools::KeyStroke &stroke, strokes) {
const QString fileName = QString("%1_%2").arg(COLORIZE_KEYSTROKE).arg(i++);
loadPaintDevice(stroke.dev, fileName);
}
mask->setKeyStrokesDirect(QList<KisLazyFillTools::KeyStroke>::fromVector(strokes));
loadPaintDevice(mask->coloringProjection(), COLORIZE_COLORING_DEVICE);
mask->resetCache();
m_store->popDirectory();
return true;
}
QStringList KisKraLoadVisitor::errorMessages() const
{
return m_errorMessages;
}
QStringList KisKraLoadVisitor::warningMessages() const
{
return m_warningMessages;
}
struct SimpleDevicePolicy
{
bool read(KisPaintDeviceSP dev, QIODevice *stream) {
return dev->read(stream);
}
void setDefaultPixel(KisPaintDeviceSP dev, const KoColor &defaultPixel) const {
return dev->setDefaultPixel(defaultPixel);
}
};
struct FramedDevicePolicy
{
FramedDevicePolicy(int frameId)
: m_frameId(frameId) {}
bool read(KisPaintDeviceSP dev, QIODevice *stream) {
return dev->framesInterface()->readFrame(stream, m_frameId);
}
void setDefaultPixel(KisPaintDeviceSP dev, const KoColor &defaultPixel) const {
return dev->framesInterface()->setFrameDefaultPixel(defaultPixel, m_frameId);
}
int m_frameId;
};
bool KisKraLoadVisitor::loadPaintDevice(KisPaintDeviceSP device, const QString& location)
{
// Layer data
KisPaintDeviceFramesInterface *frameInterface = device->framesInterface();
QList<int> frames;
if (frameInterface) {
frames = device->framesInterface()->frames();
}
if (!frameInterface || frames.count() <= 1) {
return loadPaintDeviceFrame(device, location, SimpleDevicePolicy());
} else {
KisRasterKeyframeChannel *keyframeChannel = device->keyframeChannel();
for (int i = 0; i < frames.count(); i++) {
int id = frames[i];
if (keyframeChannel->frameFilename(id).isEmpty()) {
m_warningMessages << i18n("Could not find keyframe pixel data for frame %1 in %2.", id, location);
}
else {
Q_ASSERT(!keyframeChannel->frameFilename(id).isEmpty());
QString frameFilename = getLocation(keyframeChannel->frameFilename(id));
Q_ASSERT(!frameFilename.isEmpty());
if (!loadPaintDeviceFrame(device, frameFilename, FramedDevicePolicy(id))) {
m_warningMessages << i18n("Could not load keyframe pixel data for frame %1 in %2.", id, location);
}
}
}
}
return true;
}
template<class DevicePolicy>
bool KisKraLoadVisitor::loadPaintDeviceFrame(KisPaintDeviceSP device, const QString &location, DevicePolicy policy)
{
{
const int pixelSize = device->colorSpace()->pixelSize();
KoColor color(Qt::transparent, device->colorSpace());
if (m_store->open(location + ".defaultpixel")) {
if (m_store->size() == pixelSize) {
m_store->read((char*)color.data(), pixelSize);
}
m_store->close();
}
policy.setDefaultPixel(device, color);
}
if (m_store->open(location)) {
if (!policy.read(device, m_store->device())) {
m_warningMessages << i18n("Could not read pixel data: %1.", location);
device->disconnect();
m_store->close();
return true;
}
m_store->close();
} else {
m_warningMessages << i18n("Could not load pixel data: %1.", location);
return true;
}
return true;
}
bool KisKraLoadVisitor::loadProfile(KisPaintDeviceSP device, const QString& location)
{
if (m_store->hasFile(location)) {
m_store->open(location);
QByteArray data;
data.resize(m_store->size());
dbgFile << "Data to load: " << m_store->size() << " from " << location << " with color space " << device->colorSpace()->id();
int read = m_store->read(data.data(), m_store->size());
dbgFile << "Profile size: " << data.size() << " " << m_store->atEnd() << " " << m_store->device()->bytesAvailable() << " " << read;
m_store->close();
QByteArray hash = KoMD5Generator::generateHash(data);
if (m_profileCache.contains(hash)) {
if (device->setProfile(m_profileCache[hash], 0)) {
return true;
}
}
else {
// Create a colorspace with the embedded profile
const KoColorProfile *profile = KoColorSpaceRegistry::instance()->createColorProfile(device->colorSpace()->colorModelId().id(), device->colorSpace()->colorDepthId().id(), data);
m_profileCache[hash] = profile;
if (device->setProfile(profile, 0)) {
return true;
}
}
}
m_warningMessages << i18n("Could not load profile: %1.", location);
return true;
}
bool KisKraLoadVisitor::loadFilterConfiguration(KisFilterConfigurationSP kfc, const QString& location)
{
if (m_store->hasFile(location)) {
QByteArray data;
m_store->open(location);
data = m_store->read(m_store->size());
m_store->close();
if (!data.isEmpty()) {
QDomDocument doc;
doc.setContent(data);
QDomElement e = doc.documentElement();
if (e.tagName() == "filterconfig") {
kfc->fromLegacyXML(e);
} else {
kfc->fromXML(e);
}
loadDeprecatedFilter(kfc);
return true;
}
}
m_warningMessages << i18n("Could not filter configuration %1.", location);
return true;
}
void KisKraLoadVisitor::fixOldFilterConfigurations(KisFilterConfigurationSP kfc)
{
KisFilterSP filter = KisFilterRegistry::instance()->value(kfc->name());
KIS_SAFE_ASSERT_RECOVER_RETURN(filter);
if (!filter->configurationAllowedForMask(kfc)) {
filter->fixLoadedFilterConfigurationForMasks(kfc);
}
KIS_SAFE_ASSERT_RECOVER_NOOP(filter->configurationAllowedForMask(kfc));
}
bool KisKraLoadVisitor::loadMetaData(KisNode* node)
{
KisLayer* layer = qobject_cast<KisLayer*>(node);
if (!layer) return true;
KisMetaData::IOBackend* backend = KisMetaData::IOBackendRegistry::instance()->get("xmp");
if (!backend || !backend->supportLoading()) {
if (backend)
dbgFile << "Backend " << backend->id() << " does not support loading.";
else
dbgFile << "Could not load the XMP backend at all";
return true;
}
QString location = getLocation(node, QString(".") + backend->id() + DOT_METADATA);
dbgFile << "going to load " << backend->id() << ", " << backend->name() << " from " << location;
if (m_store->hasFile(location)) {
QByteArray data;
m_store->open(location);
data = m_store->read(m_store->size());
m_store->close();
QBuffer buffer(&data);
if (!backend->loadFrom(layer->metaData(), &buffer)) {
m_warningMessages << i18n("Could not load metadata for layer %1.", layer->name());
}
}
return true;
}
bool KisKraLoadVisitor::loadSelection(const QString& location, KisSelectionSP dstSelection)
{
// by default the selection is expected to be fully transparent
{
KisPixelSelectionSP pixelSelection = dstSelection->pixelSelection();
KoColor transparent(Qt::transparent, pixelSelection->colorSpace());
pixelSelection->setDefaultPixel(transparent);
}
// Pixel selection
bool result = true;
QString pixelSelectionLocation = location + DOT_PIXEL_SELECTION;
if (m_store->hasFile(pixelSelectionLocation)) {
KisPixelSelectionSP pixelSelection = dstSelection->pixelSelection();
result = loadPaintDevice(pixelSelection, pixelSelectionLocation);
if (!result) {
m_warningMessages << i18n("Could not load raster selection %1.", location);
}
pixelSelection->invalidateOutlineCache();
}
// Shape selection
QString shapeSelectionLocation = location + DOT_SHAPE_SELECTION;
if (m_store->hasFile(shapeSelectionLocation + "/content.svg") ||
m_store->hasFile(shapeSelectionLocation + "/content.xml")) {
m_store->pushDirectory();
m_store->enterDirectory(shapeSelectionLocation) ;
KisShapeSelection* shapeSelection = new KisShapeSelection(m_shapeController, m_image, dstSelection);
- dstSelection->setShapeSelection(shapeSelection);
+ dstSelection->convertToVectorSelectionNoUndo(shapeSelection);
result = shapeSelection->loadSelection(m_store);
m_store->popDirectory();
if (!result) {
m_warningMessages << i18n("Could not load vector selection %1.", location);
}
}
return true;
}
QString KisKraLoadVisitor::getLocation(KisNode* node, const QString& suffix)
{
return getLocation(m_layerFilenames[node], suffix);
}
QString KisKraLoadVisitor::getLocation(const QString &filename, const QString& suffix)
{
QString location = m_external ? QString() : m_uri;
location += m_name + LAYER_PATH + filename + suffix;
return location;
}
void KisKraLoadVisitor::loadNodeKeyframes(KisNode *node)
{
if (!m_keyframeFilenames.contains(node)) return;
node->enableAnimation();
const QString &location = getLocation(m_keyframeFilenames[node]);
if (!m_store->open(location)) {
m_errorMessages << i18n("Could not load keyframes from %1.", location);
return;
}
QString errorMsg;
int errorLine;
int errorColumn;
QDomDocument dom;
bool ok = dom.setContent(m_store->device(), &errorMsg, &errorLine, &errorColumn);
m_store->close();
if (!ok) {
m_errorMessages << i18n("parsing error in the keyframe file %1 at line %2, column %3\nError message: %4", location, errorLine, errorColumn, i18n(errorMsg.toUtf8()));
return;
}
QDomElement root = dom.firstChildElement();
for (QDomElement child = root.firstChildElement(); !child.isNull(); child = child.nextSiblingElement()) {
if (child.nodeName().toUpper() == "CHANNEL") {
QString id = child.attribute("name");
KisKeyframeChannel *channel = node->getKeyframeChannel(id, true);
if (!channel) {
m_warningMessages << i18n("unknown keyframe channel type: %1 in %2", id, location);
continue;
}
channel->loadXML(child);
}
}
}
void KisKraLoadVisitor::loadDeprecatedFilter(KisFilterConfigurationSP cfg)
{
if (cfg->getString("legacy") == "left edge detections") {
cfg->setProperty("horizRadius", 1);
cfg->setProperty("vertRadius", 1);
cfg->setProperty("type", "prewitt");
cfg->setProperty("output", "yFall");
cfg->setProperty("lockAspect", true);
cfg->setProperty("transparency", false);
} else if (cfg->getString("legacy") == "right edge detections") {
cfg->setProperty("horizRadius", 1);
cfg->setProperty("vertRadius", 1);
cfg->setProperty("type", "prewitt");
cfg->setProperty("output", "yGrowth");
cfg->setProperty("lockAspect", true);
cfg->setProperty("transparency", false);
} else if (cfg->getString("legacy") == "top edge detections") {
cfg->setProperty("horizRadius", 1);
cfg->setProperty("vertRadius", 1);
cfg->setProperty("type", "prewitt");
cfg->setProperty("output", "xGrowth");
cfg->setProperty("lockAspect", true);
cfg->setProperty("transparency", false);
} else if (cfg->getString("legacy") == "bottom edge detections") {
cfg->setProperty("horizRadius", 1);
cfg->setProperty("vertRadius", 1);
cfg->setProperty("type", "prewitt");
cfg->setProperty("output", "xFall");
cfg->setProperty("lockAspect", true);
cfg->setProperty("transparency", false);
}
}
diff --git a/plugins/impex/libkra/kis_kra_save_visitor.cpp b/plugins/impex/libkra/kis_kra_save_visitor.cpp
index a61f5ba456..e9b4d124ff 100644
--- a/plugins/impex/libkra/kis_kra_save_visitor.cpp
+++ b/plugins/impex/libkra/kis_kra_save_visitor.cpp
@@ -1,549 +1,549 @@
/*
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
* Copyright (c) 2005 C. Boemann <cbo@boemann.dk>
* Copyright (c) 2007-2008 Boudewijn Rempt <boud@valdyas.org>
*
* 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_kra_save_visitor.h"
#include "kis_kra_tags.h"
#include <QBuffer>
#include <QByteArray>
#include <KoColorProfile.h>
#include <KoStore.h>
#include <KoColorSpace.h>
#include <filter/kis_filter_configuration.h>
#include <generator/kis_generator_layer.h>
#include <kis_adjustment_layer.h>
#include <kis_annotation.h>
#include <kis_group_layer.h>
#include <kis_image.h>
#include <kis_layer.h>
#include <kis_paint_layer.h>
#include <kis_selection.h>
#include <kis_shape_layer.h>
#include <KisReferenceImagesLayer.h>
#include <KisReferenceImage.h>
#include <kis_file_layer.h>
#include <kis_clone_layer.h>
#include <kis_mask.h>
#include <kis_filter_mask.h>
#include <kis_transform_mask.h>
#include <kis_transform_mask_params_interface.h>
#include <kis_transparency_mask.h>
#include <kis_selection_mask.h>
#include "lazybrush/kis_colorize_mask.h"
#include <kis_selection_component.h>
#include <kis_pixel_selection.h>
#include <kis_meta_data_store.h>
#include <kis_meta_data_io_backend.h>
#include "kis_config.h"
#include "kis_store_paintdevice_writer.h"
#include "flake/kis_shape_selection.h"
#include "kis_raster_keyframe_channel.h"
#include "kis_paint_device_frames_interface.h"
#include "lazybrush/kis_lazy_fill_tools.h"
#include <KoStoreDevice.h>
#include "kis_colorize_dom_utils.h"
#include "kis_dom_utils.h"
using namespace KRA;
KisKraSaveVisitor::KisKraSaveVisitor(KoStore *store, const QString & name, QMap<const KisNode*, QString> nodeFileNames)
: KisNodeVisitor()
, m_store(store)
, m_external(false)
, m_name(name)
, m_nodeFileNames(nodeFileNames)
, m_writer(new KisStorePaintDeviceWriter(store))
{
}
KisKraSaveVisitor::~KisKraSaveVisitor()
{
delete m_writer;
}
void KisKraSaveVisitor::setExternalUri(const QString &uri)
{
m_external = true;
m_uri = uri;
}
bool KisKraSaveVisitor::visit(KisExternalLayer * layer)
{
bool result = false;
if (auto* referencesLayer = dynamic_cast<KisReferenceImagesLayer*>(layer)) {
result = true;
Q_FOREACH(KoShape *shape, referencesLayer->shapes()) {
auto *reference = dynamic_cast<KisReferenceImage*>(shape);
KIS_ASSERT_RECOVER_RETURN_VALUE(reference, false);
bool saved = reference->saveImage(m_store);
if (!saved) {
m_errorMessages << i18n("Failed to save reference image %1.", reference->internalFile());
result = false;
}
}
}
else if (KisShapeLayer *shapeLayer = dynamic_cast<KisShapeLayer*>(layer)) {
if (!saveMetaData(layer)) {
m_errorMessages << i18n("Failed to save the metadata for layer %1.", layer->name());
return false;
}
m_store->pushDirectory();
QString location = getLocation(layer, DOT_SHAPE_LAYER);
result = m_store->enterDirectory(location);
if (!result) {
m_errorMessages << i18n("Failed to open %1.", location);
}
else {
result = shapeLayer->saveLayer(m_store);
m_store->popDirectory();
}
}
else if (KisFileLayer *fileLayer = dynamic_cast<KisFileLayer*>(layer)) {
Q_UNUSED(fileLayer); // We don't save data for file layers, but we still want to save the masks.
result = true;
}
return result && visitAllInverse(layer);
}
bool KisKraSaveVisitor::visit(KisPaintLayer *layer)
{
if (!savePaintDevice(layer->paintDevice(), getLocation(layer))) {
m_errorMessages << i18n("Failed to save the pixel data for layer %1.", layer->name());
return false;
}
if (!saveAnnotations(layer)) {
m_errorMessages << i18n("Failed to save the annotations for layer %1.", layer->name());
return false;
}
if (!saveMetaData(layer)) {
m_errorMessages << i18n("Failed to save the metadata for layer %1.", layer->name());
return false;
}
return visitAllInverse(layer);
}
bool KisKraSaveVisitor::visit(KisGroupLayer *layer)
{
if (!saveMetaData(layer)) {
m_errorMessages << i18n("Failed to save the metadata for layer %1.", layer->name());
return false;
}
return visitAllInverse(layer);
}
bool KisKraSaveVisitor::visit(KisAdjustmentLayer* layer)
{
if (!layer->filter()) {
m_errorMessages << i18n("Failed to save the filter layer %1: it has no filter.", layer->name());
return false;
}
if (!saveSelection(layer)) {
m_errorMessages << i18n("Failed to save the selection for filter layer %1.", layer->name());
return false;
}
if (!saveFilterConfiguration(layer)) {
m_errorMessages << i18n("Failed to save the filter configuration for filter layer %1.", layer->name());
return false;
}
if (!saveMetaData(layer)) {
m_errorMessages << i18n("Failed to save the metadata for layer %1.", layer->name());
return false;
}
return visitAllInverse(layer);
}
bool KisKraSaveVisitor::visit(KisGeneratorLayer * layer)
{
if (!saveSelection(layer)) {
m_errorMessages << i18n("Failed to save the selection for layer %1.", layer->name());
return false;
}
if (!saveFilterConfiguration(layer)) {
m_errorMessages << i18n("Failed to save the generator configuration for layer %1.", layer->name());
return false;
}
if (!saveMetaData(layer)) {
m_errorMessages << i18n("Failed to save the metadata for layer %1.", layer->name());
return false;
}
return visitAllInverse(layer);
}
bool KisKraSaveVisitor::visit(KisCloneLayer *layer)
{
// Clone layers do not have a profile
if (!saveMetaData(layer)) {
m_errorMessages << i18n("Failed to save the metadata for layer %1.", layer->name());
return false;
}
return visitAllInverse(layer);
}
bool KisKraSaveVisitor::visit(KisFilterMask *mask)
{
if (!mask->filter()) {
m_errorMessages << i18n("Failed to save filter mask %1. It has no filter.", mask->name());
return false;
}
if (!saveSelection(mask)) {
m_errorMessages << i18n("Failed to save the selection for filter mask %1.", mask->name());
return false;
}
if (!saveFilterConfiguration(mask)) {
m_errorMessages << i18n("Failed to save the filter configuration for filter mask %1.", mask->name());
return false;
}
return true;
}
bool KisKraSaveVisitor::visit(KisTransformMask *mask)
{
QDomDocument doc("transform_params");
QDomElement root = doc.createElement("transform_params");
QDomElement main = doc.createElement("main");
main.setAttribute("id", mask->transformParams()->id());
QDomElement data = doc.createElement("data");
mask->transformParams()->toXML(&data);
doc.appendChild(root);
root.appendChild(main);
root.appendChild(data);
QString location = getLocation(mask, DOT_TRANSFORMCONFIG);
if (m_store->open(location)) {
QByteArray a = doc.toByteArray();
bool retval = m_store->write(a) == a.size();
if (!retval) {
warnFile << "Could not write transform mask configuration";
}
if (!m_store->close()) {
warnFile << "Could not close store after writing transform mask configuration";
retval = false;
}
return retval;
}
return false;
}
bool KisKraSaveVisitor::visit(KisTransparencyMask *mask)
{
if (!saveSelection(mask)) {
m_errorMessages << i18n("Failed to save the selection for transparency mask %1.", mask->name());
return false;
}
return true;
}
bool KisKraSaveVisitor::visit(KisSelectionMask *mask)
{
if (!saveSelection(mask)) {
m_errorMessages << i18n("Failed to save the selection for local selection %1.", mask->name());
return false;
}
return true;
}
bool KisKraSaveVisitor::visit(KisColorizeMask *mask)
{
m_store->pushDirectory();
QString location = getLocation(mask, DOT_COLORIZE_MASK);
bool result = m_store->enterDirectory(location);
if (!result) {
m_errorMessages << i18n("Failed to open %1.", location);
return false;
}
if (!m_store->open("content.xml"))
return false;
KoStoreDevice storeDev(m_store);
QDomDocument doc("doc");
QDomElement root = doc.createElement("colorize");
doc.appendChild(root);
KisDomUtils::saveValue(&root, COLORIZE_KEYSTROKES_SECTION, QVector<KisLazyFillTools::KeyStroke>::fromList(mask->fetchKeyStrokesDirect()));
QTextStream stream(&storeDev);
stream << doc;
if (!m_store->close())
return false;
int i = 0;
Q_FOREACH (const KisLazyFillTools::KeyStroke &stroke, mask->fetchKeyStrokesDirect()) {
const QString fileName = QString("%1_%2").arg(COLORIZE_KEYSTROKE).arg(i++);
savePaintDevice(stroke.dev, fileName);
}
savePaintDevice(mask->coloringProjection(), COLORIZE_COLORING_DEVICE);
m_store->popDirectory();
return true;
}
QStringList KisKraSaveVisitor::errorMessages() const
{
return m_errorMessages;
}
struct SimpleDevicePolicy
{
bool write(KisPaintDeviceSP dev, KisPaintDeviceWriter &store) {
return dev->write(store);
}
KoColor defaultPixel(KisPaintDeviceSP dev) const {
return dev->defaultPixel();
}
};
struct FramedDevicePolicy
{
FramedDevicePolicy(int frameId)
: m_frameId(frameId) {}
bool write(KisPaintDeviceSP dev, KisPaintDeviceWriter &store) {
return dev->framesInterface()->writeFrame(store, m_frameId);
}
KoColor defaultPixel(KisPaintDeviceSP dev) const {
return dev->framesInterface()->frameDefaultPixel(m_frameId);
}
int m_frameId;
};
bool KisKraSaveVisitor::savePaintDevice(KisPaintDeviceSP device,
QString location)
{
// Layer data
KisConfig cfg(true);
m_store->setCompressionEnabled(cfg.compressKra());
KisPaintDeviceFramesInterface *frameInterface = device->framesInterface();
QList<int> frames;
if (frameInterface) {
frames = frameInterface->frames();
}
if (!frameInterface || frames.count() <= 1) {
savePaintDeviceFrame(device, location, SimpleDevicePolicy());
} else {
KisRasterKeyframeChannel *keyframeChannel = device->keyframeChannel();
for (int i = 0; i < frames.count(); i++) {
int id = frames[i];
QString frameFilename = getLocation(keyframeChannel->frameFilename(id));
Q_ASSERT(!frameFilename.isEmpty());
if (!savePaintDeviceFrame(device, frameFilename, FramedDevicePolicy(id))) {
return false;
}
}
}
m_store->setCompressionEnabled(true);
return true;
}
template<class DevicePolicy>
bool KisKraSaveVisitor::savePaintDeviceFrame(KisPaintDeviceSP device, QString location, DevicePolicy policy)
{
if (m_store->open(location)) {
if (!policy.write(device, *m_writer)) {
device->disconnect();
m_store->close();
return false;
}
m_store->close();
}
if (m_store->open(location + ".defaultpixel")) {
m_store->write((char*)policy.defaultPixel(device).data(), device->colorSpace()->pixelSize());
m_store->close();
}
return true;
}
bool KisKraSaveVisitor::saveAnnotations(KisLayer* layer)
{
if (!layer) return false;
if (!layer->paintDevice()) return false;
if (!layer->paintDevice()->colorSpace()) return false;
if (layer->paintDevice()->colorSpace()->profile()) {
const KoColorProfile *profile = layer->paintDevice()->colorSpace()->profile();
KisAnnotationSP annotation;
if (profile) {
QByteArray profileRawData = profile->rawData();
if (!profileRawData.isEmpty()) {
if (profile->type() == "icc") {
annotation = new KisAnnotation(ICC, profile->name(), profile->rawData());
} else {
annotation = new KisAnnotation(PROFILE, profile->name(), profile->rawData());
}
}
}
if (annotation) {
// save layer profile
if (m_store->open(getLocation(layer, DOT_ICC))) {
m_store->write(annotation->annotation());
m_store->close();
} else {
return false;
}
}
}
return true;
}
bool KisKraSaveVisitor::saveSelection(KisNode* node)
{
KisSelectionSP selection;
if (node->inherits("KisMask")) {
selection = static_cast<KisMask*>(node)->selection();
} else if (node->inherits("KisAdjustmentLayer")) {
selection = static_cast<KisAdjustmentLayer*>(node)->internalSelection();
} else if (node->inherits("KisGeneratorLayer")) {
selection = static_cast<KisGeneratorLayer*>(node)->internalSelection();
} else {
return false;
}
bool retval = true;
- if (selection->hasPixelSelection()) {
+ if (selection->hasNonEmptyPixelSelection()) {
KisPaintDeviceSP dev = selection->pixelSelection();
if (!savePaintDevice(dev, getLocation(node, DOT_PIXEL_SELECTION))) {
m_errorMessages << i18n("Failed to save the pixel selection data for layer %1.", node->name());
retval = false;
}
}
- if (selection->hasShapeSelection()) {
+ if (selection->hasNonEmptyShapeSelection()) {
m_store->pushDirectory();
retval = m_store->enterDirectory(getLocation(node, DOT_SHAPE_SELECTION));
if (retval) {
KisShapeSelection* shapeSelection = dynamic_cast<KisShapeSelection*>(selection->shapeSelection());
if (!shapeSelection) {
retval = false;
}
if (retval && !shapeSelection->saveSelection(m_store)) {
m_errorMessages << i18n("Failed to save the vector selection data for layer %1.", node->name());
retval = false;
}
}
m_store->popDirectory();
}
return retval;
}
bool KisKraSaveVisitor::saveFilterConfiguration(KisNode* node)
{
KisNodeFilterInterface *filterInterface =
dynamic_cast<KisNodeFilterInterface*>(node);
KisFilterConfigurationSP filter;
if (filterInterface) {
filter = filterInterface->filter();
}
bool retval = false;
if (filter) {
QString location = getLocation(node, DOT_FILTERCONFIG);
if (m_store->open(location)) {
QString s = filter->toXML();
retval = (m_store->write(s.toUtf8(), qstrlen(s.toUtf8())) == qstrlen(s.toUtf8())); m_store->close();
}
}
return retval;
}
bool KisKraSaveVisitor::saveMetaData(KisNode* node)
{
if (!node->inherits("KisLayer")) return true;
KisMetaData::Store* metadata = (static_cast<KisLayer*>(node))->metaData();
if (metadata->isEmpty()) return true;
// Serialize all the types of metadata there are
KisMetaData::IOBackend* backend = KisMetaData::IOBackendRegistry::instance()->get("xmp");
if (!backend->supportSaving()) {
dbgFile << "Backend " << backend->id() << " does not support saving.";
return false;
}
QString location = getLocation(node, QString(".") + backend->id() + DOT_METADATA);
dbgFile << "going to save " << backend->id() << ", " << backend->name() << " to " << location;
QBuffer buffer;
// not that the metadata backends every return anything but true...
bool retval = backend->saveTo(metadata, &buffer);
if (!retval) {
m_errorMessages << i18n("The metadata backend failed to save the metadata for %1", node->name());
}
else {
QByteArray data = buffer.data();
dbgFile << "\t information size is" << data.size();
if (data.size() > 0 && m_store->open(location)) {
retval = m_store->write(data, data.size());
m_store->close();
}
if (!retval) {
m_errorMessages << i18n("Could not write for %1 metadata to the file.", node->name());
}
}
return retval;
}
QString KisKraSaveVisitor::getLocation(KisNode* node, const QString& suffix)
{
Q_ASSERT(m_nodeFileNames.contains(node));
return getLocation(m_nodeFileNames[node], suffix);
}
QString KisKraSaveVisitor::getLocation(const QString &filename, const QString& suffix)
{
QString location = m_external ? QString() : m_uri;
location += m_name + LAYER_PATH + filename + suffix;
return location;
}
diff --git a/plugins/impex/libkra/tests/kis_kra_saver_test.cpp b/plugins/impex/libkra/tests/kis_kra_saver_test.cpp
index 8cf9e50351..5f29ab0282 100644
--- a/plugins/impex/libkra/tests/kis_kra_saver_test.cpp
+++ b/plugins/impex/libkra/tests/kis_kra_saver_test.cpp
@@ -1,553 +1,553 @@
/*
* Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org
*
* 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_kra_saver_test.h"
#include <QTest>
#include <QBitArray>
#include <KisDocument.h>
#include <KoDocumentInfo.h>
#include <KoShapeContainer.h>
#include <KoPathShape.h>
#include "filter/kis_filter_registry.h"
#include "filter/kis_filter_configuration.h"
#include "filter/kis_filter.h"
#include "kis_image.h"
#include "kis_pixel_selection.h"
#include "kis_group_layer.h"
#include "kis_paint_layer.h"
#include "kis_clone_layer.h"
#include "kis_adjustment_layer.h"
#include "kis_shape_layer.h"
#include "kis_filter_mask.h"
#include "kis_transparency_mask.h"
#include "kis_selection_mask.h"
#include "kis_selection.h"
#include "kis_fill_painter.h"
#include "kis_shape_selection.h"
#include "util.h"
#include "testutil.h"
#include "kis_keyframe_channel.h"
#include "kis_image_animation_interface.h"
#include "kis_layer_properties_icons.h"
#include <KisGlobalResourcesInterface.h>
#include "kis_transform_mask_params_interface.h"
#include <generator/kis_generator_registry.h>
#include <KoResourcePaths.h>
#include <sdk/tests/kistest.h>
#include <filestest.h>
const QString KraMimetype = "application/x-krita";
void KisKraSaverTest::initTestCase()
{
KoResourcePaths::addResourceDir(ResourceType::Patterns, QString(SYSTEM_RESOURCES_DATA_DIR) + "/patterns");
KisFilterRegistry::instance();
KisGeneratorRegistry::instance();
}
void KisKraSaverTest::testCrashyShapeLayer()
{
/**
* KisShapeLayer used to call setImage from its destructor and
* therefore causing an infinite recursion (when at least one transparency
* mask was preset. This testcase just checks that.
*/
//QScopedPointer<KisDocument> doc(createCompleteDocument(true));
//Q_UNUSED(doc);
}
void KisKraSaverTest::testRoundTrip()
{
KisDocument* doc = createCompleteDocument();
KoColor bgColor(Qt::red, doc->image()->colorSpace());
doc->image()->setDefaultProjectionColor(bgColor);
doc->exportDocumentSync(QUrl::fromLocalFile("roundtriptest.kra"), doc->mimeType());
QStringList list;
KisCountVisitor cv1(list, KoProperties());
doc->image()->rootLayer()->accept(cv1);
KisDocument *doc2 = KisPart::instance()->createDocument();
bool result = doc2->loadNativeFormat("roundtriptest.kra");
QVERIFY(result);
KisCountVisitor cv2(list, KoProperties());
doc2->image()->rootLayer()->accept(cv2);
QCOMPARE(cv1.count(), cv2.count());
// check whether the BG color is saved correctly
QCOMPARE(doc2->image()->defaultProjectionColor(), bgColor);
// test round trip of a transform mask
KisNode* tnode =
TestUtil::findNode(doc2->image()->rootLayer(), "testTransformMask").data();
QVERIFY(tnode);
KisTransformMask *tmask = dynamic_cast<KisTransformMask*>(tnode);
QVERIFY(tmask);
KisDumbTransformMaskParams *params = dynamic_cast<KisDumbTransformMaskParams*>(tmask->transformParams().data());
QVERIFY(params);
QTransform t = params->testingGetTransform();
QCOMPARE(t, createTestingTransform());
delete doc2;
delete doc;
}
void KisKraSaverTest::testSaveEmpty()
{
KisDocument* doc = createEmptyDocument();
doc->exportDocumentSync(QUrl::fromLocalFile("emptytest.kra"), doc->mimeType());
QStringList list;
KisCountVisitor cv1(list, KoProperties());
doc->image()->rootLayer()->accept(cv1);
KisDocument *doc2 = KisPart::instance()->createDocument();
doc2->loadNativeFormat("emptytest.kra");
KisCountVisitor cv2(list, KoProperties());
doc2->image()->rootLayer()->accept(cv2);
QCOMPARE(cv1.count(), cv2.count());
delete doc2;
delete doc;
}
#include <generator/kis_generator.h>
void testRoundTripFillLayerImpl(const QString &testName, KisFilterConfigurationSP config)
{
TestUtil::ReferenceImageChecker chk(testName, "fill_layer");
chk.setFuzzy(2);
QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument());
// mask parent should be destructed before the document!
QRect refRect(0,0,512,512);
TestUtil::MaskParent p(refRect);
doc->setCurrentImage(p.image);
doc->documentInfo()->setAboutInfo("title", p.image->objectName());
KisSelectionSP selection;
KisGeneratorLayerSP glayer = new KisGeneratorLayer(p.image, "glayer", config->cloneWithResourcesSnapshot(), selection);
p.image->addNode(glayer, p.image->root(), KisNodeSP());
glayer->setDirty();
p.image->waitForDone();
chk.checkImage(p.image, "00_initial_layer_update");
doc->exportDocumentSync(QUrl::fromLocalFile("roundtrip_fill_layer_test.kra"), doc->mimeType());
QScopedPointer<KisDocument> doc2(KisPart::instance()->createDocument());
doc2->loadNativeFormat("roundtrip_fill_layer_test.kra");
doc2->image()->waitForDone();
chk.checkImage(doc2->image(), "01_fill_layer_round_trip");
QVERIFY(chk.testPassed());
}
void KisKraSaverTest::testRoundTripFillLayerColor()
{
const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
KisGeneratorSP generator = KisGeneratorRegistry::instance()->get("color");
Q_ASSERT(generator);
// warning: we pass null paint device to the default constructed value
KisFilterConfigurationSP config = generator->defaultConfiguration(KisGlobalResourcesInterface::instance());
Q_ASSERT(config);
QVariant v;
v.setValue(KoColor(Qt::red, cs));
config->setProperty("color", v);
testRoundTripFillLayerImpl("fill_layer_color", config);
}
void KisKraSaverTest::testRoundTripFillLayerPattern()
{
KisGeneratorSP generator = KisGeneratorRegistry::instance()->get("pattern");
QVERIFY(generator);
// warning: we pass null paint device to the default constructed value
KisFilterConfigurationSP config = generator->defaultConfiguration(KisGlobalResourcesInterface::instance());
QVERIFY(config);
QVariant v;
v.setValue(QString("11_drawed_furry.png"));
config->setProperty("pattern", v);
testRoundTripFillLayerImpl("fill_layer_pattern", config);
}
#include "kis_psd_layer_style.h"
void KisKraSaverTest::testRoundTripLayerStyles()
{
TestUtil::ReferenceImageChecker chk("kra_saver_test", "layer_styles");
QRect imageRect(0,0,512,512);
// the document should be created before the image!
QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument());
const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
KisImageSP image = new KisImage(new KisSurrogateUndoStore(), imageRect.width(), imageRect.height(), cs, "test image");
KisPaintLayerSP layer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8);
KisPaintLayerSP layer2 = new KisPaintLayer(image, "paint2", OPACITY_OPAQUE_U8);
KisPaintLayerSP layer3 = new KisPaintLayer(image, "paint3", OPACITY_OPAQUE_U8);
image->addNode(layer1);
image->addNode(layer2);
image->addNode(layer3);
doc->setCurrentImage(image);
doc->documentInfo()->setAboutInfo("title", image->objectName());
layer1->paintDevice()->fill(QRect(100, 100, 100, 100), KoColor(Qt::red, cs));
layer2->paintDevice()->fill(QRect(200, 200, 100, 100), KoColor(Qt::green, cs));
layer3->paintDevice()->fill(QRect(300, 300, 100, 100), KoColor(Qt::blue, cs));
KisPSDLayerStyleSP style(new KisPSDLayerStyle());
style->dropShadow()->setEffectEnabled(true);
style->dropShadow()->setAngle(-90);
style->dropShadow()->setUseGlobalLight(false);
layer1->setLayerStyle(style->clone().dynamicCast<KisPSDLayerStyle>());
style->dropShadow()->setAngle(180);
style->dropShadow()->setUseGlobalLight(true);
layer2->setLayerStyle(style->clone().dynamicCast<KisPSDLayerStyle>());
style->dropShadow()->setAngle(90);
style->dropShadow()->setUseGlobalLight(false);
layer3->setLayerStyle(style->clone().dynamicCast<KisPSDLayerStyle>());
image->initialRefreshGraph();
chk.checkImage(image, "00_initial_layers");
doc->exportDocumentSync(QUrl::fromLocalFile("roundtrip_layer_styles.kra"), doc->mimeType());
QScopedPointer<KisDocument> doc2(KisPart::instance()->createDocument());
doc2->loadNativeFormat("roundtrip_layer_styles.kra");
doc2->image()->waitForDone();
chk.checkImage(doc2->image(), "00_initial_layers");
QVERIFY(chk.testPassed());
}
void KisKraSaverTest::testRoundTripAnimation()
{
QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument());
QRect imageRect(0,0,512,512);
const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
KisImageSP image = new KisImage(new KisSurrogateUndoStore(), imageRect.width(), imageRect.height(), cs, "test image");
KisPaintLayerSP layer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8);
image->addNode(layer1);
layer1->paintDevice()->fill(QRect(100, 100, 50, 50), KoColor(Qt::black, cs));
layer1->paintDevice()->setDefaultPixel(KoColor(Qt::red, cs));
KUndo2Command parentCommand;
layer1->enableAnimation();
KisKeyframeChannel *rasterChannel = layer1->getKeyframeChannel(KisKeyframeChannel::Content.id(), true);
QVERIFY(rasterChannel);
rasterChannel->addKeyframe(10, &parentCommand);
image->animationInterface()->switchCurrentTimeAsync(10);
image->waitForDone();
layer1->paintDevice()->fill(QRect(200, 50, 10, 10), KoColor(Qt::black, cs));
layer1->paintDevice()->moveTo(25, 15);
layer1->paintDevice()->setDefaultPixel(KoColor(Qt::green, cs));
rasterChannel->addKeyframe(20, &parentCommand);
image->animationInterface()->switchCurrentTimeAsync(20);
image->waitForDone();
layer1->paintDevice()->fill(QRect(150, 200, 30, 30), KoColor(Qt::black, cs));
layer1->paintDevice()->moveTo(100, 50);
layer1->paintDevice()->setDefaultPixel(KoColor(Qt::blue, cs));
QVERIFY(!layer1->isPinnedToTimeline());
layer1->setPinnedToTimeline(true);
doc->setCurrentImage(image);
doc->exportDocumentSync(QUrl::fromLocalFile("roundtrip_animation.kra"), doc->mimeType());
QScopedPointer<KisDocument> doc2(KisPart::instance()->createDocument());
doc2->loadNativeFormat("roundtrip_animation.kra");
KisImageSP image2 = doc2->image();
KisNodeSP node = image2->root()->firstChild();
QVERIFY(node->inherits("KisPaintLayer"));
KisPaintLayerSP layer2 = qobject_cast<KisPaintLayer*>(node.data());
cs = layer2->paintDevice()->colorSpace();
QCOMPARE(image2->animationInterface()->currentTime(), 20);
KisKeyframeChannel *channel = layer2->getKeyframeChannel(KisKeyframeChannel::Content.id());
QVERIFY(channel);
QCOMPARE(channel->keyframeCount(), 3);
image2->animationInterface()->switchCurrentTimeAsync(0);
image2->waitForDone();
QCOMPARE(layer2->paintDevice()->nonDefaultPixelArea(), QRect(64, 64, 128, 128));
QCOMPARE(layer2->paintDevice()->x(), 0);
QCOMPARE(layer2->paintDevice()->y(), 0);
QCOMPARE(layer2->paintDevice()->defaultPixel(), KoColor(Qt::red, cs));
image2->animationInterface()->switchCurrentTimeAsync(10);
image2->waitForDone();
QCOMPARE(layer2->paintDevice()->nonDefaultPixelArea(), QRect(217, 15, 64, 64));
QCOMPARE(layer2->paintDevice()->x(), 25);
QCOMPARE(layer2->paintDevice()->y(), 15);
QCOMPARE(layer2->paintDevice()->defaultPixel(), KoColor(Qt::green, cs));
image2->animationInterface()->switchCurrentTimeAsync(20);
image2->waitForDone();
QCOMPARE(layer2->paintDevice()->nonDefaultPixelArea(), QRect(228, 242, 64, 64));
QCOMPARE(layer2->paintDevice()->x(), 100);
QCOMPARE(layer2->paintDevice()->y(), 50);
QCOMPARE(layer2->paintDevice()->defaultPixel(), KoColor(Qt::blue, cs));
QVERIFY(layer2->isPinnedToTimeline());
}
#include "lazybrush/kis_lazy_fill_tools.h"
void KisKraSaverTest::testRoundTripColorizeMask()
{
QRect imageRect(0,0,512,512);
const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
const KoColorSpace * weirdCS = KoColorSpaceRegistry::instance()->rgb16();
QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument());
KisImageSP image = new KisImage(new KisSurrogateUndoStore(), imageRect.width(), imageRect.height(), cs, "test image");
doc->setCurrentImage(image);
KisPaintLayerSP layer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8, weirdCS);
image->addNode(layer1);
KisColorizeMaskSP mask = new KisColorizeMask();
image->addNode(mask, layer1);
mask->initializeCompositeOp();
delete mask->setColorSpace(layer1->colorSpace());
{
KisPaintDeviceSP key1 = new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8());
key1->fill(QRect(50,50,10,20), KoColor(Qt::black, key1->colorSpace()));
mask->testingAddKeyStroke(key1, KoColor(Qt::green, layer1->colorSpace()));
// KIS_DUMP_DEVICE_2(key1, refRect, "key1", "dd");
}
{
KisPaintDeviceSP key2 = new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8());
key2->fill(QRect(150,50,10,20), KoColor(Qt::black, key2->colorSpace()));
mask->testingAddKeyStroke(key2, KoColor(Qt::red, layer1->colorSpace()));
// KIS_DUMP_DEVICE_2(key2, refRect, "key2", "dd");
}
{
KisPaintDeviceSP key3 = new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8());
key3->fill(QRect(0,0,10,10), KoColor(Qt::black, key3->colorSpace()));
mask->testingAddKeyStroke(key3, KoColor(Qt::blue, layer1->colorSpace()), true);
// KIS_DUMP_DEVICE_2(key3, refRect, "key3", "dd");
}
KisLayerPropertiesIcons::setNodeProperty(mask, KisLayerPropertiesIcons::colorizeEditKeyStrokes, false, image);
KisLayerPropertiesIcons::setNodeProperty(mask, KisLayerPropertiesIcons::colorizeShowColoring, false, image);
doc->exportDocumentSync(QUrl::fromLocalFile("roundtrip_colorize.kra"), doc->mimeType());
QScopedPointer<KisDocument> doc2(KisPart::instance()->createDocument());
doc2->loadNativeFormat("roundtrip_colorize.kra");
KisImageSP image2 = doc2->image();
KisNodeSP node = image2->root()->firstChild()->firstChild();
KisColorizeMaskSP mask2 = dynamic_cast<KisColorizeMask*>(node.data());
QVERIFY(mask2);
QCOMPARE(mask2->compositeOpId(), mask->compositeOpId());
QCOMPARE(mask2->colorSpace(), mask->colorSpace());
QCOMPARE(KisLayerPropertiesIcons::nodeProperty(mask, KisLayerPropertiesIcons::colorizeEditKeyStrokes, true).toBool(), false);
QCOMPARE(KisLayerPropertiesIcons::nodeProperty(mask, KisLayerPropertiesIcons::colorizeShowColoring, true).toBool(), false);
QList<KisLazyFillTools::KeyStroke> strokes = mask->fetchKeyStrokesDirect();
qDebug() << ppVar(strokes.size());
QCOMPARE(strokes[0].dev->exactBounds(), QRect(50,50,10,20));
QCOMPARE(strokes[0].isTransparent, false);
QCOMPARE(strokes[0].color.colorSpace(), weirdCS);
QCOMPARE(strokes[1].dev->exactBounds(), QRect(150,50,10,20));
QCOMPARE(strokes[1].isTransparent, false);
QCOMPARE(strokes[1].color.colorSpace(), weirdCS);
QCOMPARE(strokes[2].dev->exactBounds(), QRect(0,0,10,10));
QCOMPARE(strokes[2].isTransparent, true);
QCOMPARE(strokes[2].color.colorSpace(), weirdCS);
}
#include <KoColorBackground.h>
void KisKraSaverTest::testRoundTripShapeLayer()
{
TestUtil::ReferenceImageChecker chk("kra_saver_test", "shape_layer");
QRect refRect(0,0,512,512);
QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument());
TestUtil::MaskParent p(refRect);
const qreal resolution = 144.0 / 72.0;
p.image->setResolution(resolution, resolution);
doc->setCurrentImage(p.image);
doc->documentInfo()->setAboutInfo("title", p.image->objectName());
KoPathShape* path = new KoPathShape();
path->setShapeId(KoPathShapeId);
path->moveTo(QPointF(10, 10));
path->lineTo(QPointF( 10, 110));
path->lineTo(QPointF(110, 110));
path->lineTo(QPointF(110, 10));
path->close();
path->normalize();
path->setBackground(toQShared(new KoColorBackground(Qt::red)));
path->setName("my_precious_shape");
KisShapeLayerSP shapeLayer = new KisShapeLayer(doc->shapeController(), p.image, "shapeLayer1", 75);
shapeLayer->addShape(path);
p.image->addNode(shapeLayer);
shapeLayer->setDirty();
qApp->processEvents();
p.image->waitForDone();
chk.checkImage(p.image, "00_initial_layer_update");
doc->exportDocumentSync(QUrl::fromLocalFile("roundtrip_shapelayer_test.kra"), doc->mimeType());
QScopedPointer<KisDocument> doc2(KisPart::instance()->createDocument());
doc2->loadNativeFormat("roundtrip_shapelayer_test.kra");
qApp->processEvents();
doc2->image()->waitForDone();
QCOMPARE(doc2->image()->xRes(), resolution);
QCOMPARE(doc2->image()->yRes(), resolution);
chk.checkImage(doc2->image(), "01_shape_layer_round_trip");
QVERIFY(chk.testPassed());
}
void KisKraSaverTest::testRoundTripShapeSelection()
{
TestUtil::ReferenceImageChecker chk("kra_saver_test", "shape_selection");
QRect refRect(0,0,512,512);
QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument());
TestUtil::MaskParent p(refRect);
doc->setCurrentImage(p.image);
const qreal resolution = 144.0 / 72.0;
p.image->setResolution(resolution, resolution);
doc->setCurrentImage(p.image);
doc->documentInfo()->setAboutInfo("title", p.image->objectName());
p.layer->paintDevice()->setDefaultPixel(KoColor(Qt::green, p.layer->colorSpace()));
KisSelectionSP selection = new KisSelection(p.layer->paintDevice()->defaultBounds());
KisShapeSelection *shapeSelection = new KisShapeSelection(doc->shapeController(), p.image, selection);
- selection->setShapeSelection(shapeSelection);
+ selection->convertToVectorSelectionNoUndo(shapeSelection);
KoPathShape* path = new KoPathShape();
path->setShapeId(KoPathShapeId);
path->moveTo(QPointF(10, 10));
path->lineTo(QPointF( 10, 110));
path->lineTo(QPointF(110, 110));
path->lineTo(QPointF(110, 10));
path->close();
path->normalize();
path->setBackground(toQShared(new KoColorBackground(Qt::red)));
path->setName("my_precious_shape");
shapeSelection->addShape(path);
KisTransparencyMaskSP tmask = new KisTransparencyMask();
tmask->setSelection(selection);
p.image->addNode(tmask, p.layer);
tmask->setDirty(p.image->bounds());
qApp->processEvents();
p.image->waitForDone();
chk.checkImage(p.image, "00_initial_shape_selection");
doc->exportDocumentSync(QUrl::fromLocalFile("roundtrip_shapeselection_test.kra"), doc->mimeType());
QScopedPointer<KisDocument> doc2(KisPart::instance()->createDocument());
doc2->loadNativeFormat("roundtrip_shapeselection_test.kra");
qApp->processEvents();
doc2->image()->waitForDone();
QCOMPARE(doc2->image()->xRes(), resolution);
QCOMPARE(doc2->image()->yRes(), resolution);
chk.checkImage(doc2->image(), "00_initial_shape_selection");
KisNodeSP node = doc2->image()->root()->firstChild()->firstChild();
KisTransparencyMask *newMask = dynamic_cast<KisTransparencyMask*>(node.data());
QVERIFY(newMask);
- QVERIFY(newMask->selection()->hasShapeSelection());
+ QVERIFY(newMask->selection()->hasNonEmptyShapeSelection());
QVERIFY(chk.testPassed());
}
void KisKraSaverTest::testExportToReadonly()
{
TestUtil::testExportToReadonly(QString(FILES_DATA_DIR), KraMimetype);
}
KISTEST_MAIN(KisKraSaverTest)
diff --git a/plugins/impex/libkra/tests/util.h b/plugins/impex/libkra/tests/util.h
index ce4c705662..1481543127 100644
--- a/plugins/impex/libkra/tests/util.h
+++ b/plugins/impex/libkra/tests/util.h
@@ -1,222 +1,222 @@
/*
* Copyright (c) 2008 Boudewijn Rempt boud@valdyas.org
*
* 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 _UTIL_H_
#define _UTIL_H_
#include <QTest>
#include <QBitArray>
#include <KisDocument.h>
#include <KoDocumentInfo.h>
#include <KoColorSpaceRegistry.h>
#include <KoShapeContainer.h>
#include <KoColorSpace.h>
#include <KoPathShape.h>
#include <kis_count_visitor.h>
#include "kis_types.h"
#include "filter/kis_filter_registry.h"
#include "filter/kis_filter_configuration.h"
#include "filter/kis_filter.h"
#include "KisPart.h"
#include "kis_image.h"
#include "kis_pixel_selection.h"
#include "kis_group_layer.h"
#include "kis_paint_layer.h"
#include "kis_clone_layer.h"
#include "kis_adjustment_layer.h"
#include "kis_shape_layer.h"
#include "kis_filter_mask.h"
#include "kis_transparency_mask.h"
#include "kis_selection_mask.h"
#include "kis_selection.h"
#include "kis_fill_painter.h"
#include "kis_shape_selection.h"
#include "kis_default_bounds.h"
#include "kis_transform_mask_params_interface.h"
#include <KisGlobalResourcesInterface.h>
KisSelectionSP createPixelSelection(KisPaintDeviceSP paintDevice)
{
KisSelectionSP pixelSelection = new KisSelection(new KisSelectionDefaultBounds(paintDevice));
KisFillPainter gc(pixelSelection->pixelSelection());
gc.fillRect(10, 10, 200, 200, KoColor(gc.device()->colorSpace()));
gc.fillRect(150, 150, 200, 200, KoColor(QColor(100, 100, 100, 100), gc.device()->colorSpace()));
gc.end();
return pixelSelection;
}
KisSelectionSP createVectorSelection(KisPaintDeviceSP paintDevice, KisImageSP image, KoShapeControllerBase *shapeController)
{
- KisSelectionSP vectorSelection = new KisSelection(new KisSelectionDefaultBounds(paintDevice));
+ KisSelectionSP selection = new KisSelection(new KisSelectionDefaultBounds(paintDevice));
KoPathShape* path = new KoPathShape();
path->setShapeId(KoPathShapeId);
path->moveTo(QPointF(10, 10));
path->lineTo(QPointF(10, 10) + QPointF(100, 0));
path->lineTo(QPointF(100, 100));
path->lineTo(QPointF(10, 10) + QPointF(0, 100));
path->close();
path->normalize();
- KisShapeSelection* shapeSelection = new KisShapeSelection(shapeController, image, vectorSelection);
+ KisShapeSelection* shapeSelection = new KisShapeSelection(shapeController, image, selection);
shapeSelection->addShape(path);
- vectorSelection->setShapeSelection(shapeSelection);
+ selection->convertToVectorSelectionNoUndo(shapeSelection);
- return vectorSelection;
+ return selection;
}
QTransform createTestingTransform() {
return QTransform(1,2,3,4,5,6,7,8,9);
}
KisDocument* createCompleteDocument()
{
KisImageSP image = new KisImage(0, 1024, 1024, KoColorSpaceRegistry::instance()->rgb8(), "test for roundtrip");
KisDocument *doc = qobject_cast<KisDocument*>(KisPart::instance()->createDocument());
doc->setCurrentImage(image);
doc->documentInfo()->setAboutInfo("title", image->objectName());
KisGroupLayerSP group1 = new KisGroupLayer(image, "group1", 50);
KisGroupLayerSP group2 = new KisGroupLayer(image, "group2", 100);
KisPaintLayerSP paintLayer1 = new KisPaintLayer(image, "paintlayer1", OPACITY_OPAQUE_U8);
paintLayer1->setUserLocked(true);
QBitArray channelFlags(4);
channelFlags[0] = true;
channelFlags[2] = true;
paintLayer1->setChannelFlags(channelFlags);
{
KisFillPainter gc(paintLayer1->paintDevice());
gc.fillRect(10, 10, 200, 200, KoColor(Qt::red, paintLayer1->paintDevice()->colorSpace()));
gc.end();
}
KisPaintLayerSP paintLayer2 = new KisPaintLayer(image, "paintlayer2", OPACITY_TRANSPARENT_U8, KoColorSpaceRegistry::instance()->lab16());
paintLayer2->setVisible(false);
{
KisFillPainter gc(paintLayer2->paintDevice());
gc.fillRect(0, 0, 900, 1024, KoColor(QColor(10, 20, 30), paintLayer2->paintDevice()->colorSpace()));
gc.end();
}
KisCloneLayerSP cloneLayer1 = new KisCloneLayer(group1, image, "clonelayer1", 150);
cloneLayer1->setX(100);
cloneLayer1->setY(100);
KisSelectionSP pixelSelection = createPixelSelection(paintLayer1->paintDevice());
KisFilterConfigurationSP kfc = KisFilterRegistry::instance()->get("pixelize")->defaultConfiguration(KisGlobalResourcesInterface::instance());
Q_ASSERT(kfc);
KisAdjustmentLayerSP adjustmentLayer1 = new KisAdjustmentLayer(image, "adjustmentLayer1", kfc->cloneWithResourcesSnapshot(), pixelSelection);
KisSelectionSP vectorSelection = createVectorSelection(paintLayer2->paintDevice(), image, doc->shapeController());
KisAdjustmentLayerSP adjustmentLayer2 = new KisAdjustmentLayer(image, "adjustmentLayer2", kfc->cloneWithResourcesSnapshot(), vectorSelection);
image->addNode(paintLayer1);
image->addNode(group1);
image->addNode(paintLayer2, group1);
image->addNode(group2);
image->addNode(cloneLayer1, group2);
image->addNode(adjustmentLayer1, group2);
// KoShapeContainer * parentContainer =
// dynamic_cast<KoShapeContainer*>(doc->shapeForNode(group1));
KoPathShape* path = new KoPathShape();
path->setShapeId(KoPathShapeId);
path->moveTo(QPointF(10, 10));
path->lineTo(QPointF(10, 10) + QPointF(100, 0));
path->lineTo(QPointF(100, 100));
path->lineTo(QPointF(10, 10) + QPointF(0, 100));
path->close();
path->normalize();
KisShapeLayerSP shapeLayer = new KisShapeLayer(doc->shapeController(), image, "shapeLayer1", 75);
shapeLayer->addShape(path);
image->addNode(shapeLayer, group1);
image->addNode(adjustmentLayer2, group1);
KisFilterMaskSP filterMask1 = new KisFilterMask();
filterMask1->setName("filterMask1");
kfc = KisFilterRegistry::instance()->get("pixelize")->defaultConfiguration(KisGlobalResourcesInterface::instance());
filterMask1->setFilter(kfc->cloneWithResourcesSnapshot());
kfc = 0; // kfc cannot be shared!
filterMask1->setSelection(createPixelSelection(paintLayer1->paintDevice()));
image->addNode(filterMask1, paintLayer1);
KisFilterMaskSP filterMask2 = new KisFilterMask();
filterMask2->setName("filterMask2");
kfc = KisFilterRegistry::instance()->get("pixelize")->defaultConfiguration(KisGlobalResourcesInterface::instance());
filterMask2->setFilter(kfc);
kfc = 0; // kfc cannot be shared!
filterMask2->setSelection(createVectorSelection(paintLayer2->paintDevice(), image, doc->shapeController()));
image->addNode(filterMask2, paintLayer2);
KisTransparencyMaskSP transparencyMask1 = new KisTransparencyMask();
transparencyMask1->setName("transparencyMask1");
transparencyMask1->setSelection(createPixelSelection(paintLayer1->paintDevice()));
image->addNode(transparencyMask1, group1);
KisTransparencyMaskSP transparencyMask2 = new KisTransparencyMask();
transparencyMask2->setName("transparencyMask2");
transparencyMask2->setSelection(createPixelSelection(paintLayer1->paintDevice()));
image->addNode(transparencyMask2, group2);
KisSelectionMaskSP selectionMask1 = new KisSelectionMask(image);
image->addNode(selectionMask1, paintLayer1);
selectionMask1->setName("selectionMask1");
selectionMask1->setSelection(createPixelSelection(paintLayer1->paintDevice()));
KisSelectionMaskSP selectionMask2 = new KisSelectionMask(image);
selectionMask2->setName("selectionMask2");
selectionMask2->setSelection(createPixelSelection(paintLayer2->paintDevice()));
image->addNode(selectionMask2, paintLayer2);
KisTransformMaskSP transformMask = new KisTransformMask();
transformMask->setName("testTransformMask");
transformMask->setTransformParams(KisTransformMaskParamsInterfaceSP(
new KisDumbTransformMaskParams(createTestingTransform())));
image->addNode(transformMask, paintLayer2);
return doc;
}
KisDocument *createEmptyDocument()
{
KisImageSP image = new KisImage(0, 1024, 1024, KoColorSpaceRegistry::instance()->rgb8(), "test for roundtrip");
KisDocument *doc = qobject_cast<KisDocument*>(KisPart::instance()->createDocument());
doc->setCurrentImage(image);
doc->documentInfo()->setAboutInfo("title", image->objectName());
return doc;
}
#endif
diff --git a/plugins/paintops/libpaintop/forms/wdgautobrush.ui b/plugins/paintops/libpaintop/forms/wdgautobrush.ui
index a9eccf67c1..b106b8af4d 100644
--- a/plugins/paintops/libpaintop/forms/wdgautobrush.ui
+++ b/plugins/paintops/libpaintop/forms/wdgautobrush.ui
@@ -1,432 +1,435 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>KisWdgAutoBrush</class>
<widget class="QWidget" name="KisWdgAutoBrush">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>429</width>
- <height>279</height>
+ <height>288</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout_3" columnstretch="0,1">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<layout class="QVBoxLayout">
<property name="spacing">
<number>8</number>
</property>
<item>
<widget class="QToolButton" name="brushPreview">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>110</horstretch>
<verstretch>110</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>110</width>
<height>110</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblMaskType">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Mask Type:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxMaskType"/>
</item>
<item>
<widget class="QLabel" name="lblMaskShape">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Shape:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxShape">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<item>
<property name="text">
<string>Circle</string>
</property>
</item>
<item>
<property name="text">
<string>Square</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QCheckBox" name="btnAntialiasing">
<property name="toolTip">
<string>The border of the brush will be smoothed to avoid aliasing</string>
</property>
<property name="text">
<string>Anti-alias</string>
</property>
</widget>
</item>
<item>
<spacer name="spacer4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>13</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="1" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>17</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1">
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,0,1">
<item row="0" column="1" colspan="2">
- <widget class="KisDoubleSliderSpinBox" name="inputRadius" >
+ <widget class="KisDoubleSliderSpinBox" name="inputRadius" native="true">
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lblAngle">
<property name="text">
<string>Angle:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblDiameter">
<property name="text">
<string>Diameter:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblRatio">
<property name="text">
<string>Ratio:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
- <widget class="KisDoubleSliderSpinBox" name="inputRatio" />
+ <widget class="KisDoubleSliderSpinBox" name="inputRatio" native="true"/>
</item>
<item row="2" column="0" colspan="3">
<widget class="QStackedWidget" name="stackedWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="currentIndex">
- <number>1</number>
+ <number>0</number>
</property>
<widget class="QWidget" name="PageFade">
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="QGroupBox" name="grpFade">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>1024</width>
<height>1024</height>
</size>
</property>
+ <property name="toolTip">
+ <string comment="Fade for brush softness"/>
+ </property>
<property name="title">
<string>Fade</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>4</number>
</property>
<item>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0">
<item row="0" column="0">
<widget class="QLabel" name="lblHorizontalFade">
<property name="text">
<string>Horizontal:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
- <widget class="KisDoubleSliderSpinBox" name="inputHFade" />
+ <widget class="KisDoubleSliderSpinBox" name="inputHFade" native="true"/>
</item>
<item row="0" column="2" rowspan="2">
- <widget class="KoAspectButton" name="aspectButton" />
+ <widget class="KoAspectButton" name="aspectButton" native="true"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblVerticalFade">
<property name="text">
<string>Vertical:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
- <widget class="KisDoubleSliderSpinBox" name="inputVFade" />
+ <widget class="KisDoubleSliderSpinBox" name="inputVFade" native="true"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="PageCurve">
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
- <widget class="QLabel" name="label_2">
+ <widget class="QLabel" name="lblSoftness">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Softness:</string>
</property>
<property name="alignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="0" column="1">
- <widget class="KisCurveWidget" name="softnessCurve" >
+ <widget class="KisCurveWidget" name="softnessCurve" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>10000</width>
<height>10000</height>
</size>
</property>
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="lblRandomness">
<property name="text">
<string>Randomness:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="lblSpikes">
<property name="text">
<string>Spikes:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
- <widget class="KisSliderSpinBox" name="inputAngle" >
- <property name="minimumSize">
+ <widget class="KisSliderSpinBox" name="inputAngle" native="true">
+ <property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item row="4" column="1" colspan="2">
- <widget class="KisSliderSpinBox" name="inputSpikes" />
+ <widget class="KisSliderSpinBox" name="inputSpikes" native="true"/>
</item>
<item row="6" column="1" colspan="2">
- <widget class="KisDoubleSliderSpinBox" name="density" />
+ <widget class="KisDoubleSliderSpinBox" name="density" native="true"/>
</item>
<item row="5" column="1" colspan="2">
- <widget class="KisDoubleSliderSpinBox" name="inputRandomness" />
+ <widget class="KisDoubleSliderSpinBox" name="inputRandomness" native="true"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="lblDensity">
<property name="text">
<string>Density:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="7" column="1" colspan="2">
- <widget class="KisSpacingSelectionWidget" name="spacingWidget" />
+ <widget class="KisSpacingSelectionWidget" name="spacingWidget" native="true"/>
</item>
<item row="7" column="0">
<widget class="QLabel" name="lblSpacing">
<property name="text">
<string>Spacing:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KisSliderSpinBox</class>
<extends>QWidget</extends>
<header>kis_slider_spin_box.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>KoAspectButton</class>
<extends>QWidget</extends>
<header>KoAspectButton.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>KisDoubleSliderSpinBox</class>
<extends>QWidget</extends>
<header>kis_slider_spin_box.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>KisCurveWidget</class>
<extends>QWidget</extends>
<header>widgets/kis_curve_widget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>KisSpacingSelectionWidget</class>
<extends>QWidget</extends>
<header>kis_spacing_selection_widget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
diff --git a/plugins/paintops/libpaintop/kis_dynamic_sensor.h b/plugins/paintops/libpaintop/kis_dynamic_sensor.h
index e06e98ea2f..d1ba080c3e 100644
--- a/plugins/paintops/libpaintop/kis_dynamic_sensor.h
+++ b/plugins/paintops/libpaintop/kis_dynamic_sensor.h
@@ -1,229 +1,229 @@
/*
* Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
* Copyright (c) 2011 Lukáš Tvrdý <lukast.dev@gmail.com>
*
* 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; 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 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 _KIS_DYNAMIC_SENSOR_H_
#define _KIS_DYNAMIC_SENSOR_H_
#include <kritapaintop_export.h>
#include <QObject>
#include <KoID.h>
#include <klocalizedstring.h>
#include "kis_serializable_configuration.h"
#include "kis_curve_label.h"
#include <kis_cubic_curve.h>
#include <kis_shared_ptr.h>
#include <kis_shared.h>
class QWidget;
class KisPaintInformation;
-const KoID FuzzyPerDabId("fuzzy", ki18n("Fuzzy Dab")); ///< generate a random number
-const KoID FuzzyPerStrokeId("fuzzystroke", ki18n("Fuzzy Stroke")); ///< generate a random number
-const KoID SpeedId("speed", ki18n("Speed")); ///< generate a number depending on the speed of the cursor
-const KoID FadeId("fade", ki18n("Fade")); ///< generate a number that increase every time you call it (e.g. per dab)
-const KoID DistanceId("distance", ki18n("Distance")); ///< generate a number that increase with distance
-const KoID TimeId("time", ki18n("Time")); ///< generate a number that increase with time
-const KoID DrawingAngleId("drawingangle", ki18n("Drawing angle")); ///< number depending on the angle
-const KoID RotationId("rotation", ki18n("Rotation")); ///< rotation coming from the device
-const KoID PressureId("pressure", ki18n("Pressure")); ///< number depending on the pressure
-const KoID PressureInId("pressurein", ki18n("PressureIn")); ///< number depending on the pressure
-const KoID XTiltId("xtilt", ki18n("X-Tilt")); ///< number depending on X-tilt
-const KoID YTiltId("ytilt", ki18n("Y-Tilt")); ///< number depending on Y-tilt
+const KoID FuzzyPerDabId("fuzzy", ki18nc("Context: dynamic sensors", "Fuzzy Dab")); ///< generate a random number
+const KoID FuzzyPerStrokeId("fuzzystroke", ki18nc("Context: dynamic sensors", "Fuzzy Stroke")); ///< generate a random number
+const KoID SpeedId("speed", ki18nc("Context: dynamic sensors", "Speed")); ///< generate a number depending on the speed of the cursor
+const KoID FadeId("fade", ki18nc("Context: dynamic sensors", "Fade")); ///< generate a number that increase every time you call it (e.g. per dab)
+const KoID DistanceId("distance", ki18nc("Context: dynamic sensors", "Distance")); ///< generate a number that increase with distance
+const KoID TimeId("time", ki18nc("Context: dynamic sensors", "Time")); ///< generate a number that increase with time
+const KoID DrawingAngleId("drawingangle", ki18nc("Context: dynamic sensors", "Drawing angle")); ///< number depending on the angle
+const KoID RotationId("rotation", ki18nc("Context: dynamic sensors", "Rotation")); ///< rotation coming from the device
+const KoID PressureId("pressure", ki18nc("Context: dynamic sensors", "Pressure")); ///< number depending on the pressure
+const KoID PressureInId("pressurein", ki18nc("Context: dynamic sensors", "PressureIn")); ///< number depending on the pressure
+const KoID XTiltId("xtilt", ki18nc("Context: dynamic sensors", "X-Tilt")); ///< number depending on X-tilt
+const KoID YTiltId("ytilt", ki18nc("Context: dynamic sensors", "Y-Tilt")); ///< number depending on Y-tilt
/**
* "TiltDirection" and "TiltElevation" parameters are written to
* preset files as "ascension" and "declination" to keep backward
* compatibility with older presets from the days when they were called
* differently.
*/
-const KoID TiltDirectionId("ascension", ki18n("Tilt direction")); /// < number depending on the X and Y tilt, tilt direction is 0 when stylus nib points to you and changes clockwise from -180 to +180.
-const KoID TiltElevationId("declination", ki18n("Tilt elevation")); /// < tilt elevation is 90 when stylus is perpendicular to tablet and 0 when it's parallel to tablet
+const KoID TiltDirectionId("ascension", ki18nc("Context: dynamic sensors", "Tilt direction")); /// < number depending on the X and Y tilt, tilt direction is 0 when stylus nib points to you and changes clockwise from -180 to +180.
+const KoID TiltElevationId("declination", ki18nc("Context: dynamic sensors", "Tilt elevation")); /// < tilt elevation is 90 when stylus is perpendicular to tablet and 0 when it's parallel to tablet
-const KoID PerspectiveId("perspective", ki18n("Perspective")); ///< number depending on the distance on the perspective grid
-const KoID TangentialPressureId("tangentialpressure", ki18n("Tangential pressure")); ///< the wheel on an airbrush device
+const KoID PerspectiveId("perspective", ki18nc("Context: dynamic sensors", "Perspective")); ///< number depending on the distance on the perspective grid
+const KoID TangentialPressureId("tangentialpressure", ki18nc("Context: dynamic sensors", "Tangential pressure")); ///< the wheel on an airbrush device
const KoID SensorsListId("sensorslist", "SHOULD NOT APPEAR IN THE UI !"); ///< this a non user-visible sensor that can store a list of other sensors, and multiply their output
class KisDynamicSensor;
typedef KisSharedPtr<KisDynamicSensor> KisDynamicSensorSP;
enum DynamicSensorType {
FUZZY_PER_DAB,
FUZZY_PER_STROKE,
SPEED,
FADE,
DISTANCE,
TIME,
ANGLE,
ROTATION,
PRESSURE,
XTILT,
YTILT,
TILT_DIRECTION,
TILT_ELEVATATION,
PERSPECTIVE,
TANGENTIAL_PRESSURE,
SENSORS_LIST,
PRESSURE_IN,
UNKNOWN = 255
};
/**
* Sensors are used to extract from KisPaintInformation a single
* double value which can be used to control the parameters of
* a brush.
*/
class PAINTOP_EXPORT KisDynamicSensor : public KisSerializableConfiguration
{
public:
enum ParameterSign {
NegativeParameter = -1,
UnSignedParameter = 0,
PositiveParameter = 1
};
protected:
KisDynamicSensor(DynamicSensorType type);
public:
~KisDynamicSensor() override;
/**
* @return the value of this sensor for the given KisPaintInformation
*/
qreal parameter(const KisPaintInformation& info);
/**
* @return the value of this sensor for the given KisPaintInformation
* curve -- a custom, temporary curve that should be used instead of the one for the sensor
* customCurve -- if it's a new curve or not; should always be true if the function is called from outside
* (aka not in parameter(info) function)
*/
qreal parameter(const KisPaintInformation& info, const KisCubicCurve curve, const bool customCurve);
/**
* This function is call before beginning a stroke to reset the sensor.
* Default implementation does nothing.
*/
virtual void reset();
/**
* @param parent the parent QWidget
* @param selector is a \ref QWidget that contains a signal called "parametersChanged()"
*/
virtual QWidget* createConfigurationWidget(QWidget* parent, QWidget* selector);
/**
* Creates a sensor from its identifier.
*/
static KisDynamicSensorSP id2Sensor(const KoID& id, const QString &parentOptionName);
static KisDynamicSensorSP id2Sensor(const QString& s, const QString &parentOptionName) {
return id2Sensor(KoID(s), parentOptionName);
}
static DynamicSensorType id2Type(const KoID& id);
static DynamicSensorType id2Type(const QString& s) {
return id2Type(KoID(s));
}
/**
* type2Sensor creates a new sensor for the give type
*/
static KisDynamicSensorSP type2Sensor(DynamicSensorType sensorType, const QString &parentOptionName);
static QString minimumLabel(DynamicSensorType sensorType);
static QString maximumLabel(DynamicSensorType sensorType, int max = -1);
static int minimumValue(DynamicSensorType sensorType);
static int maximumValue(DynamicSensorType sensorType, int max = -1);
static QString valueSuffix(DynamicSensorType sensorType);
static KisDynamicSensorSP createFromXML(const QString&, const QString &parentOptionName);
static KisDynamicSensorSP createFromXML(const QDomElement&, const QString &parentOptionName);
/**
* @return the list of sensors
*/
static QList<KoID> sensorsIds();
static QList<DynamicSensorType> sensorsTypes();
/**
* @return the identifier of this sensor
*/
static QString id(DynamicSensorType sensorType);
using KisSerializableConfiguration::fromXML;
using KisSerializableConfiguration::toXML;
void toXML(QDomDocument&, QDomElement&) const override;
void fromXML(const QDomElement&) override;
void setCurve(const KisCubicCurve& curve);
const KisCubicCurve& curve() const;
void removeCurve();
bool hasCustomCurve() const;
void setActive(bool active);
bool isActive() const;
virtual bool dependsOnCanvasRotation() const;
virtual bool isAdditive() const;
virtual bool isAbsoluteRotation() const;
inline DynamicSensorType sensorType() const { return m_type; }
/**
* @return the currently set length or -1 if not relevant
*/
int length() { return m_length; }
public:
static inline qreal scalingToAdditive(qreal x) {
return -1.0 + 2.0 * x;
}
static inline qreal additiveToScaling(qreal x) {
return 0.5 * (1.0 + x);
}
protected:
virtual qreal value(const KisPaintInformation& info) = 0;
int m_length;
private:
Q_DISABLE_COPY(KisDynamicSensor)
DynamicSensorType m_type;
bool m_customCurve;
KisCubicCurve m_curve;
bool m_active;
};
#endif
diff --git a/plugins/python/CMakeLists.txt b/plugins/python/CMakeLists.txt
index 3e46581bfd..88e5a0db60 100644
--- a/plugins/python/CMakeLists.txt
+++ b/plugins/python/CMakeLists.txt
@@ -1,118 +1,120 @@
# Copyright (C) 2012, 2013 Shaheed Haque <srhaque@theiet.org>
# Copyright (C) 2013 Alex Turbov <i.zaufi@gmail.com>
# Copyright (C) 2014-2016 Boudewijn Rempt <boud@valdyas.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
include(CMakeParseArguments)
#
# Simple helper function to install plugin and related files
# having only a name of the plugin...
# (just to reduce syntactic noise when a lot of plugins get installed)
#
function(install_pykrita_plugin name)
set(_options)
set(_one_value_args)
set(_multi_value_args PATTERNS FILE)
cmake_parse_arguments(install_pykrita_plugin "${_options}" "${_one_value_args}" "${_multi_value_args}" ${ARGN})
if(NOT name)
message(FATAL_ERROR "Plugin filename is not given")
endif()
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py)
install(FILES kritapykrita_${name}.desktop DESTINATION ${DATA_INSTALL_DIR}/krita/pykrita)
foreach(_f ${name}.py ${name}.ui ${install_pykrita_plugin_FILE})
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_f})
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${_f} DESTINATION ${DATA_INSTALL_DIR}/krita/pykrita)
endif()
endforeach()
elseif(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${name})
install(FILES ${name}/kritapykrita_${name}.desktop DESTINATION ${DATA_INSTALL_DIR}/krita/pykrita)
install(
DIRECTORY ${name}
DESTINATION ${DATA_INSTALL_DIR}/krita/pykrita
FILES_MATCHING
PATTERN "*.py"
PATTERN "*.ui"
PATTERN "*.txt"
PATTERN "*.csv"
PATTERN "*.html"
PATTERN "__pycache__*" EXCLUDE
PATTERN "tests*" EXCLUDE
)
# TODO Is there any way to form a long PATTERN options string
# and use it in a single install() call?
# NOTE Install specified patterns one-by-one...
foreach(_pattern ${install_pykrita_plugin_PATTERNS})
install(
DIRECTORY ${name}
DESTINATION ${DATA_INSTALL_DIR}/krita/pykrita
FILES_MATCHING
PATTERN "${_pattern}"
PATTERN "__pycache__*" EXCLUDE
PATTERN "tests*" EXCLUDE
)
endforeach()
else()
message(FATAL_ERROR "Do not know what to do with ${name}")
endif()
endfunction()
install_pykrita_plugin(hello)
install_pykrita_plugin(assignprofiledialog)
install_pykrita_plugin(scripter)
install_pykrita_plugin(colorspace)
install_pykrita_plugin(documenttools)
install_pykrita_plugin(filtermanager)
install_pykrita_plugin(exportlayers)
+install_pykrita_plugin(batch_exporter)
#install_pykrita_plugin(highpass)
install_pykrita_plugin(tenbrushes)
install_pykrita_plugin(tenscripts)
#install_pykrita_plugin(palette_docker) # Needs fixing -> bug 405194
install_pykrita_plugin(quick_settings_docker)
install_pykrita_plugin(lastdocumentsdocker)
# install_pykrita_plugin(scriptdocker)
install_pykrita_plugin(comics_project_management_tools)
install_pykrita_plugin(krita_script_starter)
install_pykrita_plugin(plugin_importer)
install_pykrita_plugin(mixer_slider_docker)
+install_pykrita_plugin(channels2layers)
# if(PYTHON_VERSION_MAJOR VERSION_EQUAL 3)
# install_pykrita_plugin(cmake_utils)
# install_pykrita_plugin(js_utils PATTERNS "*.json")
# install_pykrita_plugin(expand PATTERNS "*.expand" "templates/*.tpl")
# endif()
install( FILES
hello/hello.action
tenbrushes/tenbrushes.action
tenscripts/tenscripts.action
plugin_importer/plugin_importer.action
DESTINATION ${DATA_INSTALL_DIR}/krita/actions)
install(
DIRECTORY libkritapykrita
DESTINATION ${DATA_INSTALL_DIR}/krita/pykrita
FILES_MATCHING
PATTERN "*.py"
PATTERN "__pycache__*" EXCLUDE
)
diff --git a/plugins/python/assignprofiledialog/kritapykrita_assignprofiledialog.desktop b/plugins/python/assignprofiledialog/kritapykrita_assignprofiledialog.desktop
index fb4a784a97..968d3173f6 100644
--- a/plugins/python/assignprofiledialog/kritapykrita_assignprofiledialog.desktop
+++ b/plugins/python/assignprofiledialog/kritapykrita_assignprofiledialog.desktop
@@ -1,59 +1,60 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=assignprofiledialog
X-Python-2-Compatible=true
X-Krita-Manual=Manual.html
Name=Assign Profile to Image
Name[ar]=إسناد اللاحات إلى الصور
Name[ca]=Assigna un perfil a una imatge
Name[ca@valencia]=Assigna un perfil a una imatge
Name[cs]=Přiřadit obrázku profil
Name[el]=Αντιστοίχιση προφίλ σε εικόνα
Name[en_GB]=Assign Profile to Image
Name[es]=Asignar perfil a imagen
Name[et]=Pildile profiili omistamine
Name[eu]=Esleitu profila irudiari
Name[fi]=Liitä kuvaan profiili
Name[fr]=Attribuer un profil à l'image
Name[gl]=Asignar un perfil á imaxe
Name[is]=Úthluta litasniði á myndina
Name[it]=Assegna profilo a immagine
Name[ko]=이미지에 프로필 할당
Name[nl]=Profiel aan afbeelding toewijzen
Name[nn]=Tildel profil til bilete
Name[pl]=Przypisz profil do obrazu
Name[pt]=Atribuir um Perfil à Imagem
Name[pt_BR]=Atribuir perfil a imagem
+Name[sk]=Priradiť profil obrázku
Name[sv]=Tilldela profil till bild
Name[tr]=Görüntüye Profil Ata
Name[uk]=Призначити профіль до зображення
Name[x-test]=xxAssign Profile to Imagexx
Name[zh_CN]=为图像指定特性文件
Name[zh_TW]=指定設定檔到圖像
Comment=Assign a profile to an image without converting it.
Comment[ar]=أسنِد لاحة إلى صورة دون تحويلها.
Comment[ca]=Assigna un perfil a una imatge sense convertir-la.
Comment[ca@valencia]=Assigna un perfil a una imatge sense convertir-la.
Comment[el]=Αντιστοιχίζει ένα προφίλ σε μια εικόνα χωρίς μετατροπή.
Comment[en_GB]=Assign a profile to an image without converting it.
Comment[es]=Asignar un perfil a una imagen sin convertirla.
Comment[et]=Pildile profiili omistamine ilma seda teisendamata.
Comment[eu]=Esleitu profil bat irudi bati hura bihurtu gabe.
Comment[fi]=Liitä kuvaan profiili muuntamatta kuvaa
Comment[fr]=Attribuer un profil à une image sans la convertir.
Comment[gl]=Asignar un perfil a unha imaxe sen convertela.
Comment[is]=Úthluta litasniði á myndina án þess að umbreyta henni.
Comment[it]=Assegna un profilo a un'immagine senza convertirla.
Comment[ko]=프로필을 변환하지 않고 이미지에 할당합니다.
Comment[nl]=Een profiel aan een afbeelding toewijzen zonder het te converteren.
Comment[nn]=Tildel fargeprofil til eit bilete utan å konvertera det til profilen
Comment[pl]=Przypisz profil do obrazu bez jego przekształcania.
Comment[pt]=Atribui um perfil à imagem sem a converter.
Comment[pt_BR]=Atribui um perfil para uma imagem sem convertê-la.
Comment[sv]=Tilldela en profil till en bild utan att konvertera den.
Comment[tr]=Bir görüntüye, görüntüyü değiştirmeden bir profil ata.
Comment[uk]=Призначити профіль до зображення без його перетворення.
Comment[x-test]=xxAssign a profile to an image without converting it.xx
Comment[zh_CN]=仅为图像指定特性文件,不转换其色彩空间
Comment[zh_TW]=將設定檔指定給圖像,而不進行轉換。
diff --git a/plugins/python/batch_exporter/COATools.py b/plugins/python/batch_exporter/COATools.py
new file mode 100644
index 0000000000..02214ed5cd
--- /dev/null
+++ b/plugins/python/batch_exporter/COATools.py
@@ -0,0 +1,99 @@
+import os
+import json
+
+
+class COAToolsFormat:
+ def __init__(self, cfg, statusBar):
+ self.cfg = cfg
+ self.statusBar = statusBar
+ self.reset()
+
+ def reset(self):
+ self.nodes = []
+
+ def showError(self, msg):
+ msg, timeout = (self.cfg["error"]["msg"].format(msg), self.cfg["error"]["timeout"])
+ self.statusBar.showMessage(msg, timeout)
+
+ def collect(self, node):
+ print("COAToolsFormat collecting %s" % (node.name))
+ self.nodes.append(node)
+
+ def remap(self, oldValue, oldMin, oldMax, newMin, newMax):
+ if oldMin == newMin and oldMax == newMax:
+ return oldValue
+ return (((oldValue - oldMin) * (newMax - newMin)) / (oldMax - oldMin)) + newMin
+
+ def save(self, output_dir=""):
+ """
+ Parses layers configured to export to COA Tools and builds the JSON data
+ COA Tools need to import the files
+ """
+ # For each top-level node (Group Layer)
+ cfg = self.cfg
+ export_dir = output_dir
+ for wn in self.nodes:
+ children = wn.children
+ path = wn.path
+
+ if path != "":
+ export_dir = path
+
+ print("COAToolsFormat exporting %d items from %s" % (len(children), wn.name))
+ try:
+ if len(children) <= 0:
+ raise ValueError(wn.name, "has no children to export")
+
+ coa_data = {"name": wn.name, "nodes": []}
+ print("COAToolsFormat exporting %s to %s" % (wn.name, export_dir))
+ for idx, child in enumerate(children):
+ sheet_meta = dict()
+ if child.coa != "":
+ fn, sheet_meta = child.saveCOASpriteSheet(export_dir)
+ else:
+ fn = child.saveCOA(export_dir)
+
+ node = child.node
+ coords = node.bounds().getCoords()
+ relative_coords = coords
+
+ parent_node = node.parentNode()
+ parent_coords = parent_node.bounds().getCoords()
+ relative_coords = [coords[0] - parent_coords[0], coords[1] - parent_coords[1]]
+
+ p_width = parent_coords[2] - parent_coords[0]
+ p_height = parent_coords[3] - parent_coords[1]
+
+ tiles_x, tiles_y = 1, 1
+ if len(sheet_meta) > 0:
+ tiles_x, tiles_y = sheet_meta["tiles_x"], sheet_meta["tiles_y"]
+
+ coa_entry = {
+ "children": [],
+ "frame_index": 0,
+ "name": child.name,
+ "node_path": child.name,
+ "offset": [-p_width / 2, p_height / 2],
+ "opacity": self.remap(node.opacity(), 0, 255, 0, 1),
+ "pivot_offset": [0.0, 0.0],
+ "position": relative_coords,
+ "resource_path": fn.replace(
+ export_dir + os.path.sep + cfg["outDir"] + os.path.sep, ""
+ ),
+ "rotation": 0.0,
+ "scale": [1.0, 1.0],
+ "tiles_x": tiles_x,
+ "tiles_y": tiles_y,
+ "type": "SPRITE",
+ "z": idx - len(children) + 1,
+ }
+ coa_data["nodes"].append(coa_entry)
+
+ json_data = json.dumps(coa_data, sort_keys=True, indent=4, separators=(",", ": "))
+ with open(
+ export_dir + os.path.sep + cfg["outDir"] + os.path.sep + wn.name + ".json", "w"
+ ) as fh:
+ fh.write(json_data)
+
+ except ValueError as e:
+ self.showError(e)
diff --git a/plugins/python/batch_exporter/Config.py b/plugins/python/batch_exporter/Config.py
new file mode 100644
index 0000000000..a7b31281dc
--- /dev/null
+++ b/plugins/python/batch_exporter/Config.py
@@ -0,0 +1,15 @@
+import re
+from collections import OrderedDict
+
+
+CONFIG = {
+ "outDir": "export",
+ "rootPat": r"^root",
+ "sym": r"[^a-zA-Z0-9_-]",
+ "error": {"msg": "ERROR: {}", "timeout": 8000},
+ "done": {"msg": "DONE: {}", "timeout": 5000},
+ "delimiters": OrderedDict((("assign", "="), ("separator", ","))), # yapf: disable
+ "meta": {"c": [""], "e": ["png"], "m": [0], "p": [""], "s": [100]},
+}
+CONFIG["rootPat"] = re.compile(CONFIG["rootPat"])
+CONFIG["sym"] = re.compile(CONFIG["sym"])
diff --git a/plugins/python/batch_exporter/Infrastructure.py b/plugins/python/batch_exporter/Infrastructure.py
new file mode 100644
index 0000000000..90ff682514
--- /dev/null
+++ b/plugins/python/batch_exporter/Infrastructure.py
@@ -0,0 +1,363 @@
+import os
+import re
+from collections import OrderedDict
+from functools import partial
+from itertools import groupby, product, starmap, tee
+
+from krita import Krita
+from PyQt5.QtCore import QSize
+from PyQt5.QtGui import QColor, QImage, QPainter
+
+from .Utils import flip, kickstart
+from .Utils.Export import exportPath, sanitize
+from .Utils.Tree import pathFS
+
+KI = Krita.instance()
+
+
+def nodeToImage(wnode):
+ """
+ Returns an QImage 8-bit sRGB
+ """
+ SRGB_PROFILE = "sRGB-elle-V2-srgbtrc.icc"
+ [x, y, w, h] = wnode.bounds
+
+ is_srgb = (
+ wnode.node.colorModel() == "RGBA"
+ and wnode.node.colorDepth() == "U8"
+ and wnode.node.colorProfile().lower() == SRGB_PROFILE.lower()
+ )
+
+ if is_srgb:
+ pixel_data = wnode.node.projectionPixelData(x, y, w, h).data()
+ else:
+ temp_node = wnode.node.duplicate()
+ temp_node.setColorSpace("RGBA", "U8", SRGB_PROFILE)
+ pixel_data = temp_node.projectionPixelData(x, y, w, h).data()
+
+ return QImage(pixel_data, w, h, QImage.Format_ARGB32)
+
+
+def expandAndFormat(img, margin=0, is_jpg=False):
+ """
+ Draws the image with transparent background if `is_jpg == False`, otherwise with a white background.
+ It's done in a single function, to avoid creating extra images
+ """
+ if not margin and not is_jpg:
+ return img
+ corner = QSize(margin, margin)
+ white = QColor(255, 255, 255) if is_jpg else QColor(255, 255, 255, 0)
+ canvas = QImage(
+ img.size() + corner * 2, QImage.Format_RGB32 if is_jpg else QImage.Format_ARGB32
+ )
+ canvas.fill(white)
+ p = QPainter(canvas)
+ p.drawImage(margin, margin, img)
+ return canvas
+
+
+class WNode:
+ """
+ Wrapper around Krita's Node class, that represents a layer.
+ Adds support for export metadata and methods to export the layer
+ based on its metadata.
+ See the meta property for a list of supported metadata.
+ """
+
+ def __init__(self, cfg, node):
+ self.cfg = cfg
+ self.node = node
+
+ def __bool__(self):
+ return bool(self.node)
+
+ @property
+ def name(self):
+ a = self.cfg["delimiters"]["assign"]
+ name = self.node.name()
+ name = name.split()
+ name = filter(lambda n: a not in n, name)
+ name = "_".join(name)
+ return sanitize(name)
+
+ @property
+ def meta(self):
+ a, s = self.cfg["delimiters"].values()
+ meta = self.node.name().strip().split(a)
+ meta = starmap(lambda fst, snd: (fst[-1], snd.split()[0]), zip(meta[:-1], meta[1:]))
+ meta = filter(lambda m: m[0] in self.cfg["meta"].keys(), meta)
+ meta = OrderedDict((k, v.lower().split(s)) for k, v in meta)
+ meta.update({k: list(map(int, v)) for k, v in meta.items() if k in "ms"})
+ meta.setdefault("c", self.cfg["meta"]["c"]) # coa_tools
+ meta.setdefault("e", self.cfg["meta"]["e"]) # extension
+ meta.setdefault("m", self.cfg["meta"]["m"]) # margin
+ meta.setdefault("p", self.cfg["meta"]["p"]) # path
+ meta.setdefault("s", self.cfg["meta"]["s"]) # scale
+ return meta
+
+ @property
+ def path(self):
+ return self.meta["p"][0]
+
+ @property
+ def coa(self):
+ return self.meta["c"][0]
+
+ @property
+ def parent(self):
+ return WNode(self.cfg, self.node.parentNode())
+
+ @property
+ def children(self):
+ return [WNode(self.cfg, n) for n in self.node.childNodes()]
+
+ @property
+ def type(self):
+ return self.node.type()
+
+ @property
+ def position(self):
+ bounds = self.node.bounds()
+ return bounds.x(), bounds.y()
+
+ @property
+ def bounds(self):
+ bounds = self.node.bounds()
+ return bounds.x(), bounds.y(), bounds.width(), bounds.height()
+
+ @property
+ def size(self):
+ bounds = self.node.bounds()
+ return bounds.width(), bounds.height()
+
+ def hasDestination(self):
+ return "d=" in self.node.name()
+
+ def isExportable(self):
+ return (
+ self.isPaintLayer() or self.isGroupLayer() or self.isFileLayer() or self.isVectorLayer()
+ ) # yapf: disable
+
+ def isMarked(self):
+ return "e=" in self.node.name()
+
+ def isLayer(self):
+ return "layer" in self.type
+
+ def isMask(self):
+ return "mask" in self.type
+
+ def isPaintLayer(self):
+ return self.type == "paintlayer"
+
+ def isGroupLayer(self):
+ return self.type == "grouplayer"
+
+ def isFileLayer(self):
+ return self.type == "filelayer"
+
+ def isFilterLayer(self):
+ return self.type == "filterlayer"
+
+ def isFillLayer(self):
+ return self.type == "filllayer"
+
+ def isCloneLayer(self):
+ return self.type == "clonelayer"
+
+ def isVectorLayer(self):
+ return self.type == "vectorlayer"
+
+ def isTransparencyMask(self):
+ return self.type == "transparencyMask"
+
+ def isFilterMask(self):
+ return self.type == "filtermask"
+
+ def isTransformMask(self):
+ return self.type == "transformmask"
+
+ def isSelectionMask(self):
+ return self.type == "selectionmask"
+
+ def isColorizeMask(self):
+ return self.type == "colorizemask"
+
+ def rename(self, pattern):
+ """
+ Renames the layer, scanning for patterns in the user's input trying to preserve metadata.
+ Patterns have the form meta_name=value,
+ E.g. s=50,100 to tell the tool to export two copies of the layer at 50% and 100% of its size
+ This function will only replace or update corresponding metadata.
+ If the rename string starts with a name, the layer's name will change to that.
+ """
+ patterns = pattern.strip().split()
+ a = self.cfg["delimiters"]["assign"]
+
+ patterns = map(partial(flip(str.split), a), patterns)
+
+ success, patterns = tee(patterns)
+ success = map(lambda p: len(p) == 2, success)
+ if not all(success):
+ raise ValueError("malformed pattern.")
+
+ key = lambda p: p[0] in self.cfg["meta"].keys()
+ patterns = sorted(patterns, key=key)
+ patterns = groupby(patterns, key)
+
+ newName = self.node.name()
+ for k, ps in patterns:
+ for p in ps:
+ how = (
+ "replace"
+ if k is False
+ else "add"
+ if p[1] != "" and "{}{}".format(p[0], a) not in newName
+ else "subtract"
+ if p[1] == ""
+ else "update"
+ )
+ pat = (
+ p
+ if how == "replace"
+ else (r"$", r" {}{}{}".format(p[0], a, p[1]))
+ if how == "add"
+ else (
+ r"\s*({}{})[\w,]+\s*".format(p[0], a),
+ " " if how == "subtract" else r" \g<1>{} ".format(p[1]),
+ )
+ )
+ newName = re.sub(pat[0], pat[1], newName).strip()
+ self.node.setName(newName)
+
+ def save(self, dirname=""):
+ """
+ Transform Node to a QImage
+ processes the image, names it based on metadata, and saves the image to the disk.
+ """
+ img = nodeToImage(self)
+ meta = self.meta
+ margin, scale = meta["m"], meta["s"]
+ extension, path = meta["e"], meta["p"][0]
+
+ dirPath = (
+ exportPath(self.cfg, path, dirname)
+ if path
+ else exportPath(self.cfg, pathFS(self.parent), dirname)
+ )
+ os.makedirs(dirPath, exist_ok=True)
+
+ def append_name(path, name, scale, margin, extension):
+ """
+ Appends a formatted name to the path argument
+ Returns the full path with the file
+ """
+ meta_s = self.cfg["meta"]["s"][0]
+ out = os.path.join(path, name)
+ out += "_@{}x".format(scale / 100) if scale != meta_s else ""
+ out += "_m{:03d}".format(margin) if margin else ""
+ out += "." + extension
+ return out
+
+ it = product(scale, margin, extension)
+ # Below: scale for scale, margin for margin, extension for extension
+ it = starmap(
+ lambda scale, margin, extension: (
+ scale,
+ margin,
+ extension,
+ append_name(dirPath, self.name, scale, margin, extension),
+ ),
+ it,
+ )
+ it = starmap(
+ lambda scale, margin, extension, path: (
+ [int(1e-2 * wh * scale) for wh in self.size],
+ 100 - scale != 0,
+ margin,
+ extension,
+ path,
+ ),
+ it,
+ )
+ it = starmap(
+ lambda width_height, should_scale, margin, extension, path: (
+ img.smoothScaled(*width_height) if should_scale else img,
+ margin,
+ extension in ("jpg", "jpeg"),
+ path,
+ ),
+ it,
+ )
+ it = starmap(
+ lambda image, margin, is_jpg, path: (
+ expandAndFormat(image, margin, is_jpg=is_jpg),
+ path,
+ is_jpg
+ ),
+ it,
+ )
+ it = starmap(lambda image, path, is_jpg: image.save(path, quality=90 if is_jpg else -1), it)
+ kickstart(it)
+
+ def saveCOA(self, dirname=""):
+ img = nodeToImage(self)
+ meta = self.meta
+ path, extension = "", meta["e"]
+
+ dirPath = (
+ exportPath(self.cfg, path, dirname)
+ if path
+ else exportPath(self.cfg, pathFS(self.parent), dirname)
+ )
+ os.makedirs(dirPath, exist_ok=True)
+ ext = extension[0]
+ path = "{}{}".format(os.path.join(dirPath, self.name), ".{e}")
+ path = path.format(e=ext)
+ is_jpg = ext in ("jpg", "jpeg")
+ if is_jpg in ("jpg", "jpeg"):
+ img = expandAndFormat(img, is_jpg=is_jpg)
+ img.save(path, quality=90 if is_jpg else -1)
+
+ return path
+
+ def saveCOASpriteSheet(self, dirname=""):
+ """
+ Generate a vertical sheet of equaly sized frames
+ Each child of self is pasted to a master sheet
+ """
+ images = self.children
+ tiles_x, tiles_y = 1, len(images) # Length of vertical sheet
+ image_width, image_height = self.size # Target frame size
+ sheet_width, sheet_height = (image_width, image_height * tiles_y) # Sheet dimensions
+
+ sheet = QImage(sheet_width, sheet_height, QImage.Format_ARGB32)
+ sheet.fill(QColor(255, 255, 255, 0))
+ painter = QPainter(sheet)
+
+ p_coord_x, p_coord_y = self.position
+ for count, image in enumerate(images):
+ coord_x, coord_y = image.position
+ coord_rel_x, coord_rel_y = coord_x - p_coord_x, coord_y - p_coord_y
+
+ painter.drawImage(
+ coord_rel_x, image_height * count + coord_rel_y, nodeToImage(image),
+ )
+
+ meta = self.meta
+ path, extension = "", meta["e"]
+
+ dirPath = (
+ exportPath(self.cfg, path, dirname)
+ if path
+ else exportPath(self.cfg, pathFS(self.parent), dirname)
+ )
+ os.makedirs(dirPath, exist_ok=True)
+ path = "{}{}".format(os.path.join(dirPath, self.name), ".{e}")
+ path = path.format(e=extension[0])
+ is_jpg = extension in ("jpg", "jpeg")
+ if is_jpg:
+ sheet = expandAndFormat(sheet, is_jpg=True)
+ sheet.save(path, quality=90 if is_jpg else -1)
+
+ return path, {"tiles_x": tiles_x, "tiles_y": tiles_y}
diff --git a/plugins/python/batch_exporter/Manual.html b/plugins/python/batch_exporter/Manual.html
new file mode 100644
index 0000000000..d3cb2f87a0
--- /dev/null
+++ b/plugins/python/batch_exporter/Manual.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
+<head>
+ <meta charset="utf-8" />
+ <meta name="generator" content="pandoc" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
+ <title>Manual</title>
+ <style type="text/css">
+ code{white-space: pre-wrap;}
+ span.smallcaps{font-variant: small-caps;}
+ span.underline{text-decoration: underline;}
+ div.column{display: inline-block; vertical-align: top; width: 50%;}
+ </style>
+</head>
+<body>
+<h1 id="gdquest-art-tools-krita-plugin-for-game-developers-and-graphic-designers">Batch Exporter: Krita Plugin for Game Developers and Graphic Designers</h1>
+<p>Free Krita plugin for designers, game artists and digital artists to work more productively:</p>
+<ul>
+<li>Batch export assets to multiple sizes, file types, and custom paths. Supports <code>jpg</code> and <code>png</code>.</li>
+<li>Rename layers quickly with the smart rename tool</li>
+</ul>
+<h2 id="batch-export-layers">Batch Export Layers</h2>
+<p>Batch Exporter exports individual layers to image files based on metadata in the layer name. The supported options are:</p>
+<ul>
+<li><code>[e=jpg,png]</code> - supported export image extensions</li>
+<li><code>[s=20,50,100,150]</code> - size in <code>%</code></li>
+<li><code>[p=path/to/custom/export/directory]</code> - custom output path. Paths can be absolute or relative to the Krita document.</li>
+<li><code>[m=20,30,100]</code> - extra margin in <code>px</code>. The layer is trimmed to the smallest bounding box by default. This option adds extra padding around the layer.</li>
+</ul>
+<p>A typical layer name with metadata looks like: <code>CharacterTorso e=png m=30 s=50,100</code>. This exports the layer as two images, with an added padding of 30 pixels on each side: <code>CharacterTorso_s100_m030.png</code>, and <code>CharacterTorso_s050_m030.png</code>, a copy of the layer scaled down to half the original size.</p>
+<p>All the metadata tags are optional. Each tag can contain one or multiple options separated by comma <code>,</code>. Write <code>e=jpg</code> to export the layer to <code>jpg</code> only and <code>e=jpg,png</code> to export the layer twice, as a <code>jpg</code> and as a <code>png</code> file. Note that the other tag, <code>p=</code> has been left out. Below we describe how the plugin works.</p>
+<h2 id="getting-started">Getting Started</h2>
+<p>Batch Exporter gives two options to batch export layers: <code>Export All Layers</code> or <code>Export Selected Layers</code>.</p>
+<p><code>Export All Layers</code> only takes layers with the <code>e=extension[s]</code> tag into account. For example, if the layer name is <code>LeftArm e=png s=50,100</code>, <code>Export All Layers</code> will take it into account. If the layer name is <code>LeftArm s=50,100</code>, it will not be exported with this option.</p>
+<p><code>Export Selected Layers</code> exports all selected layers regardless of the tags.</p>
+<p>By default, the plugin exports the images in an <code>export</code> folder next to your Krita document. The export follows the structure of your layer stack. The group layers become directories and other layers export as files.</p>
+<blockquote>
+<p><strong>Supported layer types:</strong> paint, vector, group &amp; file layers.</p>
+</blockquote>
+<h2 id="smart-layer-rename-tool">Smart Layer Rename tool</h2>
+<p>Say we have this Krita document structure:</p>
+<pre><code>GodetteGroupLayer
+ +-- HeadGroupLayer
+ +-- Hair
+ +-- Eyes
+ +-- Rest
+ +-- Torso
+ +-- LeftArm
+ +-- RightArm
+Background</code></pre>
+<p>If you want to export <code>GodetteGroupLayer</code>, <code>HeadGroupLayer</code>, <code>Torso</code>, <code>LeftArm</code>, and <code>RightArm</code>, but not the other layers, you can select these layers and write the following in the <code>Update Layer Name</code> text box: <code>e=png s=40,100</code> and press <kbd>Enter</kbd>. In this example, Art Tools will export two copies of the selected layers to png at <code>40%</code> and <code>100%</code> scale. This is what <code>s=40,100</code> does.</p>
+<p>Say that we made a mistake: we want to export to <code>50%</code> instead of <code>40%</code>. Select the layers once more and write <code>s=50,100</code> in the text box. Press <kbd>Enter</kbd>. This will update the size tag and leave <code>e=png</code> untouched.</p>
+<p>The tool can do more than add and update meta tags. If you want to remove <code>GroupLayer</code> from the name on <code>GodetteGroupLayer</code> and <code>HeadGroupLayer</code>, select them and write <code>GroupLayer=</code> in the text box. Press <kbd>Enter</kbd> and the <code>GroupLayer</code> text will disappear from the selected layers.</p>
+<p>The <code>=</code> tells the tool to search and replace. <code>this=[that]</code> will replace <code>this</code> with <code>[that]</code>. If you don’t write anything after the equal sign, the tool will erase the text you searched for.</p>
+<p>The rename tool is smarter with meta tags. Writing <code>e=</code> will remove the extension tag entirely. For example, <code>Godete e=png s=50,100</code> will become <code>Godette s=50,100</code>.</p>
+</body>
+</html>
diff --git a/plugins/python/batch_exporter/Manual.md b/plugins/python/batch_exporter/Manual.md
new file mode 100644
index 0000000000..c9d32fcba6
--- /dev/null
+++ b/plugins/python/batch_exporter/Manual.md
@@ -0,0 +1,151 @@
+# Batch Exporter: Krita Plugin for Game Developers and Graphic Designers
+
+Free Krita plugin for designers, game artists and digital artists to work more
+productively:
+
+- Batch export assets to multiple sizes, file types, and custom paths. Supports
+ `jpg` and `png`.
+- Rename layers quickly with the smart rename tool
+
+## Batch Export Layers
+
+Batch Exporter exports individual layers to image files based on metadata in
+the layer name. The supported options are:
+
+- `[e=jpg,png]` - supported export image extensions
+- `[s=20,50,100,150]` - size in `%`
+- `[p=path/to/custom/export/directory]` - custom output path.
+ Paths can be absolute or relative to the Krita document.
+- `[m=20,30,100]` - extra margin in `px`. The layer is trimmed to the
+ smallest bounding box by default. This option adds extra padding around the
+ layer.
+
+A typical layer name with metadata looks like: `CharacterTorso e=png m=30
+s=50,100`. This exports the layer as two images, with an added padding of 30 pixels
+on each side: `CharacterTorso_s100_m030.png`, and `CharacterTorso_s050_m030.png`,
+a copy of the layer scaled down to half the original size.
+
+All the metadata tags are optional. Each tag can contain one or multiple options
+separated by comma `,`. Write `e=jpg` to export the layer to `jpg` only and
+`e=jpg,png` to export the layer twice, as a `jpg` and as a `png` file. Note that
+the other tag, `p=` has been left out. Below we describe how the plugin works.
+
+## Getting Started
+
+Batch Exporter gives two options to batch export layers: `Export All Layers`
+or `Export Selected Layers`.
+
+`Export All Layers` only takes layers with the `e=extension[s]` tag into
+account. For example, if the layer name is `LeftArm e=png s=50,100`, `Export All
+Layers` will take it into account. If the layer name is `LeftArm s=50,100`, it
+will not be exported with this option.
+
+`Export Selected Layers` exports all selected layers regardless of the tags.
+
+By default, the plugin exports the images in an `export` folder next to your
+Krita document. The export follows the structure of your layer stack. The group
+layers become directories and other layers export as files.
+
+> **Supported layer types:** paint, vector, group & file layers.
+
+## Smart Layer Rename tool
+
+Say we have this Krita document structure:
+
+```
+GodetteGroupLayer
+ +-- HeadGroupLayer
+ +-- Hair
+ +-- Eyes
+ +-- Rest
+ +-- Torso
+ +-- LeftArm
+ +-- RightArm
+Background
+```
+
+If you want to export `GodetteGroupLayer`, `HeadGroupLayer`, `Torso`, `LeftArm`,
+and `RightArm`, but not the other layers, you can select these layers and write
+the following in the `Update Layer Name` text box: `e=png s=40,100` and press
+<kbd>Enter</kbd>. In this example, Art Tools will export two copies of the
+selected layers to png at `40%` and `100%` scale. This is what `s=40,100` does.
+
+Say that we made a mistake: we want to export to `50%` instead of `40%`. Select
+the layers once more and write `s=50,100` in the text box. Press
+<kbd>Enter</kbd>. This will update the size tag and leave `e=png` untouched.
+
+The tool can do more than add and update meta tags. If you want to remove
+`GroupLayer` from the name on `GodetteGroupLayer` and `HeadGroupLayer`, select them
+and write `GroupLayer=` in the text box. Press <kbd>Enter</kbd> and the
+`GroupLayer` text will disappear from the selected layers.
+
+The `=` tells the tool to search and replace. `this=[that]` will replace `this`
+with `[that]`. If you don't write anything after the equal sign, the tool will
+erase the text you searched for.
+
+The rename tool is smarter with meta tags. Writing `e=` will remove the
+extension tag entirely. For example, `Godete e=png s=50,100` will become
+`Godette s=50,100`.
+
+## COA Tools format
+
+The exporter will generate the necessary sprite contents and metadata file for
+easy import in COA Tools / Blender.
+
+If you want to export your krita document to COA Tools format,
+simply click the `Document` button under COA Tools.
+
+If you want to export multiple or specific COA Tool documents from one Krita document
+(if you have e.g. multiple characters in one Krita document),
+you can do so by selecting a Group Layer to serve as root for each COA Tool export
+you want done.
+
+### Example
+You want to export two characters from the same Krita document in one go
+```
+Root
+ +-- Robot (Group Layer) <-- Select this layer
+ | +-- Head
+ | +-- Body
+ | +-- Legs
+ |
+ +-- Sketches
+ | +-- ...
+ |
+ +-- Minion (Group Layer) <-- ... and this layer
+ | +-- Hat
+ | +-- Head
+ |
+ Background
+```
+Once the Group Layers are selected you push "COA Tools -> Selected Layers".
+
+Each export root supports the following metadata:
+- `[p=path/to/custom/export/directory]` - custom output path.
+ Paths can be absolute or relative to the Krita document.
+
+Each child node of an export root supports the following metadata:
+- `[e=jpg,png]` - supported export image extensions
+
+Generating frames to a sprite sheet from a Group Layer is also possible.
+Simply mark the layer containing each frame you want in the sheet with a
+`c=sheet` and each child layer will act as one frame you can switch when
+Working with COA Tools in Blender.
+
+### Example
+You want to export a character from the document, and be
+able to switch between each state of e.g. the mouth:
+```
+Root
+ +-- Robot (Group Layer) <-- If this is the export root
+ | +-- Mouth States c=sheet <-- ... mark this layer
+ | | +-- Open
+ | | +-- Half Open
+ | | +-- Closed
+ | |
+ | +-- Head
+ | +-- Body
+ | +-- Legs
+ |
+ Background
+```
diff --git a/plugins/python/batch_exporter/Utils/Export.py b/plugins/python/batch_exporter/Utils/Export.py
new file mode 100644
index 0000000000..0867267a7b
--- /dev/null
+++ b/plugins/python/batch_exporter/Utils/Export.py
@@ -0,0 +1,19 @@
+import os
+import re
+from ..Config import CONFIG
+
+
+def exportPath(cfg, path, dirname=""):
+ return os.path.join(dirname, subRoot(cfg, path))
+
+
+def subRoot(cfg, path):
+ patF, patR = cfg["rootPat"], CONFIG["outDir"]
+ return re.sub(patF, patR, path, count=1)
+
+
+def sanitize(path):
+ ps = path.split(os.path.sep)
+ ps = map(lambda p: re.sub(CONFIG["sym"], "_", p), ps)
+ ps = os.path.sep.join(ps)
+ return ps
diff --git a/plugins/python/batch_exporter/Utils/Tree.py b/plugins/python/batch_exporter/Utils/Tree.py
new file mode 100644
index 0000000000..b5ec25076e
--- /dev/null
+++ b/plugins/python/batch_exporter/Utils/Tree.py
@@ -0,0 +1,152 @@
+import os
+from itertools import chain
+
+def iterPre(node, maxDepth=-1):
+ """
+ Visit nodes in pre order.
+
+ Parameters
+ ----------
+ node: Node
+ maxDepth: int
+ Maximum depth level at which traversal will stop.
+
+ Returns
+ -------
+ out: iter(Node)
+ """
+
+ def go(nodes, depth=0):
+ for n in nodes:
+ yield n
+ # recursively call the generator if depth < maxDepth
+ it = go(n.children, depth + 1) if maxDepth == -1 or depth < maxDepth else iter()
+ yield from it
+
+ return go([node])
+
+
+def iterLevel(node, maxDepth=-1):
+ """
+ Visit nodes in level order.
+
+ Parameters
+ ----------
+ node: Node
+ maxDepth: int
+ Maximum depth level at which traversal will stop.
+
+ Returns
+ -------
+ out: iter(Node)
+ """
+
+ def go(nodes, depth=0):
+ yield from nodes
+ it = map(lambda n: go(n.children, depth + 1), nodes)
+ it = chain(*it) if maxDepth == -1 or depth < maxDepth else iter()
+ yield from it
+
+ return go([node])
+
+
+def iterLevelGroup(node, maxDepth=-1):
+ """
+ Visit nodes in level order just like `iterLevel`, but group nodes per level in an iterator.
+
+ Parameters
+ ----------
+ node: Node
+ maxDepth: int
+ Maximum depth level at which traversal will stop.
+
+ Returns
+ -------
+ out: iter(iter(Node))
+ Returns an iterator that holds an iterator for each depth level.
+ """
+
+ def go(nodes, depth=0):
+ yield iter(nodes)
+ it = map(lambda n: go(n.children, depth + 1), nodes)
+ it = chain(*it) if maxDepth == -1 or depth < maxDepth else iter()
+ yield from filter(None, it)
+
+ return go([node])
+
+
+def iterPost(node, maxDepth=-1):
+ """
+ Visit nodes in post order.
+
+ Parameters
+ ----------
+ node: Node
+ maxDepth: int
+ Maximum depth level at which traversal will stop.
+
+ Returns
+ -------
+ out: iter(Node)
+ """
+
+ def go(nodes, depth=0):
+ for n in nodes:
+ it = go(n.children, depth + 1) if maxDepth == -1 or depth < maxDepth else iter()
+ yield from it
+ yield n
+
+ return go([node])
+
+
+def path(node):
+ """
+ Get the path of the given node.
+
+ Parameters
+ ----------
+ node: Node
+
+ Return
+ ------
+ out: list(Node)
+ The path of nodes going through all the parents to the given node.
+ """
+
+ def go(n, acc=[]):
+ acc += [n]
+ n.parent and go(n.parent, acc)
+ return reversed(acc)
+
+ return list(go(node))
+
+
+def pathFS(node):
+ """
+ Get the path of the given node just like `path`, but returns a OS filesystem path based on
+ node names.
+
+ Parameters
+ ----------
+ node: Node
+ A node that has a `name` method.
+
+ Return
+ ------
+ out: str
+ The path of nodes going through all the parents to the given node in filesystem-compatile
+ string format.
+ """
+ it = filter(lambda n: n.parent, path(node))
+ it = map(lambda n: n.name, it)
+ return os.path.join('', *it)
+
+
+def iterDirs(node):
+ it = iterPre(node)
+ it = filter(lambda n: n.isGroupLayer(), it)
+ it = filter(
+ lambda n: any(i.isExportable() for i in chain(*map(lambda c: iterPre(c), n.children))), it
+ )
+ it = map(pathFS, it)
+ return it
diff --git a/plugins/python/batch_exporter/Utils/__init__.py b/plugins/python/batch_exporter/Utils/__init__.py
new file mode 100644
index 0000000000..b9a90cd743
--- /dev/null
+++ b/plugins/python/batch_exporter/Utils/__init__.py
@@ -0,0 +1,9 @@
+from collections import deque
+
+
+def flip(f):
+ return lambda *a: f(*reversed(a))
+
+
+def kickstart(it):
+ deque(it, maxlen=0)
diff --git a/plugins/python/batch_exporter/__init__.py b/plugins/python/batch_exporter/__init__.py
new file mode 100644
index 0000000000..bd7687d505
--- /dev/null
+++ b/plugins/python/batch_exporter/__init__.py
@@ -0,0 +1,3 @@
+from .batch_exporter import registerDocker # noqa
+
+registerDocker()
diff --git a/plugins/python/batch_exporter/batch_exporter.py b/plugins/python/batch_exporter/batch_exporter.py
new file mode 100644
index 0000000000..fc13e1e481
--- /dev/null
+++ b/plugins/python/batch_exporter/batch_exporter.py
@@ -0,0 +1,194 @@
+"""
+GDQuest Batch Exporter
+-----------------
+Batch export art assets from Krita using layer metadata.
+Updates and reads metadata in Krita's layer names, and uses it to smartly process and export layers.
+Export to the Blender Cut-Out Animation tools for modular 2d game animation.
+Licensed under the GNU GPL v3.0 terms
+"""
+
+from functools import partial
+from krita import DockWidget, DockWidgetFactory, DockWidgetFactoryBase, Krita
+from PyQt5.QtWidgets import (
+ QPushButton,
+ QStatusBar,
+ QLabel,
+ QLineEdit,
+ QHBoxLayout,
+ QVBoxLayout,
+ QGroupBox,
+ QWidget,
+)
+import os
+from .Config import CONFIG
+from .Infrastructure import WNode
+from .COATools import COAToolsFormat
+from .Utils import kickstart, flip
+from .Utils.Tree import iterPre
+
+KI = Krita.instance()
+
+
+def ensureRGBAU8(doc):
+ ensured = doc.colorModel() == "RGBA" and doc.colorDepth() == "U8"
+ if not ensured:
+ raise ValueError("only RGBA 8-bit depth supported!")
+
+
+def exportAllLayers(cfg, statusBar):
+ msg, timeout = (cfg["done"]["msg"].format("Exported all layers."), cfg["done"]["timeout"])
+ try:
+ doc = KI.activeDocument()
+
+ root = doc.rootNode()
+ root = WNode(cfg, root)
+
+ dirName = os.path.dirname(doc.fileName())
+ it = filter(lambda n: n.isExportable() and n.isMarked(), iterPre(root))
+ it = map(partial(flip(WNode.save), dirName), it)
+ kickstart(it)
+ except ValueError as e:
+ msg, timeout = cfg["error"]["msg"].format(e), cfg["error"]["timeout"]
+ statusBar.showMessage(msg, timeout)
+
+
+def exportSelectedLayers(cfg, statusBar):
+ msg, timeout = (cfg["done"]["msg"].format("Exported selected layers."), cfg["done"]["timeout"])
+ try:
+ doc = KI.activeDocument()
+
+ dirName = os.path.dirname(doc.fileName())
+ nodes = KI.activeWindow().activeView().selectedNodes()
+ it = map(partial(WNode, cfg), nodes)
+ it = map(partial(flip(WNode.save), dirName), it)
+ kickstart(it)
+ except ValueError as e:
+ msg, timeout = cfg["error"]["msg"].format(e), cfg["error"]["timeout"]
+ statusBar.showMessage(msg, timeout)
+
+
+def exportCOATools(mode, cfg, statusBar):
+ msg, timeout = (
+ cfg["done"]["msg"].format("Exported %s layers to COA Tools format." % (mode)),
+ cfg["done"]["timeout"],
+ )
+ try:
+ doc = KI.activeDocument()
+ ensureRGBAU8(doc)
+
+ coat_format = COAToolsFormat(cfg, statusBar)
+ dirName = os.path.dirname(doc.fileName())
+ nodes = KI.activeWindow().activeView().selectedNodes()
+
+ # If mode is document or no nodes are selected, use document root
+ if mode == "document" or len(nodes) == 0:
+ nodes = [doc.rootNode()]
+
+ it = map(partial(WNode, cfg), nodes)
+ # By convention all selected nodes should be Group Layers
+ # This is to represent a logical root for each export in COATools format
+ it = filter(lambda n: n.isGroupLayer(), it)
+ it = map(coat_format.collect, it)
+ kickstart(it)
+ coat_format.save(dirName)
+
+ except ValueError as e:
+ msg, timeout = cfg["error"]["msg"].format(e), cfg["error"]["timeout"]
+ statusBar.showMessage(msg, timeout)
+
+
+def renameLayers(cfg, statusBar, lineEdit):
+ msg, timeout = (cfg["done"]["msg"].format("Renaming successful!"), cfg["done"]["timeout"])
+ try:
+ nodes = KI.activeWindow().activeView().selectedNodes()
+ it = map(partial(WNode, cfg), nodes)
+ it = map(partial(flip(WNode.rename), lineEdit.text()), it)
+ kickstart(it)
+ except ValueError as e:
+ msg, timeout = cfg["error"]["msg"].format(e), cfg["error"]["timeout"]
+ statusBar.showMessage(msg, timeout)
+
+
+class GameArtTools(DockWidget):
+ title = "Batch Exporter"
+
+ def __init__(self):
+ super().__init__()
+ KI.setBatchmode(True)
+ self.setWindowTitle(self.title)
+ self.createInterface()
+
+ def createInterface(self):
+ uiContainer = QWidget(self)
+
+ exportLabel = QLabel("Export")
+ exportAllLayersButton = QPushButton("All Layers")
+ exportSelectedLayersButton = QPushButton("Selected Layers")
+ renameLabel = QLabel("Update Name and Metadata")
+ renameLineEdit = QLineEdit()
+ renameButton = QPushButton("Update")
+ statusBar = QStatusBar()
+
+ exportLabel.setToolTip("Export individual images")
+ exportAllLayersButton.setToolTip("Export all layers with metadata")
+ exportSelectedLayersButton.setToolTip("Export selected layers only")
+ renameButton.setToolTip("Batch update selected layer names and metadata")
+
+ # COA Tools GroupBox
+ coaToolsGroupBox = QGroupBox("COA Tools")
+ coaToolsHBoxLayout = QHBoxLayout()
+ coaToolsExportSelectedLayersButton = QPushButton("Selected Layers")
+ coaToolsExportDocumentButton = QPushButton("Document")
+
+ coaToolsGroupBox.setToolTip("Blender Cut-Out Animation Tools")
+ coaToolsExportSelectedLayersButton.setToolTip("Export selected layers only")
+ coaToolsExportDocumentButton.setToolTip("Export all layers with metadata")
+
+ coaToolsHBoxLayout.addWidget(coaToolsExportDocumentButton)
+ coaToolsHBoxLayout.addWidget(coaToolsExportSelectedLayersButton)
+ coaToolsGroupBox.setLayout(coaToolsHBoxLayout)
+
+ vboxlayout = QVBoxLayout()
+ vboxlayout.addWidget(exportLabel)
+ vboxlayout.addWidget(exportAllLayersButton)
+ vboxlayout.addWidget(exportSelectedLayersButton)
+
+ vboxlayout.addWidget(coaToolsGroupBox)
+ vboxlayout.addWidget(renameLabel)
+ vboxlayout.addWidget(renameLineEdit)
+
+ hboxlayout = QHBoxLayout()
+ hboxlayout.addStretch()
+ hboxlayout.addWidget(renameButton)
+
+ vboxlayout.addLayout(hboxlayout)
+ vboxlayout.addStretch()
+ vboxlayout.addWidget(statusBar)
+
+ uiContainer.setLayout(vboxlayout)
+ self.setWidget(uiContainer)
+
+ exportSelectedLayersButton.released.connect(
+ partial(exportSelectedLayers, CONFIG, statusBar)
+ )
+ exportAllLayersButton.released.connect(partial(exportAllLayers, CONFIG, statusBar))
+ coaToolsExportSelectedLayersButton.released.connect(
+ partial(exportCOATools, "selected", CONFIG, statusBar)
+ )
+ coaToolsExportDocumentButton.released.connect(
+ partial(exportCOATools, "document", CONFIG, statusBar)
+ )
+ renameLineEdit.returnPressed.connect(
+ partial(renameLayers, CONFIG, statusBar, renameLineEdit)
+ )
+ renameButton.released.connect(partial(renameLayers, CONFIG, statusBar, renameLineEdit))
+
+ def canvasChanged(self, canvas):
+ pass
+
+
+def registerDocker():
+ docker = DockWidgetFactory(
+ "pykrita_gdquest_art_tools", DockWidgetFactoryBase.DockRight, GameArtTools
+ )
+ KI.addDockWidgetFactory(docker)
diff --git a/plugins/python/batch_exporter/kritapykrita_batch_exporter.desktop b/plugins/python/batch_exporter/kritapykrita_batch_exporter.desktop
new file mode 100644
index 0000000000..4a4a549ba4
--- /dev/null
+++ b/plugins/python/batch_exporter/kritapykrita_batch_exporter.desktop
@@ -0,0 +1,20 @@
+[Desktop Entry]
+Type=Service
+ServiceTypes=Krita/PythonPlugin
+X-KDE-Library=batch_exporter
+X-Krita-Manual=Manual.html
+X-Python-2-Compatible=false
+Name=Batch Exporter
+Name[ca]=Exportador per lots
+Name[es]=Exportador por lotes
+Name[nl]=Exportprogramma voor bulk
+Name[pt]=Exportação em Lote
+Name[uk]=Пакетне експортування
+Name[x-test]=xxBatch Exporterxx
+Comment=Smart export tool that uses layer names to scale and (re-)export art assets in batches fast
+Comment[ca]=Eina d'exportació intel·ligent que usa els noms de les capes per escalar i (re)exportar elements d'art en lots ràpidament
+Comment[es]=Herramienta de exportación inteligente que usa nombres de capas para escalar y (volver a) exportar recursos artísticos por lotes de un modo rápido
+Comment[nl]=Slim hulpmiddel voor exporteren die lagennamen gebruikt om snel kunstbezittingen te schalen en (opnieuw) te exporteren in bulk
+Comment[pt]=Uma ferramenta inteligente de exportação em lote que usa os nomes das camadas para definir a escala e (re-)exportar os itens gráficos em lote de forma rápida
+Comment[uk]=Інструмент пакетного експортування, який використовує назви шарів для масштабування і швидкого (повторного) пакетного експортування художніх елементів
+Comment[x-test]=xxSmart export tool that uses layer names to scale and (re-)export art assets in batches fastxx
diff --git a/plugins/python/batch_exporter/pyproject.toml b/plugins/python/batch_exporter/pyproject.toml
new file mode 100644
index 0000000000..440365c381
--- /dev/null
+++ b/plugins/python/batch_exporter/pyproject.toml
@@ -0,0 +1,9 @@
+[tool.black]
+line-length=100
+include = '\.py$'
+exclude = '''
+/(
+ \.git
+ | Dependencies
+)/
+'''
\ No newline at end of file
diff --git a/plugins/python/channels2layers/Manual.html b/plugins/python/channels2layers/Manual.html
new file mode 100644
index 0000000000..e797ddc3fb
--- /dev/null
+++ b/plugins/python/channels2layers/Manual.html
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>Channels to Layers</title>
+ </head>
+ <body>
+ <h3>Channels to Layers</h3>
+
+ A Krita plugin designed to split channels from a layer to sub-layers:
+ <ul>
+ <li>RGB</li>
+ <li>CMY</li>
+ <li>CMYK</li>
+ <li>RGB as greayscale values</li>
+ <li>CMY as greayscale values</li>
+ <li>CMYK as greayscale values</li>
+ </ul>
+
+ <h3>Screenshot</h3>
+ <i>User interface to convert CMYK channel for a layer</i><br>
+ <img src="data:image/png;base64, /9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9Pjv/2wBDAQoLCw4NDhwQEBw7KCIoOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozv/wAARCAIaBUwDAREAAhEBAxEB/8QAGwABAAIDAQEAAAAAAAAAAAAAAAEEAgMFBgf/xABVEAABAwIDBAQICgcGBQMEAQUBAAIDBBESIVEFEzFBIlJhkQYUMlNxgZKhBxdVYpOisdHS4RUjM1SUssEWNkJyc/AkNXTC8UNjgiU0RYMmZER1s4T/xAAbAQEAAwEBAQEAAAAAAAAAAAAAAQIDBAUGB//EADkRAQACAQIDAwsEAgICAwEBAAABAhEDIQQSMRNBUQUUFSJSYXGBodHwMlORscHhM/EjQjRDVESS/9oADAMBAAIRAxEAPwD5+21gAxvAchorKuxSeDG1KyBs7KZjWPF2l1hcLr0+E1LxzdHdpcBq6teaMR8VPaGzKvZkojq6YR4vJOEWPoKx1NK2nOLOfW0L6M4vCpcdRvsrNiAg8GN9kIGXUb7KBcdRvsoFx1G+ygXHUb7KBcdRvsoH/wAG+ygXHUb7KBcdRvsoFx1G+ygf/BvsoFx1G+ygXHUb7KBcdRvsoFx1G+ygXHUb7KBcdRvsoFx1W+yEC46jfZCBcdRvshAuOq3uCBcdRvsoFx1G+ygXHUb7KBcdVvshA/8Ag32UDLqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lAuOo32UC46jfZQLjqN9lBFx1G+yoGYjuAehn8xShO6/wAvsBBi5pa5rbMOLnhRLLdf5fYCIN1/l9gIMWtLnObZgw88KJZbr/L7ARCDHYE9DL5iCnUZycAMuShL0HgrQwbQ8IKSmqQHRO4tPOzeC004ibREq2vGnHNL3dJsHa+wtrsbRXqdlyu6TXG+7H9FrNraU7Ts30OMx+mdlvwspdn7R8Eq2ohlilFPmHsIOF4PDsK5NTi83ik97t1taNXTnL514NU8EldUVE8LZm0VJLUtieLte5oyBHMXN/UrPNWtmbbrtp7c2ZBWuhlb47EWncsaWdMZAgDLsQY7Q2bs2eCrqqB9U6SnrRFK17W/rA8usWAcMxaxug27R8GoYNniqjiq6YsqI4ZI6mSNziHXzAbm0i3AoMNp7E2XAzasNFPVPqNlv6bpQ3BI3HhNgMwQSPTnwQbK7YOyoX19HTz1bqujphUY3hu7cLNJbYZ3s7j2IN/9jWNpQx7asVBpd/4x0RADhxYLceGV9eSCDsqDalVStkErzFsmGRkEDmtkmPCwLsuBvzOSDz1ZDDT7RfEIamKNjgDHPYSt1Bytf1IPQ7V2Vsmo8JK5kTaimp6OIz1AbgzAa2zWAAWJJHFBxtq7PpYKWjr6F8ppqsPAZNYvY5ps4EjIjMG/ag6Bo21tH4PwGCeYPhnJZT2xm0juZyHpKDZUeDFO2uooWvnhbXwyblkj2Pc2VvBpc3Igm2hzQV9neDba07OifJIyerbLNIxoBLIWaDm4kO9yC7/ZOmkrdnNPjdHDVzPikZUFjpGWbiDhbIg+jkgrbP2PsvaUdTPSRbRqRAWNFPG9gmde932twyGQBOfFBxPFnTVpp6aKVznSFscbh0znkCNUEVVHUUM5p6qF8MoAJY8WIug7NfUurPA2ikkigY6KtfE0xRNZ0RG3jYZ5m9yg0+DrWxfpGvwNfLRUZkhD2hwDy5rQ6x0xXQTt13jeztlbSka0VNTHI2ZzWhu8LH2DiBle1h6kHS2fP+jodgUkcMT4dokvqw6MOMwdIWYSSLgADK3PNB56agkO1pqGlY6Z7ZnRsa0XLrE/cgsf2a238lVf0ZQUqqjqKKYw1UD4ZAL4Hixsg9htynh2NRQbWp4GTVFTTQwtcGgspTum3JHXdfK/aeKDmQ7M2fSzbFDZ6vx6u3Moc3DghvJa+Yz4Zf1QTtCDZ0fg5jkinfWHaFQwTNwDE4BtsWV7Z8NSUCu8G4otjT1kcFZTSUzWPc2pfGcbXEDyW9JpzHFB5uyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAIyQb2joj0KUJsg1vH62P1oPQbM2gNl7DknbQ0VTJJVYL1VO2SwDAcr8FCTae0BtXYTZ3UNFTSR1QYDS07Y7gsJsbceCDz7B+tk9SlD3WwdiUHhHsmmlrKTxR9K7dNkiswVoGeHP8Ax9qhLy23JxU7TqHtoWUIb0BTsbhwAC1j26nmpQ4E/wC09ShLoUdTLRVENTA/DLEQ5p7VaJxOYU1KRqVmtukvo1J4f7OqqMCrmmoprWe1rC5pPYQujtq9ZjLyqcJraU4icw8vtjb9J+jpdk7GZIylnmM9RJJk6R2gHJq8+2lF9ftrfKHrafNWnLLj7Nr5tl1rKqANc5oLXMeLte0ixaRoQtll0bZo4KinnodjQ074Z2TEmZ7ycJvhF+A96DTS7anpBPuo2YpqqOpxH/C5jiQO0ZoLNT4QRyU08FNsyKmFRUMqJXCRznF7STbPgMzkgrTbZlmn2rKYWA7UvjAJ/V3eH5esWQZy7cllr62rMDA6spzA5tzZosBceygmfbFNWQNNZsuKarZEIhUb1zbgCzSWjIkC3cgx/S0E8kTq3Z7ahsNMyBgbM5hGH/Fccygr7V2hJtWvfVyMbGXNa0NaScLWgNGZzOQ4oOg7wkxVxrHbOhL5ojDVjG61Q0gDh/hOQOXNBS2ltIVzKeCGnbTUtK0tiia4uzJuSSeJP9EFik28+mbSxupo5YqeCWBzC4jeMkJJzHA58kGw7TG0p9mUtOyn2XFQucYpHSGzbkOu4nibj1oNm0/CJ0nhVNtSkZG6Ft4o4nNsx8VsJBGhFz60FaLa9JR19PV0Gyo6d0DnOIMzn47i1s+ACDRs2tpKI4p9nipka8PjeJ3RlpHLLiEGitq5a6vnrZbCWeR0jsOQBJvkg0G7jckk6lB15Nt0r9ht2WNkRNDXGRswnfiEhaGl1uHAcOCDVSbXbR1DZI6GHdOp/F54sRtODxJPI8Dlwsgmo2xHUVNOTs+IUlLE6KGmLyQL3JJPEm5ug27P8IPEqamZJQxVM1E5zqSV7iDETnmBk4A5i/NByHOc97nucS5xJJ1KBid13d6CDc8SSg7A8JJ/HHSvp45IJaZlPNTOJwSNa0AHsOVwRwKCu7a73VuzqkQtB2eyNjG3PSDHFwv3oNn6ax0ctNNRxyYqh9TE/G4GF7rX7CMhkUG+r8I2VMNe2PZkMMu0QPGJRI5xLg4Ou0HgCRw7exBxLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkCyBZAsgWQLIFkEEZIL+ztoz7MqWVVLIxsrAQC5jXDMWORBClDp1PhfterppKaaogdHK0teBTRNJB7Q24TCcuC8jeMzGSIX6Xas9HA6CMwOjc/GWywsk6VrXGIG2SBVbVnq6cQSGBsbX48MULI7uta5wgXyTAoMI3jzcZoL9RtasqoqWKWqJZSMDIGts0MA0tz7eKDXtHaNRtOodVVkwlmc0Nc+wBNhYXtz7UHGqP2vqUJWmjoj0D7FImwUBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggWCBYIFggqVP7X1ILbfJHoH2KRKgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBBTqv23qQW2+SPQPsUiVA9PXbB2U1+0aWk8bjqdn0wnMkjmujkFm3HAFvlZcUHPk8GNqRVMdK9kO/ff9WJmktbbFidnk23MoNT9gbQbWU9KyNkzqkF0L4pA5jwOJxcMrZ6II/QdY6tZSRPpp3vaX4op2uY1o4lzuAt2oMj4P14qmQAQuEkZlbM2ZpiwDi7HwsOBQYs2HVSVMsLJaUthYHvm8Ybumg5DpcL35cUE/ouQUsw3TZJWVUcImjnaWXcDYZcb248rIJrvB7aGzoJJqhsVoZN3K2OVr3RuPDEBwvZBlP4N7Sp6aaeRkNqeMSTsbM0viBtbE3iDmEGnZtHDVUu0pJcWKmpd7HY26WNoz9TigmTYtWyhdWB9PKxjQ+RsU7XvjaeBLRmOI9CDB2x61tZNSGNu8hhMz+mMIYG4r34HIhBt/s/tDxPxnBF+y3253rd7u+tg425+hBhVbFrKOhjrKjcsjlY18bTK3G9p4EN42QWfBmPZlTtOOj2hQTVbqqRkUW6m3eAk2JORvxCDqbR2VsraG0arZewdnyQPpJXb6tqKr9U2NtwScss7IKT/A3aDaxsQqKN9O6Dxjxxsv6kR3tcutfjlwQXdn+BkEsG0Zana1C5lPC3dSxVH6vG49HEbcMj60GpngrNWUuz6Omip21Usc1S+qdOcL4mmwytZoyyPO6CtN4HbSZV0cEEtLVNrGOkjmhlvGGt8ouJAsAg1bY8GqnY9DBXPq6Opp6h5ZE+nkLg6wzPAcOCDdR7Hgm8FmVDmxisrK8QQSyyYGsY1t3E52te2ZQZO8DK41FDHBWUNSyukdFFNDKSwPAuWk2yKClR+Dm0a6mdPBG02qBTMYTZ0snMN9AFyeSC1U+B9fC2mdFU0dW2eoFMTTy4xHIf8AC7L08L8EFXbWwZdhvbHPWUc0pc5ro6eXG6MjrZZIOWgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICCnVftvUgtt8kegfYpEqB3vCPwjqdo1k8FPXSP2e4MDYwMINmjjlc534oNz9rUMvhRtOZ05bSV9O+nE+AnBiaADbja4t6EGyn2ns3Z8dHsw1e/ibDUxzVUTHYWGYAdEGxIGEX9JQV9kz0Oxa+aM7Qp6iOrpXwmdsDnsiJIIJa4dIdHPLmg3Hacja2njbtzZ7WRRSAGOiIh6RF2OGHPFa/C2SCfHaFm05Ds+toKVj4GNqGyUz3U8773Nm2JA4ac7WQYzbS2REaiOiIjhO0KeZjQxwGFrSHkX4DEcgc7FBXdtWlbNt+USYjVztkgBaemBNi9WWqDqTtpJIPCPasNRK7xyDFunwuZui+RpwuJyJ0tfIXQee2XVw01JtSOV+F1RSbuMWJxOxsNuzIFB35dq7Kioa+OnrKdsFRRbqmpo6Uh7XdG4e/DxuDncgoK1ZVsb4GQSua5tdVt8TLiLYoYziv72t/wDigsVe3Y6mPx2l2hRUzzSiJ8MlFimBDMBAfhzBtxvldBwts1cNZJRmF+MRUcUTsiLOAzGaDf4J1tHs3wip66uk3cVO172nCXXfhOEZdqDqeCm3aakpdqwVNbHQ1Na5r2VEtPvmZEktLbHVB0IPCCJ1e+Y+FcLBCwQhr9m2imjObhgA11QVK7avg/tDZe2qamn/AEb4xVNmij3DiJWsZkMvJu65z4XQTXeEGzG0m0Y6SoLnDZsFBSgMcMQyMhzGWevGyC5suvoayibsqB1QYGbI8WfUw0737mV78TrgC9jYC40Qcrw1ZT7Oi2VsKmkc9tFTl8heMLsbzc3HI2Ay5ILeydsbDih2TSVFQxopaOZ28khL2RVL3XBLbZ2Hq4ILs22HbU2r4OU2y6qTaktFUb6pmbAYxiLgL2sABa6DA+FWzKTw1DInbjZdIyaGGRrcYbI/ypbc8/cgiPwlpabalF4ztyCtpqd76hwgoNyzeNYQwZC5JJ9AQeEkkdLK+V5u97i5xPMnMoMUBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQU6r9t6kFtvkj0D7FIlQCAgICAgICAgsz7SrqqBlPUVtRNCzyY3yFzR6igrICDbPVVFUWGonkl3bQxmNxOFo4AaBBqQEBAQEBAQWKPaFbs9znUVZPTOeLOMMhZcdtkGl73yyOkke573G7nONyT2lBig309bV0bZW01TLAJm4ZN28txjQ24hBoQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBBTqv23qQW2+SPQPsUiVA2TwS00zoZ43RyNtdrhYi4ug1oCAgICAgICAgICAgICAgyjikmfgijdI4gnC0XOQufcgxQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBBTqv23qQW2+SPQPsUiVA7nhNE+fwumhjAc+R0TGgniSxoCDobRpaH9E1cwjoZKjZ1TG1wpad8bcyQ5hJPSGXHigwrNj0VM2efA0QbSniZQE/wDpxus9zh/lBDe9BltyPYkEe0KJrqOOWndhpmwwStlBDrEPcRZ1xe/bwQTXTbHpvCmqoZaCkpaWnL2wvMTnjeWFi8A3Lb3yHYg4m3qeSnrmueyka2WJr43UYtHI3rAcu1B6BsezBXN2e7ZNM6L9GCpc+xEhkEWO+K+QNrEdpQVWUse0Rsmtio6KB8rKgztLCIcMeeItBvwPAcbBBcj2fsuq2hsOq3NPNFVOnZM2KF0UcmBtwcJORz4jRBz4qdm2qHZ8tPs+kgqTXeLhrAWxvbhDhizztnnxKC8dmbM2pHs+RppiHbRbTSSUsDoWuaRe1jxPb2oK27pdqbKrXP2ZTUT4a6CBksTC3A1znAtNzxFhmgz25HsSCPaFE11HHLTuw0zYYJWygh1iHuIs64vft4IN9d+jIq3blO3Y1II9mtEkFmm5dia3pG+belw7EGEFBs6onG0pYKaAfosVRhLHGHeY8Fy1tzbnYIMI2bEnrDPHFS1bo9nzSTxxRvji3jfJIDrEZWvZBv2RJCa7ZO0Y6GlilqaerZIxkdmEsabEC+RtkUHkJpvGJTLuoosVuhE3C0egINaAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgp1X7b1ILbfJHoH2KRKgdSfwl21UwGGauc9jgAf1bAbDhmBfkEGFXt7alfC6Cqq3PhkIMjQxoxkHibDM9qDLa+0o6yKipKUTCloYiyPfEYiSbuOWQz+xBhU7d2pWUppqipMjCAHEsbicBwu61z3oMI9rV8dfLXicmomuJHuY12O9r3BFuQQaaytqdoT7+qkMj7BoNgAAOAAGQHoQZ/pGt3+/3797udzisPIw4cPdkgmn2pX0hpzBUPZ4sXGGwHRxeV6b9qDdLt7as00Mr6t+KnLtzha0CPELGwAsLhBWgrqumjjjgnfG2KUTMDcsL7WxILFTtvaNcGR1VS90TZBJgja1gDhzFhke1B0dseETa3ZbqKKWtnMsrZJJKrACMN7ABvE3ObjmbBBzqnbu1KylNNUVJkYQA4ljcTgOF3Wue9Bpk2jWyy1Msk73PqxackD9YLg5+sBBlDtXaFPNBNDUvY+nj3cZAHRZn0e0Znigyn2ztGolMj57ExGKzI2tGA8RYC2aDXDtGtp/FjDUPZ4qXOgt/gLuNvSg1VNRNWVD6id2OR/lODQ2/qAsg1WOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogWOiBY6IFjogICCnVftvUgtt8kegfYpEqAJNzmUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lAudSgXOpQLnUoFzqUC51KBc6lA/wAJ9KAgp1X7b1ILbfJHoH2KRPNQB4n0oIQEBAQEBAQEBAQEBAQEBAQEBAQEGEryxtwg1b9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CBv36BA379Agb9+gQN+/QIG/foEDfv0CDe03aDqgyHkn0hAQU6r9t6kFtvkj0D7FInmoA8T6UHovBWm2fUUW027QiYWvEUTJXDOFz3EBw9BtfsQZjwdkqKXZdDuxDVGaqFRJguQIyL5DM2F7DtQYP8FWumo9zNUsiq5Hwt8ZpjG8SBtwLXzByzug1xeC7pKfZ0zqoNFUyR8wwfsA1peOed2jsQVfB2OOWvnEjGvAoqhwDhexEbiD6UFnZ/g43aOzHTwurBMInyXdSncnCCS3HfjYcbcUGmDYO/nocNTamqqZ1Q+Ys/ZBl8YIvxFveEFug8EzWUtKXy1LZ61uOAMpi+NouQ3G++V7dtkFKo2TSUexqesqKx4qaprzHTsiuAWvLTidfIZaINdBs2ml2fNtCvqn09OyRsTN3Hjc95BPC4yAGaC/J4NUtPU17ajaZFPRRRSmVkNzIH2yAv2oMabwfopvFIpNovin2jc0jDDcYcRa0vN+jcjldBUGxXX2W182F1fK6Nww/sy2TBrmgst2FQQ0jKmu2lJC2Sqkpmtjgxm7SOkcxlnmg5tVs+Sj2tJs6Zw3kc26c5uY42uEHS2lsCkpItotpdouqJ9mvAna6HA0tLsN2m5vYkXyQKzwdbFsWXaNO6sIga1z/GKUxNe0m12m5vmQg3v8GKBk09MdrOFRT07amS9P0Awta4i983AO4cO1Bqj8GmVdZTCiqpJKSopn1BkMP6xrWEhwwAm5uMrHO4QVds7F/RkNNUxunMFTiDRUQmKRrm2uCLnUWKDjT+QPSg6tRFJs3wPp2yUzIp6+pe4ukiGN8IazCQSLhuLFw4qErLfBagc8Ux2uW1Zom1pBp+g1mAPcC697gX5Z2QaW+DdPU1FE+jr3OoqmKWV80sOF0Qjvju0E37M87oEfg3BWyUc2z65z6KpdI18s0WF0JjbifdoJv0cxnmgtDY1JX7D2fT7Im376vaboxJNFgezoNydYnLnxQVNq+Do2ds/wDSNLJVOjhnEUgqqUwm5uQ5tybtyKDHb9NJUwbL2nFSgNq6VokkhiDWOmDnAiwFg6wGSDRsXZFTU+ENHST0MxG9Y6aN0ZFo8QxE6C180Finov7Sbcr3ufgjgY+QMpKcFzmNcAAxgsDkR6gSg1w7HoHisq5a2oioKVzI8Rp/1rnuvZuDFYWsc78kCu8HfE4a2ZtUJYoI4JoXBlt6yXyTxyPZmg20/g3DI+9RX7mJuzG1737rEQCQMIF8+PFBg7ZGyoKOOsqdo1DIapz/ABRraYOe5rTYueMVhnlYX4ILWzfBA1tJRvkmqWS14Jp91SmSNouWgvdfo3I7bDNBztn7GZXbQoqF1Y1k9TUugkjDCTDY2xHkb59yDOr2PRM2eKyh2g+oZHUinqMUGHCSCQ5uZxA2OhyQWtoeC4pqGOsgfWCMzsheKulMJ6XBzczcZH3INlT4M7LpztAfpmR36LlDKo+LcQSWjB0szfLOyDCPwUEm0KhrKmaWihp46kSxU5dI9r7YQGX43OedhYoMH0J8G/CCgeSJKapDXjxqnAO7LsLg5jr2ORQc/btBJs3bVXTSQOgaJXGNrha7CThI1Fuakc9ECAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgILbPIb6EGQ8k+kICCnVftvUgtt8kegfYpE81AHifSg6mzn/8A0iupd9TR+NFgvLNgLcJve1s73Qdet8JZI/0ZM5tLNJTMkiqNzUXM4e0NcTYAtNhx1QcifalMyqpaihZWh1PKJL1NTvL2IIAyFuHFBeqfC0zfpcMohGzaDWshbjv4uAMJ5Z3bcckHI2ZXjZ1RJKY95jglhte1sbS2/qug61N4TUsLaeV9DNJUwUhpRae0VsJbiDbcc0ERVrqDwKkpnvhdNVy2gwvBeyI2MlwPJBLWix7UGmPblNLQU0FbDWGWlj3bHU1Vu2vbckBwscxfiEFCsr/G6Khpt2W+KMewuLr48Ty6/Zxsg6GwiKuiqdnT08U8BkbMA6rbTuY4Ai4LuItxCDdt/bNO+v2rBTMZJFUshibJG7ot3YF7ai4sEGqi2/Swx0MlTQvmq9mgine2XCxwuXNxi2dieRCBQ7fpYo6J1dQyVNRQzulhc2XA12J2Ihwsedzlqgsu2lsx+wqR1dTPnLq6omDIpg1zL4CAcjkf6IOJVbQkrNrybRlaMck29LW8BnewQW37cxVG1phT2/SLg4Auvu7SB+eWfC3JBar/AAjpaqDaQiop2z7SaN4+SoxNjIcHWaLcMvsQV5tvCXaFbVeLEeNUgpsOPyei1uLhn5PDtQZUXhEaOOji8XLo4IJaeYCTCZGSOJNiPJIy7kFPaVVS1BjFK2rAbfEamfeE+jIWQc2fyB6UHRfNFV+CMULquPxmjqnv3cjjiMbmsAw65g5KEpPhADtB9X4sels7xLDj/wDawYr29dlIUHhD4lDQwml3sdO2eOVpfbeslyIGWRA55qBui8JKehfRw7PoXiipnSukjmlxPmMjcDrkAW6OQyQGeElNQQ0MOyaGSIUVWakPnlxmS7QC02A5C2SCptKuoKyMMpIq2J75A4+M1e8YwZ5AW7eJ0QbNvVTGnZtLS1bZRRUjGOdC44BJic4kHmcxmg0bM2rNFt6irquqmeIpmGR7nlxwBwJHaLXyUja91DQbbqXSyPqIi5zoZaCowFtzcEEjTKygXKnwnptoS1cVdRTPpKkReTMN8HRiweXEWcSCb5c0GDvCOmqairjq6F/iE9PFAyKKWz4mx2wHERmeN8uaDGq8I4ZnTCGgMMcmzW0DGb3FhAcDivbPhwQaIdqUE2yqeh2lRzSmkL9xJBMGHC43LXXBuL537UG6Hb1LJs6mpq6CtL6NpjidS1W7D2XJAcLHgScwgq7M2pTbNraCtbRvdPS1BlkcZf2jcrN4ZWzz53UjLZ22zs6m3TacSOFbFVAuOXQxdEjtuguVXhFRupJ6eloqkGoq46l8lRU7x12knCMuGfFQKlTtsVH6Z/4ct/SkrZB077uz8VuGenJELUPhO1r3Ry00vi0tHFTStimwPvHmHtdbI35Ilop5KKu2/SubK+nponNdI+vqMZIBuc7acggo7Wq/HtrVdVvHPbLM9zC454STb3KUKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICC2zyG+hBkPJPpCAgp1X7b1ILbfJHoH2KRPNQB4n0oIQEBAQEBAQEBAQEBAQEBAQEBAQEEOaHixQYbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KBuGalA3DNSgbhmpQNwzUoG4ZqUDcM1KDYBYWCCR5J9IQEFOq/bepBbb5I9A+xSJ5qAPE+lAAJBIBIHE24IFjYGxseBQQgIJaxzzZjS4gE2AvkOKCEBAQEBAQEEljgwPLSGk2BtkUEICAgICAgIMJnFrLg2zQa2iofG6RrXuYzynBtw30nkgw3j+sUDeP6xQN4/rFBlimwY+lgvbFbK+l0EB8hIAcSTwACDJ4qIpDHI17Hg2LXNse5BMramnfu5mSRPtfC9uE29BQRIKiEhsrXxki4D22JGuaDDeP6xQZNdM++HE7CLmwvYaoMd4/rFA3j+sUDeP6xQZF0wa15xBrr4SRkUGO8f1igbx/WKDKMzSvEceJ73Gwa0XJ9SCW790oia15kJwhgb0r6WQRIZ4nmOQOY9uRa4WI9SCWCokY97Gvc1gu5zW3DR26IMN4/rFA3j+sUDeP6xQN4/rFA3j+sUDeP6xQN4/rFA3j+sUDeP6xQN4/rFA3j+sUGbxURsY97Xta8Xa4tsHeg80GG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igbx/WKBvH9YoG8f1igstN2gnmEGQ8k+kICCnVftvUgtt8kegfYpE81AHifSg9N4J1NPS7N2uatgfTSiGGa4zDHOIJHaOPqQW/wCzxkh2XsqqdhbBLWPkc1wbjYzC7InIXFszqgrO2HsuWr2e0Yac1UroHwMrWTlpw9B9xyvkQdEEx+DNGKWilmModHFJJtBuK2DoF7LaZCyDmeDP/MKj/oan/wD1OQdDZ2wKas2c1s9N4vPJTPmjldWNxusCQRFa+E2t70Fel2LSVAoq0mQULqWSWq6WbXx+U0Hlcllv8yC7Q+DuzzR0PjmEOrYt46d1ayPxcEkNsw5uta59yCjJQ7IpNl7OdO2V1RW48cwk6EQbKW4gLZ5Dggx8IdmQULWOpaB0cDpC2OqbVCZkwHDgMjzsg109Ns6j2LBtCvppap9XK9kcbJd2GNZa5Jsbkl3uQWaPZ+yY4Nm+OwVEr9qSODHMlw7hmPAMrdI3zQW4tjtnptn7LqJSI4a6sErmcS2NrS63aQ0oNFFsnZO13bPqaeGelglrhSzxGXGbFuIOa62l7oOJtB9E6otQ08kMTLt/WSYy8g+VwFvQg7tbsjY7Zq+gp4ahtRS0fjLZ3y3BIa1xbhtwzOd0CDYFNPsmTeUwpqplG6pa91Y1z3WbizitcAjh6kGVPsjYj5aGiliqhNV0AqXztlFo3YS6wbbO+HmeaDXSbE2fth+zJKNktJFUSyxzMfKHn9W0PuHEC1wbZ80FfbWzaGn2dFV0zY6eUzGN1O2sZUFzbXD7t4aH1IPOz+QPSg7Nc2bZ/gZQU++FqypknduX4mluFgDXEZXBBNjwuoSvN2NsDxjxF8NWJRs1ta+dswyIjD3MDbcCLi98roNMOxdl176CsiinpqSWnnmnh3uN36riGut/iy5ZIFLsTZe1W0NfTxz0tK987amAyY3DdM3nRcRzBA7Cgs01FQ7c2LsujoYpKOOp2q9sjXybzB+rbcgm3Ic+aCjtrZWz6fZhrKQMpZopwwRCvZUGVhB6XRzBBAvyzQZbWZLUxeD205JWvMkEcT8b/wBa5zZHC5BzItbpdiBV0021fhEqaczMJ/SDxeeSwwiThc+4IMHRx7b8J9q1e0JKh9NSiad7cVnljXWDBfycyPQg10dPsitFdtA0M8VLQ07XuphUYjI9z8I6Vshnn6EF6KipaWGqq6JskdPXbFkmbFI7EYyH4XC/MXbkgwfsPZQqZNiiOfx+Oi8Y8a3nQLxHvC3BbybZXve6CptKl2Ls+LZ8Jp6l0tRTwzzzCUdAO8oNbbPLUoN2yNk7OrqKeWnpJNo1Anc1tN40IZGxWu1wH+MnPhwt2oLVOzZb9ibCpto0tRKZ6maJoZLg3QL2i/DMi/DsQVv0TsrZUMR2lDPVuqayWnYYpd3u2RuDS7gbuJPDhkgVex9lbG2fVyVsU1ZPDtCSkjDJd20ta0EOORzz4dqDDwtqKWHa0RoaaSlnjggdvWzHhum2sLCx7eaDDwvjlh27+kGytaauNk7Cx/6xpwNuXDi031QbvCjZtXWeEG1ayIMdHC5pkLpWtP7Np4E3PqQaZ2zbP8CIGCYWr6t0hEMlwWtYBhfbgbnySg21OxqQbCjqKGjdV4omGSrZVA7mQkXDorXAByz9N0GddsbZLXbU2bSxztrNlwGQ1L5LtmLbYwW26IzNs+Xag0zbDo49t7Ro27zdU1CZ2dLPFu2uz7LkoLDNibJlrNmbMZHUCerpo6ieoMtxGMJc4NbbO4HM80FXZ1Fsrb22IaakpJqKFjJJZi+pDi9jW3GZADTlx4Z9iDZtTZmyKVlFVOHi8b5jHUU0FYyoeGAAh7SOF8xY6IMKKk2LDsWmrq2mqal9RWvpw1k27DWANN+Bz6SCxTbApafaG0Iamk8YpqarNO2eWtbTjInIXBu62aCJ9jbK2Qza0lbFPV+I17KeJrJcAe0tcczY8hyQZ1+xtixy7ToaWKpE1LSeORzySgi1muwFttHWvfiEG+o8F9nUtO+lmdHHOyl3pq3V0Y/WYMQZuuNjw15oOdStmr/AmqjMwtRVjJGiZ9gGljgWsvzvY4Qg8+pQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgts8hvoQZDyT6QgIKdV+29SC23yR6B9ikTzUAeJ9KCxDXSwUVVSMDTHVYMZIzGE3FkF93hRtJw2dd0ROzmOjiJZfG05EP1Fhb0IK1RtNsksEtNQUtE6F+8Bga65dkcyScsuCCzUeFG0ah21HP3Q/SgaJg1pAaBww55cLc8kFbZVTFRyzSvqDE50L4gNxvAQ9paf8AELZHtQWqfwnqqeOLDSUjp46c0wqHMJfu7EW424G17XQS3aUdH4JSbMhqt7JWztkkjDCNy1o4XPEk24dUINEW23No4qapoKOs8XBbC+dji5jSb2yIuLngUFeTaMssVFFJHE5lECI2luTgXFxDs88z3INtbtd1XRijio6ajg3m9cyBruk+1rkknlyQTR7YfTUfic1JTVkAeZGMqGk7txyJBBBzsLjhkg20fhDPRwxR+KUsxp5HSUz5WEmBxNzhz4Xzsb5oNUG3a6n8WLHtx00z5mvc25c59g7FqDb3lBuPhHUMmpX0tLS0sdLKZmQxNOBzzxcbm5yy45IOSTiJJ5m6DoP23VSVlVVlsW8qoDA8BpsGloblnxsEFgeE9UIngUlJv5KY0slQWHePjw4dbA25gckFZm26plVT1IbFjp6bxZnRNsGEtzz42JQRS7ZrKKGljgLG+KzOmY7DckuABB5EWHDtKDGu2hHWMa2PZ1JSWdiJga4Fx9ZOXYEHOn8gelBcFZSS+DA2fI+SOpgqnTx2Zdsgc1rSCb5EYbqEsTt2rNW6qwxY3UfiZGE2wYMF+PG3vUhSberKIUbYRFaj3gaHNuHh/lNdqCMlA3Hwlq2VNJJS09NSRUZcYqeJhwHFk7Fckm4yOfBAl8JasxUsVJT01DHSVHjELadh6LyBe5JN+HNBortqRbQaGjZtFRl0gfJLTxuxHXi4gDO9hZBu2ptCklrNnCkMkkFBBHFjewNc/C4uJtc246oMNqbQpZ/CSXadGJXRSVHjGGUBrgS7ERkSg3VW146XwjqNpbLkM0VQXufHURWBD74mOF8x23Qa4tvGCqkkg2dRxQSw7mWlDXGORt753de97Z3ysEET+EFXNLK4RQRxvpTSNhY0hkcd72bnxvnc34lBsd4TVbqUx+L0wqXQeLOrAw70x2thve3DK9r2QU5tpzVFVS1EscTjSxxxtYW9FzWcMQvn2qRYotu+JSmduzKF87ZjNFK5jrxOvcWs61geAN0Gl22ap4o8eBxo5nTMJbm5znBxvnqOxQLcHhPUxl5no6SqBqXVUYmYSIZHG5LbEZcMjcZIKVVtaqrKR1NUOa8PqX1LnkdJz3AA+rJSNtRtMbVdSxV7IYd2Gxvq4oiZXMaLC4vY2AGigTtitpNqeEE1V+ujpJHNF8ILwwAC9r2vlwugw2/Xw7U25VVsDXtilcC0PAxWDQM+5BsirKR/g1Ns+Z8kc7KjfwlrMTX9HCWk3y9OaANuujoZKanoKOnfNDuZaiJjg97MrjM2F7C5AQbKvwmqqulnjdTUzJ6pjY6mqYwiSZotkc7C9hewF7INjvCqrdBIzxSjE01N4tNU7s7yRlgBc3sDYDMDkgpnbVYK+krmOZHPRxsjiLW5WaLC4PHtQbTt58ddDWUVBR0UkRcSIWOLZMQsQ4OJytcW7Sgwk2xG6qp54dk7Pg3D8eBkbi2Q6Ou43HYg0O2lM6iho8MYjhqHTtsM8TgAR6OiFIvjwnqXOqXVFHR1InqTVBsrCRHKeJbY8OGRuMlAr1+3azaTaxs7Yv8AjaltTKWtI6YBGWeQ6RUg/btXJV1VSWxY6qm8WkAabBlgMs+NmhBnNt51TSiOq2fRTzti3Lap7HbwNAsOBsSBwJCgRJWUkfgy3Z8L5JKiWpFRLdmFsdmloAN8+N+SDlqUCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlbZ5DfQiGQ8k+kICCnVftvUgtt8kegfYpE81AHifSghAQEBAQEBAQEBAQEBAQEBAQEBAQQQHCxF0EbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCBumdUIG6Z1QgbpnVCDJBI8k+kICCnVftvUgtt8kegfYpE81AHifSg3UlFU19QKekgfPKRcMYLm2voQTW7PrNmzCGtp5IHkYgHjiNQeaDCOmmlgmnYy8cGHeOv5NzYe9BqQbammmpJzDOzBI0AkXvkQCPcQg1INsFNNUiUwsLxDGZZLf4WggE+8IEFNNUiUwsLxDGZH2/wtHE+9BqQEBAQEBAQEBAQEBBtp2tdO0OAIsTY+hBfkpd1FHLJTMayUEscWCzgDY29aDZLsyWFsxlo2s3DmtlDmAFpdwyQYRUe+illjpo3MhaHSHAOiCbfaQpCGj8YEpipo3CJhkfZgyaLC/vCDVu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBA3cXmo/YCBu4vNR+wEDdxeaj9gIG7i81H7AQN3F5qP2AgbuLzUfsBBIjhLgDDHmeoFA5yCR5J9IQEFOq/bepBbb5I9A+xSJ5qAPE+lB2tmlzfBPbLqe4m3kAkLeO5u6/qxYboOnsGGOr2RsiGvjEsTtrFsLH/AOKPB0wOy9vWgox+LbToNpyuo6am3LoI4jEy27aZCCe024lBerYaVx8IaMbJp4mbNitBK1lnss9rbuPMkZ3KCKqCi2d+mZ2bPp5XU7aTctkZdrC9oxG3O+iDB9HA3aB2iyGipqY7PhqJhLCZI43PsOgzUn1C5QbqmkpqaprpKVjWMqth74hkZY25c0Ehp4A2vbtQcXYOUW1f/wDHyfa1B2WbNpnbOqtn1TaLxqCg8YDYKZwfGcIcC6S+ZIIuOGaCuKCj8R/T/i0fiviOHdW6PjP7O1vroLT6fYVBT0tHVy0jYpqJkj3GnkdO572XDmvAtkbC3CwzQcra8lPS7L2dSwUNMx9RRMlmnwXkc7E7geXD1oOGgICAgICAgINtPlOPQfsQesqJNlt8Htj+Pw1cjzFLhMEjWi28PG4KC5tmlp6nam2TI0AirpWNkPFjXCx/ogxllidTeEFIyghpmUwbEx7G2cG70CzjzOV7+lBlK6GCbb+z4aCGKOjpHMZI1tn2xNzced+KDGth2LQsdQTSUrW+KhzSKeQzGQsxB2O1rXPDhZBixlE6ppdm/o6mDJ9miV8uH9ZvN2XBwPLMD3oPKh2SBiUhiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSDtMqdgfosyPoj42OjuxI+xOvHgoHGDrvB4Z8EHPQSPJPpCAgp1X7b1ILbfJHoH2KRPNQB4n0oOhsraUey5DM1tUJ8xjhqGsBaeRBY66DdXbedVTxVcZq2VUBG5kfUMc2MaBojaAg5rKmdkM0LJCI57bxvJ1jcX9aDu1XhKx+xZaGOavnfPG2JxqXNwxtBBNrZuOQFzwCDjS7RrJ2zNlqHvE+Deg26eAWbf0INsG2do00wliqnBzYRBmAQYxwaQRYgIIm2xtGpkfJNWSSPfDuHOdbOO98PougrQ1E1OJBDIWCVhjfb/E08Qgunwg2saXxXx6TdbvdEWF3MtbCTa5FtUGVTtKE7Cp9lUgmEYlM85kIs6QgAAAcgB6c0GEO3dqQUYo46twhaC1rS0EtB4gEi4HoQVJqiaoEQmkLxDGI47/AOFovYe8oNSAgICAgICAgzhNphnyP2ILslRPNDFDJIXRwgtjabWaCbn3oNs20a2o3++qHv8AGHNdLe3TLfJJ9CDdUbd2pVU7qeese+J7Q17cumBa19eAzKBJt3astMaZ9Y8xOZu3DLpN0J4nhzQQ3be0m0XiYqnbkMLACGkhp4tBIuB2XQaRtCsEzJhO7eRx7prsrhlrW7skFfNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0DNAzQM0Eg2cCTkDqgpDggkeSfSEBBTqv23qQW2+SPQPsUieagDxPpQQgICAgICAgICAgICAgICAgICAgICCMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBhGgQMI0CBYaBBKCR5J9IQEFOq/bepBbb5I9A+xSJUBl2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qB0e1A6PagdHtQOj2oHR7UDo9qBlawugIKdV+29SC23yR6B9ikSoFpuzK99GaxtFUOphxmEZw96CqgnC7BjwnDe2K2V9EEICCS1zQC5pAcLi44hBCAgICDbNTT07i2WF7C1rXEFvAEXB9d0GpAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEFOq/bepBbb5I9A+xSM2BpkaHeSXAH0XUD1VbV10PwisggkeGR1TIIIgThMOQAtwsW/agqbT2dQxyUZpohhm2lPCSCekwPaGjuJQWdqPpqDwf2hSR0MDmR7XlijLy67OgbEZ8QMkGdXQ7LdtOo2PFs1kOGg37agPcXh4iEl8zbCeFu1BVh2XRv2/R0xpwYpdnb57bnN25c6/eLoNW3aqN+x9jRCjgY80TSJRixCz3ZcbWPHhzQa6YUVL4MGtloIqmpfVuha6RzrNbgB4Ai5vwQdSt2bsOijkoJ5KGNzaUOExfIZzKWYhlbDYk2tpzQU6uloptjCXZdPRTRRRRmd+N4qYnZBxcCbEYjbIWzCCKrZdGzanhDCyC0dHTOfCLnoHEwA+88dUHUq6qOnh2yZKSGoApKEkS4rHotFsiPSg5U0NDL4PiTZ8NDI+OAOqS97hURvxZkAmxbmBlfI5oPPoCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICCnVftvUgtt8kegfYpEqB1Y/CXasdO2JtQy7GbtkxiaZWt0D7Yh3oNVDtzaGzqfcU0rAwSbxuOJryx/DE0kZHIcEGP6a2hu6thlY9tY8vma+JrgXG93C46JzOYsgv7Y8J6msklipXhlPJDHES6JokwhrQW4uOG4OV0FaDwk2pT00dPFOxrY4zE1xiYXhhv0cRF7ZnJBVftOql2dHs+R7XQRfswY24mi97B1r2ueF0Gs1UxohRl/6gSGQNsPKIte/Hggtnb1e6jFK90MjWx7pr3wMdIGdUPIvZBE23K6eidSOdCyN7Q2QxwMY6QDgHOAueCDZN4R7UqKWSmknZgliEUpETQ6RotbE61zawzQa4tu7RiqZKhszS+WNsTw+Jrmua0ANBaRbKwQQ/bVa+iNIdw2NzAxzmwMa9zRnYuAvbIIKCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgp1X7b1ILbfJHoH2KRKgCTc5lAxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70DEdT3oGI6nvQMR1PegYjqe9AxHU96BiOp70C5INzfNAQU6r9t6kFtvkj0D7FInmoA8T6UEICAgICCQMTg0cSQEFnxIee+p+aB4kPPfU/NSHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgeJDz31PzQPEh576n5oHiQ899T80DxIee+p+aB4kPPfU/NA8SHnvqfmgChubCbj8z81AqoJHkn0hAQU6r9t6kFtvkj0D7FInmoA8T6UHovBXZ9FtCk2nHVwtc9zY4oJDxje4kAj12QbHbHgi8DjemB2m+eF2I+U1r3Oa1vrwX9aCnWeDzIYqoUteyrqKJzW1MLYy3Dc4btP+IB2R4ILbdh0dFSbZjdWR1VXSUwEke6I3b8bQcLv8VswTkg0VHgs+CCdvjRdW08O+lg3Dg0NsCQH8CQDn60HCj/AGrP84+1B6aibT0OxH7Umpo6qWSo3ELJbljbNDnOIHE5gBBd2Gdm7UrKuSsoIIY2UoBEdw1ri9rcYBOVsXuQItlwUPg5Xvq6dr65jsbC7/A1sgZ7zi7kGuqpdm09FJtqNjHQ1bMFNTE33cv+O/Y3iPSEFjauzqLY8EG0JadsnjNNGKaDPBiwDE959JyHP0IORsOlgrK9xqgXQQQvnkY02Lw0Xw35XNggyNUNsSRUUGy6SCeWVrYnwhzSL5WNyb+lBv8A0RTseyemrmVkUNUyGoG7LLEnIi/FpsQgyqNk0xqquoqaxtDTmsfBCBEX3IOeQ4NFx3oNZ2CKaKrk2hWtpxS1G4c1sZeXutcW7EGraGyodnUzDLWONQ+NsjY9wcBDgDk++eR0QczEpDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEgYkDEg67PB6d9F46Kyk3GG5fjdl7uKgckHpjO+fFBzUEjyT6QgIKdV+29SC23yR6B9ikTzUAeJ9KDr7JkkZsquiidA1874sDpKmOMsLHYr2cQSgvVO1K80tdUVctJLVTz08wfFVREN3d7AMa6/McO1Boqtu0LWVs2zqaeKq2g5rpTK4FkQDg4htszdwHHkgzqdu7Mezac0FHUtqtpx2fie3BE7EHHDzIJHNA2l4RxbShllfPtSOoljDXwMqP1BdaxNuNj1UHn2ftGf5h9qDu0G0qVtBLs7aEMslO+QSsfC4B8b7WJF8iCOI7EGQ2jQU0dbDRQVAjqaYQh0rwXYsYdiNuAytYIMpfCGoq4a0Vt5ZamBkLHNAAaGuBzHqPrKCrNtBsuxqWgEbg+CWSQvvkQ4DL3IOjJ4RxTyuhqKd8lBLBHG+LEMTXsYGiRh5HL1jIoOdszaP6NrxOI99GWujkjcbY2OFiOzJBaZX7K2fUQVWzYKt08UzZGmoe3C0A+TYDO+qDY/bGz6eF0Wz6eoa2epZPNvnA2DCSGNt2k5nsQS7bOz61ksW0Keo3Xjb6mIwubi6XFpv6Bmg07R25+kaepa+HBJUVnjFwei0YcIag2v2zSs2JNQQmtlEzGtEdQ9ro4SCCXNtnfly4oOLiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSBiQMSDMTyiEwiR27LsRZfInVBi13Sb6QgohBI8k+kICCnVftvUgtt8kegfYpE81AHifSghAQEBAQOBuOIQbN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UDfyfN9lA38nzfZQN/J832UGtBI8k+kICCnVftvUgtt8kegfYpE81AHifSghAQEBAQEHZd4L1zQ6PfUprGM3jqIS/rgLXOVrXtna90HHa0uNh6zog2Tw7mpkhZIycRuI3kdy1wHMdiA2FrqaSYzMa5jmgRm+J975jsFveg12IFyDY80AghuIg2PA6oLFfQybOqvF5XNc7dsfdvCzmhw+1BWQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEG2mpp6ypjpqaN0sshs1jeJKC7V7FdSUz5htCgndEQJIoZ8T23y0sfUSg5qCS0t4gi+qBYgAkGx4FBCAgICAgICAgICAgICAgICAgICAgICAgICAgkAkgDMnIIOrU+DW0aXbcOx3sY6qnDXNDXXaAdTytY39CCjWUUtDXT0cmF0lO8seWG4uOOaDQATwF+eSAAXGwBJ0CAASbAIN1PRz1QnMTLinjMklzbC0ED7SEGnCbE2NhxNuCCEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQdAbErXVVJTsa17qyITROa7o4De5J5Wsb6WQUXswPeAQ9rXWxt8koOhTbEqKllI4SRtFUyWRuInotjviJ7j3IOcAS3FY21QQgICAgICAgICAgICAgICAgICAgICAgICAgICDo0Gxpa6kkqzVUtLBHII8dRJgDnEXsMjyCCZ9hVlLLXx1BjY6hjbJIcVw4OLQ3CRxviBQc4tIAJBAPDtQMLiAQ0kE2HagsbQopNnV8tHK5r5ISA8s4A24erggrICAgICAgICAgICAgICAgICAgICAgICAgICCR5J9IQEFOq/bepBbb5I9A+xSJ5qAPE+lBCAgICAgsUE0dPtGlnlF44pmPeNQHAlB6iHZddB4dHacjHChZVGrNZ/wCmYrl1w7gbjK2uSCpXbSqI9h7JgppDFBUumdI1uWMb3IHUdiDpVv6Qa/bH6EEnjn6Vdv8Acjp7u3R/+N735cLoI24P+J2xiDL+O0V8HDyTw7EGra1bU183hRR1MuKnp34oYyOjE4TBtxpkTfW6C1tCmnbsPbFJUmvqIqWmY6Oepc3dOcHNsY22uBYnMHhx4oPN+FH/ADkf9NB//qag5CAgICAgICAgICAgICAgICAgICAgICAgICAg7vgvE+X9KMphirXULm07B5TiSMWHtw3Qatm0tXsbbezKmtppKdhqG2EjcJLQRiyOdrFB1zszxbaZ8H6eRwmie+rq3QgOeSy5ZG0cyB7z2IL8odO/YPjjKsvE81W4VsgfI2KNoJBIAsCWnJBw6/alXtDwUdNWymQ1G0CYWkC0Ya27sOgu5o9SDzqAgICAgICAgICAgICAgICAgICAgICAgICAg6Pg9StrPCChgeLsMzXP/wArek73AoPU7O2vSbR2hQ1IkL66QyCoyP6qBr3yk31IsPRfVBPg5BVsqaKqMleWbRkdVyvp3NZCxuI3DyQcRsDl2hBX2dT7Qlptnu2G0wsrqyR1VNHkGjHZrHHk0NztzugtGfexVe0qCCvdNV7QlY6TZ4bjiY2wYzPyQeOXG3Yg51ZtWaGh2htGijfSz7RrmwtuBjbgbd3DgS5w4IL20KnaMDfCCpoJJjPG+ngmkh8roNJke63DNtr+lBso6eo2XSVcVS+vlgioHzSvc5opnl7L2DbXfm4Z34hB4EcEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQeiqK6el8Ctn0wcGuqpJgH26QhBb0b6F9z6kHa2nUN2NHUU8NFtJ2z46UxNADPFpMTLCQm2ZJN78UFGpHiVPVjh4hsqKlB0kmIc73Ocgt1njezZtqU8rXRbEp6MwwRkWjncWjA4dZxPSuNEFmmpGvdTUrCzxna2x2xgn/042xcey7vc1B4zbNZHWbRcacWpoWiGAfMbkD68z60FBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBB7TZtJVM8HNkwx7Cj2jFVTvqJHzNdgYLhgNwQBk08UGM1MNpT1dPBV4xtXawgjncAbxxgnIetth2BBZqGCr2TTU+0jXxx1O04ommve27WgHEWgAYBYgIKDv01V+EUGz6+KemoH1YDaYtwxtYw3s0cMmjigr+FFQXtbUUGWzdoOMxkHlyyX6TZDq0nIcLWKDzaAgICAgICAgICAgICAgICAgICAgICAgICAgkeSfSEBBTqv23qQW2+SPQPsUieagDxPpQQgICAgICDPeymLdb1+7vfBiOHuQY3JAFzYcM+CC5QV8VG57p6GKsL7W3kj229ki4Pag1V1dPtCtmq53DeTOxODcgNAB2INGJ2fSPS458UGTpZXNDXSvc1osAXEgDRBiSSbkkntQQgICAgICAgICAgICAgICAgICAgICAgICAgIJa5zXBzXFrhwINiEFui2iaWs8bmgZWStF4zO4kNdydxztockFd1RM+odUOleZnOL3SX6RJ4m6DEyPcbl7iTzLigi5sBc2HAIIQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEEglpuCQdQUAEjMEj0IMhLKIxGJXhgNw0ONr+hB0aPbXiFM1tNQQMqWtIFVieXC/8Aiw3w4rHjZBzo5pYgRHK9gdk7C4i/pQY3NgLmwzGaCQ94xWe4YvKzOfpQS6aVzQ10ry1osAXGwGiDBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEEkkgAkkDh2IMjNK6MROleY28GFxsPUgxLnG93E343PFBk6WR7WtfI9zWeSHOJA9CCMbrg4nXAsDfkgxQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEGe9kwYN4/D1cRt3IMQ5wtZxFjcWPBBL5JJXF0kj3km5LnEoJfPNIQXzSOLRYFzibBBjc4cNza97XyQQgICAgICAgICAgICAgICAgICAgICAgICAgIJHkn0hAQU6r9t6kFtvkj0D7FInmoA8T6UEICAgICDfRUpra2GmD8BldhxEXsr0rz2iviraeWMu/wD2Lk/fmfRH712eZT7TDt48D+xcn78z6I/enmU+0dvHgf2Lk/f2fRH708yn2jt48D+xcn7+z6I/enmU+0dvHgf2Lk/f2fRH708yn2jt48D+xcn7+z6I/ep8yn2jt/cn+xcn7+z6I/enmU+0dv7j+xcn7+z6I/enmU+0dv7j+xcn7+z6I/eo8yn2jt48D+xcn7+z6I/enmU+0dv7kf2Lk/f2fRH71PmU+0dvHgf2Lk/f2/RH708yn2jt48E/2Lk/f2fRH708yn2jt/cf2Lk/f2fRH71HmU+0dv7j+xcn7+36I/ep8yn2jt/cf2Lk/f2fRH71HmU+0nt/cj+xcn7+z6I/ep8yn2kdv7j+xcn78z6I/eo8yn2jt48D+xcn78z6M/ep8yn2jt48D+xkn78z6M/enmU+0dvHgf2Mk/fmfRn708yn2jt48D+xkn7836I/enmU+0dvHgf2Mk/fmfRn708yn2jt48Ef2Mk/fm/Rn708yn2jt48D+xsn78z6M/enmU+0dv7j+xsn7836M/enmU+0dvHgf2Nk/fm/Rn708yn2jt/cj+x0n7836M/enmU+0dv7j+x0n7836M/enmU+0dv7mit8GH0dFLUmra8RNxYQy1/eqX4SaVm2ei1dbmnGHCXE3EBB6fwa8CpPCPZ0lYyvbThkpjwmIuvYA3vcarWmnzRlw8RxkaF+WYy6/wAVU/yvH9AfxK3Y+9zek49n6nxVT/K8f0B/EnY+9PpOPZ+p8VU/yvH9AfxJ2PvPScez9U/FVP8AK8f0B/EnY+89Jx7P1R8VU/yvH9AfxJ2PvPScez9U/FVP8rx/QH8Sdj7z0nHs/U+Kqf5Xj+gP4k7H3npOPZ+p8VU/yvH9AfxJ2PvPScez9T4qp/leP6A/iTsfeek49n6nxVT/ACvH9AfxJ2PvPScez9UfFVP8rx/QH8Sdj7z0nHs/VPxVT/K8f0B/EnY+89Jx7P1Piqn+V4/oD+JOx956Tj2fqfFVP8rx/QH8Sdj7z0nHs/U+Kqf5Xj+gP4k7H3npOPZ+p8VU/wArx/QH8Sdj7z0nHs/U+Kqf5Xj+gP4k7H3npOPZ+qPiqn+V4/oD+JOx956Tj2fqfFVP8rx/QH8Sdj7z0nHs/U+Kqf5Xj+gP4k7H3o9Jx7P1Piqn+V4/oD+JOx956Tj2fqfFVP8AK8f0B/EnY+89Jx7P1Pirn+V4/oD+JOx956Tj2fqfFXP8rx/QH8Sdj7z0pHs/U+Kuf5Xj+gP4k7H3npSvs/U+Kuf5Xj+gP4k7H3npSPZ+p8Vc/wArx/QH8Sdj7z0pHs/U+Kuf5Xj+gP4k7H3npSvs/U+Kuf5Xj+gP4k7H3npSvs/V5jwl2A/wc2jHRvqRUF8QkxBmG1yRbidFnevLOHdw2vGvTmiMJ8G/B9/hFWy0zKltOYo95iLMV8wLcRqppTnnDu0tLtJxl6L4sJvlaP6A/iWvm8+Lo8znxPiwm+Vo/oD+JPN58TzOfE+LCb5Wj+gP4k83nxPM58T4sJvlaP6A/iTzefE8znxPiwm+Vo/oD+JPN58TzOfE+LCb5Wj+gP4k83nxPM58T4sJvlaP6A/iTzefE8znxPiwm+Vo/oD+JPN58TzOfE+LCb5Wj+gP4k83nxPM58U/FhN8rR/QH8Sebz4nmc+KPiwm+Vo/oD+JPN58TzOfE+LCb5Wj+gP4k83nxPM58T4sJvlaP6A/iTzefE8znxPiwm+Vo/oD+JPN58TzOfE+LCb5Wj+gP4k83955nPifFhN8rR/QH8Sebz4nmc+J8WE3ytH9AfxJ5vPieZz4nxYTfK0f0B/Enm8+J5nPifFhN8rR/QH8Sebz4nmc+J8WE3ytH9AfxJ5vPieZz4nxYTfK0f0B/Enm/vT5nPifFhN8rR/QH8SnzefE8znxPiwm+Vo/oD+JPN58TzOfE+LCb5Wj+gP4k83nxPM58T4sJvlaP6A/iTzefE8znxPiwm+Vo/oD+JPN58TzOfE+LCb5Wj+gP4k83nxPM58T4sJvlaP6A/iTzefE8znxPiwm+Vo/oD+JPN58TzOfFx/CTwRk8HaOKpfWtqBLJgwiPDbIm/E6LPU0uSM5Y62hOlGcqXg1sJ3hHtyHZbKgU5la528LcQFhfhcLFzvb/EvUfLkX8MfxKMpwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkwfEvUfLkX8MfxJkw5XhN8Gs3g3sOXaj9qMqBE5rd2IS0nE4DjiOqnKMPJbLoTtPatLQNkEZqZWxh5F8Nzxsg9z8Us/yzH/Dn8SjKcHxST/LUf8OfxJkwfFJP8tR/w5/EmTB8Uk/y1F/Dn8SZMHxST/LUX8OfxJkwfFJP8tR/w5/EmTB8Uk/y1H/Dn8SZMHxST/LUX8OfxJkwfFJP8tRfw5/EmTCfikn+Wo/4c/iTJhHxST/LUf8ADn8SZMHxST/LUf8ADn8SZMHxST/LUf8ADn8SZMHxST/LUf8ADn8SZMHxST/LUf8ADn8SZMHxST/LUX8OfxJkwfFJP8tR/wAOfxJkwfFJP8tRfw5/EmTB8Uk/y1H/AA5/EmTB8Uk/y1H/AA5/EmTB8Us/yzH/AA5/EmTB8Us/yzH/AA5/EmTCPiln+WY/4c/iTJg+KWf5Zi/hz+JMmD4pZ/lmL+HP4kyYPiln+WY/4c/iTJg+Kaf5Zj/hz+JMmEfFPP8ALMf8OfxJkwfFPP8ALMf8OfxJkwq7U+DWbZmy6qudtWOQU8TpCwQEYrDhe6ZMPEKUJHkn0hAQU6r9t6kFtvkj0D7FInmoA8T6UEICAgICC/sL/ntH/qj7Ftof8tWep+iX0PCvacKcKBhQThQLIGFAwoFkANQMKBhQThQRhQMKBhQSGE5AEnsF1EzEdUxus/oyobNFFK0RGZhe3ERmOWXFc9uJ06x4tY0bSryROjkLHZFuRW1LxevNDO0TWcSwwqyphQRhUhhUBhUiMKCLIFkEWQLIIsgobcH/ANEq/wDTWOv/AMVl9P8AXDwC8V3iAg+p/Bh/dyo/6t38jF06X6Xg+Uv+WPh93sls85KgEBAQEBAQEBAQESICAgzjhklPQaSqzaI6tdPRvqT6sM3UkjId4bW5jmFEakTOGt+D1K6faS0q7kEBDCEMFlJgshgRAgICCEQIPlvwn/3kp/8ApG/zvXNrfqe95N/4Z+P2T8GX/O6v/pv+4K2h+qXvcJ+uX0pdb0hARBZARJZAsgWQLIFkCyBZAsgWQLIhkyN0jrMaXHsCiZiOqJtEdVhuz53BxsAW8r8VnOtWGU69IwrWWrbKLIksiCyJLIFkCyBZDKLKTJZAsiSyDxnwmf8AJaT/AKn/ALSufX/TDi4z9MOH8GH9/KP/AE5f5CuOXnQ+7KqwgICAgICAgICAgICAgICAgICAgICAgICAgICAg8h8KP8AcSr/ANSL+cKYRL5D4Kf3s2V/1cf2qUPvFlVZNkCyBZBNkCyBZAsggDNBNskCyBZAsgWQRZAtbPgg1TTxwOia91t6LttzCDNjhI0ObwQTZAsgWQLIIsgWQRZAsgIIQQUHJ8Kv7qbV/wClf9iD4WrKpHkn0hAQU6r9t6kFtvkj0D7FInmoA8T6UEICAgICDobAz29Rf6o+wrbQ/wCWrPU/RL6NhXsuFOFAwoFkE4UDCgYUDCmQwoFkCyBZAsgWQA27g0Wu42Fza5VbWisZlatZtOIei2PseOs2TFJJGYnyPD3OcLPw24DQHNeVq683t7nbTTisO1u6WkjM2FpcxgBe4Z2XPjPVo8v4QRx+P7yOVj94MRDeWa9Dg7erNXLrxvEuVZdzmLKRFkCyBZBFkCyCMKBhQQWoIwoOft0f/Q6z/T/qstf/AIrL6f64fPV4rvEBB9U+C/8Au3Uf9W7+Ri6dL9LwvKP/ACx8Pu9ktXnCAgWRKbIYLIYLIYLIYLIYLIYECyAgWQw301MZXguuG/as735Y2dnDcN2ts26Oi2NrLm1hyA4BcszMvdrp1rul1nAtPAiyiNt1retE1lx3NLXFp4hd0Tl8tas1nEsbKVcCIEBAQEBAQEMCIwhSPlnwn/3kp/8ApG/zvXNq/qe75N/4p+P2T8GX/O6v/pv+4K2h+qXu8J+uX0uy63ollAmyBZAshksgWRGSyBZAsgWQLIFkCyJbIYXTPDQMr5nRVtaKxlS94rGZdiKmZEGhuQaPaPauG15t1edbUm3VtxAWA4KuGeHFrY8FW/Qm67tKc0h6WjbNIaLLRqIFkCyJEBAUiECyBZAsg8X8Jv8AyWk/6n/tcufX/TDj4v8ATDhfBh/fyj/05f5CuSXnw+7KqwgICAgICAgICAgICAgICgEBSCAgICAgICAgICAg8h8KP9xKv/Ui/nCmES+ReCf97tk/9XH9qlD71ZVWTZAsgWQLBAQECyAgICAgWQEGEkjIm4pHBo4C5tcoNdKw7Uog+SIwAvuMXlWGiC62Cmp2iVzWl0bLY3DMNQVMUXjUmCZjzJ+swt4gcEGyyBZBFkCyBZAsgiyBZBFkEWQLIOR4Vj/+J7V/6V/2JBL4SrKpHkn0hAQU6r9t6kFtvkj0D7FInmoA8T6UEICAgICDo+D/APz+i/1R9hW2h/yVZ6n6JfSbL2MuEsiU4UDCoCyCWYHVMNOXhr5nYWXBtdVveKVzK1azacQvT7Gq6eF8z2DBGSHZ5i3O2nNY04nTtOF7aNojKkWFpsRYjkV0ZZIwoGFAwoGFAwoMHubHG57zZrRclMmFOjjm2tK2RoIZf9Sy1ruuOPv9YXBxGtH6XXp6eN3p2VdPSRGLaUstIWxXsJyQ4G4F2gXvqPzXJFZtOzaZiHmoJDWiQVW0JaiB8oDQx1jYaDmeAtkui/qziIZ13ekrIGSUjTHVGoZFdrA4EvblmC4nMc/UFz6d5reJXvGa4cgtXtZeejCgjCmRmynlka50cMjw0XJY0myra9a9ZTFZnpDGkZ47S72EHGLl0ZsHButr9hWMa8c81lpOlPLmGJauhkjCpQYUEEIIsgg2aLuIA1Kra0VjMpis2nEOdt10btg7QO8aMDMNifKNwLDVcutr1ms1jvhvp6cxOZfO15rqEBB9V+C/+7dR/wBW7+Ri6dL9Lw/KP/LHw+72Vlo8/BZDCUSWQLIYboaZ8zMTSAL2zVLXis4l1aPC31q81ejCSF8TrOapi0T0Z6mhfTnFoYWVmWBARGBEiIwIYS1pe8NHElRM4jK1KTe0Vh0oYtzGL58yVy2tzS97R0eypvu11MrThayXCTxV6VnrMMOJ1azitbYlshbZ5Jc4u9Kpadm+jXFszO6vXxgPa8DiLFa6U7YcPlDTiLRaFSy2ebgshgshhsZA7G0Pa5rXc7Ks3jGzemhbmiLxMRKJYXROzFweBHApW0Srq6NtOd+ni12V2OCyIwIFkBBk2F7mhwGRNlWbRDWuje0Zjp0fK/hVj3XhPTsxAnxNvD/M9c97c05e5wel2VJrnO/+IR8GH/PKz/pv+4K+h+p63C/rl9Msut6CbKAsgWQLINkEDqiRzGWu0XN1W94rGZUveKRmWc1JLDYuFweYzVa6lbdFaatbdGiy0a5LIFkMlkMlkMlkEOIaLqY3TG7o0VG5jcbzdx5cLBcurqRM4hxa2rEziG2qqI2QOG9wPvYZ8CFTTpM26bKaWnM2jbMNdPHi3Zklc82u0gq95xnEL6lsZxDPaEWODGBctOnJV0bYthXQti2HLsut3FkCyDLdSYMYjcW6gKOaM4yjmrnGW2elMYD2HHGeenpVK6mdp6s6anNtPVostGqLKUlkCyBZBkyJzwS0XsLlRNohWbRHV434U4DFsGgeXA46m4A/ylc2rbMYcfE35ox4S858GH9/KP8A05f5CueXFD7sqrCAgICAgICAgICAgICAgKAUiFAlSCAgICAgICAgICDyHwo/3Eq/9SL+cKYRL5F4J/3u2T/1cf2qUPvaqsIJsgWQEGqaohpywSyBpkdhbkcyg2Z9MlpaGEgl2Xr9CCeSBZAsgWQLIFkGD3CNjnuNmtFyUHmaquk2u8MY20YP6tpHE9vvQdOnlZA1sdc6Wms3FZsxs4dotkexByXy750jJKt0sRc0MDXWPA8tRcCyDrENbupIql0rIH2a0g4mZZi5OYseGgQdUWIBHAoFkCyCHdEEm9hmbAlBSo9pR1kj2taW2PRxWBItxtfsKC7ZBFkCyCCEEINc00dPEZZXhrW8SUHA8Kdq07/BzakDHB16R/SuOJHD05hIJfFFZVI8k+kICCnVftvUgtt8kegfYpE81AHifSghAQEBAQdLwe/vDQ/6o+wrbR/5IZ6n6JfTLL1nEpybQgJ3dPIJZC7DaPpYSs9W/LXbq0pTM79Gio2jHTMhfaSRjpcm8XNJABvqONs+5cdZvaeu7pmKx3LdHVtqmDLC62bTkb88l001omeW3VhfSmN4bZJcIk3TGzSQgPfGHAHDcArS9sQpWuWvYG0pG1lVWmCJoY8hrQ0fq3OPAOPdf77rh1+6HVR6KfaDNqOpJWxB8ErHtnfkCOxp1F725gZBc/JNcxPVfOVeupaGMbulme50LcO7c3pNAtxJ0H9Fvoa1qzieks9TTiYzHVz7L0XIYUEYUMGFMjF5axpc4hrQLknkpQ5tfJHX7LxU1Qx7XvwuYGkuIFjfsHHuXNfXxPLh0U0tsyvbI2fVwiN8Em7jlsIJHyDKwJAtyN/VdcFrRMunGIcjwmqKyoqmbxxxRttvN4HYrHiCO0ldejTljLG85dDZcL9otFFFNDJTRFjDcN/W5Am4OeXZ2rHUnl3nrLSsZ+DuQbLnoKw7Oax1VhGJht0ALmwdp+a57b+sv7nYloYaijc10DnOaC1uFgLmkWyuD2c1NNW9J2lW1K26vMT7qmmDJn4GlwbmLEd69ONaJ0+eHJ2frcsru0/B+ui2c6ekkbMCwuJZk4C3EDmVj53E7Yw07DG7k7L8IpdnV7JmytdFK3B4uXEWABPPnc+u5WN6TaJy1rMR0d11VsWj2xBNVbLmpqyZpezCQWuFuw258Fli0067LbRKaukpa+hbtPZ+FkRZidGRhI9I15LfR15pPJdlqaUWjmq5k1M6ANxkXcL4eYXZTWre2Ic9tOaxmWktWyiMKCjX7Tp9nvayQEve0uba1stf98lEzhMVy6OwDQ1JxS1DnzA2fHgvdhPC1jY3uO0BeTrWvad3dStY6K3hbLGPA+tpmuDGteHRPay5mjubAjPCAed+Q1CziY3TL5UqpEBB9V+C7+7dR/1bv5GLo0ujxfKH/LHwezJA4my1edMxHVap4m4bvacV8rhZXtOdnocPpV5c2jdDt3I4swFjgfKtkkZiM5Rbs9S005cTHf3NMkbozZwt26q8TE9HLqadtOcWM2AHALuILSU6p3pEbbzjDose2INYeeWWq5pibbvcpeulEUlLQ14u8a9yicx0TWK2jN1GohETuibtPBdFLc0PI4nQjTtt0lqsrubBZDBZDCLIYS1odI1lwCdUmcRlNK814rnqsw0pZKeld1siMgsrXzDv0eF5NSd98LMryxhPEWta6yrGZd2reaVy58TsMrpHZkeSNSum0bYeLpX5dSbz17o8ZdBkZaMbnXcMyf6Lmme57VNKYjmmcz+bNg6QzbxHAqjojeN4VqqlbhL4xYjiAtqak5xLz+K4SvLz0hohphM3J4B0Wlr8vc49DhY1o2tuyEG4dZ9s+BVebmjZr2HY2xfv6SsRSCaIhwDg0lZ2jlnZ2aWpGrSYtGcJY6GWINwnC4mwI4FRMWicrUto6lIrjaVV9HI2TC3NvG+i2jVjGZedqcFeL8td4V3tLHFp4haROYy470mlprKFKggzpTHI/p5DtVdTMRs24SdPUt67piwaMGYHD0Lk7930EYiscr418Lgt4WQG970bf53q09xpxibfFr+C/wD55Wf9L/3Ba6PV3cL+qX002aLk2AXU9CN22mayR2JwcWWyI4FUvMx0U1JmsYjqzmfEyQROicSW3xNHAKtYtMZiVKVtMc0SwkgdHn5TTwcFaLRK9bxOzXe0ZkwB7c28eat34X78Zwv0UghpGyPA6WeQAy4Bc2rXmviHJrV5r8sLIcJZCCOjkW631WeMQxxyxt1U6ynYLyx8L5jRbaV56S6NHUmfVsp2W7oSgiyBZBDiGi7jZTG6YiZ6NxogZI3OkDmnPo8ln2u04hn220xEOi0Pii6Ts23JN+K5ZxM7OOcWnZyJX76tDpDgZfPsHFdtY5abdXoVjl08RvLpU7HVLBI8gYh0G9XtC5bzFJxDj1Jik8sLUZJBuPJNr69qylz2aqijjmaS1oa/kQFampNZ3aaeras79HOhgEkpjc8McOR1XVa+IzDsvfljMRltkonU5D3kOYOOSpGrFto6qV1ovtHVvpqgF5hu1zSL29Kpem3My1KbczOOSmY6VoYW4bB4sqzF5xOVLV1JiJyr1VAQ4OhFw4+SOS009XbFm2nr7YsqywOhcGvtmL5Latot0b1vFozDCysuiyDFksZn3br5ce5TNZ5cwm1bcuYduBsQhtEQe0Zi64LTbm3eZebc3rPn/wAMIcdi7Pccv+JsW24HC7mo2xhS2OXHveS+DD+/lH/py/yFVllD7sqrCAgICAgKAQFIICAgICCFGYEqRCgEBBKkEBQCAgKQQEBAUDyHwo/3Eq/9SL+cKYRL5F4J/wB7tk/9XH9qsh99sqrObtDbFPTwvZTzMlqL4QxvSseGaDgP2rMxrJPGJSd4HWLjiBtbPla/ag7Wy9uMq7RVA3cvC5yBPo5IL1XViBjxFhkna3EI752uPvQcOm2lIdoTVL4mXaeBAOBxsB0u4X7UHVmqhWmleIw9rriY5dHLgDqL37bZIJilpaIingme9jABu3DpM4cSeQBug6CAgiyAghxDQXOIAGZJ5IPP7X2vFVUMkNJIH4nYHdG5I43Ggy49yCjs+jqA9ksThHHI7DG9zxkc8rem3rsgw2saxz2OmcS9g8sSB1878R6UGdKySqYaVkkcjcLQScPSvmQQdM+H9UHQbsuWgqhSNaai/SYGjotF/wDEOQv9pQdqFpZT4Qx/QGENDQcJFssj6eKDS/aEMVLv33bYhrmHIh2iDOubVfo90tIA8uZcOacwNR2oPO0e2amlq21Dpi9hYGblzjnYdvO5+1B1X1OzYquCqq9nzQVEoxR2cCCLc7G3NBegqYKimbUU9mw4c2OyLPT/AL0QZCeIyiNrwXOGIDsQZkIIsgo7S2pT7NwiUEve1xYBbMjkdOKDkUNTHXy3qap7pGuyjw3GEmxFrHO5AGqCn4TTwx+Ce1KdhEbCwmJwaSZG3PRtnYA878h2JA+PqyqR5J9IQEFOq/bepBbb5I9A+xSJ5qAPE+lBCAgICAgu7GqG0u2KWoexz2xvuWtNicjwOa00880YVtjG71ddtuslldBE5ojmjDWtMZY4X4uvfj7ivU5sRmXLFIy2NkZGYI6Rzd02NoON2bXCxzt6DkVxTE7zZ0x7nb234O7Rq9kOq6d7nxwkShuIudbibDjfO6y0tSItie9NozGylQSw1r4JQ7dSvk6TgbHtNhmT6/tVrRNcwRug1UezPCCqo6hhe1xDZGk2LrH+ozBOq1mbTWLQrERnDtbGFJTw1E1PK2WKe4N23ELSci63Zy15rG9ptbfuWiMQu1VRQUszTSUwbZ7AGYb+MtDuQ5m/PjkdFWZnrJiHVqIZ6+aR0ULadjm3dJgxGW1xhJvdvIEW1WUYXccbPqS2Q4AXReW1puR29q79LiaziturlvpTG8K+FdeWCLIMJJI4mF73hrRxJKjMQmImXnNr7fZLFJTUw6Jye88xoFEyvWuOp4PxMkpzKHOe6NxcWZWt99/s7cuLXnE4dOnGz1VXt91FsSCmZSRVVULlzZL9AG2lr8+B5Lm06RM79GlpcF1M6qozFjjp5SblhDjcHPFw5ldUauGXJlqmmZDV0+zmFrWyFrnFhIwi+hHHSypETMTeVpmInEPZbM202SoaHbptM2MYHvFy11si43te3ov6Fz2jELtomqBUmaORzoXSHfROkvIIze5A5jMcOA7VG0jl+EWz6J7Ipp46iKle7ctLiTgeW3Dszm0WIt2rXStaMxClojq52y6qt2LO+Jkwkc1wZE1+JzS3Fy9PFXti26IzCvWbCqq9+/iaGzl5wxFu7c/M3DTwdbjrnwV41IiMSjlU5dovotmS0NdBUmqjFoHvkcx0JINxhI4WPBWivNbMdETOIa6fwhqo9iO2dJWgsmFun0iwX4jmOH5K86UZ5kc89He8H9sP2jW/8Y+KaGNpxyVBDSQ4ZNbc3yIJv85YXpNN69V4mJ6o2/tfYpe+DZ0k0Ml8O8iPkm/Idttb5grbTtq4xZnalM5hxqCtmq5rxSyubbC50rnSPBuORPAC6tbU7ONiKc/Vt2psGIxT7RbWMqHWwtY697jjxH+7FYU1rXtESvNIrGzT4NVsmzXz1LWRPFTYmPOxAzsDyP5etrb4jwTTZ1No1n/8M2tTVLWxzNprRBzr9HK4Bz7O89q5pjfZd8pUAgIPq3wXuH9l6loBxeNuN7X/AMDF0aUTjLxfKNo5orEb4e0pLY95IRkLNPK601OmIcXCY5u01J90fFep7uBDsraLnvt0exw+bZizUWGGrcH9JspBCvnmpt3OaaTo8RMW3izKZrTTucRcA5HsKiszzYW1q1nRm090/wBsWbuZkZvZ2XPkpnNZlWnZ61az3rLrE3c29sh96yj3O62Jn1o/PFMZFnEC91Er6cxvMbomhM0dja/I6Ka25ZV1tGdWmJ6qMkL4jZw9a6K2i3R4+po305xaGCsyEEOOEZpG6LTy9WDXXlZnbPuVpjaWVbZ1KuvEN2zPhxuVxW3l9NpRyV+rRI50r8JZ0RnfmrxEVhyal7at8TXaEMhbG90jnAgC4NuCmbTMYUpoVpadSZzCaeXeYn8L5DPRL1xstw2t2mb+P+Fni0cll3u+N6wC5uHC+nahGZzEqZiAcSw2e05hbc3i8ydKImZptMM3l0jMPK44BVjETlrqTbUrytIifCQ8XLQeIWnNFtnLGlfR9aOjXJUkTAx3YBna/NWrTbdhq8TMakTTb7s/HCXl+LOwFmjiFHZ7YaeezNubO/uWHOp3RB0wbiIztxWURaJxV22toW04tq4ypPcxjiGOeGnKxOS3iJmN3l3tStsVmcLEVE10bhIeIsLclnbVmJ2dulwVbUmLy0zQNbIIW4bEAX9CvW0zHNLl19Ctb9lXHd9P8r7XnC0AXsueYezS84iI7nx/4X/710tv3Fv871V0K/wYSNj23WYmk4qawty6YW+jEzbZ18LWZvOH0eJzppg2UgxtdidYWIGi7rRFY26vUtEVrmvV1IHmSpIGHASbEcwuO8Yr73DeuKe9jXxPp54qsOJY0YSOPFTpWi1ZonQtF6zp97a1jZA9obcYL2aefJUmZjEqTaYxMqlNJBLTujdyPRJ1K3vFq2y6NSt63iYdBjGNhZGRiYBck8zouWZmZme9xzMzaZ72URbvBhbwB6PVKi2cbotnG7Y5hkY5pHRPAWVYnE5Ui3LOYc2akkhFyLt1C6q6kWdtNWtmmy0aCA4hgucgkbkRlTmmxjLILatcOilMO1QxgQtkuXAgDPkuHVnfDzda2bTDKqne8iGOMOa7JxUadIj1plGlSI9aZaPFGvlY7EC0HpNI4LTtJiJhr2sxEwmKobJWFo8mLK4PE8FFqTFM+KLac108+K+xxc132hc8xhyTGJSMQdY5tI46KNsE4wpVNOx9QQei9wxNPL0LopeYr7nTp6kxX3DJJBFuybnCb5ZqJiM5JrXmyrOopBifHckjMNFiPUtY1Y6S2jWjpLXVVd2NABbJcYnX4hX09Pf3L6WlvPgn9IufgDpM2G9wLkngo7GIziOqPN4jOI6rlPPHPAX1IbYcL2uf/KwvWa2xRz6lLUtiilUSU4figdIAL+SeK3pW2MWdOnW8xi+G2jpt+Q9zugc+d/Wq6l+XaFNbU5No6tdZRx0bGlmF5c4npcrq2nqTqTutpattWd9lyiDoKQQgBxH2rHVxa/M59bF78zxfwwnF4OUFxY+OZj/4OXPjEuO0YeO+DD+/lH/py/yFJVh92VVhBCiBKkEBQCSIQEyJUggICCFEgOCivQSrCFAICCUBSCAgICAgIIURIlSPIfCj/cSr/wBSL+cJHVEvjewJvF/CCgms47uoa6zTY8eSsh9WrPCOttgjc0MkisAYy11yPKvqOzJVWcwkNEbIndDDnidni7bevIoOrVbGrqvZ754Tjia0PALi46mw4359yClTvjnLHYt3LiHSvY93MoLE9XLs/bEjJOm42a8nIv4EH1g5HleyC/s+SlZLNVQva6NwPRLf2QPAu/3y7UFusqKSl/WQQjEMIBt+3FxcAczcDt7kF2aOWukc6OEQBzOlKWXLrEjCc7tNuOXMoMqCWSSPczD9dELP6V79qC1la6CCg1yzRQtLpJGtA1KDzm2fCRj4pKWkBOIFr5DwtzsEHFomtc1xuXFpvhytbn60He/S242JFTup456i5OB9+iPVx5jJBQbK+elez9XE95xAG+YIvfnx/qgqvdgkjgD2gSHi2+WduFvsQejoNrAysjdu20zGZPkzc1wFwXHgMkG0zzeNOnikJYZOnG6S7sFjiIbw5CwGYsUFTalLTmFsjmTx0pcI7OJNnFps4XPAcLdqCjRVFRsuZ27lxltmxNcSWkE8R6boFXs+etJe1jWTOebMw4C8k3IB4HXVBV8adTUstJVxTmQfs8by0xHjwPpQKfaU0WypKd1VcTC2F5vYE8dRr26ah0tj109RWML5GyiNt3SSm12keSL+gnsugubT29RgvpqeR8bz0d43i3lcf75goOPTbXljeRA+Z+RDnSuLyDwGXqv3oNdXQurXSVjqwTuAwhuYIIHDMakD1lBW2VWSUMz52NidvABgPB2Y58jl70G6vqwPBTa1PO1rH+JO3Ic69gW8Ac+SD5ErKpHkn0hAQU6r9t6kFtvkj0D7FInmoA8T6UEICAgICC1sxsb9p07Zag0zC/pSgE4BrYLTTnF4wrbo9RTUtDtSpDBVYCxtrvOEDLiT6AuzU1JpHRnWsSVIbSSmN7bGB/61kYDsbr2VKzzLTs6TNp18FN45BJPExoJs5zrttzOfDMBZ8tZtyynM4yyq6Nm0KGl2jswSMkx7uppWZ4HEYgWDjY2PosVMTjNbGO+HLiDdp7Ya8tMjzGXTeMG9yCbk5i/2rSZmmmr1suUtbTTGUtD6cTDBFE15uwaHU2/3yWdqzmMLRLs7L2tNRmXFLNM2MX3jW5xgAHLlfhcnLPms7RFsLRs9ZSbbBipxTNFY1wvM/EGSRk83Nt6M1lNfFOWufbWy6974DvI5AQxkkbTcXGJpy1tw7E5ZiDKnGY6l4qKi+5AIkLQGu4eVYf8Ak8uCvXWvXaJVtp1neWnbni+yKe4ZNI/DiY7CRe1+XC2fuXRTVvfrLOaVq8FWbRqtoVuKaUuubkE5ALorERCstFBBTOZM+qLRG1hw3dYk3AFtTmPeq3tOYwmIjvW9i1ztn1jIoKt4Y8gyvj6NgOIF+OV/Tks9WvNGcLVnGz2UW3tm0dFM2kIqJXlxDXtu/wBJd1bZrmik97TK1sDZ9ZLK2rqKVjGTxjPyTm0Zjjp2ehVtMdxDqVXgnsmqZIHUoY5xu17HEOafSoi9o6SnEPO1sH6LYKR02bSSWtkPHkSOfHuPBTG6G7YcUm0qtpwNiaxr24mucACRawucxfOwzBtqotsmHRfsqjlrhRVjG3qIi2XducG4+RA4A5cLn76RMx0ThxNreB+1aJolgnNTTwA4cJO9a3jkPWcgV011KzO7OazDiUklVMW0slTJTw2bja+8Ya++RA55W7Ve1d8wjLq7W2Qz9VHV1JndGwXDJrj02HDO/cp0522Vt1eaqdmvgOKne6Rh8hrTnc9unEroiVGyJtLR0jWvlvIOk84za+lr56KYzJLjF7p8TAcOM4g3XkLKLYjeUx4PoXgp4MNj2UK/aExYxwxDd2uWgHLUZDP1rz9bU57bN615YdWPZGz9oNcKCKN8E7QZHT4i+RvMNsciP6rLmtWfgtiJeL2tsfaOwJdyI2yxib9XIH2uD5IP++K662rfeWcxMG3NtSV/g7UMY5zZWw7uqLmtAkzve4HEXI7vQMrU5YWzl8+WSRAQfVfguDB4N1BfJb/i3C2nQZmujSzjaHieUIpGrE2t3dP8veMpo44w++NpHP7Um8zOEU4XT06c+cx+bkTyJCyznOcb4rZJaNsmlqTF5rvMz39zZvf1wjl9N9PQq8u2Yb9r/wCSNPU/6anAwseyQuLSSBbnorx60xMOa0TpVtW+ZjePsxjaI4IzYXf/AItFNpzaVNKsU0qz49/gsFwf0mSFpbkVljG0w7ptF/WrbGG9sgxBrrjK9lnMOuupGYi2zLeWF3CyjHgv2mI9bY6MjbWuDyTeD1bxhqNJEeRHrV+0s554PSlVlcGXDAWhbVjPV52taKZimyoQXW7TktujzpibNskcTQwhwDgOkOKpE2nLo1NPSrFZid+9cp6jFGDI45nK5WF6YnZ6nD8RzUzeWwvMjg1gy1VcY6tpvOpOKxs3YARYgKmXVyRMYlhuWNdiaMOuinmmdpZ9jSs5rsxL88s81OFJvvs2tHRH2Kst6xs1vhD7PYcLgrRbG0sdTQi+LV2lWe2SGQYr2zzGYWsTFo2efeuppX9Zmy7gSXjFbPNVnbubUzaJmbbqz4W8ib63WsWl599Gvd1agyzukch2q+fBzxTE+t0YyObkBrrdTWJU1bV6Q208DqiYOv0eZVL2ikYdHD6FuI1ItnZ1SG3seJXHmX0k1rnEtM9NjIe0APb7wtK3xtLl1+G55i9esNMcz43P3jSGg2yN81eaxMRhyaevfTtbnjZ8k+Fsk+FNNiN/+Cbn/wDN6ynD0tKZmu7R8GYb+mqsukwWprgdY4xkt9DPNOIehwmeecR3PqdLRQzMM8T8VjmCMjbkt9TVtWeWYdmprWrPJaDeNhna5rXuaRha1o8lMTauDlm1cSsTTyRBrZGhzJDbCb535elZVrFuncxpStszHWGL2uhndNG95hc0HLiORVomLV5Z6rRMWryzG6rTtZhnqGsxBrui08eyy1vM5iuW+pM5rSZXI3tfE2MSODhncfcsJiYnOHNaJi2cLMM2GJgeSQ42xdZZWrmZwxvTMzhY3tichhysQeKz5WPKhsjJAS1JrMdUzWa9Wt1HC45gj0K8aloXjVtCnVFlMSI2kOGWLittPN+rp0836uXI50mIl1x2rsiIh3ViIw2CCI0vTcGSE9Ek8lTmtzbdFOe3Pt0XNn1WEFjnndsFhna6x1tPO8Ru5tfSzvEbyvPqA6zYgHXIBK54pjezlimN7N0ceFlnALO1t9mdrZnZi+lic7EGAOBvcZXUxqWjZaNW0RjLF7gw2BBIGeeStEZTEZbIruBdwuqW2UttsiWnZO0tPRI4EclNbzWcprqTScqFVBURfrD0v8ufeuil6Ts6tO9LbMoXGZ4xSHj0QcjZRaOWOiLRyxtDTUQRukc57i4344rrSl5iNmmne0RiFJ0BDsJdfU6BbxbvdUXiYymZ8bI7NOdrDNRWJmd0Ui0zu1xxyVJaxhHRNgNFa1opvK1rRTMy9FDCyngYwm+EWvqvMtabWmXj3vN7TKKikZURFlmg8Wm3Aqaak1nKdPVmlsqGKopqhrCwGzbkh3JdGKXrl14peucvGfC1NvvB+he1xLHVd2gi1ug5YWry7d7j1acu09XlPgw/v5R/6cv8hWcsIfdlVYQEBQCkEBQCAghMiVIICAoBAUggIIUAogSrAgICAgIIVd5BMyJVh5D4Uf7iVf8AqRfzhIRL4zsQNO3KEOlMTd+28gFy3PirIfRHOpKqZkQmwtaLF7za+XEn0BVWaZbQSOiksHR+WGWdcg2QW4ayqY0SwySxtaDbpHK3P0ZhBtnp46+gbVUuMTB4ZUQNzF3DJzeedu+6CkMVXUx4g58ri4SGU3zGuY5etBtjqYJZXPjaYGuGGNjXm41ueeRKDpUO0pIJMJfLIGC92tzYOJt29p9d0HoqXa5MEO4b4252clyGyNueJbbMcM0GNRtTZtU6SB4ex3ksfG25sRkRb19yDRS7QlJbI+QugjykuAHGw8r+vbyQb9o1gpKYvJlccN2kMIxflnryQeRqNoVFfVgyPJu69icgEFSBsRe8yEYGgnyrE+jtQZ0tQ6nkbuJ3NLrY3Nyw9mfFB6On2ts+ihmMJ3z3uLgyRt3k64uQt3WKDZsekqp5Y6qSma2OWMWdw4tGY48h2IOpN4O7NnEmKnDC43xNJDgfSUHAqqc7Ob4q+XmS8CTs4255En/wgz2TE+urGdBrGsLgS1zha45XPrsMxZBeOzqYV0dLVNaTOwslwOcGlxGRtwDjbhftQU6/wZrqez4Zd/DEMgD02jibD7kHIhNS+TcGZ8MJAMgfdgBByP2IOxUbMAiiiqah0zmi5DZMu7ig481A+GzqdzpGf4WtOd+H+/Qg20zIKWmAlk/W+U7pkWOnHNBxp5BI97icLXZgajgLIPS7B2EJ6UVtXNu4gLN3ZzIF+7mgvw7Poqxxds5rCyUDG+cuLni5xNbnkcvTn2oPO7U2VV7KlkZuw6IPu1wd/hPAH/fEIKu3NpvqPBqpjbcTincyZ5Df1jeI4DiLn3IPmKsqkeSfSEBBTqv23qQW2+SPQPsUieagDxPpQQgICAgIM4ThmabXzWul/wAkK26S9fseRlPE4NAbKwND3cMhmSfTe3qXRqxzSrXaG6TaY2rO99VDHHJE2wcD0iSMjx48NbZqOTliMGcrIme9kkMkbZAynwk3tiJyIy9B7wssd8LKdaWUNSG0jycRaWOeekw88ufG3q4LSvrRmUTsmXYu1I5mbQMOCOe7ocrOOdvJHA8O9TOtWY5UcsxOXRqZ6SqrGzSUW/a2NrHTNls64F7gEcbnne4FllXMRiJWlg9zqeWN1I7J8oa5txdosMRI0NyFOMxuO8dpRwhjNnVFHGWuaJC3oNlFibglwzzNxbms4jPVPwQJotqV8xLxHUgBrGscAyQAC4xEd1z61ExMRg6rOz4Y9oSGFheHE3YDxGE8zrzyyWdswtDqeEGz4q2kjdUV/iM5t0nGzTb+vPitNK9o7lbREvne1Kdhmkjh6Ts8bmswjjxJ5+70LupO27GXClDBI1gfkD0nALXohZglpzPjiLzhGYNumb8/TosbRaY3XjHc97sXbLdnUjIYNnzSvAdi3Z8q3DEABq0X0XFau+8tWyXwh2pV0RnicDLTTCR0TWPaDGciDbQnLPPPsUREZxJMrlJ4bUVVRWla6klDOMmJ7crC5Lc9eOimdKYOZ5OvEjdqiOadkj5jjilgmxscHA8ATcG+ua1j9Kne7eyKt0Wy3U1ZTCQ07THGN3d17nECbjPl/wCFlaPWzC0dG47WrJmPa+llEETrYg8Xa0+kHMEAtKiawnL1OztrQ7R2YKppwEXa9riAWuHJUxvhOXz7wk2jM+WpjlIaJWgRvIuDmbi/I6cgu7TrEMJl5KpkrYJS2aSVrgB0cXLlwW8YVYOkqaoA4RiA8ouIJFra9inaELD6WeSnZIxzhGWkF7ySCeQsOHLlzVJ1KxOFopOMvQ0ngjTMZs+pjnje+5fUSzEiMNF7EcDlbhzy0K5ra02iYlpFIh2dgNp/04ImTGsjka5pnYCGYtQ05Xtz93FYX2hpD0ex6CDZcrovG2uBltGwgh3A5HO17X5Z2us5nMpaNueDkO0JInQ4qeSAdBzs43DPK/Ii+V1et+WJhWYzOXzbbOy59l7MrWTiMkl1nsza4cRYrW14tGysRh4pYrCAg+pfBd/yGckXDap1/W1gXVpfoeB5Q/8AkxMxtEf3Mw+gy1G5i6IDm8gTy4Klac07t9XiOxp6sZj/AB0TGcJxM5NJI1Ki2+0p0p5Z5q+CXMDwHOFnYeN/ckTjotakXiJt1x+Q0lj6kOY2175f1KvmKby5ZpfiImlWyGN0LHMeL3Fjxsq2tFpzDfQ0raVZraGbGtDSC3D23VZmWlKViMTGGcTrlxdbJ1m3VbR4NtK2czbx2ZbwgODyCOxMeC3aTETFpZts21ibHgqzu1rivRnYEelVbYiYU542Nud5fs42W9bTPc8vX06VzPN8lF4t0j6l0Q8jUjG8sYzGLmQnPl/VJz3Kac0je69SuaLDygAM1hqRL1uEtWMR1wtmQ34EDUhY4enOpOejAzGOSzhdrswQp5cxsynWml8W6T0RLJvGdAi/GxyU1jE7o1dTnr6k7tcRuWuZwBIsrW8Jc+lOZi1e5Yc8jMDNZxDuteY3iEtcQbEWvwUTC1bTE4mGNQ8hnR4qaRuz4i8xXZzZnOeTh0z1C66xEdXg61rXn1WjE4ZXJV8Q4+e0bJjje54FjnwAKTMRC2np3taI8W+KhxyWldYAXICztq4j1XZo8DzXxqytxRNgjLLhuImwHEhY2tNpy9LR0a6NJr0zKyG9FvZqsc7u+K7Qy5KGitLSnAGszAfexW1dTfd5+rws8sRXxy+P/C1l4U0w0o2/zvVZdOjtXCp8HLS/bdQwDyoP+4Lp4WcWmfc9XgZxe0+59cp6gR0gdE0C+eHgC48vUApvTN8S1vTmvizGCUVGGYAMe9w4HkOKm9eX1e5N68ma9yw7/iB+taAMdhY6c1nHq9GUep+nwVSXb0wtsRa1+N9BZa7Y5m0Y5eaWVJRT0coMljnmWk8FGpqV1I2Rq61NWuzcxjBIXOhtizuDr6VnMzjGWVpnGIlsiP64RkgxBtyTwuot0z3q2j1c97dvntkHSZgI4LPliYZ8kTHvTGWYS9pJHEhROc4lFs5xLe2xsVnLKVSqgjc7EZcJAzaea207THc30r2iMYcedgNyMmjnay7qy9KktDSwyYnuIaBy59i0nONms5xiF6jfHjswEtLr4Ty/3ZYakTjdy6sWxu6++OAYWH02yXDy77vO5IzvLCaodERKBij4OHarVpFtu9emnFvV72TqlkjCA7A7h0uCiKTEqxpzE5Um3djZciRtiRe97LonbE9zqnEYnuXzIS0HDmubDj5dxsjwMTmZJNY6Qmax0iWcj8MZIPJVrGZUrGZcWqkkkOAZPxHLX0Lv06xG709KtY37lAvkY7Nzr34X5roxEuvlrMGGRxxWsL524pmIM1jZZGz3vla2R+Brjx4lZdtERswnXiKzMRl0IKGOjle9jg1uEDEeN75rmvqzqRES5L61tWsRK7C0OiIubE81hacS5rzizcOCzZKs9JjErmGznttY8LraupjGe5vTVxiJ7nz34WIzD4P0EZABFSMv/g5Te3NujWtzbvLfBh/fyj/05f5Cspc8PuyqsICgFIhRnIlBCCUBBCiRKmAUggIIUCUEIJUiFGATAlAUggICCFAICjvBTnA8j8KP9xKv/Ui/nCmES+K7MNtqUp0lb9qsh9Co3taLAdMAXde3aT/RVWbpKxtbIDPGxro28b5nt48eHvQI5Cbsc0OLYiL3zJOVv96oNVQ6OnlDoC7EQ3CXcWu4+uxy5IM5qOuc2OqMWBkg/VuIAvYhvAZ34cu1BvkqKaomjc+n3wZGGySCSzr2vcC2Rued8gQgxdiiIkp3W6QFri/DMkaZkIOu2vijY2OklpmStwh7m9Fsg9JI6Qubi3JBDpW19bI17mxzAWjwOGB+oxH3XKDOkgZWTOpwXBxya3nkb5nX0IO3tOmFRRME1X4rLkMZNgbf71QeTrYWukexgxSZ4nNba/aTz9yDkzNawhrXXPMhBGNj5MQLrtzPC7swg9Lsjabdnwsjjo5ZHknEYzmdLgDO1wL6ehBtO3do1lM97CN7DKJBGxrmjBwIOouQguU3hXTTUpbKx1O9rTYuJeDYajP/AMIPO7QLhWjezxyGR28bJFLiYbk8jmMyg6OzagxUktPVQB4hDmxgx3cHG9wcxrb/AMINjtpVMsckRp5BAznjF2tPHiDmCAQeVkHpNmbTi2hQ74HC5pwvDiLgoPM7arZN5O19mtkZZjyLi9zcd3BB52aSrhcGyPlYQ0WAdy9SCDLPUNGQxAZOLrG3DVBnI526Zu3OsAQ4uJsdBYIL8Owo5aajmEjC8uLpXPJ3eEG3HI5EH096C5slsEe2oo2S+OMfcOmYCGg2NiAcrgc/zQd7ZlBBs2pkZ400h0oDGEEOvnYHO189M7dwNr7FjrA2OHFC+PNj3ZsOdyCeI7EHz/btDNRbLr2y4Hfq3We03DhbKxSB85VlUjyT6QgIKdV+29SC23yR6B9ikTzUAeJ9KCEBAQEBBb2WGu2pTB/k7wXyurV67Il61ssUtRLhcHl+J2JuQJ9S6ZzEKuXs2GSWeWksXF5u3tPJa6k9JUrHc6lTtBzKDcyW3kUlo5A2+EZktvzzt6FjFPWyvnZz8LJiJqioawvOLCOkdM+3mrzMxGIRjxX6jwurJWxUszGzxU+TCXuBta2ZaRfhx9I5qsaUdYTN2btvtljijdFd0bcAD7WGQ6QIAz9PKyp2eE8zsbHpINqUk1ZCGvnj6JgHldL/ABDWyztaa7SmMJpqCdn7WEteyQYmlrha2V7f75KszCXT2t4PyUbGTCRr4yGtLmizgANNLpS/iTDLYkTmVctM3FHNG29zlkpnxFjas+zmRt8aqI3P4NDHXd61pTm7lLY73l9qGCoLmQ4mx8Dc5rprzd7OcPLbRMENoonYsN7kZraMyqqwTPhaWtNt5YO9F7/0SYyRL12x/CVlBTzmFokmfGGDPA+wI4eq4/rkuG+jm0ZbRfZb2bNVFs9XHkxowytkkaXYSeFnceHes7YicLw3y0eyH0A2k+d1KyJxaaYNBMjrAgMuMxa57PsRNs4RsrTUOwfFvGodvRB7hjax8RAZytYcT9qtFr9JhGzn7L2k3ZtZLGwyVFPmQ5os6wueB4c/fxV7xzYlETh2YNrb9roZKmmYcAls5+Em9ujY2uexZ8vfhOXWpq2roKaVklLT1FPObh7CC1p4crj1e9Z4iJWzlzNovbFE6abAwA3a1h8rnkuiluacQzmMdXnayspZJA+V7hgObR/VbxFlNlSpr9nzlpjuzDyHk+hWiLYMwuU5bUUhle+wF8Jt0QQNFzX2tiGkbxlrl2kWUeCJu8kFgz/FgHHIW9PeVMUnOZM7Nke137NrGbZpJnVEr5MUkkwazpHiAwHM5HPgARkk15vVlGcbu9P8IzajC50c1LNZzZBGbi1jYt534ccllOhPcvzuts/b1FWS7s7RdHKX4g90uFkzTa3RPrJ0PHmspraFsxLDwomoz4H7agDmb1rDhZdtjYDNouTkMrqsdSXxdWQICD638FOEeCtVcgE1rv5GLWmXn8XyxO/e9jVtxQtc3kc1tpzvu8vjK504mG6MkBsoNiRms58HVpzMRGowlk3kha0gNOuVu1WrGIzLPV1O0vNa7RP5/wBDXtp2l7H3ckxzTiSupGhWb0nMsoq0k4izuKi2l3LaXGzM80w2Nma42IFrqs1mG9datuvRv3eENDRcarPOerr7PliIrGzPBe9+arlrGnnOWvBgJPIK2csez5N2eVr3Fjqqtu7KtIYbm2ZWsRZwak6W+FWQM8px4LauejzdWKfqlTcbusOC3iNnmXtm2y1TVGF93GwsAMllemY2d/DcTy2zafcveMbx4DRlbygclzcmI3ez5x2loivTxbrDJrgCORB4KnwdOI2izW5sN3ML7HX+ivE264YWro5mk2aZmsA6EgJGdlesz3w5tetIj1LbtrZw5ouMJAzuqTXd0V14mvg2NkxZte3PldVmMNqanNvWYHtc/kAkThOpWb9yrKWMJaTmOK1rEzu87VmlJmJaN7Cy9ze605bS4+10aZyQyN3gaw5uPNLRON06OpXnxTvW3lsTgT7+KxjNoejea6VolqfKJHuaSWsOg4q8VxGXPfVjUtNZ2iWUVZuiY3NBa3Q8FFtPm3aaXG9lmkxtDfHWRPNrkLOdOYdmnxunecN7XNcLtcCPSs5iYdVbVtGYl8b+GD+9dN/0Tf53qYWa/gpLW7erXuNrUhsbfOC008zOIb6ETNsQ+myta+jka05gWBC6qzMXiZehWZjUiZa6IF9M2/RdFqeStq7W+K2ttefe3VNUXFgb5QHS5YlSlMZyz09PGc9GuNrIX7wy3e3MBvC/pVpmbRjC9pm0YxsyZtN8sgxMBIPEE8QonQiI2lE8NFY2lv8AHWyOLsIz43Oaz7KYhj2M1jCy2Jm5xwgOLs+Cym05xZjNp5sWbmR+TfRUmzObMHU9nkg5cVaL7LRqZhmw4m3BtY53VZ2lWdpV53U+PpG7tGrSsXxs1pF8bOfO2OS9z0eWa6aTMOykzDmzvaXWYuqkTjd20icZlspqjdvYCbNaSchdVvTMSpqafNEuy2vDomtjGMk2OE2IXDOlicy82dDFpmdlltxH0rOa7M5rKeuzCeuzCRtMyQOe7yhwNuj2q0TeY2WrOpMYhplhp2xkNqBi4dpV62tneGtb3md6ppagiERuBvfJ3JRqU9bMI1dPNswsMma85SMBGXFZzWY7mU0mO5scHvZhLW31KrGIlSMROVOoDICMZ6R5Bb0zbo6NOZt0UXTU7ZMTjfsPBdEVvMYh1RS8xiGvxiHeY4zmeAKtyWxiV+S+MS6Lw1sLZHEXNicS5YzM4hxxmbTENU1WHFgbdosQ5wFyr108dWlNLGckVX4k8Rsbia4XzOZS2n2kZktpdrGZWmbVge8NzbfsWM6FojLnnhrxGVpkscnkvBtxF+Cxmsx1hhatq9YeB+GT+71B/wBX/wBjlEM5eM+DD+/lH/py/wAhUyiH3ZVWEBAQEBBCjIJMgkCUBSCAgIIUY3yCSCjcFIlSCCFERgSpBAQEBAUCEwCiR5H4Uf7iVf8AqRfzhTXqS+L7JAO16QHhvm/arqvoYlY+VwaQ7FfMZBVWU4WvllMQBJfwHMoLctQ9lM6ORtjG6zXWvh43af8AeSCq4iUGSSYNxG9uJPpHrQW5dv1ToYqZ4EscB6PScDYC2ZaQT/vVBgdqtMUbHsxbvKxAtw4ggDPl6LIOlsyFlfTyzx4XSxj9jzN8rj0ZIMY6OaN7scLg9jgcLmkcP98UHT2hsaWkgZKHtkjwNbiAs4D/AC93oQNkRmOtdC0OZIG3B4Zfmg6NXNStjBnmjJ5AG5ug5Fa5swLIiWtIzvxQcCu3UQETDfCSSQgqMeWA2PlCxQdfZu1hQCV0TcUrosDXHJw55e9BnSSzuknqYeiGA48cgLsJ5dLjkO9BvNNs+ajdWmc0zIXWdEADjJF2hlxzzy5W04BqdT7INMKhm142uPSDJIy0N7MufFBTpK1tJWFsT5JYTmbDPU5H1oOjDtPfNcyWaGPFHvLOfhP+XPnnw5oOlTVlTs2OUupoZoJiLuYQQ0jLlfuQaKqqBYXua1oFi0AjP0dyDl1NTHI4Oke4YcyAgrT1dLK0NZdttOCDBuGRpJdYDyTyB5ZIMHVJbAWt/WOw2a0jEG53yy9PegzG0JaeoZtSCUyzlwc98gDQ13MYQczkc9OSDr1Hhq6fC4xy08ouHYDcFpBtbnitbsQXKHbNPUOwPrpIpXOxNldJhbILNyw63uTbnftCCPCKaj/svtyAOYJBC/Cy7bO6GWEXPAc/9gPiSsqkeSfSEBBTqv23qQW2+SPQPsUieagDxPpQQgICAgILux37va9K8G2F976ZFTEZnCHojXRtpTIwBs//AKjgL3PL0Lr5d8dymdnMM5gpn7mVzTKemWOwhw42tzzsVr1lTuaWyue/eOaDfiXDikjXLOyPLCS4nLNWisyTKIiXPybnbgDdTaEQ2iQk9I5rOYWb4qqSLyHkc1WawnL0dN4VV8QBpa6YGwAZJY8De2d8uPC3oCxnTr1lfmluHhNtw1jpzMWuhc/eRuAAAvwJ92osq9nWDMtE88k8kMhlmjfgAkLpC+7dL+tWjbJLjvqjK9r3yFpFmtAAAYL5Lblx0Uyy2hUyNi3cUu8BNi9vAetaads9eqtocl8gdHG0tFm6f1WqjEAB188uSdySKUsqWydU3tqomNsETu6Um2Xb1phjDXMu4yPGJ35W/qVh2MY3X52mt23UTVDsFhcWwgk58L3KtTRiI3RN5lsmjEdHEY2EEAAONzn/ALBVMzzTlbuaHP53Odyb8Uwhk02F2kAkZjsUC1S7Rlpqg1GLGb9JmMtv3KJrnZMThu2htuo2pUNE7wGsYGMaHXAtwF/v1U0rFIJnLkVT5XPcDia25v2ldFZiejOYlWLg0YTn2qyFt1VMaZrGFzWA59qzxXOVszhFPVVEDnPY7CXNtc6diWrEkTK1IN+WwQxWfhLnWOVgFl03ldUeAwtwnFe1+wqypK8RMGAkZm5B5qI3TLN20Jm7MqKYyPMcjbYfQVnq1jGVqy465GggIPrfwVSBvgtO11sJrX3B/wAjFrSMvP4zUis1iene9jUOa94YSA0G9rcVtSMRl5fEXi9orM7Q0vecZsSb5Wvf1K8Rs5L6k804/PcXAbYjgicxEbtJmDjZrTYc7q8Vx1cttaLT6sbNrXFrRoqzGZdFbTFYZteqzDWt2+Koc03JPqWdqQ69LiLVneW7xmUC4NxlnoqckOvznUiMxvDISSE4X3tqDbJVxHc0jU1JnFujRI5zGZOOZtwzAWkREy49S1qV2nr/AExbhcHWdYjhfmrTmGdeW0TicKkjnCW7ha3AFbREY2ebqWtz5tDVkb5G6u59pTezbKO9OcVw3U1QIWG4J55FUvTml1cLxEaNJzu2N2g9sbr4QCDwHBUnRjLor5RvFJz3saeZ08wLxcNGVla9eWuzLh9edfVibxtDN2UhAFgDwVY6NrbXmOkIDr8UwiLZ6srlvPLVRhbMw2iqdGwtFibcbqvZxM5dMcXalZrH9qz8TmFzbu1WkYicS4NTmtXmrurEOvdxN+1bRjuefMWzmzKKTDJiAN1Fo2wvo6mL80Qye+Vzjcm6iIrENL31bWnMt8MpdYSWLWjlyWdq46OzR1ZtiL9IQWlzQ92TXXsmcThWa80ReekoZYk4srHvSUaeJ6oErmvyJBB1U8sTCsasxbaXy/4VZDL4TUzje/iTQb/53rlvXEvouD1Z1NPMsvgrkMe2doFpAPils/8AO1TpRmz0+HrFr7vplVMwwhkZDWPGZsuulZzmXo6dJ5sz1hUkfgwNa51mDhfnrZaxGczLesZzM9402BxNyKmUz7miWobfdtaSeeavWk9Za1056yyic6xcO9RaI6K3iOjeyRUmGU1b4ql7XDM2GhWdqRLK2nEwuNrZiP1ZLsuFuxYTpV73POjSOrJtTPI0HMtcBwyN1E0rCs6dInDVM4sL3hxsBk13Mq1YziGlIicQrxvbI4B8hBNyXFazExG0NbRMRtCpWF4dhIJYMweTltp4w6NLGM96s4h0hJHostY2hvEYhDThBOqTuTu20c+5mLze3DIqupXmrhTVpzVwuR7We2Vzmta1l7WPHvWE8PExiXNbhYmuJ6q5rn1U26OcbnXPovda9lFIz3tuxjTrzd61UdGQYW4bjMhY03jdhTeN2OPpWPDRThPLszuW5tNwo69VevVthqzABazr6uI4KltPmUvpRdokkkqS5+K7+rf7FpERTbua1rGnt3OdIHk9O7RyBXTWY7nZWY7mIf025G4OVuamY2TMbLE007yMyG2FgeCzrWsMqUpDOnmlb+qcQWk5hxzKreteql6Vn1ob3jeF7mAhjCAbnVZxtiJ6s49XET1lqbbHg5W4q89Mrz0yiSXA8AFwHIgpFcwVrmN3lPhPqHS+D9Cx7i4tqr/UK49ekV3h53F6cV3h574MP7+Uf+nL/IVzS4YfdlVYQEBAQEBBCjEAmBKkEBAQEBAQEBAQEBAQEBAQEBAQEHkPhR/uJV/6kX84UwiXxjYxttqjINv1zc/WpQ92KiMR4gMMt+k4C99PQqrK2/dG17o5C1z8nFhtcafYg0bxznYiLk6oILhe3E8kEgXNrepBiSSTdBmyR0fku7UHYh8IKqJuKCslbZmHC/O3DW+WR046INztu7VNcZjMWuie4vYQLAafaM8wg1PqHzuikL5GyYcyX4uje/8AUoKD5S7C7ERhyAtbCL3/AKoLMla8QYGS43E2LhyHpQUnSXjawgWaeXP0oMQBxQYg2eDog3yVIJBawBwN8bsz/v70GE1ZI6QkG3DLFfPW6DGRpbE02PDiSg0uN8zfPigNdhzBsSg3w1ckU++xYiLXbiIvllwQWana81U6Nsp6DGBgF72A7fvQVppzI4gE2vn2lBqxWABz7UGwzndgNJAHHtQYxyyMcXsNja19EGTxvLRRx9M6aINDgGgFpxaoMS7COjkb5kINVZUyM2VVxBzsD4iCEHkFZVI8k+kICCnVftvUgtt8kegfYpE81AHifSghAQEBAQZwkiZljY34haaX64Vt0daKGIsEN34uIBNhfVdszOcssQ0tgc9zsOTW8XHgFaZwYS9hieWte19uJHL0KBXeDJJkOHFXicQrO4HHPPJJSyDr8CqyNjXkZHiq4SyD5G2OHtBCYgWW1tQ5kl6lwJAxBxzfw7/yVZrCcywNZVuGEzuw6cE5a+BmUxmHoiSV1ybYWtUzkdBjGTwviL8AYTe7fKHLIepZZmJyv1jDmT0pY0Ycw0kEc/SuqLRLKYw0te5zTYXPAG2QClDQ07uUhxNyrdyEXOI2NxwQGENlxAAnMBRPQXHzPbaMuJAFukMwscZ3XyxdI4NF74RwTAgy3txyUYMpLgXAu4famMDFxDTiBsVMbjOOofm055c1EwZImxiQbxvQcbB1rAHtVpmZg6LccLHPvGSCLuJLScOgsL8llMz3rN0pE8bmODhDECcUkeFxvw7Ps4qI2J3cyB7onhweCNDc37Ftacqxs2VFm1pMOInB0rnPjdRWPV3J6tVXUmRrWZOfe/I5JWuJyTKtIHCLySGkZZKNT9EleqsvPbiAg+pfBg0O8H58RNm1bjYf5WLq0pxTZ8/5SrFuIjm6RH+Zezka3DiFzfU5rWsz0cGpSuOaECItbcutzsnNlWNKYjMzhDiQ3NTHVS0zEbtIaWjFwvwV85c0VmsZZ4tSq4a83iyBI5qGkTMMw4nyc+xRjxaRaZ/SyErm6gc1E1iV41bVZmaTlJ/VV5Y8Gs62p3WYYnvIL337bKcRHRnz3tOby2xObckXdY53CraJb6Vq9Y3wVMIdZ4df7uSUtjZPFaMWxfOfzZTcCw256reN3lWiaThjICRfgAphTUiZhjiBZ6FON2fNE1RyzQ7t26nJHC4w6c1S7p4aZjp3NoeXZ8SNAqYw6IvNt0CSxU4RGpiUh/EBRhMXR0SCp3PVmGIeWHI3U4yzjUms7Mn/AKxo1HBRGzS//khlHuy2xbhcDZwUWyvpdnMbxie9vb+rF888wMN1nO7rr/49/wDDRUMBwnyXHM8lpSXJxNInE9JSxw3Tg83AHHmomN9k6do5Ji89GEEjo2NubC2vJWtETLHQ1LUrGejSXmSQuDb3OWSvjEYc83nUvNoh8w+Ey/8AaOC9/wD7VvH/ADuXJr/qfR+Ss9jOfH7Mfg5bj21UsJIBp87c+kFfhpxaZfScDOLzPufS3Mjcy7S44RzNrBdcTMTu9KLWid2uOFzhjvhB4F3NXtaI2WteI2TdwB4Ea6qNjaVbAS8ycAM7rXO2G2cRhkHdHNRhExu2NJ43VZUmGwPNsuKrhTDISSMPAtPYqzWJVmtZbPGJMAwy+rT1KvJGd4V7Oud4YulmkyfJiHaFMVrHSExWtd4hsjLDJhxEutcCyrbOFbZxltqIhUU+K9rAWbbO/NUpblsy07TS2HNljMbsRGXLsXVWcu6tomMMHYnMyHpKtGIlMYiWthAaWk5q0xu0mN8obwN+HFTJLZT/ALTCBmSCSOIAVb9Mq6nTK26VzyQTf1LCKxDmisQOeWus4G51UxG2yYrExskTHFfVRyo5NkXaSbjNNzEwwxbsjCSrYz1Xxnq2F++jwuHrVccs5hTl5ZzCIAxryx7LOAuDbiOxLZmMwm+ZjMSsxta0Yml2Hhk3ESspmZ2YWmZ2ljVASxOe8WcbBuVlanqziFtOeW2IaaW7XhhfiaeI5j0K+pvGWmrvGYhrZIWTSOj8gvyJKtMZiIle1c1iJ6samffTANAIaLEgcSppTljdOnTlru8d8I2L9E0uIEf8RzHzSubiscsOLj8ckY8XJ+DD+/lH/py/yFcEvJh92VVhAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBB5D4Uf7iVf8AqRfzhTCJfFNnf8yprecb9qlD2TWtNmEuucwOAVVmvdEk25cUB7N27CHBx5kIML96AXEnsQRe/NBN7IJz42QbhUTOa/FMRkL34u4C1/8AfBBj4xLw3htoEBpYR03kHQNQWWBrsbMVgw8x5QQYvj6F2EGxzHNBg15IOVzwCDXfC6xKBfPJBjkHXsMkB7yHYeQFswgxLnWAPAIMS69hmgXz7EE5cb2QS2V4Jt70GbLOdd1wOF7ZA9qDMRhzhhJvmSSOGnBBsLt4C27gxueN7SDZBVbJYg3HrQZvFpCY73sSboNUribA8UFSvBGz5ssiw2QeXVlUjyT6QgIKdV+29SC23yR6B9ikTzUAeJ9KCEBAQEBBkzyx6Vro/wDJCtv0y6RqCaUuc0F1sjz0Xdy+sxzsiNpZSNvbdnM58EnexHRgCbYWXMZPMcVMxgZTNcxrQ4OaDewI4ehREpljHFvBcWt2myTZDJkHRx4SWnln3qs2ThmILRlznWHo4qObfBhD3tjaGkXvkCDkUiMyNQDgc+llcKyGe8z4AdgUYTlsjkAfibx96rMJWaeulhmxGJjr88NuxVmsTCYmXQY1tVHI6MioDhcxPOEtIvwtnz5KnNy9VsZcaZxhJjIwPabYSLWXTWcxllKq2MzEucLNHE6rTKrWTY5BShlGC83aL2VbThMLMG7J/WOued7myytnuWhuqYo2NaGEPxjlyVa5lMq25kEuHDmeA4K2YMNj6WeNgc+JwaTa5Uc0T0MNN78RkrITFI6J5eLEcyeaTGToz3gLSALNdxCrhLOmexj3NfK5jHH/AHfsU23gh1Y4KgyhsBDWuABc24L7jle45LHMd6+7GainoI3b2N0jr9K8gdgBGV2jMelTExZGMOPUvkYxsoyJuGvBuTZbUwpKpC0yyhtiSTdaW2hWG+Zw3bwHvNhbMWXPqfolpXqprhbOvs/Z+zdqxxU0U9RT7QORDojJFIezD0m9xQUtpbOqNlV8tFVYN7ERiwPDhmL8Qg+jfBi4t2FPbnVOH1Wrr0YzSXznlO014quO+P8AMvZPdvKhgAtYXW0RisvNvbtNasRBIQH2d5Wg5qIjbZOpb1vW6pYHPdmCXahJxCaRa079WFruzOalnjM7szFwGuhUcy86XRlujcNtn681HM07GcxDLBhdxufeozlfk5bdWtzsZ6NwQrRt1YWtzz6vchpIF7cQklZmIzhmHjmow0i8d7MOcG2ba2nJVxGd2sWtFcVb45g9mCQYO0LOa4nMOvT1ovXlvsxqYS0bwgEDi4ZqaWzspxOjNY55j5qMhvkMwuisPI1bZ6bsHMwgX4lWicsrU5Y36sL6qWefFua3BxyGqpM5dVa8vXotRsjdlcArK0zD0NKmnZqc0vJLRkFaJx1c1qzeZmsDIpHC4aSk2iE00r2jaEOa5p6QsVMTEovW1Z3jdic+wqWc7sxJ0cDgMuCrjvhrGp6vLaEP6WfB2oUxsrf1t+9YiIeLB2JwHAhZ22dujMWjGcy2GGV7ek4gN0NgFTmrHRvOjq3j1p6e9qlxXwBufCxPH71euOrn1ZtnliP9/dz5nOxYcwAeC6axGHia17Zx3NsItHjJIByyCpbrh0aMYpzzs+Y/Caf/AOR04uTakbmf871x636n03kyf/DPx+zV8HjnM2zUObxEH/cFtwkZtMT4PpPJ8RN7RPg+j1MmKJjMIu4gEhdtIxMy9TTriZllL0GtEhAFuiQVFd52RXedmLcT7BzTYDIKZxHRM4joStIeWuJFtUrO2xWdswnc9DEbW7Dmo5t8I598MxT4Wi49B0VefKvaZlmYMDRdwB0IUc+VYvmWMzwXbsAh3byU1jvWpHe1txNJuLkFWnC04lm2TUZKswrNW2N9gSywJVZjxUtHi309SW3ZIwAH/E0LO9M7wy1NOJ3iWc1MXwXYBKALg3zCrW+Lb7KU1MW32cuRwscLuHFddY8XdWPFp3fQL3C2gWmd8NebfENZyVlm+KN1sYFxbjos7T3M7WjouwNhcAcQJ1z4rC02hzXm0ImYDLumC5B4pWdsyUttzS1MhkcS1rSSFebRG7Sb1jeWUkUkY6bLZZKItE9EVtW3SWsm/HI8irLMo5DE0tc0Fp1UWrmcwi1eacwlzg8YSMuVuSRGERGN22lc0WjdJnyB/wB8VS8T1iFNSJ6xC02GokBY27WnkzL7VjNqxvLnm9I3lrlDoWYOJ5PLr588+StXFpyvWYtOXNrHPY4tthuMw3guvTiJjLt0oiYywpW4yXG4DRmQLqdScLas42eX+Eh19jUnScb1N8/8pXDxMerDy+Oj1I+Lj/Bh/fyj/wBOX+Qrhl5cPuyqsICAgICAgICAgICAgICAgICAgICAgICAgICAgIPIfCj/AHEq/wDUi/nCmES+KbPNto05/wDcClD2JeSy5ANlVZi1pEY6pOeaCMm+TmDqEESBwAxAjM5FBiBiOQQA08bXCBh6JJNvVxQLhvHNBHvQMWfAepBLXFpuCg3R1DmSYsLSeWSC1E/eYiCJQ4ZscbEWzytmgrGQxgtcLOHLggwaHSG5yHM6oMXG2QCDEuvkEBpF+kb+nkgyfGA0FpDroNZaQ4C1roMnRSNbcsIGpQYX7kEtcQSUAOOdufFBsicy5a5zmg8wgtsjk3jWsIDSBdwyvflzCBJSzUzSXxl7uYxgloPYM+PNBSL3Boe2/GwdfM2QagC51uZQaa8jxGozOUZCDyysqkeSfSEBBTqv23qQW2+SPQPsUieagDxPpQQgICAgIMmGzwVrpfrhW3SVt7wGMjA4DNehHXLBqfK8tLQ6zOFlaIRMs4nOlbgxXaxvAKJxG6YX2uY5kTXBwYLEWdYBYyuyrbyOjlZG3pCxLR+SrXbYkp5HY8DpcLr8S291FvGCGirmJeyNhBYzjY5K9I23RMsMntzBTpJ1SwvhNnc8gRzCTiegMlY7FjGTs8TtPSk7ENIr6Vgw3c5mKxcGONvXZY21qRO8tIpae5sZtihjkaY3SOvxaY3HuyVe2p4p5LeC1+kW7wTQ09S0k3c7dvz9VvSo7bTmN5OS/dBPUN2jVgtY5hDb/rG4D3mwKmuvp1jGSdK8z0UHOkxvYIpshcuLLC3pNlbzrT8UdjYmY+GON0cAk3nPGAGnQknj2Ks8ZRMaFmdNT18gYIYomEnPePI7Mha5WOpx1KxmYaU4W1pxDc17Z5ZqWNp3sJuWutic3rXHEX46cDqtNDia6sZV1dG2nOJTUwGN7Q1+H5pOYXTWcwwmG1gewknM2yOHgqTOUoBEgLXFzrm9i45JnAqvwteQBZpOV1pHRDEvwtNsmu6JsrQgs6NmLyhfimcydG6MAysLcBzt0hlftVJSu0tTug+Il+YyF8h6LH+h5KsxndaJI5KiATSEtdHMSHBzruy5HvUTicCm7DNOzouAbxGRv6VeNoV6sZIxSPJ3eTr2JH2KYnmOihJI59zmp1I9SUVndrXnOhfbtvaEVA2ip5hTwgWduGhjpP8AM4ZnvQUO1B9P+DIgbBnJ/wANU4/VauzR/RL5vypMRxNZnuj/ADL1pfa7hkeRXRjueLN8et3sd44SYy7MBTiMYZxqWi/NMrMNw5riSSW3BWVvB36GYmLTvMwsRYbkWuXcnLO2XbpYzMY3nxahiaSbWAOittLnjmrM+EN2MCPEXg+qypjfDq54inNMqrHuJJfncrWYjuefp3tMzNu9m5hJuzjzvzURPivbTmZzUL7tAz4pEJm+YwyAa8AhuegF/cFG8NIitsTEfnybWxuc6xjeC7gQ0hUm0RHV0V0rWtiazmfdLNkb3jDunHK/CyrMxG+W1NO945eWf6/tlGJsL4927Sx4C6i3LtOVtKNbFqcs/wDbQ7Z8+HJnctI1q5clvJ2vy7QM2bNKA5zcI0PEJOvWNkU8ma2pEWmMe6WTdlSuOeFgB1vdROvWGlfJOrM74jDaKB8bS6V2IA8GZ5f75KnaxM4h0R5PvSvNqTnHdH59IaBFiJdcFpza4cFpzY2ckaPNM27u6Y6NcTHZ9K/vVrTDn0qW33bDk0DNvoyVe90TtWI6fRjI1paXWNyeN1NZlnq1riZw03B48VdzZiUEFzsjZwyzU9FJjmnbrDIGzy12RCjuzDWJxaa2bGXDLiwIPEcVSeramYr+ZbHvdNGA02vqciqxEVlve9tWkRH5+fEkkNgHtFwLZJEeBqak4iLxu0tgEkZuCTfmFpNsS5K6EXpv1apZLNDQAPQr1ru59XVxWIiHy34SST4QwXv/APat4/5nLl4j9T3/ACPMzoTnx/xDD4PRfbFS3WD/ALgtOE/VPwfU+T/+S0+59EkkDpCQBYcLarviMQ9etcQ0Pke+xc7IZhaRER0axWI6LERdLaR5JGIC2iytiu0MbYr6sL7CBNjcDlwxcD6lzz0w5Jj1cQxmY8VBDGBo45DJTWY5d1qWjl3luhe1zCXSWwjMEaKloxO0M7xMTtCnJK59S5xzbyzW8ViK4dFaxFIjvZPZvAMOTuRKiJx1RFuXqCQxtLX3BA4D7UxneDli28AdFuXF4whgxEpiebbvMW5tu9m18bojKRaONmIuILSB68zwKrMTnHfKk1tE8sdZbIaiJ8TpWEyRDibHEPVxVbUtE4naVb0tForO0tsL3xB0rWFsTb3uc+5UtEW272d4i2Kz1V3Qmd73twguJsOB7clpFuWIiW0X5IiJV20z3uwODmAHyntsCtZvERmGs6kRGY3RNTOieGMYHAi5cCMvVxPqSt4mMzKaakWjMy2O/wCGeWvfaINsSD0r6W5ekqsevG3VSPXjMRv9G6FrKrA+Mh8eEXLBbO1+HJUtM0zE9Wd5nTzE7SxMThVkNkHG3G6nmjk6J5o5N4WbYGEHieJta6yzmWOcywcxr2XcC/C3M3KtEzErxMxO2ynkCWkcORW3vdHvYusSGE2vm0qY8Ux4srGPAJODuYUdc4R1zhtY3N2TSLXudOxUmWcz0b2zudGWXfcf4r5rOaYnLKaRE5GmSKmDJGtcAbiyTibZgnltfMK4ibNK+4OYyH3LXm5YhtNprEYan2p2OjwgEc7Zq0etOV6+vMS8T8ITnO2TSk3tv/8AtKx4uIisfFy+UIiNOPi5vwYf38o/9OX+QrzpePD7sqrCAgICAgICAgIMDLGOLwuS/HcNT9V4W5ZnuQJoybB4WdfKXCWnljUjJyW8E71lr4lp57w+Itzf2csglYf8QUV47hrdLx/X9nLKDMwC91W/lDh6xnJySh07BqVnqeU9CkbZn896YpModUtaL2PrXPq+WdHTrzcs/PZMacyyilbK24PqXZwXG6fF05qzv4K2rNZbF3KiAgICAgICAgICDyHwo/3Eq/8AUi/nCmES+J7P/wCY0/8AqBSh64uADRb0qqyMbgCAckAEuAbfIDNBsxNLGtcDhuOByCBOcRa5oBytkgxa8h3lAG/GyDF7zYMByHG3BBhx4oJa4t4ZXQC8AEusAc7nLL0oKTtsUUTnN3j3AGznMjc4D1gWQG+EGzWPbhkkJP8AhMTjf3ILX6Ygf+sZDVAk3J3D8/cgyO0YauZrGNkacN/1kZZ73ABBWftICUxiGoNgSXBlmgekkIMZ66SOFkkVK6QP4kyNaG9hJNr9iCYH7Tqy1lLSQte48JpSOdssrnNBvbUXrajZ0keCeEXDTa7283Ag68Ry5oNjmFv+Kx0QBcE8+2yCcWK+Ik31KDWSL5cEAPLQbEgEWPaEDMNvxQZN8sZjI80FqGXCHscSCRa3Idx/oUGIkljMktxhebODjc+vvQabte9uRFuPO4QHjdG+DJ3AoKNe7FRTm3+ApA8yrKpHkn0hAQU6r9t6kFtvkj0D7FInmoA8T6UEICAgICCW+UPStdL/AJIVt+mW7pYi5els5kwNa6T9Y0lljeyT02TDZTAsrGuaMgeByuFW0xNUx1dCWUPa2A3LGu6WHIG2YWOMbr57lcPGMFwcAb2aTewU4QzbE5rrvyxcM1WZiY2SxdDCS7p8MraqYtZGFYHduwG9r8VfrujosteH4SbEHiFnMYWytUlIXSNlMU4gJteOEyG/o5rm19eKRjva005tv3OrvJ4GujgfI0gXY4MmZkOqCCDYfavL3mcy7O5zaysrWS4KqesjbazpT0b3vycW81MQnKWVTX0wZKxs7iOgMReAT1gC690iMSid1d9ZWQODJpA7eOvgY0MAyyBDbEZcrK2I6oV3+MueXOa+Jhzc8sw6f4nWP/gJgZU8Tdo7RIhnjLGHpFrnS8uF8iOH+7qmpqRp1zK+nSdScQ6DaqCJ8bo2tjjD8YaBxAJ4niePO64L82p+p2V5dOMQ5viba2rjY2aSKSO5bMzouYbXP++avp6ltLeqtq11PVs1RPqDVPg2g+PxltrcG7xuo1OoXvcNxVdSrytbh7adt3XiDgzoSMwkA8VrPVhGyo6O1U83aByDBa5Wmdle9hPNhY/o4sRzJ5KaxmSZaQ28JbkeFgeKtM7nchhta4vlYgHipkSJXxPEjLFoNnAhMROxldkqKeeFscUbmi92jELB3p4qkRMTutsrzvq2FrHNc2PmHC1+y/qVq8swrOVqGTySBu8RvkLX7M1SVobJXvkD2ng7K2DNv9FUcapp5IXPEjC0DLMj+i0vMTScKxHrKi4W4gIPpnwb3/s9UAc6p38rV28P+l8r5Zz28RHhH9y9ab5BdDxZz0Zlo3QyOP8Aoozu1msdn03WKZxZDd3Bpy1WV4zbZ3cLaaaeZ7mbnXu6zsTncb8AoiO5pa2fWxvM/RDW7xuFmvElJnE7orXnrirJzW7vpcsj6VETOdmlq15PWapYmixacRH2K9bT3ubV0qxiazlMctzY8T7lFqp0tXMtzWiSzcN3HgRxVJnDqrWL7Y3dGlpzCwF9i/s5Ll1L807Pd4Thp0q+t1WFm7RAQEGLntBDcTQ4+SCeKmI71LXiJ5cxmeieWaheEoKtVTuMZ3IA4lzQBn6O1a6d4z6zz+K4a00nsvnHj8Pf9J+qhAwAA3sDwJ5rptLxtCkRifHp+f4bZgXxEOLT6VSu0ujXibUnMw1Dox8SVed5c9fVo1PdjmthsQrxGIc2pfn1MYxhDx+sByzFkjoi8evlNxh910TmMM4ZQ12CUXIzaQq2rneGujrcs8upHwZEOc4via7ttr6FG0bS0mLWmbacS1wukLjvAHZ5ditaI7mGjbUmZ7SMrIccJscvRwWWHoRacbNNUx724mgm2XABXpMRO7l4rTveM1jOHyb4Sxh8IqcEWPijbj/5vWWv+p6XkmMaExPj9mn4Prja9SdKf/uC14T9cvp/J3/JPwe/s4N52Xp7Ze1tMso2AsfjaSf8NhzVbTvsi0zmMN9AHNe8W6JHAqmriYhlrzExC06USkvLXHC2zQcsysYrjZzxWa7QhhxuLc3PIHE8Ck7Qm0YjPc2xQ4WuZMeVznyVLWzvVS18zmrTJTQuiJY8kkmwOVlpW9ondpXUtE4mGmOYxkAi2EWAKvNctLUiVsYSSHNDhyWO/cwnMdFmniMQde+ebbsJsO3tWV7ZYalubH3bbSAEB7vSLkqm3gp6vg0SucZW4nyM45E2xDnzGoWlYjGzWsRy7R+fwze5rouiMTuGINLrcuGeqrETE7qRExO7FsrhJgN5LtBba1jr5P3BWmsYz0/PetNYmM9Pz3tbCWOY6a0dzbqNceQ43Jt2K075iu/1WneJiu/1/P5a3VkIfeMh+QFhc+u/NWjTtjdpGlbG+354Km7xEyyEXcOAGWZB+9bZxtDfmx6sK0sVVE41FDO6OQWsD5D9Q4f7sta2paOXUjMfX5N6207RyasZj6x8JXtnytna2Z5GL/HfLC7K+Xr48Fz61Zr6sOTXrNM1j5Oq5uJpaXNI7c1yROJcMTicqtOzd3z58G8AFrect9SctFVJcMjLLA8HLTTjrLXSr1nLCVl4WcCWlWrO8rVnFpQ1wF7jEBnx4JMExllHMYXgSgPhfqEtXmjbqWpzR6u0w3vtM9pia7E3tHBZR6sbsY9WPWV8VRv8Mo6A/wALhb1rXFOXMNsU5c16rsTuQyy8mywtDmtDGdjpoQxtyeOQtfvU1mKzmU0mK2zL578IzHM2RS424San/tcnFTE1jCvHzE0jHi5PwYf38o/9OX+Qrgl5UPuyqsICAgICAgICDXJJhyHH0cFw8VxUaUctes+7OPitWuWnPVeJ/wCTPX+/6a7IN7c8ljqTqY3mYx+eMJjBy4XUxMcvTP580FyO1RM2piJ3+ny23+iUWN+BCpyWiemPp39M7T/Yxc9oPEHsC5dbidOJmc590Zn67LREtZJcbkry9S9tWZvafzdeNkMLmOu0m6pw2pq6N+fStOfsmYiY3XoZmyjtGq+/8n+UdPi6dd428M/DeXJek1bV6iggICAgICAgICDyHwo/3Eq/9SL+cKYRL4ns/wD5hT/6gUoerPlFVWSy1+lwQS0gSXba3bldBukdePADcXzw5CyDRwcCQQOQKCCDzyugiw4EoIy4IJvwQZxxOdZ27nMd7F0URkN/RzQXd7NCx8UDpL2ux2CZnDPIZg5IOdW19ayUNqp6yNpBDpfJve/JxbzsgxbWB9KGTNbOSOgMePpcOkAXXv8A+EFaStrKdwZLK07xwIYxoYGi2Vw2xHrBQV3mpLy4tdGw+U8ssAP8zrHlb1IN1BSHbW1txS1EZay2NzXOlwnhmcrcDzKD0EFTR7PEfi7WsG8xE2zIaQczxPE8boOZLQw7Yq4aaSaSJ7XlzJ2HC6IkXNj3+lBUilq6SrfQbWlj8YABhl8kTtPC3LFqEHRYHAXa5vC5Qa3D9YSSPUgxL+Ovagx5IJ4Wv7igAlrri1xqgsGaJ0eBrXDO4F8roMHvlwhpBDO0IM2P4EDBc3uEGUkjnF1/J0Lcx+aDm7RjcyjnDmkWYfsQeXVlUjyT6QgIKdV+29SC23yR6B9ikTzUAeJ9KCEBAQEBBshGKZg1Kvp/qhW3RfcMDsmYr5Xuu2JyxZhkMMePDd2fHgAmZlOMMAC6zy0EDO5ICe4bS925JY1125ONrjNRiMjW2IEh1nZcCApm0objUF8DI8Dv1Zu27uCpjdbLXML5uaRzJGeSVQw4sOFhc0A3Kt3oaqh3i9PLPjwEN6LTzPJRa+IzMLRGZcGLa20KexhqZ2Z36MxGa86YzOZdGcMJ9o19V/8AcVdU8HjikcbpFYMy1tq6uEHdVs7L8ek4JywnMs5dpV07DHLWyyt0fK4juJTEIzKsQWuxNxNdq0oMWucSGl7nA8jmkj3GyKLxGlgiuBK6J0knIg2vbuy9S8nWntNX3PS0vU08Q01DP+Ce+5a7dyEAi4OSnEcyO5axXc5znXc27Sb3ywgBUqtLn7dY6qZK5gJljaHtdkSLC6vpTyXjwL+vSYbKWsE1NHK1o/WNDszax5r6KnrViXjXjE4ZOlbjBcC11+Wa0xsoiWz+BbYnIFK7AG59H3G6nIgNdcXZlyITIhkmEXLQbg3CTGRkHGNt4WYfSU69TozZtPCwxygkO8oHNR2ffBzM4akHoDOLjqQomExK2MAs/eHlxuSB/wCFRZSrogGSeXexPTCWn1ZhEdXJXK1EBB9T+DBmLwcqD/8A1bv5WLp0pxV4PlKnNqxPu/zL2LWB+RbhwraZw8ytIttMYwkkAhjBlyUe+VpmInlrCWdA5ttzsCk7lPU6wPuX2cCAOFwkdE3zNsSmO0RDgHZHVRPrLaeNKYmMs7lxd0eJublRjDTM2mdurUbB+dwTwCt3MJxzbhaXGxaQSOOimJwi1ZttMYlcoYwxxldIDhFgOaw1ZzGIh6vAacVmdS1s42wtPmcDZoc8cyLZLGKx3vRvrWicViZ/jZgaktZYBxcSbHCTZW5MyyniZrXEZzOe6ZSyVz5cLZBwHRI4dqTWIjMwU1bX1OWtvl/lm/A5lpLOB5GyrGYnZtfktXGpuxeSY4nQ3HSsG5W9YUxG8xZnqWzSltLbfp9/h1bWsDXXNi7OxtwVJnZ0104i2Z6tiq2EBBQrIiHvcGEtLcdxqOPoy+xdGnbaIy8bjdKYta0V2xn5x1+GY/nCmZLjyRbnYreIeZbUzHRDXNIIaefPVTMT3q1vWYmKyxw9InLvU5Z8m8ps7KwPrUZhbFu6GNrW6Ns81KmMY2TdrrXZcjgnROYtjMdE758ZzHR7Co5Ylbt76c7xsk1TJSHZh44KOSY2Wniqam/e3Mdj45E8wqTGHVS/P12lk5oLS259AURO+VrViazXL5H8KIA8Jae3OkaeHz3rPVnd6Hk+sRpTjxR8GbMe26saU1+Pzgr6E4tL3ODnF5fR8IxGLd2B4uJ4rtz35ennbmylwZCAGDMmxJ5pGbdSM26gaQ8uLLE2AIOZTO2DMYxlnKXPa3IhjjzF1WsY+KtYiJnxQ2JrLus8mwyGV1M2mdkzaZ2WN8Xyte1hxEYb4lly4jDHkiK4mWiZrcQxgsFrdHhdaVme5rSZ7kPGK14yQT0e1TG3emNu9spaMSvbG6W7Dm9t8Jt6b6qmpqcsZiN1NXWmsTMRu7bGRXDWmwAsBe+S4Zm3V5lpt1lTrKale90r45JCGhoDXOsMzyC2073iMROP4dGlqakRFYmI/g3wBgbiZE7ERhdFbGM8hfMfknL1nr8zkzzT1j49F57YnN/WBpYciCBY9i54m0dHLWbRO3VULI4YHxwOfHE2xAjs1rAM7DS/P0rbM2tE23l0RNrWib7z7+//AKZNrozI+NwcZGMBLcPRaf8ANrnryUTpTiJjp+dys6M4iY6T/P8ADiRR4pJZHG54r0LWxERD1LWxERDVUXbJTkE5y2+qSrU3i3w/yvp7xb4f5b2tBy1AWcyymXJqb0dbFUtuGtfhk0LTe9/tXbT/AMlJpPy+L0NPGrpzSeuNvi7jalwbhDG5ZeVmvPmkZzl5c6cZzMsGTRiW2YJGY4hWms4WtS2GErS94JLTlrbJTWcQtWcQBjgOB77gqcwnMIcHAOLmWOqR7pIxPSU4mFhjcwOBIyCYnOYMTnMSkyyxZsYAOPHNRyxPVHLW3WUmuimaI5AcuBUdlau8I7C1ZzDdFMX2DrEDJpHFUtXHRnamOjcGhtxjOYPAG6zz7mWZnueC+FCIR7HpCP3kDMfNdzVda2awy4q3NSHA+DD+/lH/AKcv8hXLLgh92VVhAQEBAQEBBBJAyF1TUtNazNYzJDANwgdG/rXDXSnTiJime/rv9V85Tu2u4t96vPC6OrEc9frP+JRzTCN0ARhyA5KI4HTpNez2iO7qc0944ttawI5qurOnMcnLEx3+5MZ6sXMIOIC3LL7VjrcPalp1KRjMY2x39Z+XimJztLFzmseG3JFsxZcurq6WjrRpc2a43jG3u6R170xEzGVe2KYkr5mYnV4q1rNulWDguXVpH58ZWhk1bae/X3/2iUMdhlyJ9RsqaGrOlxO0z8pxv3e7GfFMxmrotcHNDhzC/SdHUjV066lekxlxzGJwlaoEBAQEBAQEBB5D4Uf7iVf+pF/OFMIl8ToP+YU/+oFKHq878FVZmMDWBxFzfggwF3XNvegyxZXaDdvE8kGOZzscuaCTLiiwWNhwJKDA20QBfkL80GmrqG0tLLUPyDGk2PPsQeHbtnacTzJFUzsLnYjgmIAKDCfam0qof8RW1br8S6Vxv70GttZWQX3VfOwn57ggmXalfMwxS180rBlhdK4geolBWLSDjAIdq0oMQ5xIBkc4HiDmg+n+C9F+idj0zG2bUTxySy3FnN4WFvQEGuZt6J0mItcGSEAi4OSC01+ZLnXcwAE3vlgy7s0FHwgjdtShmiaC6aOLHG7IkFpuLd1kGOzqwVuz4ajnI3pdh4H3hBYJHPigg2Jz5oJyJyOfYgnQWQRe3EXQAebRZBm2ocxpBzB4g5oDJRwscOiDddoGIO4d4CCltIWo6gdL9m4jEOxIHlFZVI8k+kICCnVftvUgtt8kegfYpE81AHifSghAQEBAQbqQXq4h85WrOJRPR1cDnNwgXF+K6OaGeEGFxb5JHqU80GGe7YA4btx0z4FMmGoxv5Fw1F8lbMIwzaZQC27gTx7VGxhgI3mXGYxmb2CTMYwYZuLiSGxeVqqxiO8w0bmQdLdkAm+ErTmjxRhx9uVDmmOn6Icek7EeI5LDVtGMQ0pHe44wl1nBrraFYNEdEk2abHt4qMiHSZWDnAcM1XKUXJAIcHcswoSxda9ixt+eElMmF3ZFM2orm4mjdxHG7PuHfZZ6lsQvSuZe3ikPioqDhxydEgN8m4txXn9bOzpDmVM2Khc3pACN4y5/7upiJ5jOy3LgZLLuySLA3P8AlVIjotPexp4y6seC7M5AjOyrqQmk4lUpKY0m0avZpc1+6eZIi3mwlexwmtNqQ8/idPlut7h1ruNhddvO5cBgviNrjtI/3zTnkwwMdhcC3oFlPMYGsNi4B3HgUmxhBBabAXHZyTJhDXuHM2RA+NszRiaCdVMWmpjLR4oW5tJ9AV+0z1RytgbO0Wt7lXNU4kqpqiSnIkkxADhfgqW5eWcJjOXOXM1EBB9Z+CthPgzUEfvjv5GLbTnZ5XG0mbxMPaGJxNyzj2LTmhwzpWmc4RurEkgqeZHY4neBzOYaRrmkSW0/CGIY8cyfSpzDONO8Je17mkWuDryURMRK163tGEtBa0gtvdJnMprWa1xhi9j5AP1fdyUxMR3qXpe8fpYGORlyW3AzJ7FOYlnOneuZmG6I/q22MRYeLicwqW6+91aM+pGJjl8WcNKwMcBCW4tDx96rbUnPVro8JSKzEUxn39fqtRRDdNw3blx52WVrb7vQ0dGOSOXb+25vM4r5W4WWcuqvfOUbphBu1pvfkp5pR2NJjeAxtywtHH+t05pLaVdsR+ZyzF7C4APOxVWsZxv1SiRAQa5ml0ZsXZZ2bbPsz1VqziWOtWbUnGfl3+7fx6KD6bC4tGViumL5eLfhuWZiGJhGd1PMpOjCDA0ck5kToR4MXRnh0vUpiyltKejIx2yPLVRzLTp42ljY+hWUxKew+9Qn3S0vpGvNx0T2K8akw578HW05jYZA9h6NyEm8T1RTh70/S2N37TkbdqrPLLavbVnZ8o+FLF/aWDFx8Ub/ADvWGrjOz2OA5uznm8Wz4K4zJtytA5Ut/rtTSnEvY4e2LPp7qeR2ZjJA7F0xePF3RqRHex8WdcExutzyU88eK3aR4pMYw5RnFmMSZ36o5t+rARyA3BcByBPBW5oW5qsxvg21r/Ndwuq+qrPLlFO10LrmO4HKyXmLR1TqTFo6kmN7C0QXAvYDiUjETnJXETnLT4vOwj9WTllfkr89Z72nPSe9upCHRyFjWGUOs5rzk23P7VTU2mM9GertMZ6NsNHFPVGUQFx4b5rh6+arbUtWuM/JS+talOXm+S3TUscTZmDEA12TiS4tNuV7rC+pMzEubU1bWmJaaqvZBAwCqdFidhD3x8Sr6elNrT6uWmnoTe05rn5tslQ9zY2wGKY3u4vysLXvlzzBVYpEZm2YUrpxEzN8x8HKftKiZUO8ZaGOgyAY4gZgg3A5XceN+K7I0dSa+p3/AJ/h314fVmnqb5/P8R4MWSxVMvjT4GxysB6LZS5o5cMh7lM1mkckTmPgtatqRyROYn3RH1bAP1ZI4kaKnezmd1adoMlPiDv2v/YVtSdrfD/Lek7Wx4f5htaML3Ach96znozneFaopd9BIw2u+97i4vbmFtS/LaJb6epy2iVzZL2bSonTNa1j2PdG9reRB4d1lhxETo35Z+Ln4qJ0NTlnpMRP8rZpC2wdpqse0z0c/a56MfE22vhue1T2kp7WWLqZzW5NNtApi8SmNSJkbT2YLtdZw/xBJvuTfdGGxItYahTlOcpFwMzfRQNU1FFOC6wB1CvXVtVemtamzU2gkjd0HEq86sT1aTrxaN21rKlrrgf0sqTNJZzOnLxfwpGY7GozKb/8T/2uXPrcvLGHHxPLyRyvP/Bh/fyj/wBOX+Qrmlww+7KqwgICAgICAghQF0mYjqIxdG9isJ1p5IthOGmSdtuY5XsvF4vyppY74jOM4/r7tK0lhvHW6LgSeRC454vUiM6d8zbumIW5Y72DpbkYm5jqkrg1uN5rR2ld49mZ69Z+c+K8V8GOJrjkLW7Vj2ujqWjFcY989evf1TiYSM89VbTmJ9fxyT4NZ4LgvMzX+P7laGQFnWW1a8t8R+dEdzHCSTmufs5tad05W6R948NwSNOS+z8ha8X0OyzEzX6Z3x8nPqxvlYXvshAQEBAQEBAQeQ+FH+4lX/qRfzhTCJfE6D/7+D/UClD1IeCLXCqsk+Tc5IMujY5E6ZoMeVr2CCQ9wBAJBPagxNyb2HqQBkMhmUEcM/cg894V12CGKkY5gMhxPuf8PL3/AGIPL3aTZ4Y62hQYktN7NIB7eKDF0lhYOc0DVBGZAIeDbUIIIBIBY2/YSEF/YtE2r2ixj2jcxneSZ3yH3mwQfSYJS2hZUuw7x4wkYeFwAg5tRUB1AWXIAY8Zc0Fx5Y10u7cT+rYb8M8KBRNvXG7s3dG4ztcoOayB2ytu1+yy8PZjNRDh5tcc+eViDkgt3J4m2aCSTmRn3IMcVuz1IGLiQUAlwy+xBAe8a9qCcZIFwCgi4HJAxEDRBqrpnvoJml9wGHL1JA80rKpHkn0hAQU6r9t6kFtvkj0D7FInmoA8T6UEICAgICDdSG1XEfnKYRPR2m2dxyJtbOysoAERg3455njbJJgY7x3HHZut0xAyD3HPFewUYAdI3seHEKRuZFNKLRMLrC9zpe1/RdVm1Y6pitp6IZTTyNDsD34gS0Bpztb7dRosp16x0aRpT3odDI0ljhgcOLXXJBt9/JZzxE90NI0Y75U3+DlPU1N6ie88oOnSPIcQOSpOteV4pWG+TwGpILMmhdG/jjkdYdvOx9SpOrdbkq2N8EKBpe/dmeGMHE6NtsJ0PYdc1HaW8U8lfBL/AAZ2cxjH+KBjy0uIfwBGZAz6WVuCrz375Ty18GMjNkNoGR4ImiBzhge03uTfDfTK3+87Ta3LmEViM4lSl/RUlWIYKWmwk5Oz6TjyOfD3qk3v4SvFKd8r9FPsmSYspYoWyMtvAbPxvzLQASMVswb6DhneZrfEWsrE1zy1dSSioJA1zTSOFg4xRulYb8TcYgOziufmxLflmVUeDVJUOe6TxmBgJLG08sbhbQ4nEq3ae5HJEd6tP4PbRE2OlrW1kbgDg3YY4i3DMAXtzupm9fBMUlqkpp6Z96lppHNBwhwa4HsGFx99vSq5idkxGFWGkE+1zOKlpkZDjaQw4XXeMnA+laaer2cZhTU0+ecSsbupswiPfbwOIDXjkSLAG2ZtlmV1afG0tOJjDlvwlqxmJU4q+GRxY6UMfkMMpDLE8s7Arsrq0mNpc86Vo6w6LKGrkjJa0OB4ESNt9qnnr4qfFH6KqzezcOnSBKntKoSdmVVrEE65j7056DU/ZNW53kCxHMhTGrWEIGyKoZua1o7DcgepJ1qpjdkNk1lyLx5ZA3yPana1Gt2z545mxGVhe9pcM+Qtf7QonVqnuaJ4BuagGduOMXLc89bZcrjvUTqROyYjvctUXEBB9d+Cb+69SP8A+sd/IxaV6OLXn1sPcEgEferOeZiJCQoTMwYuRKnBzeMpuoTlIvyRMRPcy3UruFgO1RzVheNLVt0ZinP+J3cq87avDz3yy3EZFnC4PEFV55aeb0mMTuPp4XkYmA25FTF7R0lF+G0r45q5ZbqPLogW4WUc0tOyp4Mg0A3AUZWisRvCHOwi/LmkRktbl3SoWyhz2sYXk5BTETM4UtqVrWbT3JULpQQglAQapIRJniIOoVothhqaEX3ziWl9K8DouBWkakd7kvwt/wD1lr3UoPk5jjmFbmhh2WpE9EOjec7HhqpiYVtp3lAikB45aKeaERpakT1DE8jtUc0E6V5hr8Wf2dwV+eGHm12Xi0mDECONrKvPGWnmt+XOTxeXrhTzwjzfU8R0LrXDwWngUi0Jto2xmJ2fJvhYjMfhTTtxYh4m2x/+b1jacvU4bT7OsxnO7d8EV/7Q1tv3T/vaoh2afV9bN2tuT71brLaMTLIOAAId67qMIwB7+bhbldMQcsJxnDc2sVGEYgaBe9iO0KZTOUPcWgkOt6QkRkiMtYkOd2uee5W5V+XwYOne5oDRhPDVWisRK0UiJ3acBeBDiFuIYAB6Sr5x6zTOPWwyaHxjCx5jA5NAA7lE4nruicW3mMhMtiTI83OuRT1fA9Xwa3EghhlGQyDz/s24K8eOF4jvwymlc2ZtgSHi7bA8Lfaq1rEwrSsTX4KjKmrmlN6U2DsrtPDX0reaUrH6nTbT061/UsTNYHA36TvKxM5ZjgcwMuKyrMsKTMq5bGHXD8R5NaXAD3rXM4b5nHT+mt0DnnEJ5oza2WEt9Od1MWiNsRP8rReI2xE/z/pXw1sMkkjrVAcTZjLCw5cbf1WudO0REbfnzbZ0rRER6v57skkpMd5Q6EuNsLgD2cj/AFSK77b/AJ7ytd8V3/PeUjpKFtTNTyMLpJAHNcCW5AZ6jK/empEanLW0dINWK6s1reNohfbtJ4hfJLETgvcseCbcjY2++6550IzERLknh45ois9UwbUo6l5Yyrixjk5wYbeg2UW0NSkZms/2X4bVpGZrOP5X3QTuAGE2vqFzxasOSL0hh4pU8WnCfSFbtKLdrp97Lxac+UL9yrz17le0pHRoOzZiSTY55XAWnbVaxxFEjZs1vKa024p29SeIqn9HVPnGhR21PBHnFPBl+j5gLCRt+ajtq+CO3p4PB/CxTui8H6B5eHNdVcjf/A5UveJ2wx1rxbbDy/wYf38o/wDTl/kKylzQ+7KqwgKAUggguA4lZ31aUjNpTiWBlHIErjvx1Y/TWZ+i3KxMzuQAXLfyjqTtWMfVMUhjvJL2xZ+hc0cXxMzjm3+ELcsIcXE5nNU1NTWtbNrb/IiIRd1vKJCy5tbln15mPzZOyDlmSVlf1Yzefz3JhLjYNIvY8Frrak0pS9c8s9Ov1wiI3ay5xNhGT6l599bWvfkrpTPyndeIiO9m5tgHHiQuvU0+WK6lusxnx+k/WVYnuYWbfkewXXHNdOLbTE+6Mx/mFt0YQeRFln2VbdYmMfD7yZQQ4OvkVnfT1a35oxP0/wAQmJhBOXCyztbMbxj6/wCUpjfuyXNtey14PiZ4W9tTTxnHv3z4otHNtLe2rB4sPqXvaHl+L559Ofl9pwynS97a2eN/B1vSvU0PKnCa8ZrfHx2UmloZ3Gq7o1KzvEq4LjVOeviYLhO0qjBcJz1MFwonUrEJwXCntKowYgonUiJTh5H4USP7C1Y/9yL+cK1bxNuVExs+JUZtWwn54Wir0IIdxBBPA8FVZkWFrQb5Z26XGyDXjJ/xWHYUEhxP+K9ggkXNsuSDbHFLLlEwvsL+q9r96DJtLM9oIjebg2AB4j7QexAdSyNcWv6Dhxa69/8AfDJBTl8GqWqqg+rqLzSXAvz5AcQB/vigsP8AAGgha1s0DmPOeOR9h287HVBtZ4FbMa5x3InhjaS8xMzYe3s7RdBkfBPZIjjf4k2ORzTlIeiCM8s+llbgEGs0+xW0m4dHFFuXOO7kYbgm3RvyGVj23QV5INiS1DYoYKRrXG+IG93Hlx4dvFBcoqjYjqx1NRRQNkaAJi5wdvDcloaCRexFs+VvSg7r9nUVRGxzW0ti0OMbHyMdcZ5gOAy9KCqfBSiqJXukdPTsxEsFPLG71HE+6CvP4MbSbJvKLaHjcT25xmEMeQBwzAF+2/rQYOoqikkBqGOpHAHDja1wJHAdFx99vSgovoBWbZjnNU0vZCXMIZkbu8l1+XFBtl2fWxNjdgbUCQuA3bgCS02OTiOPLMoOcyvhxGOV+5kGRbN0LE8rnJBfZSVErcQAcNQ8ce9BI2fUdW3/AMggHZ8tvJN+eYQYmiqepf8A+QQR4lUDMsAA7UEiiqDfJvZnxQa5IJI5o4i5hdIHEdLS1/tQVarAYKmPeNxsjJtnnkLjhx6Q70gefVlUjyT6QgIKdV+29SC23yR6B9ikTzUAeJ9KCEBAQEBBa2Y0P2nTtLS4F/AC91FpxGUS9Q+NobdtA55FyRu3ZDX3LHtPeriGsNxON9mkZXJwu+9ROp7zAHCNoI2YbngMBv8A7yUdrnvHOqPCWOkkbHVbGkhLhiyYCQCdMtCr+vbpK8RTvb6nwn8HmMxQGrdJcFrDTbsAdpuc7qs01PFpE0juaIvCrY0uASw1tPYWc6JmP12xBU7Ky3aVWZvCrYkkDd1tCvZJcEvdRG4HNuT+CdlZPPUm8MNguc6WN1Zjtbo0xGLKxvd3uTsrHaVYQ+Guy5I9zL42RmRjpg5t+IyxcLp2NjtYdCFtXHDHU7uGJr24mukkDG2tcEXtq2w4nkueZxOG0Rlg/wDT07Q4YGuAuXRTMbhIub5nFbUZ/wBFXmzOy8Vjvc2Ojr5Kmle4vkZO/fNcCXOw3aS4DX087dijEzE5WzEbQiq2YyfbVbGGhsUb43MjfGbWsLXbnyWsTMacbsuupOy7Bs51JGZ6WjiklY8FhjZaQWGeHoi4z/8AKxm2Z3lr0jonZ1HUz7Ur62GJrSRHbfFrS0hgve51urXmZ06wzrGLzKa7atVRVkcBdRslJbgJo2vDrkC+LFbn9qzrSJjMw15nSG0vCiJmHxqMxHjGyEEAep11GY/JTy75cWaDae2GNimgD7F+GNkBLrty4Y72yTMROycyr7OMNFOYmgNe1txI2zb563vdTqYxmZKzOcLstJLJNPPBNHK+WADAZRi8oEjQnLUWSsxjCL5ysiBsuzqVrnxQTRscQHEjC7ESMwCOBWeMTO6eaZhRfsGop9l1Ej3tn6W8wsa4i2ty2xyWlY5rRhE3xXdqpfBt7XR7mp8VEovja90bXNAueGRPqV51bUnEyiNOt46K2LbsUzo4J21pDA9wOYYMwc7C1rXW9NXMZlz30KxOHUphVzNvM9rADa7DiF+w5X9KvOpEOOYjuSYt7MWtqXYonWcAwC2XpTtNkYlondKxlUyGOcyRtcwOGRDvT6xx1C0iZndMRPVph2oCYoiwvkmlaBdlzdz3AAZ8Bh96TnGUzG7ZVVkbKxrGbhxELnYjDn/hIAz7c/QkZwYlznTNrRV4HMaGRiS7GYGvJAJH5HRWjOYydznLYEBB9g+CNrT4L1N/313L5jFaJlz6tazbd7khvVJ9SsxmK+AQ0HySfUo3JivghzmtBOAm3YpiJ8UWtWN+XLVHWwlhc+CRpHIi9x9ivOlbO0ubT47RmszakxPhj8hkNq0uWFrz6AFHm9+9ePK3Df8ArE/x/sG1YLgFkzSeF2J5vbxhMeV9DMRNbRnxhLNqQPI6EouL9JlrdiidC0eCaeVdC/daPjGPzPcl204W/wDpzH/9ZSNC098Jt5V0a/8Arb+G2nq2VF8LXttwxi11S+nNOrp4fi6cRnliY+MYy3rN1iDF+bDZTHVS+9ZwlQuxlYZInMBLcQtcclas4nLLW0+005pE4yyVWqUBAQEBAQQQCcwDbNSrMRM7wjC08QmZJpWe5g5gDeGfYFaJY208R72uxvkFZjiUBrs8rpmERS24XvjLQ5hwubkOeKxP9CpxEqze+nMRMbTH1xM/1EkLzK54DbYDbMdgP9UtHLhOjedWbREdJx9In/LWSI4I3ODAy3kgXvbPLuVutpiOrCZimlW045fD4b7PknwuAjwppbgj/gWZH/O9ZS9HTjFYb/gcF/COuv8Auf8A3tUS1h9gwjRRlbJhbbgEzJmWMuJkTjHCJHDgy4F/WprvO84WribetOGrfG9nvijI/wAN7lX5fDdfk8ImWp0hJsCSAbHMAcR29t1eIXiuEPIiBc/EBewwgvJ9Qvkkb7R9k1zbaPt/bFs7nT7oRTNFr4nR5EDt/px7FaaxFc5haaRFebMfz+fZAka5zmNbLiBIzie0HjwJAB70xMbzj+YJrMREzj+Y/wADcUkbXGGRlwcpALttyOfPla6TiJxlM4iZiJz8GiWSaPKPdguGWJ2d/QtKxWerWta2/VlUmmqnkhxMbDkXBwsbm1tbrataR729KacdN5+zU2mkdMBO0OwtuTa5aeWfq+xXm8RX1Wk6lYr6q9XQxvnje8/+mBbj/viufStMVmI8XLo3tFZiPFpijbTOxMZ0XXxFgzueZV7TN9paWtN4xMrdUC6S4Lb2AuXWusdOcQ59KYiMOYZarxlzY5Ym2NsJhP24v6Lr5acuZj6/6d3Lp8mZif5/0zmlrzAbyxuLQTbBx+sFWtdLm6fn8K0roxbpP8/6VJKOaoGKd7CMukIjkPaW1dStf0x9f9OiurWm1Y+v+m6BjII92xjY87FrcgqWmbTmZZ3mbzmZyzMDhTlzBvbvu7D6LXzVeaObfZTnibYnbZtmgDsTGvYHGwsL8O5VrfG8qUvMYmYaBsszgROe11m5l7Tb0cPStO35d4azxMV9aIaWQS0Y/wCHqXwhgHQbI4C57Dlbirzaup+qM/JpN66v665+Uf2uUFXt0VDYMUNTHexklGGwA43bx7lhq6fDcvNvE+7/AG5tfS4OaTfes+Ef7+70YvYYrX52XlvHn3GXFENVQ5rIt6+R7GRdN2EXuAOB/JXpEzPLEdWmnEzbliMzOzZjaOJtbmVXEqYliJWl7mkgEdvH/d1PLOMrcs4y+e/C+APBrZ4a0NaKuwaBYAYHKZ67q3zM7vHfBibeHVGf/bl/kKx1rclMq16vueNcXnExPVphBf6VW3EzEZMG8y5rOeLnlzucqC9+ht2C6pbX4jryzj3Rn8/hOIQS48ndyy1L609Yt/H+0xhiL3HQcPUsKxeZjOnaPl/tPzT/AIbgn0WKtMzNIvWZ+GJzPu/JDMjEGut6E9a1O1rS2Ph/jOT3IFzlgf62rKs2vHLNLfOv/eDp3sC4tzy9ZXNfVtp7xt8ZwtjLFzpOVh61yaurxO8xtj3xtj6rREMQx5tc5Lmrw2taY55zH+E5hse0YWZ8l6fE6Fez09+kfJSJ3lgBhzFz9q4qU7L16xnf35xhbqzcXOa02tlzXZr21dTTpaIxt3qxiJaySHWyB9C8+2pal4jaJ+H+cr42ZYpLWJyWs6vFRGLTt+e9GKtebuIPcuKYvrfrju8On1W2hOTfvSOTSn/JvKcORtnw5rXs8xM136d/d+e9GTDZvEA2UzpRWkRmInH/AH3GUCI2Avn9iy0+BviK82/z2+iZtCem3LHbifStpniNOeXtMTvPx+/zRtPczZLJqHdq7OH47i5jGYt7/j8lZrVuxkcbXXtRr2iPX6s8Jxq/nHTCMJOK2RWmp2uNp8CMILiA08is7at60pbut9smEkkAcLk5LS2peIjHWZ2MPI/Cff8AsNV385F6+mFtw8X7SJv/AN7K2xh8Y2a3HtOmaWl15WiwF75r02b2DowGnDQOeQcxgdkNbqqzUGkvsdmnhmcLvvQSDgaD+jTmchgJKDm1PhK2jkayq2JLEXgnotF7cOGWhQWKjwp8HGR4om1hkOEtYabABrc3PNBpi8LtjShm9p66DrPijx37bYggsS+F2wpKcCOv2iyW46bqE3AHECz+BQTL4a+DxO8jdW42i120xBdlY3u7JBjB4ebKkZuZRWYSSRipQ5o0yxaoOrSNqjTw1hihijkaHMc94jaW2BvnbUWvx5aoM9xtypY29sZGbopWMseOLM4h25oOb4vWyyUz2kyNqn71riS4luRLgNcufZ2IMNo7Mjq/CeuibGBC1kTmRSRm2V7Ym2PL1IOjTbMNJE+am2fTSTNcDGYo7PBGZw9EXBvqg1bMo6qo8Iq+uiha1wiiFpg0FpDcyQTrdBZ2jtqqoKmOFzqKORxaGOdRNkDiTbysVskHT8d8J4QHCpiLT/6bKcEW5/4kHJmj2vthggnhYQHOaxjaZ2K7dBjvZBU2U6Oiq/FxGGSBlxK2zb52Ive97lBdq6WaapkqIp45HyQYcDpgXXJzF+B9FxzKCy1gqNk00cgZBNEJDZxtgcTcXIuPtQU5Nj1FLsusmkIqMRMwbGC4ZZ8cNuHJBVofBVk4ifC80gntZ7HuiaW2ucxlfjyQUKim23TVT4KaoFY9rMbmE4g0XLSMWVswTzQWaYVc4/XSNYASCWHGL35HK/pQZOg3s5jFU4uiIxAMAtcceKCvUPfGKqOKOdz4mObiGRBw34jsPNBWh2qGNbHI1z5ZJAM23N3SFlhnqPeg31dXFHWsjbuXOEbzd0OY4ZDP1FBzHTsrnVIY5rQ2Ey4mMwNc7DmPTZoyOnFIHKVlUjyT6QgIKdV+29SC23yR6B9ikTzUAeJ9KCEBAQEBBZ2c4N2jASLgP4LHiJxpWlD1YmbcWjvfloF4na29oyxcTK14ZES4i9g6wvbKyvOrNaxzSttiGbJCC1roWmTC3ol173t/VXi0zXMSnDyXhTK07ZGNmEtiaAGWN+J5HtXp8Jns/WZ26uMZCCSxgI7TZdeUBdKeMMfqIUZSjHJisY2C2uFRkL55sh9HRSJnwBoiuf2NzyIAt60H0aiqaaelgpCGbun2dimMbrNc5wGE53ByB4AcSvMvG+3i7qzt8lalrJZaZwxNfM1j2us0vuBkOYIKzvT18r1v6uFfZtJMaWndLXT0oljDIpHTbuMgNGQN7jgOAIyvw4XtO+IhEdMqcEhi8IXRiqfLK4tbeSd8bpGlud3uDS0duQC1xnTjDPpqbu5K2mjaXSR4o2dLpbdB/wC9c01v+Q6ItRVbth42nUwbIpAXSkExve+cEABos5pJPpNxmFrNPViZYxb1pw6L27QmYySs2FTOdF/6m6mxC2Y4sOg46KnJ4fn1X54/P+lZ202vc1s2y42Na2xm3kj2lw8m4tcDjfinZbdfz+U9rOWnYlVjY2B7YiWAuZOJgzog24kcM7evsVtWsR3Kadpy7sccFPEfFqihppLBuNkgxuGmLHn965+eG8VU20lI1sldV1MMgNgd6wPAtlle9uWfFIv4ItWZ2XIZNnVzm00VJVSACzpaa7rduQHcq5rPdKfXjvhFT4NspY6ir2aXSTbt2BtQxwN7cMhcn1q9eWJjKtptMdSipW1exaYSP3QDG9N7nBrbggg58r6KNSM3k074q0bJ2VhnqIo6eWopXNJkkY1wDc35A+scjqkxaOUm8TlXp6OVjehFHEGk2a7MO77ED1FdlrRZwYcjZuwK+TaFZUT08LopXAslmlayxI+c3P1DkrZxSDErVPs1jpK+mY1kjKeobI8QjfBrbEuGK7eTLG2vC6tN94lPcvU/g9sOvkptoTTlxiaCA2EsY4g4uF72z1TnmNjEOfV7I2Ls8CoElS5jCAN28s6JIF82E5E3vfI2UxeTDm7Rptn7OicafEyecYSzeGS7SBbMsGivW3NKsuQt1RAQfX/gkdbwXqRcf/eO/kYrxGzl1rYs92x93AXBz0SY2UpfNojKb3vY30ULZznEomLmxyEAEAFTXEzCNebVpaY6RDjsL3AsaAOebfzXdOI3fLUm9omsR9P9oMc5OHDCQNSma9d0Tp60zy4qkxvaRibHx1aE5onomdK9Z9aI+n3BGMOb4m9t2m3vTm90ojSjG81j+PugxxhvSkitblYpme6JROnp49a1cfJd2Xg35wOYRhzw2WGvnl3et5K5O1nkmOndh1Vxvo0XRGUPHQNslMdVbx6smIXAuLnMZphPNHTKb5XUJmdi+iEz4F9UM+KC61uFzwBNrlThE2x8+jJQsIIsLk2zKIxGcpRKM8VuVlPcrvzJULIJ4dqlWZaJo5HtAaRx5G2XpV6zEdXJraepeMR9vrvLNzGute3RNxbVREy1vSs4z3bsrtxYTkTwvzVd+rTNc4lgymjj8kG9rEk3JysrTeZ6sqcNp6f6fzuYvp4XsMcmJzWttbPh6laL2icwyvw+jevZ3zMRGO//ABs+PfC5b+1NLY3HiTbZWsMb1WXRp45dun8N/wADn9467/o/+9qiWsPsSqlrBdgucjfnpdW2ytOMs/SqqqU8Um9JG76RyuTddFbRh1UtXl72lxqWkNjMLieRcQbenNXjknrlpHZzvOWyKKUvBklwniQ3MFVtauNoUteuPVhsDLFwJcwDgb8feqZUmfm0uDd7lIHaWvce9aRnHRrGeXePz+GwuIhcS4uDRmS6wtzuqY3Z49ZqykcC1lyG9G4tmr9I3afpjeVCamdI0teyQtD2mzW53aQ7jpkumt4icxP5OzrpqRE5ie7+9mc4xvtvXs6OQLi0m/k/Z/uyrXaOitNo6Z/N1uqp31EMUZxA4bkMkc3P0jPmsdO8VtMufT1IpaZ/xH+VTxIxTtc9shFrAmd9vRYlbdrmu39Q6O2i1ZiMfxDfLimqjHFHiwWxnFwy5Dn7lnXFa5mWVcVpzWnql9G5xL3RAHhfCAft7EjUjpE/n8IjViNon8/hWfuYXfr2zQH/AAkNxXz1BIHrWsc1o9XE/n50bV57R6uJ+n2n+FidsZeLC1snWNhfjb3rKkzhlSbYanvFsnAahrR96vELxH5+Qx3dNHu3yOLni+FxaLi/apzecxC3NqWzFejO1LNf9VUAahosVXN698K51K98NlLTwQ4gxrrkHM+hVve1urPUve3VqnoRIx+eRB4B35q9NXEw0prcsx/pZo6cxVI6Jwt4OzF1lq3zVjrXi1HRvfVcrjw0xOa+ka6R1uh0sy30nOx9a0tExfZpaJi8xHj7k2kIGBzbDUE6cM9LqNu9Hq97ZYEEcVVXva5A4EljGvcRljdhz5DgcslaJjvWrMd8vnvwuuhOw6OOJ7Q5lZeSMcbljs/cfSptFsRM/JGpFuWJtHXpLx/wbm3htSH/ANuT+QryfK15pwlrRPh/amnGbPte8PWXx/nd/adXKlzyAM81prcRetYiZ9ZEQyuS0W4kro7S06cTTrMoxusQk7sXFivpvJ9rTw8c8Ylhfq2LuVQkxEwMeP8AhXN13muZWSCeYWlLXxiYRKCBmQLdtljNaRMzFcT44Sr5OsBmF87E01JitYzEf223hg4E3NjmFw6lLzzTMdYn/PT/AKWiYLcMyPTdTybREzMR78jY4dFovnbXkvQ1NPOlp1zvjx3x/wBwpE7ywczDm7h2krh1uGnTiJ1Onvmy0Tnol3IBpPrXRq/+taVmfmiDBc3LfXZI0JtPNNfnj/ZlBYL5g2PPis76EROLxOJ7+v8AUymJSbAWI4c7pqYiOW9cY6znHdjf+CPci4tkQPQqTqU5fVmI/PiYlHRaLl3HsWcdlp157W6+6P8Aad5AWO4Nf6QrVvw2rtFbfGEYmEtY1huAfWtNHh9LRvz0iZ+JMzI5mLO6jU4ftJzn+/8Af+CJwMYWkCxLRzUcNoX07ViYmaxjxj8/gmctriXA2C9bWvbUrMxH59P6ZxshgsL5ekqmhXlrNpjfbedunXvTLIutwNhrxW9tSa45JxHj1jp3zM9M4RhJDXCx5La9NPUiIv3fTKN4QXBtieSzvraenMWt3fkd0/mUxEy8n8J7r+A9XqJIrj/5hdHD6vPrRGd42mPlM+EK2jZ8Z2YbbTpiRf8AWtyHNesye3D2ZYYCcQyB5BVWY4BM5zY4CXEdIB1uHDJBiyQtMTJIGiXdtJaXXzNr39aDynhZNH+l2B7MOGIYQwB18z2hBxHTZ/q47j52SCHSSHjTx+ohBjvZMVjCwW1woAeSbGKn9FmoJbuQ45U+I8i0C3rsg+l7HqqeSjoKMmMR0+zDJOYzZj7gBp0JFjla97oMdl7SlfSCIPY+eMuYeiXktaAOGIEH3IKex6SV1DTTTV81I2SMRwyOmEcZAbmASbj0gEfYAobw03hYIzVvmlIYGmSd7XSAtIIxuDSB22sON0Hp3uoGAue3FG3p57faf+9BzG7dLNuVUOxqZuKVrehI99Q1zWgAWc0kn3hB1TLXVEcbq7YdLI6O3T3c1xbMcYjwsO5BXk28XPa2XZMQY1hBm3srxceTlhBA1QVPB6ve+bcybg2dI9k++wAAOzsSLgC4tw4nhZB6eGmggZeCo2fTy2DRI2W7zztixZ/+EFM7PpnGSsq6imlbYA75okaLcwLHv4oLsEtJVYaWGGSUAWdJTFxt25AW9CBU+DjohNVbNlx1AjdgbUscM7ZcBc94QaNisE3g3StmLozgb0nvIaw3zBF+XoQRszZ7P0hVxxwyVED2frJGDJtnPvhPr0QcSnoJYycEccTWvOEOzD++xHvQceh2DtCXbNZVS08L4ZC0tkllawA2sBdzc/QAeCC1T7JY+baNFG2OQRSxSOEI32FtrOAPRtk3lrqguQeD+wtp+K1805IiAIDISxjjfFwJvb180FGt2PsWgvVtkqHMjNxu3lnRuL8WG+Z1yNkHM2jS7P2dC59PjZPM3CGb0y3YRYZlgtwKQOIrKpHkn0hAQU6r9t6kFtvkj0D7FInmoA8T6UEICAgICCzs6oFJtCCoLXOET8Vmi5PoWPERM6Vojqh2H+E1Iy262ZLa5AIjtw/Irw68HNv1WQR7fjqmPFPTu3jyQwPBABy4nhe60twcTMb9ERuh20aktZ0HSOxDetF2nIf4XWtrlne3YpjRpWpl5/alPV1m0XzwwufC7CGmQBp4aHl6Ml6OjradKRWZTMqc2zq8huCkw88TSLd9lt5zp+KMwwds7asQy3xHDoy/mojitKe9MNU1LtKIkytmaRkSZOHvV416WnESnonxCSQXfIXObk9pv0TpwzUdtXmxlB+jC42ZiLueRNhb0K/aVxnJl6hpoxA3/ii6V1Lu4475NkzzuTewzyz4+pcHNEz823ax0V3SQSuLoK1jIziZunOecQsOOPEO3l6dLxbHWPz5HaQstn2dhidWGWINwsBpKlsTjYWOIiP7+OarzWz/AK/2ntK4UaC8m12TQSSS9LLePxl2R/xG1xewzC0tb1cIrbNntTNTvjBma1lmZRB7HDLVrWj+uRK5pz3S17SI6wwinio2xVJpaF8k7QQ9sAs3M2BFzmRbhlxvbgrzqVmOqkWjq6Ta+Es3cde+lqA0vZEIY42yWFyASw3VOaZjP2X5qw2x7d2dVU5ildQyStFwzEbWHEl2Q/8AIVYt3HPSekuHsSOjZXTM/UthMj2xPe0mzS7FlbI52AIHPu1taJVraPF2aaaSKmghpNzL0id3I+waeWZANzfgDlZZRFLRu07XfaWZrNjvkmk2tDJShkYx4o3lg7SeF73yvwF7qk6WZ9WVo1/F0I6vwfpw4004a5kYeSyMuLWnhks+zlbto8XIZt00M7379zA3pYZaewkzOYsARcZi5tqoiIid2c68KGzvCGsp6Cjig3LWB2J5ccLwMR4O4cs8uC0tNeaVLakxERCzWbSZAyoNAKu1QL1AuyzG4nEm2d73IB58FflnHTYnU2y0Gvmjqty/ZJnikaHEzBxbYjonojhY8BzyV5mI3Y9/RwXbTjodrmrotgQQSk9GZsUgGLhbCXZBbc+YxlE2xOzbR7TpqmofPJG7eyMaZY3gFjyDYXHoPI6ZrO+pj5I59sOuPCSKlDzBLUulLb4YogGE3ybezTkOdirc8W6L88OZtHwiqKyKV1RHNIYsmRskcMg4EkhrgeQz7dFNb5Rzw5tTtt1QKynljLWyNvdz5PLvyu45dI8csvQtKWmLxCk2nOHJXYkQEH1z4KHhvgvUXaT/AMa7gPmMWlIzDg4q8VtGYe0NSwWu17S42F2Fa8kuCeKpGMxMZ90sw5zrPFgzU3vdVxHTvaxa04tG1fq1yyyGOVoHSIOHI59hCtWsZiWOrq6k0vWI3np1VGxT5l8bcXDiP6BbTavdLza6WvvNqxn4x/iP4ahT1LxcNcAQOiHAWV+ekOaOG4m0ZiJj3ZiPsNpKyxGCUW4kyj3JOpp+7+E14PjMYxb/AP1DERTNc5rzJG1oz6Rcp5qzvG7KNLWrMxfMRHvmfuzFDFYYmyk2vr35KO1t3No4DSx60Tn867St7Pjio5i8ucGuFhiH5LDWm2pGHp+TtPS4XUm0zMRPj/0uvrYCGvEgte3HvWEaVumHq347RmItFvzvSKqE3IeAL2FufuUdnZaOL0p3idvz3eLXLWwYDgfjc4WaCf6K9dK2d2Gtx2hyzyzmZ2j/AKWKd7jECRkb5n0rK8Rl28Pe00iZ97PetxYSbHt5qOWerXta55ZRvWAceGicso7WkQkzRi3TbY87pyz4JnW04/8AZBliLWvxAi+SctuiJ1dLEWz8GWNuozUYlpz18U4ha97+hMHNGMo3jb2vY2vY5JiUdpXOMheAARmCLi2aYJvERmN0Nla42BzUzWYVrq1tOIYtlBvwsOYKTVWutE/BDpQ5tw0u5i3MKYqrbViY2jP5+fFhvbRY3xWdwwgXuVbl3xEsu1xTnvXfwVzVY4w10L42vBxZZtK07PE5icuGeL56RW1JrE5z7p/PqsNqGF2MAkEceKzmk9HbTiaTPPA6sYPJaSBa54AJGnPem3G1j9MeDXJXBlwxryRq24KtGlnqw1ePiuYrE5+D4/8ACrOZ/CWleRZ3iTb+29VvXlnDo4TXnX0+aeq38Dn9467/AKP/AL2qkuyH2JVSxxtx4L9K17dinE4ynE4ylQhzBT12N7nRsLSXENEmfHLkuvn0sRifp/t3dpo4iInw7v57yXZcktxvSy4Iu3L7M0rrxXuK8TWvdlXOz6ykcGQGoqMyQ98gwt5WsXXIWvbad4zbEfL/AE2jX0tSM2xX4RP2SymrGSBu4qCAb3dI1wJ9q+HsKib6cxnMfx/rqidTSmM5j+J+3VZl2ZFL+3idIXO5OyGno9Syrr2j9M4Y14i1f0Thqptj0sMj3wxSRki1jYA6K9+JvaIi05X1OL1LREWmJWmUe5eXlz3XAaGk3sMvuWM6nNGGFtbmjDXDRVEVRIQ9u6IbgFzZuZvlqb8bq1tWlqxtuvfWpakbb/8AX9MvEWxslbvRE6fIuaTe+oueKjtZmYnGcK9tMzE4zj83x3Ns0IDWNaeFx6f92VK26zKlL9ZlDaZ7XB2Pgb2IUzeJTOpExjA2HDcRwtbbMkNGZPEpNs9ZRN89ZQYpnG4c7LlYAFOasJ5qx3J3TnPbvIWnO97DIpzREbSjmiInEsH00jmkEZi9sJtcHVWi8RK8alYlD6bMAQmzQATcXI7M/tSL+8jU8ZYOo48VntJOKwyNjlfJWjUnuXjVtjZsFJcYWNDfSFWdTxUnV75SKV8RJxNczCb5WPDgLKO0ifiidWLfFnFA18HSyDmAdvaoteYsra8xbZlDBuzcPNgTYXyVbXyre/N3N/EZFZs0YG4g6wxWtfmpzPQzOMMBCLlznFxuSCeV1PMtN+6Esu5ocC4A8nCxSdtidpwOjxHMutYjJxCROERbD5/8MTQ3wdoAL5VfM3/wOTOZVtOXiPg4v/bWkt5uT+QryfLMzHBWx7v7W0v1PtADed/UvgqU05xz/R1zllgD823J7Vt5vXXnm0t596M46oyAGVxoozWtYzGY8N+73/yLUdQxrGgn3L6nhPK/D6WjSl5+mPpv3d7G2nMyy8ajsSb9y6PTnCxEzMz/ABP2V7OwKqI87epTTy5wdutsZ90nZWBURuNgRftVq+VuG1J5a2jPvzH+Ds5hiypY55bkLc78Vz8N5a0NTVnTzEY78zv/ADCbacxGWZmYG3xNt6V26nlLRrpzebRj47/xhWKTlXa6MnyjwXzGlrcNe2Jt3T7vHfLaYshr+kc+I4BV0uIzeZm3WJ2jPj18Jn5/ymY2ZCRuLM5nguinF6XP607z069P5x3fBWazgEhe0AZ24dqV4u2vSKV3x08Zj393j3HLiU35l35LXmxva39TEfxgSXtGl/Qt7cRpVxjGfhH3+qMSYiQTiItysFnOva1ZvzzGPdX7GECRrtDbiorxmlqx3Tjr02g5ZgBbbjfNRW+lMTGczn5/nVO6RhICvSNK9YhG7EtYSblY20dC0zzT/f8AnZOZTZovb7Fbk06xPL/WTMsA8NOZt2ELi0+IjStE3nHumPtC0xlIfmALd6vXioi8VjH87o5Uk24B1ua0teKRHLE8u2en9eIkuzsWXHat51p5uS+nmPfmf8K497HegOybbt1XNPG1jU9SmJ8e6fHv/tbl2BM05j1hK+UNKd4j4x3e/wB/8HJLPfDkSSu2PKGnjFZmZ/Ph/SvJKN9fW+ixjylN+6c+H5KeR5L4S5SfAusYfORW9sLfyZx1r8bOjbpjbr9/9q6lfVy+O7NnFLtOmqC1zhFK1xDRcmx5L6tzvTyeFlHGAYdlS2uRfd24Z8r52Kqsxj8Jo6lsm5pnY3mzWuBAByGZ4cUGL9pVb2tGB0klwJBctuAD5LgLA3vln7kHntsU9ZXbSM8FM+SFwABlAaR2WPL0WCChNszaRa3BQ4fnNcLd9kGL9mbYiFxviPmzfmg0TUm1Irum37LcXGQm3vQT+jp5Ad5MS5nltdi6Puz4oA2W91gxxL9MLjYW/wAqD1UJpY6SLFUl0niZhbFcWElrA3JvYHlzueCCu6aF7sUNdGxgOExuc84xhF834hY2vwHp5ALLKjZraeEVgliEQbHjo6pkLzawNy2PhmOZ4i6Dn0Z3u3Y6inmkkAks3eybxxAv/jNri9uVkHumVVNJDG2ohEZawjdNlY4XHzWtGfZnldBohmipGxVppKEunacL2wDoDFlitfMg8hyN7cEHWjr6WwibXPpKgguZGIWMZJYXIBLDdBuh27s6ppzDNJRmcDJmNxGXEl1mgc+SDz+xm0bNpzW3MdOZXiGR7SQ1rjiNrZHOwGXGyDu09XNTQxRUT4ZMUjv1cjiGtPLygLXvawPFBvG2dlulkk2zTS0uCO8hLHuZlq4XF7355jNB0Y9reD0LS6nqQHNjEnQYS4N4Xsg5H9pHUlTJI2d7Gi7gJoLNlzytYXF/T6UHLofCWvh2XTxUxia10jnPL8ngYzmHcL6+goLVbthsfjEtAKky1TLTNDmYWtxOJdzJ8ogH1IKJr5o52sOy3Twyxh15bkFpAwnoiwGfAcLdqDgzV0VFtk1lH4Pwwy36M7IpAA8ZAYS7IerNBupNo09XUPnlY5s0sY3zHAYX2cbXB5WJGR0zQdYeEMVGHmF9SZMBIbDEAzsbwBy1zPuQczae36msin8YjmfumkMjZI4HkSbNcDbLj/S6Dm1O2TOyshljc0PjN8T5PLFhldx61tMkgcJWVSPJPpCAgp1X7b1ILbfJHoH2KRPNQB4n0oIQEBAQEG+iF62EA26Sx4j/AIrIno78dMJJY45CImyGxN7Z6ejNeLWMzhnhM1FReJBzKgEGw6YNib2Of9FryznZLOPZcbwbVTG26ThiyaciMufP3KsVnvlOFKahmqAHywOjYwkRSOBwvNvsIVomKRnKMMGUrWxmwaxhOJww2zVOfKcNjYrWu4hpBBFye245qOaO9MY70vp5JWFrw0YSL2Isc1XMRvCN2ySFz3B0QhLjxFhpyt6ki0Z3RumOHdWEsLBhBGRNr/7+1RMyYa6rZ1HUgO3MUJF7mNthfL/frWtdW0dU4a2bMZCG+KgRt4HCL31TtpnqYltko3ywmIuOIcHhoJA07Ei++cJxLCKmlpy/dyOELn4xHfgeYv6stLqe16J3b5ny1TRiL4oowHNDn3dyuDbI5Xt+SjmhERKsyG72ASvLWizbgXDgPeLcu1RN47oMQ3vhlc03ndmAAGtLWkjUczdVi0R0gwmQQSO3riDPhDXyXzyKnmkx4p3W/cX75weDcOaA0hx9GSpz+BysaiUU7gQ6R7nO6QDQb21NvQFNYzBjDeXOka39Y9zSBkeWv2KJlOAfqnF7X4S4DFnxy96iPimK+9pfKXtvO+zOTb3yU5MM/wBTdrZpGAtyF8wO0KMp5femSojcxzt6cVwM731TmRj3tLn1D2ufFK0sAuGkm59XuTMd5iWJsLNdE1xuc72tce9VzMT1RiWbRFbpABxPAN7FeLzJhpqKmanqgKeqZG8sLHNc24z7dVtS2IzhEs5yKxvRe6OfEC7DkW+hUi0RbMwiN2mtdeifiwhxbazQP99q00M9tVbGHFXtpEBB9b+Clpd4MVGnjjv5GLWk4h53FVm14+D3AjacyefcrZlz106z1N2MRzCZ2OzjmkdGWgEG5PJIsm2lMRmOrHxeNrs7G+ZuL2KnnmWfm+nWd/yU4ADx7cgmU9nET1ZvsLFpN+YKrHvbXxGJrLHC4G+K9wpzDOK2ic5Rhec7ApmEctp7k7prhZ0Yd6RdOaY6Snsq2jFq5+LA0sVwd2CeWXBT2lvFnPCaWc8rYGP5NGXDJVzDeKX7o+jF9OXAkFzTlbQK0Xwyvw023iZif6/772R3lxcud23sFXZrPaZjMzP9fkhiJF3uIPYU5vBE6UzGbTugREDovuedx9inm8VY0ZiNp/PcyEdiQTkRYgqMtI08ZjOxumtaA02AGQTmmeqOyrWMV2Nzna+R4i6cx2G/UYekRdw7UlNJ3mN2eAHi9Vy05InrKcLg0Wff1pn3LcsxG1kBmfl8OaZIpv1Tha3g5MzJy1r0lBHJrkRMd0SwLZT/AIgclOYZzXUnvAHDI2KbEVtHVkQGgm9gnVaYisZaWvNrPeHN9FirzHg5aXnpacwybHd5e1/RPL+qiZ2w0pp5tNonb83fJPhZAHhTTAG//BN/nesrPR0IiK7LPwOf3jrv+j/72qsuiH2JVSICAgIIzQSgICAghAOY4+tSnojB5N3OJbz1y5pkz1ZKECAgICAgIIvnax9KCUEICCUBAQEBB88+GT+71B/1n/Y5TCJeH+Dn++tJ/pyfyFeT5ajPBW+X9r6X6n2lrbmxNgvh9LQi1uSZxG7qmWRjyu0rovwsYi2nKIt4giyzdwSnBbb36HN7mJbYXPqWNtPkrzW7+n5805RYepY4rEZ7vz86JBa2amvJyzzBbmqTXv8AALZ8s1aa5tnEb/niABHEBTWto6x9hJAPIBaXrS3dEf0jcB0AzSLYn1YjE/MTa/EFXms2ieaJAPIOg0U117UnbaPDu6dxgJLhnwVbaltSM2nb86mMMSRyyWEzWf07JTnyWk80b0+XhkLi9xxUzenNN469UIGfD7VnWIt+mfqk4W4lRM8mOsiT6brW856zlEHk3s5Ins8zFjqgm9sRWdrzOO0lOPBNxrwUzanfPT82EF4txUW4isxnJhBJI4rG17zGZsnCLkFZxe1ZSzDr+ldddWLfFXAHlpy58VavE20pnk7+pjPVBIJyyKztet7ZrtO5jDy3wkf3Mqv9SP8AnC9fyLmeOrM+E/0z1f0PkGz/APmNPnb9YM1945HrWwB72NktGHmxIOd9PeqrE1FQ+JuwztLb4TiBsSDY5+jgglmzong4ahjeDnDFk3gRcc//AAgqT0MtV+0pnMijcRHKb4XHX1j1INcdI1sbrMYxhs54w2uRxQbRCRhzIaQQ4Yie245oMn00kzHMe1ota5a4Z8EGySAvs6IQl2QN2jvFuPJBMUW6DRLFGMN+BNrlBqq9m0dU0HdQwuFyTG23f/vmg0s2VFAB4oN03gcNiTn/AL7kG19G6SAwl5Lhm2QNBI/396DXHRSwF+6lLYXvDhHfg7gRf7NCboLMsktSxoOOGKMYmh0gLvQbZEWJt/soKrIS57BvpHMb5IIFw7lw5ccu1BYfDK9pD6g2whuFjS0E3vnry7kCQQS9OSz593ge/FnxueH/AJQZuj37i90zw8HHiaACHHnllx/rqgxqZhTm4dI57jmA0Em3C5t6kG7G6RrbPe5pAyPI8/sQAd24vHRJABJ4lBpdOXtvM6zOpfkUGQdCcLJnxi1sN+AvzQS+ojcxzt50hYXN0Gp0k72l8MjS0AkNcTc27EC7cmvha4k3JBta4534oJAhAu4NBNsg0nkg0VNRNT1LPF6tkLw0tLXNu03/AKoNk/8AxkJbjLKi7cWDIttbMXvmg0Vz/wD6dKDa+7Is1o/32oPMqyqR5J9IQEFOq/bepBbb5I9A+xSJ5qAPE+lBCAgICAgs7NDHbSpxJcML+lYXyWWtGdOYRL1kmzoZKVzQbOaL4i4Xvewtnxty7V5UUiu8K4cXcyGtdBJRvL2yHdNAwl7gLg56c8+FltEY3hOG6igq4tlPfJEWtuMUj3OIsffpwUT1S7jY2OowJpi7ExpbI49EWvkbngPyWU1zsmYw0O2fUOqDZ9O2GwIcRa4ytftNwq1rGcTBEx3q9UfEwJZGMbCWh1yxoBFsybJP6sRBMx3N74qKeGOSkmjqHiEyuOHpFpPDPMnKym0TEYhES1vZBhbJFK5txe5Za7bAi9uHEZXUzSYjBmVmCngfUOLnTTMp8QnfnYGwIz7PVx5qY09tzLobpmB88ezN+0gnyx08+3hYfZ3uUzLlPfT0srjNVGJ7SCyDDYG4IPSIu7MHId6mKbdEZKeohhnbjNyXAC7rC5BPDO+eXpGaiKcsmZZt/RhMlHJKGSR4XGQuxG4zt6Mx35p2UR3DKXYz3xvfHZsd+GZw3PC/esbac82UuVUuFHidNHunMeI3PeMAJyz7BYqY0omYhOYdI01HLE2Snla69i57s7XAIyHoPeEnTiJxBlRkqdlwk2e5rSx7mPbwkcL5jsydlx4LSeHmTmX4v0aaUiRwDXNvE8kjo5A30tnyWc1iNkZaX0ckbQ5ga9jn4WvDr58vRdZRTCdmt1DJe2APNgC2N2INOfG3C9vsVuTPUzDTFASx0jmEsY2xFzbjr/VIg3anxfq2u3heQ4loAzH+7/am+Fd2cUDTu2B4e9xOR5Xzvf3qIiZIltqKSSONwe1suHIkOBDSP95JMTG8p5ml78JZiiIcTa9suHAnu71XEGUiSTA60bALniez+v8AVW2yZat9vpS1rTfPFlwv9uSnc5mioip2FxLelJzxWse/gr1mVVun2QyZuTnR4jZzg7E5pGeVvRbsVq1md0bNW1qSSkhkwAvp3R9CQC+eV7nXitNGuNWvxTEvPr2FxAQfXvgla0+C9TcZ+Ou/kYr1mXJrVibbw9vI0taXNbfnYc1eJzO7l1KTWszWPkwDek0sadXHUq0ztuxinrRNI+Pvb2gveRwIHBZTtDtrE2tMBtiyt61KJxnZldlvIzVd2uaY6MC5m9DLgZXA1VsTjLGbU5+XIXAEdIWPDJMJm0RMb9QnC0kvcQOQREziJmZlkMss1EtI22HF2h4cUhFplgHZECQuI/3ZWx7mUW2mItlORbmch2qFsxMbgDXC7Txscim8dUxFbRmshbgF3C40TOUTXljM9ENliDzHiGMZ2vmk1tjKK6ulFuTO/gyc4Xzw9LgLZlREL2tGd+9iJGudYOzteytyzEM41a2tiJ3ZEtJVWkzEmTczayG0dUHM9EWU/FE7z6qCDkAUVmJ2iGBFnXLrAdqt3MpjFszLMOPqVcNYtIXkckwTeY7kCQi9h3qcIjUxnEBkLQTYWTlyTqzXfCHdNvSCmNuilvXj1mGFjncOzipzMMuWlp6MhEBmCb8AOSjmaRpRG8PkXwrknwnpr/ubf53qlurt4aZmm618Dn9467/o/wDvaqS6ofYVVKUEHIIAN0EEOvk4AaWU7JjCRfmoQWQEEoIQLHESTkRwtwU9ye4UISgIIQSgICAghBKAgICAgICAgIPnnwyf3eoP+s/7HKYRLxHwbNDvDekB4buX+Qrg8p6ddXhrUt0nC2nOLPtu7aBlkvlfM9OtdtnRzSxAztbPOy561nMxNd98f5n4fmEpAIaARZa1reunEWjGfz4m2WRaLWK6NTSrMYvPv/wrEsWtzOIBc+lozFp7SsbLTPgg2DrEW9Sy1JpW/LNcR8I6eOxHRLgLdGxtxyWurSmPUxOMZ2jf86kT4hbyDs1N9HurbdGWQYL3uctV0aehWJ5pmdvHxRMpIy8m60nTiIxFMx+boyxsBzz5LnjTiuYzv3d3/fx7lsgABw8eXFNPTrW3JPw6kz3mBnDQ6pHD8PO3fE+PywZliYTe98lyank68zmJ2Wi7HC0EXyvxuuedLRpaOaMZ2nO3z/PcnMyzLG8iOK7LcNpzvSds/wAK5nvQY22420Wd+F0cdcR3fRPNKS1lre9XtpaHJNPr+f0jMsMBC5Y4e1NonqtkLOxRfhs5mY+3QygNsCbKldPFZnBlBBsFlfTtyxMT/pMSlrTwGZV9PRtPq13n+iZHNIFyPWp1NK1Y5rRn3oiUZXFxmsPVi0Zjf6LJvzsFrF5/VEQhFyTwVYva8zt+f2BA4cyq2pSNu+Us2w4s8wu3R8ndpi3SJ/lSb4eU+EppZ4GVQ5byO3theh5J0b6PlCsT0nOPhiVNSc0fIdm4TtOmx5N3rb5XyuvuHK9w+gilpnR47EA2c5w436Ns+PZ2qqzgmJ5rjTy0chIkG6DRhL3WuLX0FufBBuoIKyLZkr5YS0Dy3uc4gA8cvdkg7sTGuogJpi7ExuF5PRbhvlnyF/f2oNL6CofODHJTiAtBDjlcZZntNx3INFRipGiZ7WiItDi4tbY63QbsFBVwxSUk0dRIYzLcizsJ5Z5k8kGsimLGzRSObliF2W6OEHO3DjwQWIYIJKktJlnbT337hew6Nxn2f14oOg2ONwdURbMNQyxPljp9mZysPsQcqR9PTTOdPU7gghzIA0WN7g9IjP0BAhqYYpmbwg3cBmbC5BJyzyFwEGzebNLpKOWbA8ASGQuuQcjb0WI70GcmyXPjkkjDWxnMjM4QTwug5NS80bXmaPduiIY57xgBNhn3H7UHRFPRzwMmp5mPLgHPeTcAEAjhy4+5BSkqtlQv8shpDyJGjJ7xcZeu+XHJBfpzs19HeRwwObeJ7iQbZXB0sSc7INctI+NuOMNkjL8IeHXz5ei+SDUaKXEMg8kAObG7FhJJ424Xsg0xU+IOc6MmNjOkATbv/r2IMHRAsB3pd0i5oAzBP/lBkyGOzBjxOe6+E58Re9/980G2oopI43scGS4bglrgQ0gf7sg0vdhDMUZa4m17ZD0nSyCWueGuAYxoxWsT/vig1CUSy4Wtdi/xdl/tQaKmKnZicW5vFr3taw/NBap9ktlaek6MvIa9wdiIOo7rINW16SSlpJDGDLTmJ2GXMm+V7nXikDyasqkeSfSEBBTqv23qQW2+SPQPsUieagDxPpQQgICAgIN1HO2mrIp3M3gjdiLb8VW9easwh6KPwto4o3FuyyJz5L8eTT6NFzebTjGTDXJ4XGaxkpSekHOGPIkCw7VXzWfEw3M8MYmNw+IvIBDm3luQb68f/ASOFmO8jZDfC6lbgts594xZrhIMXG9r24ZBTHDT4rTOWmTwphfPjbQkMIAwYxYW4cvRkck81nxRO8tdb4QUda3DJQyPbgLcD5OjqMhyVPNLZzzK4c920I4nsFHE+KJrQMBcL87i4GYz4FWjhZ77Jw3ybcIgdHBG/ER0TK4ODMsrC2Q5q3m05zMow3bH8Jpdl0wgfA2ZownPUc/tS3DzM5iU4btoeFjqyRskVO+FzRkN7cX55W5qk8LbP6jDh10rK6Zr3unwtkdIAZOkCdDyzzWtdG0d4vU22vF6aGAQ4t04ua7IEZkgDLLifTdR5vMznJhcd4SU8lK6J9CGvc04nx2bd2VibegcCLqvm056mFKn2x4rFu443OFmgl7z0rXJv7u5TbhpnvF+p8JaWuoZKWroHvD87tkDS11siMsu30lUrwtonPMYciOttO9z2ARuYW2b5QJ5gn0nvWvm6MKE8bn1EMkLhCI2BhDb9LU+u6tGjtiTC2ahrqOGlLSI43Emx8rjYfYfUs/NpzM53Th049vMjiwNhkbxtZ4NgTfgR6Vn5nOc5Gun246CRzyx7y5rWkl1icNgPcFeeFmY6mFyPwpihqzJFRFsRAG7xDlw/r3qscHMd5hWk23Sua1rNn4Gi4cMd8Vzfif95KJ4Of8A1sKlZXxVEUIjhkhkj4vEnK1rAWU14Sa96MN0W2BGx0eCUteM7Psb2tlkluEme8wyj2zG1r2yUxeHXt0rWWccDPtGGDdrRtcHCB97G933F7ceCeYz7ScMDtNgDsEADnWBJP3KfMp9pGGyHa0DZWPmpXSBjLYA+wJta9+KRwM5/UYbDtmFr3GCKeNp4MDxYZm3LPI81tHDzEYyYa6jbAkhqIY2ytimB6DnggG/G9uFsleuhiYmZ6GHLXQsICD6X8G+36PZXg/PBUOjDnVTn9KUNNsLRz9C6dLSi9c82Hh+UePvw+tFI0pttnMfP3PXnwz2aSP1kNrfvDVp5tHtw4J8s6s//wA9vz5I/tls2/7WH+Iap83j24V9Mav/AOe31+zMeG2zB/jh/iGqvm0e3DWPLmpH/wDPb8+SB4abMDSMcP8AENU+bR7cIjy1qRGPN7fnyY/2y2bb9rD9O1T5vHtwp6Y1P/z2/Pk1nws2UZN5vIMdrB2/bdW7GMY54YT5RtN+fze2fH8gHhds63SqIr8iKhuSdhX2oI8qa3fo2/Pkg+F9EZWu31NhAOW+be6nsKYxzKz5V4mdSLdhOPhP2bv7abNt+0h/iGrPzavtw6vTWrj/AOPb6/ZgfDDZx4zxdlqht1bsK+1DKfKutPXQt9fs0x+FGzI5XSCeIucSf27bf7+9XnTiYxzQ5dPjdTTvOpGhbM/x/X198t/9sdm85ICL8N+1Z+bx7cOz0vq9/D2/Pkwf4XbNdIHb+IAAi3jDc1aNCsRjmhlfynq2vFuwt9fszb4Z7OHGWD6dqrPD19qGtfLGtHXh7fX7MXeF+zSS5skAcdahqmNCO+8KW8q6szM14e2fn9mo+FVA+MB9TCX2IuJ2jXP3q8aVYna0Oe3lDiLUxbRtnE+MeO/RrpPCWhgIMlXDJhddv65uV+KvqadLdLRDn4PiuJ0J/wDJpWticxt49e5vZ4W7ODi500JJN/27cllOjXpFodtPKWrEza2hac/H7Mn+F+zHtLTNFYixHjDeCiNCI/8AaF7+VNS0YnQtj89zIeGOzfOw/TtUebx7cLx5X1f/AM9vz5A8Mtm2GKWEkf8AvtSeHr7UFfK+riM8Paf5+yD4YbNJzkg+nap83j24RPlbVmd+Ht+fJgzws2a0m88RBN7eMNVp0az/AO0MaeUdWsz/AOC358mR8L9mk33sP8Q1V7CPahpPlXVmc9hb6/ZP9r9mech/iGp2Ee3CfSup/wDnt9fsj+1+zfOw/TtTsI9qEelNX/8APb8+SD4XbOLr76C3+u1T2FfahWfKmtM/8Fvr9kjwu2YG23sPp37U7CPahMeU9SIx2Fvz5JHhhs21t9F/ENUdhX2oWjytq4x2Fvz5PmnwjbSh2pt+CeF7XNbStaS1wcL4nHl6Vza1IpbETl7vk3iL8Roza9ZrOe/5MPADwhi8G9r1NTNDvRLBuwMYbbpA8/QtOG4eNe01m0V+L6DguFrxN5ra8VxHe998adD+4n6dv3Lu9F0/dj8+b1fQ2n+/X8+Z8adD+4n6dv3J6Lp+7H58z0Np/v1/PmfGnQ/uJ+nb9yei6fux+fM9Daf79fz5nxp0IFvET9O37k9F0/dj8+Z6H0/36/nzPjTof3E/Tt+5PRdP3Y/PmehtP9+v58z406H9xP07fuT0XT92Pz5nobT/AH6/nzPjTof3E/Tt+5PRdP3Y/PmehtP9+v58z406H9xP07fuT0XT92Pz5nobT/fr+fM+NOh/cT9O37k9F0/dj8+Z6G0/36/nzPjTof3E/Tt+5PRdP3Y/PmehtP8Afr+fNHxpUWInxLK3Dft+5PRdMf8ALH580+h9PH/PX8+afjTof3E/Tt+5PRdP3Y/Pmj0Np/v1/PmfGnQ/uJ+nb9yei6fux+fM9Daf79fz5nxp0P7ifp2/cnoun7sfnzPQ2n+/X8+Z8adD+4n6dv3J6Lp+7H58z0Np/v1/PmfGnQ/uJ+nb9yei6fux+fM9Daf79fz5nxp0P7ifp2/cnoun7sfnzPQ2n+/X8+Z8adD+4n6dv3J6Lp+7H58z0Np/v1/PmfGnQ/uJ+nb9yei6fux+fM9Daf79fz5g+FKgaLChNv8AXb9yei6fvR+fMnyPpz/99fz5nxp0P7ifp2/cnoun7sfnzPQ2n+/X8+Z8adD+4n6dv3J6Lp+7H58z0Np/v1/PmfGnQ/uJ+nb9yei6fux+fM9Daf79fz5nxp0P7ifp2/cnoun7sfnzPQ2n+/X8+Z8adD+4n6dv3J6Lp+7H58z0Np/v1/PmfGnQ/uJ+nb9yei6fux+fM9Daf79fz5nxp0P7ifp2/cnoun7sfnzPQ2n+/X8+Z8adD+4n6dv3J6Lp+7H58z0Np/v1/PmfGnQ/uJ+nb9yei6fux+fM9Daf79fz5vK/CB4Y0/hJsqmpoacxGKfeE7wOv0SOXpXLxPB10KxaLxbPg4eN4CvDUi1dSLZnu/7cf4PamGk8MaWaeRkcbWSXc9waPJPMrwPKl7U4W1q15p22+bztPez7F/aHZVrCvpP4hv3r5SeO1eTljQt/E/Z0cseKD4QbKP8A+QpP4hv3rO3Ga8//AE2+v2Tyx4pHhDsof/39J/EN+9XpxurWMdhb6/Y5Y8QeEOyf3+k+nb96mvHakTmeHtn4f6Ryx4o/tBsr5QpPp2/es54vVmc9hb+J+yeWPFi7buynHPaFL9O371ya1tXVmZnRt/E/ZaMR3oG3dlg5bRpbf67fvVKzxFLerpWx8P8AW5tPek7f2YRltGk9c7fvW19fipiYrpWz74mf8IiK+LIeEOyx/wDkKT6dv3rorx3E1/8Apt/E/ZHLXxQ7wg2YXXG0aQf/AL2/estTiuLtfmrpWj5T9kxFfFidu7LPHaVL/EN+9c1p4i3XTv8AX7J28WY8INlD/wDIUn8Q371104nXrjOhbPwn7K4jxQdv7KIt+kKT6dv3qt9fWtWa9hb+JTiPE/T+yxw2hSeuob96r2/EV2ro2+v2MR4h2/sojPaFJ9O371e3EatoxbQtPyn7GI8Ufp7ZWf8A9QpM/wD32/esO01t4jRnEx4T9vyE7eLE7b2XfLaNIBpv2/euaacRNsxpWiPDE/x8JTmvin9ObKNr7RpMv/fb961nt7RXOjbb3T9kbeKf09sr5Rpfp2fetZ1Nef8A6rfx/pG3in9P7L57QpPp2/erxr8R36Np+U/YxHiDb+yhf/6hSWP/AL7fvVqa+tXP/gtifdP28DEeLF23dlEWbtCkA/12/eufUnVmOXT0bRHwn7JjHfKDtvZXLaNKP/8Aob96ytTWzE00rR8p+ycx4pO3dlEW/SNL9O371rede1eXsrfxP2Rt4oG29lWsdo0h/wD3t+9Z1rrRXlto2n5T9k5jxP03srltGk+nb96rOnrd2lb+J+xmPEO29l2y2jSfTt+9Vtp6+MV0p/iTMeINt7JBudoUh/8A3t+9aadNSLTN9G0/KfsTMeLZ/aDZQ/8AyFL/ABDfvXfHFa8TGNG31+ymI8XmfhD2vQVfgdUwwVkEry+OzWStcfLHIL0/JOvq24qK207RGJ3nu2+EKakRy9XyWkmbTVkM7mY2xvDi29r25L69zPTx+GdFG1zv0SRNmWuEmTSdBpyUYTlhJ4amYDeUZJLg5wx5EgWHbqmDLa3w4hDS39HvLbhwBlucV78bf7yTBli3wzpWhgGzXgsBwuEoxC5vxtwyHcmDLVJ4XwvmxtoCGYQCzGORuCMvRlwNkwZY1nhTRVjAyTZ8rmYS3dulGC2lhy5Jgy5p2tFCYxRU74I2NAw4he+dxcC+HPgUwZWHeEeCBzIYX4iMt48FrMhawtkOPu7UwZZ7G8KZNl024kpxODhJvqDdMGVraHhp445r46SSFzRlaW4xG1za3YmDLg7Qqo9oTBz9+Gb3e2Mly06NPLgmDK7TbdFNSR0wgLxG7EHEjEOPDLtvdMGV4+FdNJTujl2d03h2ORhDS4ngTbTstfmmDKhTbd8Ui3ccT33aAS+Q9LO7vty9HFMGXRn8LaWsoZKSs2c97ZRmWSBpabWBbllw+1MGXHj2mG1GJ0Voi0twt8oE8wTpnbtTBlz6guklgfAdzumBrrcXm5ufXdMGVzx5poo6MxuEbHlxseI09F7dwTBl1IfCWOGPAymlaASR0wQPVZMGWqm8InU8pk3b3ksazEXWdZvk59/emDK6zwwhhqxLBQFkWEDd4xytbl6e9MGVeTwjo32DdmloucQ3ly4HtsmDKpWbXhqaeJkdPJFJGfLEgtaxFgLetMGW2Db4gaWbqZzXCzjvADwAuMuxMGWcXhHEwOD6Nzw4EWx8PcmDLFu34mua7xV9wM7vBBPd6EwZa/03GA4spek4AFxP3Jgy2w7fgEkb5qNzxG22ASWBNuN+OiYMpf4QQB7nQQTxAjJokFgeXLP1pgywqNviSKpiiZMyKoYQWOeHAHkb2vayYMuKpQkeSfSEBBTqv23qQW2+SPQPsUieagDxPpQQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBYIFhohksNEMlhohksNEMlhohksNEMlhohksNEMlhohksNEMlhohksNEMlhohksNEMlhohksNEMlhohksNEMlhohksNEMlhohksNEMlhohksNEMlhohksNEMlhohksNEMlhohkQEQIYEMCGBDAhgQwIYEMCGBDAhgQwIYEMCGBDAhgQwIYEMCGBDAhgQwIYEMCGBDAhgQFKUWGgTMoLDQJmQsNAmZCw0CZkLDQJmQsNAmZCw0CZkLDQJmQsNAmZCw0CZkLDQJmQsNAmZCw0CZkLDQJmQsNAmZCw0CZkLDQJmQsNAmZCw0CZkLDQJmQsNAmZCw0CZkLDQJmQsNAmZCw0CZkLDQJmQsNAmZCw0CZkLDQJmRNhomUigEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEEjyT6QgIKdV+29SC23yR6B9ikTzUAeJ9KCEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBBI8k+kICCnVftvUgtt8kegfYpEqAy096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oGWnvQMtPegZae9Ay096Blp70DLT3oHoQEFOq/bepBbb5I9A+xSJUAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDZTxCeqihJsJHtaTpc2VqxmYhW08tZl2DS0DXFviYNja5ld96v6vgzxb2v6R4vs/9yH0r/vTNfD+zFva/r7Hi+z/ANyH0r/vTNfD+zFva/r7Hi+z/wByH0r/AL0zXw/sxb2v6+x4vs/9yH0r/vTNfD+zFva/r7Hi+z/3IfSv+9M18P7MW9r+vseL7P8A3IfSv+9M18P7MW9r+vso7TpooHwuhaWNlYXYb3tYkc1W0RtMLUmd4nuaYKdkseN7nA4iLNI+5UaNnikPWk7x9ykPFIetJ7Q+5BPikXWk7x9yB4pF1pO8fcgeKRdaTvH3IHikXWk7x9yB4pF1pO8fcgeKQ9aTvH3INNRC2IMLC44rg4rKBpQU6r9t6kFtvkj0D7FIlQCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgILFB/zGl/1mfzBXp+qGep+ifhLpyO/WO/zFSJYySRr3MYXBgxOsOA1UJWaaCNsXjdXcQA2YwGzpjoOzUoN2xoIKqtmlqIw6GmgkqHRAkB2EZN9FyEkhYZLFtfZtc59JTwT0kYmjfAzAC3EGlpHPjx7FHRK7t6ipNiPfN4uySSraBTst+ribhF3HV1+XLikbk7PMYlZVX2sbspP9N38xS3SEU/VZopjaD/5H+izau7RSwUVHDd25nq2uc2qtcw2cWgW0JBuRnmPWGM5qKiKqg2g3FUU0e9ZMbYiLgWJ/xAg3BQZ0ph2dsFu0jTQ1FRUVDoY983EyNrQCTh4EnEOKDVA2HbNcccLqc4M2UNMZMZ1w3y+xBYf4OthrayGprDDFS07ajG6E4nMcQAMN7h2fDVBidhRGoD2V3/Aml8aNQ6Kzgy+G2G/lYsuKDCk2RT19RO6mqp30lPGHyP8AFyZLk2DQwHM37UFo7Jbs+OvxXljk2fvoHSRYHD9Y0ZtPAjMIPL1Ru2P0n+iCugp1X7b1ILbfJHoH2KRKgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQb6D/mNN/rM/mCvT9UM9T9E/CXQkd+sd/mKDKCpkppmzROwvbwP9DqESyqauSrl3kpHCzWtFmtGgHIINuzdoO2dWCbdiVjmujkjcbB7HCxCgWnbQomUktFsyCSE1Za2WWolBs0G4aLAAC9rk6Il0KnaAqJKwVLqWWjnaHCEVbS+N7WgBzTrlw5oPNYlKGrahvFR/6bv5ipt0hWn6rK8BtD/8j/RZtV+Cti8W8Vq4XSxBxcxzHYXxk8bHgQbcCg2VO1Q6gbQ0zHthBzfK4OkI44bgZNvnbVBc2ZJBJss0Ve6B9M6Tex2qmxyxP4HI8iBw7Agy8f2fs99TSMil8VqY2DHT1TXSXaSc3AWz09CDCt8IIql1Vu6V0bZ6KOlaDJiLcBBuTbO9kGMG3omRQ081M59OKR1LM0PsXAvLw5ptkQbdyCKPa9HQS1EUEVUKOpjDH/rg2UEG4cCBYehBi/a8DDVthZVSNqKbch1RNjcDiBvw4ZcEHEqDdrPSf6INKCnVftvUgtt8kegfYpEqAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBBkx7o5GyMNnNIIOhCmJxOUTGYxK7+lL5mipyeZ6f4lfmjw/tnyT7X9fY/Sg/cafvf+JOaPD+zkn2v6+x+lB+40/e/wDEnNHh/ZyT7X9fY/Sg/cafvf8AiTmjw/s5J9r+vsfpQfuNP3v/ABJzR4f2ck+1/X2P0oP3Gn73/iTmjw/s5J9r+vsfpQfuNP3v/EnNHh/ZyT7X9fZWqap9U5pc1rAwWa1t7AcearM5XrXDW172CzSLXvmAVVZO+k1HshA30mo9kIG+k1HshA30mo9kIG+k1HshA30mo9kIG+k1HshA30mo9kIMXPc+2I3twysgMaZHtY3ynGwzsgpVWU1uxBbb5I9A+xSJUAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgv05gg/wDWYXEjE4ONjZw+ag4tXnOUGt73ZdI8NUGGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oGJ3WPegYndY96Bid1j3oJcSbXN8kH/9k="/>
+ <br>
+ <i>
+ Testing picture from <a href="https://commons.wikimedia.org/wiki/File:Barns_grand_tetons.jpg#Licensing_information">Wikimedia</a>
+ <br>
+ color model CMYK from <a href="https://en.wikipedia.org/wiki/CMYK_color_model">Wikipedia</a>
+ </i>
+
+ <h3>Usage</h3>
+ <ol>
+ <li>Select a layer to convert
+ <br><i>Selected layer must be a 8bits RGBA paint layer, other layer type are not (yet?) supported</i>
+ <br>
+ </li>
+ <li>Execute script from <i>Tools &gt; Scripts &gt; Channels to Layers</i><br></li>
+ <li>Choose options from user interface
+ <br><b>Layers management</b>
+ <ul>
+ <li><i>New layer group name</i>
+ <br>New layers will be grouped in a Group layer for which name is defined here.
+ <br>Possible keywords can be used to build layer name:
+ <br><b>{mode}</b>: conversion mode (RGB, CMY, CMYK, ...)
+ <br><b>{source:name}:</b> original layer name
+ </li>
+ <li><i>New layers color name</i>
+ <br>Define name for each layer created from channel.
+ <br>Possible keywords can be used to build layer name:
+ <br><b>{mode}:</b> conversion mode (RGB, CMY, CMYK, ...)
+ <br><b>{color:short}:</b> current channel color, short value (R, G, B, C, M, Y, K)
+ <br><b>{color:long}:</b> current channel color, long value (Red, Green, Blue, Cyan, Magenta, Yellow, Black)
+ <br><b>{source:name}:</b> original layer name
+ </li>
+ <li><i>Original layer</i>
+ <br>Define what to do with original layer
+ <br><b>Unchanged</b> let original layer visibility unchanged
+ <br><b>Visible</b> set original layer visibility to 'Visible'
+ <br><b>Hidden</b> set original layer visibility to 'Hidden'
+ <br><b>Remove</b> remove original layer
+ </li>
+ </ul>
+ <br><br>
+ <b>Output results</b>
+ <ul>
+ <li><i>Mode</i>
+ <br>Conversion to apply
+ <br><b>RGB Colors</b> Convert layer in to Red, Green, Blue color layers
+ <br><b>CMY Colors</b> Convert layer in to Cyan, Magenta, Yellow color layers
+ <br><b>CMYK Colors</b> Convert layer in to Cyan, Magenta, Yellow, Black color layers
+ <br><b>RGB Grayscale levels</b> Convert layer in to Red, Green, Blue grayscale layers
+ <br><b>CMY Grayscale levels</b> Convert layer in to Cyan, Magenta, Yellow grayscale layers
+ <br><b>CMYK Grayscale levels</b> Convert layer in to Cyan, Magenta, Yellow, Black grayscale layers
+ </ul>
+ </li>
+ </ol>
+
+ </body>
+</html>
\ No newline at end of file
diff --git a/plugins/python/channels2layers/__init__.py b/plugins/python/channels2layers/__init__.py
new file mode 100644
index 0000000000..d98ee57218
--- /dev/null
+++ b/plugins/python/channels2layers/__init__.py
@@ -0,0 +1,7 @@
+from .channels2layers import ChannelsToLayers
+
+# And add the extension to Krita's list of extensions:
+app = Krita.instance()
+# Instantiate your class:
+extension = ChannelsToLayers(parent=app)
+app.addExtension(extension)
diff --git a/plugins/python/channels2layers/channels2layers.jpg b/plugins/python/channels2layers/channels2layers.jpg
new file mode 100644
index 0000000000..596dacfb15
Binary files /dev/null and b/plugins/python/channels2layers/channels2layers.jpg differ
diff --git a/plugins/python/channels2layers/channels2layers.py b/plugins/python/channels2layers/channels2layers.py
new file mode 100644
index 0000000000..f71f0c0073
--- /dev/null
+++ b/plugins/python/channels2layers/channels2layers.py
@@ -0,0 +1,1461 @@
+#-----------------------------------------------------------------------------
+# Channels to Layers
+# Copyright (C) 2019 - Grum999
+# -----------------------------------------------------------------------------
+# 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, see https://www.gnu.org/licenses/
+# -----------------------------------------------------------------------------
+# A Krita plugin designed to split channels from a layer to sub-layers
+# . RGB
+# . CMY
+# . CMYK
+# . RGB as greayscale values
+# . CMY as greayscale values
+# . CMYK as greayscale values
+# -----------------------------------------------------------------------------
+
+import re
+from krita import (
+ Extension,
+ InfoObject,
+ Node,
+ Selection
+ )
+from PyQt5.Qt import *
+from PyQt5 import QtCore
+from PyQt5.QtCore import (
+ pyqtSlot,
+ QBuffer,
+ QByteArray,
+ QIODevice
+ )
+from PyQt5.QtGui import (
+ QColor,
+ QImage,
+ QPixmap,
+ )
+from PyQt5.QtWidgets import (
+ QApplication,
+ QCheckBox,
+ QComboBox,
+ QDialog,
+ QDialogButtonBox,
+ QFormLayout,
+ QGroupBox,
+ QHBoxLayout,
+ QLabel,
+ QLineEdit,
+ QMessageBox,
+ QProgressBar,
+ QProgressDialog,
+ QVBoxLayout,
+ QWidget
+ )
+
+
+PLUGIN_VERSION = '1.1.0'
+
+EXTENSION_ID = 'pykrita_channels2layers'
+PLUGIN_MENU_ENTRY = i18n('Channels to layers')
+PLUGIN_DIALOG_TITLE = "{0} - {1}".format(i18n('Channels to layers'), PLUGIN_VERSION)
+
+# Define DialogBox types
+DBOX_INFO = 'i'
+DBOX_WARNING ='w'
+
+
+# Define Output modes
+OUTPUT_MODE_RGB = i18n('RGB Colors')
+OUTPUT_MODE_CMY = i18n('CMY Colors')
+OUTPUT_MODE_CMYK = i18n('CMYK Colors')
+OUTPUT_MODE_LRGB = i18n('RGB Grayscale levels')
+OUTPUT_MODE_LCMY = i18n('CMY Grayscale levels')
+OUTPUT_MODE_LCMYK = i18n('CMYK Grayscale levels')
+
+OUTPUT_PREVIEW_MAXSIZE = 320
+
+# Define original layer action
+ORIGINAL_LAYER_KEEPUNCHANGED = i18n('Unchanged')
+ORIGINAL_LAYER_KEEPVISIBLE = i18n('Visible')
+ORIGINAL_LAYER_KEEPHIDDEN = i18n('Hidden')
+ORIGINAL_LAYER_REMOVE = i18n('Remove')
+
+# define dialog option minimum dimension
+DOPT_MIN_WIDTH = OUTPUT_PREVIEW_MAXSIZE * 5 + 200
+DOPT_MIN_HEIGHT = 480
+
+
+
+OUTPUT_MODE_NFO = {
+ OUTPUT_MODE_RGB : {
+ 'description' : 'Extract channels (Red, Green, Blue) and create a colored layer per channel',
+ 'groupLayerName' : 'RGB',
+ 'layers' : [
+ {
+ 'color' : 'B',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'new',
+ 'value' : {
+ 'type' : 'filllayer',
+ 'color' : QColor(Qt.blue)
+ }
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'inverse_subtract'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ }
+ ]
+ },
+ {
+ 'color' : 'G',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'new',
+ 'value' : {
+ 'type' : 'filllayer',
+ 'color' : QColor(Qt.green)
+ }
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'inverse_subtract'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ }
+ ]
+ },
+ {
+ 'color' : 'R',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'new',
+ 'value' : {
+ 'type' : 'filllayer',
+ 'color' : QColor(Qt.red)
+ }
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'inverse_subtract'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ }
+ ]
+ }
+ ]
+ },
+ OUTPUT_MODE_CMY : {
+ 'description' : 'Extract channels (Cyan, Mangenta, Yellow) and create a colored layer per channel',
+ 'groupLayerName' : 'CMY',
+ 'layers' : [
+ {
+ 'color' : 'Y',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'new',
+ 'value' : {
+ 'type' : 'filllayer',
+ 'color' : QColor(Qt.yellow)
+ }
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'multiply'
+ }
+ ]
+ },
+ {
+ 'color' : 'M',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'new',
+ 'value' : {
+ 'type' : 'filllayer',
+ 'color' : QColor(Qt.magenta)
+ }
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'multiply'
+ }
+ ]
+ },
+ {
+ 'color' : 'C',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'new',
+ 'value' : {
+ 'type' : 'filllayer',
+ 'color' : QColor(Qt.cyan)
+ }
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'multiply'
+ }
+ ]
+ }
+ ]
+ },
+ OUTPUT_MODE_CMYK : {
+ 'description' : 'Extract channels (Cyan, Mangenta, Yellow, Black) and create a colored layer per channel',
+ 'groupLayerName' : 'CMYK',
+ 'layers' : [
+ {
+ 'color' : 'K',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'filter',
+ 'value' : 'name=desaturate;type=5' # desaturate method = max
+ }
+ ]
+ },
+ {
+ 'color' : 'Y',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'new',
+ 'value' : {
+ 'type' : 'filllayer',
+ 'color' : QColor(Qt.yellow)
+ }
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'duplicate',
+ 'value' : '@K'
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'divide'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'multiply'
+ }
+ ]
+ },
+ {
+ 'color' : 'M',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'new',
+ 'value' : {
+ 'type' : 'filllayer',
+ 'color' : QColor(Qt.magenta)
+ }
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'duplicate',
+ 'value' : '@K'
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'divide'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'multiply'
+ }
+ ]
+ },
+ {
+ 'color' : 'C',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'new',
+ 'value' : {
+ 'type' : 'filllayer',
+ 'color' : QColor(Qt.cyan)
+ }
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'duplicate',
+ 'value' : '@K'
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'divide'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'multiply'
+ }
+ ]
+ }
+ ]
+ },
+ OUTPUT_MODE_LRGB : {
+ 'description' : 'Extract channels (Red, Green, Blue) and create a grayscale layer per channel',
+ 'groupLayerName' : 'RGB[GS]',
+ 'layers' : [
+ {
+ 'color' : 'B',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'new',
+ 'value' : {
+ 'type' : 'filllayer',
+ 'color' : QColor(Qt.blue)
+ }
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'inverse_subtract'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ },
+ {
+ 'action' : 'filter',
+ 'value' : 'name=desaturate;type=5' # desaturate method = max
+ }
+ ]
+ },
+ {
+ 'color' : 'G',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'new',
+ 'value' : {
+ 'type' : 'filllayer',
+ 'color' : QColor(Qt.green)
+ }
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'inverse_subtract'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ },
+ {
+ 'action' : 'filter',
+ 'value' : 'name=desaturate;type=5' # desaturate method = max
+ }
+ ]
+ },
+ {
+ 'color' : 'R',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'new',
+ 'value' : {
+ 'type' : 'filllayer',
+ 'color' : QColor(Qt.red)
+ }
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'inverse_subtract'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ },
+ {
+ 'action' : 'filter',
+ 'value' : 'name=desaturate;type=5' # desaturate method = max
+ }
+ ]
+ }
+ ]
+ },
+ OUTPUT_MODE_LCMY : {
+ 'description' : 'Extract channels (Cyan, Mangenta, Yellow) and create a grayscale layer per channel',
+ 'groupLayerName' : 'CMY[GS]',
+ 'layers' : [
+ {
+ 'color' : 'Y',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'new',
+ 'value' : {
+ 'type' : 'filllayer',
+ 'color' : QColor(Qt.yellow)
+ }
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ },
+ {
+ 'action' : 'filter',
+ 'value' : 'name=desaturate;type=4' # desaturate method = min
+ }
+ ]
+ },
+ {
+ 'color' : 'M',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'new',
+ 'value' : {
+ 'type' : 'filllayer',
+ 'color' : QColor(Qt.magenta)
+ }
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ },
+ {
+ 'action' : 'filter',
+ 'value' : 'name=desaturate;type=4' # desaturate method = min
+ }
+ ]
+ },
+ {
+ 'color' : 'C',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'new',
+ 'value' : {
+ 'type' : 'filllayer',
+ 'color' : QColor(Qt.cyan)
+ }
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ },
+ {
+ 'action' : 'filter',
+ 'value' : 'name=desaturate;type=4' # desaturate method = min
+ }
+ ]
+ }
+ ]
+ },
+ OUTPUT_MODE_LCMYK : {
+ 'description' : 'Extract channels (Cyan, Mangenta, Yellow, Black) and create a grayscale layer per channel',
+ 'groupLayerName' : 'CMYK[GS]',
+ 'layers' : [
+ {
+ 'color' : 'K',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'filter',
+ 'value' : 'name=desaturate;type=5' # desaturate method = max
+ }
+ ]
+ },
+ {
+ 'color' : 'Y',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'new',
+ 'value' : {
+ 'type' : 'filllayer',
+ 'color' : QColor(Qt.yellow)
+ }
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'duplicate',
+ 'value' : '@K'
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'divide'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'multiply'
+ },
+ {
+ 'action' : 'filter',
+ 'value' : 'name=desaturate;type=4' # desaturate method = min
+ }
+ ]
+ },
+ {
+ 'color' : 'M',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'new',
+ 'value' : {
+ 'type' : 'filllayer',
+ 'color' : QColor(Qt.magenta)
+ }
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'duplicate',
+ 'value' : '@K'
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'divide'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'multiply'
+ },
+ {
+ 'action' : 'filter',
+ 'value' : 'name=desaturate;type=4' # desaturate method = min
+ }
+ ]
+ },
+ {
+ 'color' : 'C',
+ 'process': [
+ {
+ 'action' : 'duplicate',
+ 'value' : '@original'
+ },
+ {
+ 'action' : 'new',
+ 'value' : {
+ 'type' : 'filllayer',
+ 'color' : QColor(Qt.cyan)
+ }
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'add'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'duplicate',
+ 'value' : '@K'
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'divide'
+ },
+ {
+ 'action' : 'merge down',
+ 'value' : None
+ },
+ {
+ 'action' : 'blending mode',
+ 'value' : 'multiply'
+ },
+ {
+ 'action' : 'filter',
+ 'value' : 'name=desaturate;type=4' # desaturate method = min
+ }
+ ]
+ }
+ ]
+ }
+}
+
+TRANSLATIONS_DICT = {
+ 'colorDepth' : {
+ 'U8' : '8bits',
+ 'U16' : '16bits',
+ 'F16' : '16bits floating point',
+ 'F32' : '32bits floating point'
+ },
+ 'colorModel' : {
+ 'A' : 'Alpha mask',
+ 'RGBA' : 'RGB with alpha channel',
+ 'XYZA' : 'XYZ with alpha channel',
+ 'LABA' : 'LAB with alpha channel',
+ 'CMYKA' : 'CMYK with alpha channel',
+ 'GRAYA' : 'Gray with alpha channel',
+ 'YCbCrA' : 'YCbCr with alpha channel'
+ },
+ 'layerType' : {
+ 'paintlayer' : 'Paint layer',
+ 'grouplayer' : 'Group layer',
+ 'filelayer' : 'File layer',
+ 'filterlayer' : 'Filter layer',
+ 'filllayer' : 'Fill layer',
+ 'clonelayer' : 'Clone layer',
+ 'vectorlayer' : 'Vector layer',
+ 'transparencymask' : 'Transparency mask',
+ 'filtermask' : 'Filter mask',
+ 'transformmask': 'Transform mask',
+ 'selectionmask': 'Selection mask',
+ 'colorizemask' : 'Colorize mask'
+ }
+}
+
+
+
+
+class ChannelsToLayers(Extension):
+
+ def __init__(self, parent):
+ # Default options
+ self.__outputOptions = {
+ 'outputMode': OUTPUT_MODE_RGB,
+ 'originalLayerAction': ORIGINAL_LAYER_KEEPHIDDEN,
+ 'layerGroupName': '{mode}-{source:name}',
+ 'layerColorName': '{mode}[{color:short}]-{source:name}'
+ }
+
+ self.__sourceDocument = None
+ self.__sourceLayer = None
+
+ # Always initialise the superclass.
+ # This is necessary to create the underlying C++ object
+ super().__init__(parent)
+ self.parent = parent
+
+
+ def setup(self):
+ pass
+
+
+ def createActions(self, window):
+ action = window.createAction(EXTENSION_ID, PLUGIN_MENU_ENTRY, "tools/scripts")
+ action.triggered.connect(self.action_triggered)
+
+ def dBoxMessage(self, msgType, msg):
+ """Simplified function for DialogBox 'OK' message"""
+ if msgType == DBOX_WARNING:
+ QMessageBox.warning(
+ QWidget(),
+ PLUGIN_DIALOG_TITLE,
+ i18n(msg)
+ )
+ else:
+ QMessageBox.information(
+ QWidget(),
+ PLUGIN_DIALOG_TITLE,
+ i18n(msg)
+ )
+
+
+ def action_triggered(self):
+ """Action called when script is executed from Kitra menu"""
+ if self.checkCurrentLayer():
+ if self.openDialogOptions():
+ self.run()
+
+
+ def translateDictKey(self, key, value):
+ """Translate key from dictionnary (mostly internal Krita internal values) to human readable values"""
+ returned = i18n('Unknown')
+
+ if key in TRANSLATIONS_DICT.keys():
+ if value in TRANSLATIONS_DICT[key].keys():
+ returned = i18n(TRANSLATIONS_DICT[key][value])
+
+ return returned
+
+
+ def checkCurrentLayer(self):
+ """Check if current layer is valid
+ - A document must be opened
+ - Active layer properties must be:
+ . Layer type: a paint layer
+ . Color model: RGBA
+ . Color depth: 8bits
+ """
+ self.__sourceDocument = Application.activeDocument()
+ # Check if there's an active document
+ if self.__sourceDocument is None:
+ self.dBoxMessage(DBOX_WARNING, "There's no active document!")
+ return False
+
+ self.__sourceLayer = self.__sourceDocument.activeNode()
+
+ # Check if current layer can be processed
+ if self.__sourceLayer.type() != "paintlayer" or self.__sourceLayer.colorModel() != "RGBA" or self.__sourceLayer.colorDepth() != "U8":
+ self.dBoxMessage(DBOX_WARNING, "Selected layer must be a 8bits RGBA Paint Layer!"
+ "\n\nCurrent layer '{0}' properties:"
+ "\n- Layer type: {1}"
+ "\n- Color model: {2} ({3})"
+ "\n- Color depth: {4}"
+ "\n\n> Action is cancelled".format(self.__sourceLayer.name(),
+ self.translateDictKey('layerType', self.__sourceLayer.type()),
+ self.__sourceLayer.colorModel(), self.translateDictKey('colorModel', self.__sourceLayer.colorModel()),
+ self.translateDictKey('colorDepth', self.__sourceLayer.colorDepth())
+ ))
+ return False
+
+ return True
+
+
+
+ def toQImage(self, layerNode, rect=None):
+ """Return `layerNode` content as a QImage (as ARGB32)
+
+ The `rect` value can be:
+ - None, in this case will return all `layerNode` content
+ - A QRect() object, in this case return `layerNode` content reduced to given rectangle bounds
+ """
+ srcRect = layerNode.bounds()
+
+ if len(layerNode.childNodes()) == 0:
+ projectionMode = False
+ else:
+ projectionMode = True
+
+ if projectionMode == True:
+ img = QImage(layerNode.projectionPixelData(srcRect.left(), srcRect.top(), srcRect.width(), srcRect.height()), srcRect.width(), srcRect.height(), QImage.Format_ARGB32)
+ else:
+ img = QImage(layerNode.pixelData(srcRect.left(), srcRect.top(), srcRect.width(), srcRect.height()), srcRect.width(), srcRect.height(), QImage.Format_ARGB32)
+
+ return img.scaled(rect.width(), rect.height(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
+
+
+ def openDialogOptions(self):
+ """Open dialog box to let user define channel extraction options"""
+
+ tmpDocument = None
+ previewBaSrc = QByteArray()
+ lblPreview = [QLabel(), QLabel(), QLabel(), QLabel()]
+ lblPreviewLbl = [QLabel(), QLabel(), QLabel(), QLabel()]
+
+
+ # ----------------------------------------------------------------------
+ # Define signal and slots for UI widgets
+ @pyqtSlot('QString')
+ def ledLayerGroupName_Changed(value):
+ self.__outputOptions['layerGroupName'] = value
+
+ @pyqtSlot('QString')
+ def ledLayerColorName_Changed(value):
+ self.__outputOptions['layerColorName'] = value
+
+ @pyqtSlot('QString')
+ def cmbOutputMode_Changed(value):
+ self.__outputOptions['outputMode'] = value
+ buildPreview()
+
+ @pyqtSlot('QString')
+ def cmbOriginalLayerAction_Changed(value):
+ self.__outputOptions['originalLayerAction'] = value
+
+ def buildPreview():
+ pbProgress.setVisible(True)
+
+ backupValue = self.__outputOptions['layerColorName']
+ self.__outputOptions['layerColorName'] = '{color:long}'
+
+ # create a temporary document to work
+ tmpDocument = Application.createDocument(imgThumbSrc.width(), imgThumbSrc.height(), "tmp", "RGBA", "U8", "", 120.0)
+
+ # create a layer used as original layer
+ originalLayer = tmpDocument.createNode("Original", "paintlayer")
+ tmpDocument.rootNode().addChildNode(originalLayer, None)
+ # and set original image content
+ originalLayer.setPixelData(previewBaSrc, 0, 0, tmpDocument.width(), tmpDocument.height())
+
+ # execute process
+ groupLayer = self.process(tmpDocument, originalLayer, pbProgress)
+
+ self.__outputOptions['layerColorName'] = backupValue
+
+ originalLayer.setVisible(False)
+ groupLayer.setVisible(True)
+
+ for layer in groupLayer.childNodes():
+ layer.setBlendingMode('normal')
+ layer.setVisible(False)
+ tmpDocument.refreshProjection()
+
+ index = 0
+ for layer in groupLayer.childNodes():
+ layer.setVisible(True)
+ tmpDocument.refreshProjection()
+
+ lblPreview[index].setPixmap(QPixmap.fromImage(tmpDocument.projection(0, 0, tmpDocument.width(), tmpDocument.height())))
+ lblPreviewLbl[index].setText("<i>{0}</i>".format(layer.name()))
+ layer.setVisible(False)
+
+ index+=1
+
+ if index > 3:
+ lblPreview[3].setVisible(True)
+ lblPreviewLbl[3].setVisible(True)
+ else:
+ lblPreview[3].setVisible(False)
+ lblPreviewLbl[3].setVisible(False)
+
+
+ tmpDocument.close()
+
+ pbProgress.setVisible(False)
+
+
+ # ----------------------------------------------------------------------
+ # Create dialog box
+ dlgMain = QDialog(Application.activeWindow().qwindow())
+ dlgMain.setWindowTitle(PLUGIN_DIALOG_TITLE)
+ # resizeable with minimum size
+ dlgMain.setSizeGripEnabled(True)
+ dlgMain.setMinimumSize(DOPT_MIN_WIDTH, DOPT_MIN_HEIGHT)
+ dlgMain.setModal(True)
+
+ # ......................................................................
+ # main dialog box, container
+ vbxMainContainer = QVBoxLayout(dlgMain)
+
+ # main dialog box, current layer name
+ lblLayerName = QLabel("{0} <b><i>{1}</i></b>".format(i18n("Processing layer"), self.__sourceLayer.name()))
+ lblLayerName.setFixedHeight(30)
+ vbxMainContainer.addWidget(lblLayerName)
+
+ # main dialog box, groupbox for layers options
+ gbxLayersMgt = QGroupBox("Layers management")
+ vbxMainContainer.addWidget(gbxLayersMgt)
+
+ # main dialog box, groupbox for output options
+ gbxOutputResults = QGroupBox("Output results")
+ vbxMainContainer.addWidget(gbxOutputResults)
+
+ vbxMainContainer.addStretch()
+
+ # main dialog box, OK/Cancel buttons
+ dbbxOkCancel = QDialogButtonBox(dlgMain)
+ dbbxOkCancel.setOrientation(QtCore.Qt.Horizontal)
+ dbbxOkCancel.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
+ dbbxOkCancel.accepted.connect(dlgMain.accept)
+ dbbxOkCancel.rejected.connect(dlgMain.reject)
+ vbxMainContainer.addWidget(dbbxOkCancel)
+
+ # ......................................................................
+ # create layout for groupbox "Layers management"
+ flLayersMgt = QFormLayout()
+ gbxLayersMgt.setLayout(flLayersMgt)
+
+ ledLayerGroupName = QLineEdit()
+ ledLayerGroupName.setText(self.__outputOptions['layerGroupName'])
+ ledLayerGroupName.textChanged.connect(ledLayerGroupName_Changed)
+ flLayersMgt.addRow(i18n('New layer group name'), ledLayerGroupName)
+
+ ledLayerColorName = QLineEdit()
+ ledLayerColorName.setText(self.__outputOptions['layerColorName'])
+ ledLayerColorName.textChanged.connect(ledLayerColorName_Changed)
+ flLayersMgt.addRow(i18n('New layers color name'), ledLayerColorName)
+
+ cmbOriginalLayerAction = QComboBox()
+ cmbOriginalLayerAction.addItems([
+ ORIGINAL_LAYER_KEEPUNCHANGED,
+ ORIGINAL_LAYER_KEEPVISIBLE,
+ ORIGINAL_LAYER_KEEPHIDDEN,
+ ORIGINAL_LAYER_REMOVE
+ ])
+ cmbOriginalLayerAction.setCurrentText(self.__outputOptions['originalLayerAction'])
+ cmbOriginalLayerAction.currentTextChanged.connect(cmbOriginalLayerAction_Changed)
+ flLayersMgt.addRow(i18n("Original layer"), cmbOriginalLayerAction)
+
+ # ......................................................................
+ # create layout for groupbox "Output results"
+ flOutputResults = QFormLayout()
+ gbxOutputResults.setLayout(flOutputResults)
+
+ cmbOutputMode = QComboBox()
+ cmbOutputMode.addItems([
+ OUTPUT_MODE_RGB,
+ OUTPUT_MODE_CMY,
+ OUTPUT_MODE_CMYK,
+ OUTPUT_MODE_LRGB,
+ OUTPUT_MODE_LCMY,
+ OUTPUT_MODE_LCMYK
+ ])
+ cmbOutputMode.setCurrentText(self.__outputOptions['outputMode'])
+ cmbOutputMode.currentTextChanged.connect(cmbOutputMode_Changed)
+ flOutputResults.addRow(i18n("Mode"), cmbOutputMode)
+
+ vbxPreviewLblContainer = QHBoxLayout()
+ flOutputResults.addRow('', vbxPreviewLblContainer)
+ vbxPreviewContainer = QHBoxLayout()
+ flOutputResults.addRow('', vbxPreviewContainer)
+
+ # add preview progressbar
+ pbProgress = QProgressBar()
+ pbProgress.setFixedHeight(8)
+ pbProgress.setTextVisible(False)
+ pbProgress.setVisible(False)
+ pbProgress.setRange(0, 107)
+ flOutputResults.addRow('', pbProgress)
+
+
+ imageRatio = self.__sourceDocument.width() / self.__sourceDocument.height()
+ rect = QRect(0, 0, OUTPUT_PREVIEW_MAXSIZE, OUTPUT_PREVIEW_MAXSIZE)
+
+ # always ensure that final preview width and/or height is lower or equal than OUTPUT_PREVIEW_MAXSIZE
+ if imageRatio < 1:
+ # width < height
+ rect.setWidth(int(imageRatio * OUTPUT_PREVIEW_MAXSIZE))
+ else:
+ # width >= height
+ rect.setHeight(int(OUTPUT_PREVIEW_MAXSIZE / imageRatio))
+
+ imgThumbSrc = self.toQImage(self.__sourceLayer, rect)
+
+ previewBaSrc.resize(imgThumbSrc.byteCount())
+ ptr = imgThumbSrc.bits()
+ ptr.setsize(imgThumbSrc.byteCount())
+ previewBaSrc = QByteArray(ptr.asstring())
+
+
+ lblPreviewSrc = QLabel()
+ lblPreviewSrc.setPixmap(QPixmap.fromImage(imgThumbSrc))
+ lblPreviewSrc.setFixedHeight(imgThumbSrc.height() + 4)
+ lblPreviewSrc.setFixedWidth(imgThumbSrc.width() + 4)
+ vbxPreviewContainer.addWidget(lblPreviewSrc)
+
+ lblPreviewLblSrc = QLabel(i18n("Original"))
+ lblPreviewLblSrc.setFixedWidth(imgThumbSrc.width() + 4)
+ vbxPreviewLblContainer.addWidget(lblPreviewLblSrc)
+
+
+ vbxPreviewLblContainer.addWidget(QLabel(" "))
+ vbxPreviewContainer.addWidget(QLabel(">"))
+
+ lblPreview[3].setPixmap(QPixmap.fromImage(imgThumbSrc))
+ lblPreview[3].setFixedHeight(imgThumbSrc.height() + 4)
+ lblPreview[3].setFixedWidth(imgThumbSrc.width() + 4)
+ vbxPreviewContainer.addWidget(lblPreview[3])
+
+ lblPreviewLbl[3] = QLabel(i18n("<i>Cyan</i>"))
+ lblPreviewLbl[3].setIndent(10)
+ lblPreviewLbl[3].setFixedWidth(imgThumbSrc.width() + 4)
+ vbxPreviewLblContainer.addWidget(lblPreviewLbl[3])
+
+
+ lblPreview[2] = QLabel()
+ lblPreview[2].setPixmap(QPixmap.fromImage(imgThumbSrc))
+ lblPreview[2].setFixedHeight(imgThumbSrc.height() + 4)
+ lblPreview[2].setFixedWidth(imgThumbSrc.width() + 4)
+ vbxPreviewContainer.addWidget(lblPreview[2])
+
+ lblPreviewLbl[2] = QLabel(i18n("<i>Magenta</i>"))
+ lblPreviewLbl[2].setIndent(10)
+ lblPreviewLbl[2].setFixedWidth(imgThumbSrc.width() + 4)
+ vbxPreviewLblContainer.addWidget(lblPreviewLbl[2])
+
+
+ lblPreview[1] = QLabel()
+ lblPreview[1].setPixmap(QPixmap.fromImage(imgThumbSrc))
+ lblPreview[1].setFixedHeight(imgThumbSrc.height() + 4)
+ lblPreview[1].setFixedWidth(imgThumbSrc.width() + 4)
+ vbxPreviewContainer.addWidget(lblPreview[1])
+
+ lblPreviewLbl[1] = QLabel(i18n("<i>Yellow</i>"))
+ lblPreviewLbl[1].setIndent(10)
+ lblPreviewLbl[1].setFixedWidth(imgThumbSrc.width() + 4)
+ vbxPreviewLblContainer.addWidget(lblPreviewLbl[1])
+
+
+ lblPreview[0] = QLabel()
+ lblPreview[0].setPixmap(QPixmap.fromImage(imgThumbSrc))
+ lblPreview[0].setFixedHeight(imgThumbSrc.height() + 4)
+ lblPreview[0].setFixedWidth(imgThumbSrc.width() + 4)
+ vbxPreviewContainer.addWidget(lblPreview[0])
+
+ lblPreviewLbl[0] = QLabel(i18n("<i>Black</i>"))
+ lblPreviewLbl[0].setIndent(10)
+ lblPreviewLbl[0].setFixedWidth(imgThumbSrc.width() + 4)
+ vbxPreviewLblContainer.addWidget(lblPreviewLbl[0])
+
+
+ vbxPreviewLblContainer.addStretch()
+ vbxPreviewContainer.addStretch()
+
+ buildPreview()
+
+ returned = dlgMain.exec_()
+
+ return returned
+
+
+ def progressNext(self, pProgress):
+ """Update progress bar"""
+ if pProgress is not None:
+ stepCurrent=pProgress.value()+1
+ pProgress.setValue(stepCurrent)
+ QApplication.instance().processEvents()
+
+
+ def run(self):
+ """Run process for current layer"""
+
+ pdlgProgress = QProgressDialog(self.__outputOptions['outputMode'], None, 0, 100, Application.activeWindow().qwindow())
+ pdlgProgress.setWindowTitle(PLUGIN_DIALOG_TITLE)
+ pdlgProgress.setMinimumSize(640, 200)
+ pdlgProgress.setModal(True)
+ pdlgProgress.show()
+
+ self.process(self.__sourceDocument, self.__sourceLayer, pdlgProgress)
+
+ pdlgProgress.close()
+
+
+
+
+ def process(self, pDocument, pOriginalLayer, pProgress):
+ """Process given layer with current options"""
+
+ self.layerNum = 0
+ document = pDocument
+ originalLayer = pOriginalLayer
+ parentGroupLayer = None
+ currentProcessedLayer = None
+ originalLayerIsVisible = originalLayer.visible()
+
+
+ def getLayerByName(parent, value):
+ """search and return a layer by name, within given parent group"""
+ if parent == None:
+ return document.nodeByName(value)
+
+ for layer in parent.childNodes():
+ if layer.name() == value:
+ return layer
+
+ return None
+
+
+ def duplicateLayer(currentProcessedLayer, value):
+ """Duplicate layer from given name
+ New layer become active layer
+ """
+
+ newLayer = None
+ srcLayer = None
+ srcName = re.match("^@(.*)", value)
+
+ if not srcName is None:
+ # reference to a specific layer
+ if srcName[1] == 'original':
+ # original layer currently processed
+ srcLayer = originalLayer
+ else:
+ # a color layer previously built (and finished)
+ srcLayer = getLayerByName(parentGroupLayer, parseLayerName(self.__outputOptions['layerColorName'], srcName[1]))
+ else:
+ # a layer with a fixed name
+ srcLayer = document.nodeByName(parseLayerName(value, ''))
+
+
+ if not srcLayer is None:
+ newLayer = srcLayer.duplicate()
+
+ self.layerNum+=1
+ newLayer.setName("c2l-w{0}".format(self.layerNum))
+
+ parentGroupLayer.addChildNode(newLayer, currentProcessedLayer)
+ return newLayer
+ else:
+ return None
+
+
+ def newLayer(currentProcessedLayer, value):
+ """Create a new layer of given type
+ New layer become active layer
+ """
+
+ newLayer = None
+
+ if value is None or not value['type'] in ['filllayer']:
+ # given type for new layer is not valid
+ # currently only one layer type is implemented
+ return None
+
+ if value['type'] == 'filllayer':
+ infoObject = InfoObject();
+ infoObject.setProperty("color", value['color'])
+ selection = Selection();
+ selection.select(0, 0, document.width(), document.height(), 255)
+
+ newLayer = document.createFillLayer(value['color'].name(), "color", infoObject, selection)
+
+
+ if newLayer:
+ self.layerNum+=1
+ newLayer.setName("c2l-w{0}".format(self.layerNum))
+
+ parentGroupLayer.addChildNode(newLayer, currentProcessedLayer)
+
+ # Need to force generator otherwise, information provided when creating layer seems to not be taken in
+ # account
+ newLayer.setGenerator("color", infoObject)
+
+ return newLayer
+ else:
+ return None
+
+
+ def mergeDown(currentProcessedLayer, value):
+ """Merge current layer with layer below"""
+ if currentProcessedLayer is None:
+ return None
+
+ newLayer = currentProcessedLayer.mergeDown()
+ # note:
+ # when layer is merged down:
+ # - a new layer seems to be created (reference to 'down' layer does not match anymore layer in group)
+ # - retrieved 'newLayer' reference does not match to new layer resulting from merge
+ # - activeNode() in document doesn't match to new layer resulting from merge
+ # maybe it's norpmal, maybe not...
+ # but the only solution to be able to work on merged layer (with current script) is to consider that from
+ # parent node, last child match to last added layer and then, to our merged layer
+ currentProcessedLayer = parentGroupLayer.childNodes()[-1]
+ # for an unknown reason, merged layer bounds are not corrects... :'-(
+ currentProcessedLayer.cropNode(0, 0, document.width(), document.height())
+ return currentProcessedLayer
+
+
+ def applyBlendingMode(currentProcessedLayer, value):
+ """Set blending mode for current layer"""
+ if currentProcessedLayer is None or value is None or value == '':
+ return False
+
+ currentProcessedLayer.setBlendingMode(value)
+ return True
+
+
+ def applyFilter(currentProcessedLayer, value):
+ """Apply filter to layer"""
+ if currentProcessedLayer is None or value is None or value == '':
+ return None
+
+ filterName = re.match("name=([^;]+)", value)
+
+ if filterName is None:
+ return None
+
+ filter = Application.filter(filterName.group(1))
+ filterConfiguration = filter.configuration()
+
+ for parameter in value.split(';'):
+ parameterName = re.match("^([^=]+)=(.*)", parameter)
+
+ if not parameterName is None and parameterName != 'name':
+ filterConfiguration.setProperty(parameterName.group(1), parameterName.group(2))
+
+ filter.setConfiguration(filterConfiguration)
+ filter.apply(currentProcessedLayer, 0, 0, document.width(), document.height())
+
+ return currentProcessedLayer
+
+
+ def parseLayerName(value, color):
+ """Parse layer name"""
+
+ returned = value
+
+ returned = returned.replace("{source:name}", originalLayer.name())
+ returned = returned.replace("{mode}", OUTPUT_MODE_NFO[self.__outputOptions['outputMode']]['groupLayerName'])
+ returned = returned.replace("{color:short}", color)
+ if color == "C":
+ returned = returned.replace("{color:long}", i18n("Cyan"))
+ elif color == "M":
+ returned = returned.replace("{color:long}", i18n("Magenta"))
+ elif color == "Y":
+ returned = returned.replace("{color:long}", i18n("Yellow"))
+ elif color == "K":
+ returned = returned.replace("{color:long}", i18n("Black"))
+ elif color == "R":
+ returned = returned.replace("{color:long}", i18n("Red"))
+ elif color == "G":
+ returned = returned.replace("{color:long}", i18n("Green"))
+ elif color == "B":
+ returned = returned.replace("{color:long}", i18n("Blue"))
+ else:
+ returned = returned.replace("{color:long}", "")
+
+ return returned
+
+
+ if document is None or originalLayer is None:
+ # should not occurs, but...
+ return None
+
+ if not pProgress is None:
+ stepTotal = 4
+ for layer in OUTPUT_MODE_NFO[self.__outputOptions['outputMode']]['layers']:
+ stepTotal+=len(layer['process'])
+
+ pProgress.setRange(0, stepTotal)
+
+
+ if originalLayerIsVisible == False:
+ originalLayer.setVisible(True)
+
+ # ----------------------------------------------------------------------
+ # Create new group layer
+ parentGroupLayer = document.createGroupLayer(parseLayerName(self.__outputOptions['layerGroupName'], ''))
+
+ self.progressNext(pProgress)
+
+ currentProcessedLayer = None
+
+ for layer in OUTPUT_MODE_NFO[self.__outputOptions['outputMode']]['layers']:
+ for process in layer['process']:
+ if process['action'] == 'duplicate':
+ currentProcessedLayer = duplicateLayer(currentProcessedLayer, process['value'])
+ elif process['action'] == 'new':
+ currentProcessedLayer = newLayer(currentProcessedLayer, process['value'])
+ elif process['action'] == 'merge down':
+ currentProcessedLayer = mergeDown(currentProcessedLayer, process['value'])
+ pass
+ elif process['action'] == 'blending mode':
+ applyBlendingMode(currentProcessedLayer, process['value'])
+ elif process['action'] == 'filter':
+ applyFilter(currentProcessedLayer, process['value'])
+
+ self.progressNext(pProgress)
+
+ if not currentProcessedLayer is None:
+ # rename currentProcessedLayer
+ currentProcessedLayer.setName(parseLayerName(self.__outputOptions['layerColorName'], layer['color']))
+
+ document.rootNode().addChildNode(parentGroupLayer, originalLayer)
+ self.progressNext(pProgress)
+
+ if self.__outputOptions['originalLayerAction'] == ORIGINAL_LAYER_KEEPVISIBLE:
+ originalLayer.setVisible(True)
+ elif self.__outputOptions['originalLayerAction'] == ORIGINAL_LAYER_KEEPHIDDEN:
+ originalLayer.setVisible(False)
+ elif self.__outputOptions['originalLayerAction'] == ORIGINAL_LAYER_REMOVE:
+ originalLayer.remove()
+ else:
+ # ORIGINAL_LAYER_KEEPUNCHANGED
+ originalLayer.setVisible(originalLayerIsVisible)
+
+
+ self.progressNext(pProgress)
+
+ document.refreshProjection()
+ self.progressNext(pProgress)
+
+ document.setActiveNode(parentGroupLayer)
+
+ return parentGroupLayer
+
+
+#ChannelsToLayers(Krita.instance()).process(Application.activeDocument(), Application.activeDocument().activeNode(), None)
+#ChannelsToLayers(Krita.instance()).action_triggered()
diff --git a/plugins/python/channels2layers/kritapykrita_channels2layers.desktop b/plugins/python/channels2layers/kritapykrita_channels2layers.desktop
new file mode 100644
index 0000000000..2b15fec90b
--- /dev/null
+++ b/plugins/python/channels2layers/kritapykrita_channels2layers.desktop
@@ -0,0 +1,20 @@
+[Desktop Entry]
+Type=Service
+ServiceTypes=Krita/PythonPlugin
+X-KDE-Library=channels2layers
+X-Python-2-Compatible=false
+X-Krita-Manual=Manual.html
+Name=Channels to layers
+Name[ca]=Canals a capes
+Name[es]=Canales a capas
+Name[nl]=Kanalen naar lagen
+Name[pt]=Canais para camadas
+Name[uk]=Канали у шари
+Name[x-test]=xxChannels to layersxx
+Comment=Extract channels as color layers
+Comment[ca]=Extreu canals com a capes de color
+Comment[es]=Extraer canales como capas de color
+Comment[nl]=Kanalen als kleurlagen extraheren
+Comment[pt]=Extrair os canais como camadas de cores
+Comment[uk]=Видобування каналів як колірних шарів
+Comment[x-test]=xxExtract channels as color layersxx
diff --git a/plugins/python/documenttools/kritapykrita_documenttools.desktop b/plugins/python/documenttools/kritapykrita_documenttools.desktop
index 2e20c82584..a49b96d8fb 100644
--- a/plugins/python/documenttools/kritapykrita_documenttools.desktop
+++ b/plugins/python/documenttools/kritapykrita_documenttools.desktop
@@ -1,59 +1,61 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=documenttools
X-Python-2-Compatible=true
X-Krita-Manual=Manual.html
Name=Document Tools
Name[ar]=أدوات المستندات
Name[ca]=Eines de document
Name[ca@valencia]=Eines de document
Name[cs]=Dokumentové nástroje
Name[el]=Εργαλεία για έγγραφα
Name[en_GB]=Document Tools
Name[es]=Herramientas de documentos
Name[et]=Dokumenditööriistad
Name[eu]=Dokumentuen tresnak
Name[fi]=Tiedostotyökalut
Name[fr]=Outil Document
Name[gl]=Ferramentas de documentos
Name[it]=Strumenti per i documenti
Name[ko]=문서 도구
Name[nl]=Documenthulpmiddelen
Name[nn]=Dokumentverktøy
Name[pl]=Narzędzia dokumentu
Name[pt]=Ferramentas de Documentos
Name[pt_BR]=Ferramentas de documento
+Name[sk]=Nástroje dokumentu
Name[sl]=Orodja za dokumente
Name[sv]=Dokumentverktyg
Name[tr]=Belge Araçları
Name[uk]=Засоби документа
Name[x-test]=xxDocument Toolsxx
Name[zh_CN]=文档工具
Name[zh_TW]=檔案工具
Comment=Plugin to manipulate properties of selected documents
Comment[ar]=ملحقة لتعديل خصائص المستندات المحددة
Comment[ca]=Un connector per a manipular les propietats dels documents seleccionats
Comment[ca@valencia]=Un connector per a manipular les propietats dels documents seleccionats
Comment[cs]=Modul pro správu vlastností vybraných dokumentů
Comment[el]=Πρόσθετο χειρισμού ιδιοτήτων σε επιλεγμένα έγγραφα
Comment[en_GB]=Plugin to manipulate properties of selected documents
Comment[es]=Complemento para manipular las propiedades de los documentos seleccionados
Comment[et]=Plugin valitud dokumentide omaduste käitlemiseks
Comment[eu]=Hautatutako dokumentuen propietateak manipulatzeko plugina
Comment[fi]=Liitännäinen valittujen tiedostojen ominaisuuksien käsittelemiseksi
Comment[fr]=Module externe de gestion des propriétés des documents sélectionnés
Comment[gl]=Complemento para manipular as propiedades dos documentos seleccionados.
Comment[it]=Estensione per manipolare le proprietà dei documenti selezionati
Comment[ko]=선택한 문서의 속성을 변경하는 플러그인
Comment[nl]=Plug-in om eigenschappen van geselecteerde documenten te manipuleren
Comment[nn]=Programtillegg for å endra eigenskapar på utvalde dokument
Comment[pl]=Wtyczka do zmiany właściwości wybranych dokumentów
Comment[pt]='Plugin' para manipular as propriedades dos documentos seleccionados
Comment[pt_BR]=Plugin para manipular as propriedades de documentos selecionados
+Comment[sk]=Zásuvný modul na manipuláciu s vlastnosťami vybraných dokumentov.
Comment[sv]=Insticksprogram för att ändra egenskaper för valda dokument
Comment[tr]=Seçili belgelerin özelliklerini değiştirmek için eklenti
Comment[uk]=Додаток для керування властивостями позначених документів
Comment[x-test]=xxPlugin to manipulate properties of selected documentsxx
Comment[zh_CN]=用于编辑选定文档属性的插件
Comment[zh_TW]=用於修改所選檔案屬性的外掛程式
diff --git a/plugins/python/exportlayers/kritapykrita_exportlayers.desktop b/plugins/python/exportlayers/kritapykrita_exportlayers.desktop
index 63e1511745..fc037603b9 100644
--- a/plugins/python/exportlayers/kritapykrita_exportlayers.desktop
+++ b/plugins/python/exportlayers/kritapykrita_exportlayers.desktop
@@ -1,61 +1,63 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=exportlayers
X-Krita-Manual=Manual.html
X-Python-2-Compatible=true
Name=Export Layers
Name[ar]=تصدير الطبقات
Name[ca]=Exportació de capes
Name[ca@valencia]=Exportació de capes
Name[cs]=Exportovat vrstvy
Name[de]=Ebenen exportieren
Name[el]=Εξαγωγή επιπέδων
Name[en_GB]=Export Layers
Name[es]=Exportar capas
Name[et]=Kihtide eksport
Name[eu]=Esportatu geruzak
Name[fi]=Vie tasoja
Name[fr]=Exporter des calques
Name[gl]=Exportar as capas
Name[is]=Flytja út lög
Name[it]=Esporta livelli
Name[ko]=레이어 내보내기
Name[nl]=Lagen exporteren
Name[nn]=Eksporter lag
Name[pl]=Eksportuj warstwy
Name[pt]=Exportar as Camadas
Name[pt_BR]=Exportar camadas
+Name[sk]=Exportovať vrstvy
Name[sv]=Exportera lager
Name[tr]=Katmanları Dışa Aktar
Name[uk]=Експортувати шари
Name[x-test]=xxExport Layersxx
Name[zh_CN]=导出图层
Name[zh_TW]=匯出圖層
Comment=Plugin to export layers from a document
Comment[ar]=ملحقة لتصدير الطبقات من مستند
Comment[ca]=Un connector per exportar capes d'un document
Comment[ca@valencia]=Un connector per exportar capes d'un document
Comment[cs]=Modul pro export vrstev z dokumentu
Comment[de]=Modul zum Exportieren von Ebenen aus einem Dokument
Comment[el]=Πρόσθετο εξαγωγής επιπέδων από έγγραφο
Comment[en_GB]=Plugin to export layers from a document
Comment[es]=Complemento para exportar las capas de un documento
Comment[et]=Plugin dokumendi kihtide eksportimiseks
Comment[eu]=Dokumentu batetik geruzak esportatzeko plugina
Comment[fi]=Liitännäisen tiedoston tasojen viemiseksi
Comment[fr]=Module externe d'export de calques d'un document
Comment[gl]=Complemento para exportar as capas dun documento.
Comment[it]=Estensione per esportare i livelli da un documento
Comment[ko]=문서에서 레이어를 내보내는 플러그인
Comment[nl]=Plug-in om lagen uit een document te exporteren
Comment[nn]=Programtillegg for eksportering av biletlag i dokument
Comment[pl]=Wtyczka do eksportowania warstw z dokumentu
Comment[pt]='Plugin' para exportar as camadas de um documento
Comment[pt_BR]=Plugin para exportar as camadas de um documento
+Comment[sk]=Zásuvný modul na export vrstiev z dokumentu.
Comment[sv]=Insticksprogram för att exportera lager från ett dokument
Comment[tr]=Belgenin katmanlarını dışa aktarmak için eklenti
Comment[uk]=Додаток для експортування шарів з документа
Comment[x-test]=xxPlugin to export layers from a documentxx
Comment[zh_CN]=用于从文档导出图层的插件
Comment[zh_TW]=用於從檔案匯出圖層的外掛程式
diff --git a/plugins/python/filtermanager/kritapykrita_filtermanager.desktop b/plugins/python/filtermanager/kritapykrita_filtermanager.desktop
index 21241e34de..dbf8d1cb90 100644
--- a/plugins/python/filtermanager/kritapykrita_filtermanager.desktop
+++ b/plugins/python/filtermanager/kritapykrita_filtermanager.desktop
@@ -1,61 +1,62 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=filtermanager
X-Python-2-Compatible=true
X-Krita-Manual=Manual.html
Name=Filter Manager
Name[ar]=مدير المرشّحات
Name[ca]=Gestor de filtres
Name[ca@valencia]=Gestor de filtres
Name[cs]=Správce filtrů
Name[de]=Filterverwaltung
Name[el]=Διαχειριστής φίλτρων
Name[en_GB]=Filter Manager
Name[es]=Gestor de filtros
Name[et]=Filtrihaldur
Name[eu]=Iragazki-kudeatzailea
Name[fi]=Suodatinhallinta
Name[fr]=Gestionnaire de fichiers
Name[gl]=Xestor de filtros
Name[it]=Gestore dei filtri
Name[ko]=필터 관리자
Name[nl]=Beheerder van filters
Name[nn]=Filterhandsamar
Name[pl]=Zarządzanie filtrami
Name[pt]=Gestor de Filtros
Name[pt_BR]=Gerenciador de filtros
+Name[sk]=Správca filtrov
Name[sl]=Upravljanje filtrov
Name[sv]=Filterhantering
Name[tr]=Süzgeç Yöneticisi
Name[uk]=Керування фільтрами
Name[x-test]=xxFilter Managerxx
Name[zh_CN]=滤镜管理器
Name[zh_TW]=濾鏡管理器
Comment=Plugin to filters management
Comment[ar]=ملحقة إدارة المرشّحات
Comment[ca]=Un connector per a gestionar filtres
Comment[ca@valencia]=Un connector per a gestionar filtres
Comment[cs]=Modul pro správu filtrů
Comment[de]=Modul zum Verwalten von Filtern
Comment[el]=Πρόσθετο για τη διαχείριση φίλτρων
Comment[en_GB]=Plugin to filters management
Comment[es]=Complemento para la gestión de filtros
Comment[et]=Plugin filtrite haldamiseks
Comment[eu]=Iragazkiak kudeatzeko plugina
Comment[fi]=Liitännäinen suodatinten hallintaan
Comment[fr]=Module externe de gestion des filtres
Comment[gl]=Complemento para a xestión de filtros.
Comment[it]=Estensione per la gestione dei filtri
Comment[ko]=필터 관리에 대한 플러그인
Comment[nl]=Plug-in voor beheer van filters
Comment[nn]=Programtillegg for filterhandsaming
Comment[pl]=Wtyczka do zarządzania filtrami
Comment[pt]='Plugin' para a gestão de filtros
Comment[pt_BR]=Plugin para gerenciamento de filtros
Comment[sv]=Insticksprogram för filterhantering
Comment[tr]=Süzgeç yönetimi için eklenti
Comment[uk]=Додаток для керування фільтрами
Comment[x-test]=xxPlugin to filters managementxx
Comment[zh_CN]=用于管理滤镜的插件。
Comment[zh_TW]=用於濾鏡管理的外掛程式
diff --git a/plugins/python/krita_script_starter/kritapykrita_krita_script_starter.desktop b/plugins/python/krita_script_starter/kritapykrita_krita_script_starter.desktop
index c67432b5d7..df0e586aee 100644
--- a/plugins/python/krita_script_starter/kritapykrita_krita_script_starter.desktop
+++ b/plugins/python/krita_script_starter/kritapykrita_krita_script_starter.desktop
@@ -1,49 +1,51 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=krita_script_starter
X-Python-2-Compatible=false
X-Krita-Manual=Manual.html
Name=Krita Script Starter
Name[ca]=Iniciador de scripts del Krita
Name[ca@valencia]=Iniciador de scripts del Krita
Name[cs]=Spouštěč skriptů Krita
Name[en_GB]=Krita Script Starter
Name[es]=Iniciador de guiones de Krita
Name[et]=Krita skriptialustaja
Name[eu]=Krita-ren script abiarazlea
+Name[fr]=Lanceur de scripts Krita
Name[gl]=Iniciador de scripts de Krita
Name[it]=Iniziatore di script per Krita
Name[ko]=Krita 스크립트 시작 도구
Name[nl]=Script-starter van Krita
Name[nn]=Krita skriptbyggjar
Name[pl]=Starter skryptów Krity
Name[pt]=Inicialização do Programa do Krita
Name[pt_BR]=Inicializador de script do Krita
Name[sv]=Krita skriptstart
Name[tr]=Krita Betik Başlatıcı
Name[uk]=Створення скрипту Krita
Name[x-test]=xxKrita Script Starterxx
Name[zh_CN]=Krita 空脚本生成器
Name[zh_TW]=Krita 指令啟動器
Comment=Create the metadata and file structure for a new Krita script
Comment[ca]=Crea les metadades i l'estructura de fitxers d'un script nou del Krita
Comment[ca@valencia]=Crea les metadades i l'estructura de fitxers d'un script nou del Krita
Comment[en_GB]=Create the metadata and file structure for a new Krita script
Comment[es]=Crear los metadatos y la estructura de archivos para un nuevo guion de Krita
Comment[et]=Uue Krita skripti metaandmete ja failistruktuuri loomine
Comment[eu]=Sortu Krita-script berri baterako meta-datuak eta fitxategi egitura
+Comment[fr]=Créer les métadonnées et la structure du fichier pour le nouveau script Krita
Comment[gl]=Crear os metadatos e a estrutura de ficheiros para un novo script de Krita.
Comment[it]=Crea i metadati e la struttura dei file per un nuovo script di Krita
Comment[ko]=새 Krita 스크립트에 대한 메타데이터 및 파일 구조 생성
Comment[nl]=Maak de metagegevens en bestandsstructuur voor een nieuw Krita-script
Comment[nn]=Generer metadata og filstruktur for nye Krita-skript
Comment[pl]=Utwórz metadane i strukturę plików dla nowego skryptu Krity
Comment[pt]=Cria os meta-dados e a estrutura de ficheiros para um novo programa do Krita
Comment[pt_BR]=Cria os metadados e a estrutura de arquivos para um novo script do Krita
Comment[sv]=Skapa metadata och filstruktur för ett nytt Krita-skript
Comment[tr]=Yeni Krita betiği için üstveri ve dosya yapısı oluştur
Comment[uk]=Створення метаданих і структури файлів для нового скрипту Krita
Comment[x-test]=xxCreate the metadata and file structure for a new Krita scriptxx
Comment[zh_CN]=为新的 Krita 脚本创建元数据及文件结构
Comment[zh_TW]=為新的 Krita 指令稿建立中繼資料和檔案建構體
diff --git a/plugins/python/mixer_slider_docker/kritapykrita_mixer_slider_docker.desktop b/plugins/python/mixer_slider_docker/kritapykrita_mixer_slider_docker.desktop
index 0deb3abd84..508c9b149b 100644
--- a/plugins/python/mixer_slider_docker/kritapykrita_mixer_slider_docker.desktop
+++ b/plugins/python/mixer_slider_docker/kritapykrita_mixer_slider_docker.desktop
@@ -1,42 +1,45 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=mixer_slider_docker
X-Python-2-Compatible=false
X-Krita-Manual=Manual.html
Name=Mixer Slider docker
Name[ca]=Acoblador Control lliscant del mesclador
Name[ca@valencia]=Acoblador Control lliscant del mesclador
Name[en_GB]=Mixer Slider docker
Name[es]=Panel del deslizador del mezclador
Name[et]=Mikseri liuguri dokk
Name[eu]=Nahasle graduatzaile panela
+Name[fr]=Panneau de mixage avec curseurs
Name[it]=Area di aggancio cursore di miscelazione
Name[ko]=믹서 슬라이더 도커
Name[nl]=Vastzetter van schuifregelaar van mixer
Name[nn]=Fargeblandings-dokkpanel
Name[pt]=Área da Barra de Mistura
Name[pt_BR]=Docker do misturador de barras
+Name[sk]=Panel posuvníkov miešača
Name[sv]=Dockningsfönster för blandningsreglage
Name[uk]=Бічна панель повзунка мікшера
Name[x-test]=xxMixer Slider dockerxx
Name[zh_CN]=混色滑动条工具面板
Name[zh_TW]=混色滑動條工具面板
Comment=A color slider.
Comment[ca]=Un control lliscant per al color.
Comment[ca@valencia]=Un control lliscant per al color.
Comment[en_GB]=A colour slider.
Comment[es]=Deslizador de color.
Comment[et]=Värviliugur.
Comment[eu]=Kolore graduatzaile bat.
+Comment[fr]=Un curseur pour les couleurs.
Comment[it]=Cursore del colore.
Comment[ko]=컬러 슬라이더입니다.
Comment[nl]=Een schuifregelaar voor kleur
Comment[nn]=Palett med fargeovergangar
Comment[pt]=Uma barra de cores.
Comment[pt_BR]=Uma barra de cores.
Comment[sv]=Ett färgreglage.
Comment[uk]=Повзунок кольору.
Comment[x-test]=xxA color slider.xx
Comment[zh_CN]=这是一个通过滑动条控制颜色的面板。
Comment[zh_TW]=色彩滑動條。
diff --git a/plugins/python/plugin_importer/kritapykrita_plugin_importer.desktop b/plugins/python/plugin_importer/kritapykrita_plugin_importer.desktop
index a8e80cca8e..192ff576df 100644
--- a/plugins/python/plugin_importer/kritapykrita_plugin_importer.desktop
+++ b/plugins/python/plugin_importer/kritapykrita_plugin_importer.desktop
@@ -1,50 +1,53 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=plugin_importer
X-Python-2-Compatible=false
X-Krita-Manual=manual.html
Name=Python Plugin Importer
Name[ca]=Importador de connectors en Python
Name[ca@valencia]=Importador de connectors en Python
Name[cs]=Importér modulů pro Python
Name[en_GB]=Python Plugin Importer
Name[es]=Importador de complementos de Python
Name[et]=Pythoni plugina importija
Name[eu]=Python plugin inportatzaile bat
+Name[fr]=Importateur de modules externes Python
Name[gl]=Importador de complementos de Python
Name[it]=Importatore estensioni Python
Name[ko]=Python 플러그인 가져오기 도구
Name[nl]=Importeur van Plugin voor Python
Name[nn]=Importering av Python-tillegg
Name[pl]=Import wtyczek Pythona
Name[pt]=Importador de 'Plugins' do Python
Name[pt_BR]=Importador de plugins em Python
+Name[sk]=Importér zásuvných modulov Python
Name[sv]=Python-insticksimport
Name[tr]=Python Eklenti İçe Aktarıcı
Name[uk]=Засіб імпортування додатків Python
Name[x-test]=xxPython Plugin Importerxx
Name[zh_CN]=Python 插件导入器
Name[zh_TW]=Python 外掛程式匯入工具
Comment=Imports Python plugins from zip files.
Comment[ca]=Importa connectors en Python a partir de fitxers «zip».
Comment[ca@valencia]=Importa connectors en Python a partir de fitxers «zip».
Comment[cs]=Importuje moduly Pythonu ze souborů zip.
Comment[en_GB]=Imports Python plugins from zip files.
Comment[es]=Importa complementos de Python desde archivos zip.
Comment[et]=Pythoni pluginate import zip-failidest.
Comment[eu]=Python pluginak inportatzen ditu zip fitxategietatik.
+Comment[fr]=Importe les modules externes Python à partir des fichiers « ZIP ».
Comment[gl]=Importa complementos de Python de ficheiros zip.
Comment[it]=Importa le estensioni Python dai file compressi.
Comment[ko]=ZIP 파일에서 Python 플러그인을 가져옵니다.
Comment[nl]=Importeert Python-plug-ins uit zip-bestanden.
Comment[nn]=Importerer Python-baserte programtillegg frå .zip-filer
Comment[pl]=Importuj wtyczki Pythona z plików zip.
Comment[pt]=Importa os 'plugins' em Python a partir de ficheiros Zip.
Comment[pt_BR]=Importa plugins em Python a partir de arquivos zip.
Comment[sv]=Importerar Python-insticksprogram från zip-filer.
Comment[tr]=Python eklentilerini zip dosyasından içe aktarır.
Comment[uk]=Імпортує додатки Python з файлів zip.
Comment[x-test]=xxImports Python plugins from zip files.xx
Comment[zh_CN]=从 zip 文件导入 Python 插件。
Comment[zh_TW]=匯入 Zip 檔案中的 Python 外掛程式。
diff --git a/plugins/python/quick_settings_docker/kritapykrita_quick_settings_docker.desktop b/plugins/python/quick_settings_docker/kritapykrita_quick_settings_docker.desktop
index fc7278f2ed..b59d1cd7c5 100644
--- a/plugins/python/quick_settings_docker/kritapykrita_quick_settings_docker.desktop
+++ b/plugins/python/quick_settings_docker/kritapykrita_quick_settings_docker.desktop
@@ -1,57 +1,58 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=quick_settings_docker
X-Python-2-Compatible=true
X-Krita-Manual=Manual.html
Name=Quick Settings Docker
Name[ar]=رصيف بإعدادات سريعة
Name[ca]=Acoblador Arranjament ràpid
Name[ca@valencia]=Acoblador Arranjament ràpid
Name[cs]=Dok pro rychlé nastavení
Name[el]=Προσάρτηση γρήγορων ρυθμίσεων
Name[en_GB]=Quick Settings Docker
Name[es]=Panel de ajustes rápidos
Name[et]=Kiirseadistuste dokk
Name[eu]=Ezarpen azkarren panela
Name[fi]=Pika-asetustelakka
Name[fr]=Réglages rapides
Name[gl]=Doca de configuración rápida
Name[it]=Area di aggancio delle impostazioni rapide
Name[ko]=빠른 설정 도킹 패널
Name[nl]=Verankering voor snelle instellingen
Name[nn]=Snøgginnstillingar-dokkpanel
Name[pl]=Dok szybkich ustawień
Name[pt]=Área de Configuração Rápida
Name[pt_BR]=Área de configuração rápida
+Name[sk]=Panel rýchlych nastavení
Name[sv]=Dockningspanel med snabbinställningar
Name[tr]=Hızlı Ayarlar Doku
Name[uk]=Панель швидких параметрів
Name[x-test]=xxQuick Settings Dockerxx
Name[zh_CN]=快速设置工具面板
Name[zh_TW]=「快速設定」面板
Comment=A Python-based docker for quickly changing brush size and opacity.
Comment[ar]=رصيف بِ‍«پيثون» لتغيير حجم الفرشاة وشفافيّتها بسرعة.
Comment[ca]=Un acoblador basat en Python per a canviar ràpidament la mida i l'opacitat del pinzell.
Comment[ca@valencia]=Un acoblador basat en Python per a canviar ràpidament la mida i l'opacitat del pinzell.
Comment[el]=Ένα εργαλείο προσάρτησης σε Python για γρήγορη αλλαγή του μεγέθους και της αδιαφάνειας του πινέλου.
Comment[en_GB]=A Python-based docker for quickly changing brush size and opacity.
Comment[es]=Un panel basado en Python para cambiar rápidamente el tamaño y la opacidad del pincel.
Comment[et]=Pythoni-põhine dokk pintsli suuruse ja läbipaistmatuse kiireks muutmiseks.
Comment[eu]=Isipu-neurria eta -opakotasuna aldatzeko Python-oinarridun panel bat.
Comment[fi]=Python-pohjainen telakka siveltimen koon ja läpikuultavuuden nopean muuttamiseen.
Comment[fr]=Panneau en python pour modifier rapidement la taille et l'opacité des brosses.
Comment[gl]=Unha doca baseada en Python para cambiar rapidamente a opacidade e o tamaño dos pinceis.
Comment[it]=Un'area di aggancio basata su Python per cambiare rapidamente la dimensione del pennello e l'opacità.
Comment[ko]=브러시 크기와 불투명도를 빠르게 변경할 수 있는 Python 기반 도킹 패널입니다.
Comment[nl]=Een op Python gebaseerde docker voor snel wijzigen van penseelgrootte en dekking.
Comment[nn]=Python-basert dokkpanel for kjapp endring av penselstorleik/-tettleik
Comment[pl]=Dok oparty na Pythonie do szybkiej zmiany rozmiaru i nieprzezroczystości pędzla.
Comment[pt]=Uma área acoplável em Python para mudar rapidamente o tamanho e opacidade do pincel.
Comment[pt_BR]=Uma área acoplável em Python para mudar rapidamente o tamanho e opacidade do pincel.
Comment[sv]=En Python-baserad dockningspanel för att snabbt ändra penselstorlek och ogenomskinlighet.
Comment[tr]=Fırça boyutunu ve matlığını hızlıca değiştirmek için Python-tabanlı bir dok.
Comment[uk]=Панель на основі мови програмування Python для швидкої зміни розміру та непрозорості пензля.
Comment[x-test]=xxA Python-based docker for quickly changing brush size and opacity.xx
Comment[zh_CN]=这是一个基于 Python 的工具面板,用于快速更改笔刷尺寸和透明度。
Comment[zh_TW]=基於 Python 的面板,用於快速變更筆刷尺寸和不透明度。
diff --git a/plugins/python/scriptdocker/kritapykrita_scriptdocker.desktop b/plugins/python/scriptdocker/kritapykrita_scriptdocker.desktop
index d9f15ec2b1..3918d516a5 100644
--- a/plugins/python/scriptdocker/kritapykrita_scriptdocker.desktop
+++ b/plugins/python/scriptdocker/kritapykrita_scriptdocker.desktop
@@ -1,54 +1,56 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=scriptdocker
X-Python-2-Compatible=false
Name=Script Docker
Name[ar]=رصيف سكربتات
Name[ca]=Acoblador Script
Name[ca@valencia]=Acoblador Script
Name[cs]=Dok skriptu
Name[el]=Προσάρτηση σεναρίων
Name[en_GB]=Script Docker
Name[es]=Panel de guiones
Name[et]=Skriptidokk
Name[eu]=Script-panela
Name[fi]=Skriptitelakka
Name[fr]=Panneau de script
Name[gl]=Doca de scripts
Name[it]=Area di aggancio degli script
Name[ko]=스크립트 도킹 패널
Name[nl]=Verankering van scripts
Name[nn]=Skript-dokkpanel
Name[pl]=Dok skryptów
Name[pt]=Área de Programas
Name[pt_BR]=Área de scripts
+Name[sk]=Panel skriptov
Name[sv]=Dockningsfönster för skript
Name[tr]=Betik Doku
Name[uk]=Бічна панель скриптів
Name[x-test]=xxScript Dockerxx
Name[zh_CN]=脚本工具面板
Name[zh_TW]=「指令稿」面板
Comment=A Python-based docker for create actions and point to Python scripts
Comment[ar]=رصيف بِ‍«پيثون» لإنشاء الإجراءات والإشارة إلى سكربتات «پيثون»
Comment[ca]=Un acoblador basat en Python per a crear accions i apuntar a scripts en Python
Comment[ca@valencia]=Un acoblador basat en Python per a crear accions i apuntar a scripts en Python
Comment[el]=Ένα εργαλείο προσάρτησης σε Python για τη δημιουργία ενεργειών και τη δεικτοδότηση σεναρίων σε Python
Comment[en_GB]=A Python-based docker for create actions and point to Python scripts
Comment[es]=Un panel basado en Python para crear y apuntar a guiones de Python
Comment[et]=Pythoni-põhine dokk toimingute loomiseks ja viitamiseks Pythoni skriptidele
Comment[eu]=Python-oinarridun panel bat.
+Comment[fr]=Un panneau réalisé en Python pour créer des actions et s'interfacer avec des scripts Python
Comment[gl]=Unha doca escrita en Python para crear accións e apuntar a scripts escritos en Python.
Comment[it]=Un'area di aggancio basata su Python per creare azioni e scegliere script Python
Comment[ko]=작업 생성 및 Python 스크립트를 가리키는 Python 기반 도킹 패널
Comment[nl]=Een op Python gebaseerde vastzetter voor aanmaakacties en wijzen naar Python-scripts
Comment[nn]=Python-basert dokkpanel for å laga handlingar og peika til Python-skript
Comment[pl]=Dok oparty na pythonie do tworzenia działań i punktów dla skryptów pythona
Comment[pt]=Uma área acoplável, feita em Python, para criar acções e apontar para programas em Python
Comment[pt_BR]=Uma área acoplável feita em Python para criar ações e apontar para scripts em Python
Comment[sv]=Ett Python-baserat dockningsfönster för att skapa åtgärder och peka ut Python-skript
Comment[tr]=Eylemler oluşturmak ve Python betiklerine yönlendirmek için Python-tabanlı bir dok
Comment[uk]=Бічна панель для створення дій і керування скриптами на основі Python.
Comment[x-test]=xxA Python-based docker for create actions and point to Python scriptsxx
Comment[zh_CN]=这是一个基于 Python 的工具面板,用于创建操作,并将他们指向 Python 脚本。
Comment[zh_TW]=基於 Python 的面板,用於建立動作並指向 Python 指令稿
diff --git a/plugins/python/scripter/kritapykrita_scripter.desktop b/plugins/python/scripter/kritapykrita_scripter.desktop
index d157294c5e..4aa74a9459 100644
--- a/plugins/python/scripter/kritapykrita_scripter.desktop
+++ b/plugins/python/scripter/kritapykrita_scripter.desktop
@@ -1,53 +1,55 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=scripter
X-Python-2-Compatible=true
X-Krita-Manual=Manual.html
Name=Scripter
Name[ca]=Scripter
Name[ca@valencia]=Scripter
Name[de]=Scripter
Name[el]=Σενάρια
Name[en_GB]=Scripter
Name[es]=Guionador
Name[et]=Skriptija
Name[eu]=Script egilea
Name[fr]=Scripter
Name[gl]=Executor de scripts
Name[it]=Scripter
Name[ko]=스크립트 도구
Name[nl]=Scriptmaker
Name[nn]=Skriptkøyrer
Name[pl]=Skrypter
Name[pt]=Programador
Name[pt_BR]=Criador de scripts
+Name[sk]=Skriptér
Name[sv]=Skriptgenerator
Name[tr]=Betik yazarı
Name[uk]=Скриптер
Name[x-test]=xxScripterxx
Name[zh_CN]=脚本工具
Name[zh_TW]=指令稿編寫者
Comment=Plugin to execute ad-hoc Python code
Comment[ca]=Connector per executar codi «ad hoc» en Python
Comment[ca@valencia]=Connector per executar codi «ad hoc» en Python
Comment[el]=Πρόσθετο για την εκτέλεση συγκεκριμένου κώδικα Python
Comment[en_GB]=Plugin to execute ad-hoc Python code
Comment[es]=Complemento para ejecutar código Python a medida
Comment[et]=Plugin kohapeal loodud Pythoni koodi täitmiseks
Comment[eu]=Berariaz egindako Python kodea exekutatzeko plugina
Comment[fi]=Liitännäinen satunnaisen Python-koodin suorittamiseksi
+Comment[fr]=Module externe pour exécuter du code Python « ad-hoc »
Comment[gl]=Complemento para executar código de Python escrito no momento.
Comment[it]=Estensione per eseguire ad-hoc codice Python
Comment[ko]=즉석에서 Python 코드를 실행하는 플러그인
Comment[nl]=Plug-in om ad-hoc Python code uit te voeren
Comment[nn]=Programtillegg for køyring av ad hoc Python-kode
Comment[pl]=Wtyczka do wykonywania kodu Pythona ad-hoc
Comment[pt]='Plugin' para executar código em Python arbitrário
Comment[pt_BR]=Plugin para executar código em Python arbitrário
Comment[sv]=Insticksprogram för att köra godtycklig Python-kod
Comment[tr]=Geçici Python kodu çalıştırmak için eklenti
Comment[uk]=Додаток для виконання апріорного коду Python
Comment[x-test]=xxPlugin to execute ad-hoc Python codexx
Comment[zh_CN]=用于执行当场编写的 Python 代码的插件
Comment[zh_TW]=外掛程式,用於執行特定 Python 程式碼
diff --git a/plugins/python/tenbrushes/kritapykrita_tenbrushes.desktop b/plugins/python/tenbrushes/kritapykrita_tenbrushes.desktop
index 8b4ace4635..d4e8bfb307 100644
--- a/plugins/python/tenbrushes/kritapykrita_tenbrushes.desktop
+++ b/plugins/python/tenbrushes/kritapykrita_tenbrushes.desktop
@@ -1,56 +1,58 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=tenbrushes
X-Python-2-Compatible=true
X-Krita-Manual=Manual.html
Name=Ten Brushes
Name[ar]=عشرُ فُرش
Name[ca]=Deu pinzells
Name[ca@valencia]=Deu pinzells
Name[cs]=Deset štětců
Name[el]=Δέκα πινέλα
Name[en_GB]=Ten Brushes
Name[es]=Diez pinceles
Name[et]=Kümme pintslit
Name[eu]=Hamar isipu
Name[fi]=Kymmenen sivellintä
Name[fr]=Raccourcis des préréglages de brosses
Name[gl]=Dez pinceis
Name[is]=Tíu penslar
Name[it]=Dieci pennelli
Name[ko]=브러시 10개
Name[nl]=Tien penselen
Name[nn]=Ti penslar
Name[pl]=Dziesięć pędzli
Name[pt]=Dez Pincéis
Name[pt_BR]=Dez pincéis
+Name[sk]=10 Štetcov
Name[sv]=Tio penslar
Name[tr]=On Fırça
Name[uk]=Десять пензлів
Name[x-test]=xxTen Brushesxx
Name[zh_CN]=常用笔刷快捷键
Name[zh_TW]=10 個筆刷
Comment=Assign a preset to ctrl-1 to ctrl-0
Comment[ca]=Assigna una predefinició des de Ctrl-1 a Ctrl-0
Comment[ca@valencia]=Assigna una predefinició des de Ctrl-1 a Ctrl-0
Comment[el]=Αντιστοίχιση προκαθορισμένου από ctrl-1 στο ctrl-0
Comment[en_GB]=Assign a preset to ctrl-1 to ctrl-0
Comment[es]=Asignar una preselección a Ctrl-1 hasta Ctrl-0
Comment[et]=Valmisvaliku omistamine Ctrl+1 kuni Ctrl+0
Comment[eu]=Aurrezarpena ezarri ktrl-1'etik ktrl-0'ra arte
Comment[fi]=Kytke esiasetukset Ctrl-1:stä Ctrl-0:aan
+Comment[fr]=Associer un préréglage à de la touche « CRTL - 1 » à « CTRL - 2 »
Comment[gl]=Asigne unha predefinición do Ctrl+1 ao Ctrl+0.
Comment[it]=Assegna una preimpostazione per ctrl-1 a ctrl-0
Comment[ko]=Ctrl+1부터 Ctrl+0까지 프리셋 할당
Comment[nl]=Een voorinstelling toekennen aan Ctrl-1 tot Ctrl-0
Comment[nn]=Byt til ferdigpenslar med «Ctrl + 1» til «Ctrl + 0»
Comment[pl]=Przypisz nastawę do ctrl-1 lub ctrl-0
Comment[pt]=Atribuir uma predefinição de Ctrl-1 a Ctrl-0
Comment[pt_BR]=Atribuir uma predefinição de Ctrl-1 a Ctrl-0
Comment[sv]=Tilldela en förinställning för Ctrl+1 till Ctrl+0
Comment[tr]= ctrl-1 ve ctrl-0 için ayar atama
Comment[uk]=Прив’язування наборів налаштувань до скорочень від ctrl-1 до ctrl-0
Comment[x-test]=xxAssign a preset to ctrl-1 to ctrl-0xx
Comment[zh_CN]=将预设分配给由 Ctrl+1 到 Ctrl+0 的快捷键
Comment[zh_TW]=將預設指定給 ctrl-1 至 ctrl-0
diff --git a/plugins/python/tenscripts/kritapykrita_tenscripts.desktop b/plugins/python/tenscripts/kritapykrita_tenscripts.desktop
index c8341c94e6..bbe83ba7b7 100644
--- a/plugins/python/tenscripts/kritapykrita_tenscripts.desktop
+++ b/plugins/python/tenscripts/kritapykrita_tenscripts.desktop
@@ -1,56 +1,57 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=tenscripts
X-Python-2-Compatible=true
X-Krita-Manual=Manual.html
Name=Ten Scripts
Name[ar]=عشرُ سكربتات
Name[ca]=Deu scripts
Name[ca@valencia]=Deu scripts
Name[en_GB]=Ten Scripts
Name[es]=Diez guiones
Name[et]=Kümme skripti
Name[eu]=Hamar script
Name[fi]=Kymmenen skriptiä
Name[fr]=Raccourcis des scripts
Name[gl]=Dez scripts
Name[is]=Tíu skriftur
Name[it]=Dieci script
Name[ko]=스크립트 10개
Name[nl]=Tien scripts
Name[nn]=Ti skript
Name[pl]=Skrypty Ten
Name[pt]=Dez Programas
Name[pt_BR]=Dez scripts
+Name[sk]=Desať skriptov
Name[sl]=Deset skriptov
Name[sv]=Tio skript
Name[tr]=On Betik
Name[uk]=Десять скриптів
Name[x-test]=xxTen Scriptsxx
Name[zh_CN]=常用脚本快捷键
Name[zh_TW]=10 個指令稿
Comment=A Python-based plugin for creating ten actions and assign them to Python scripts
Comment[ar]=ملحقة بِ‍«پيثون» لإنشاء ١٠ إجراءات وإسنادها إلى سكربتات «پيثون»
Comment[ca]=Un connector basat en Python per a crear deu accions i assignar-les a scripts en Python
Comment[ca@valencia]=Un connector basat en Python per a crear deu accions i assignar-les a scripts en Python
Comment[en_GB]=A Python-based plugin for creating ten actions and assign them to Python scripts
Comment[es]=Un complemento basado en Python para crear diez acciones y asignarlas a guiones de Python
Comment[et]=Pythoni-põhine plugin kümne toimingu loomiseks ja nende omistamiseks Pythoni skriptidele
Comment[eu]=Hamar ekintza sortu eta haiek Python-scriptei esleitzeko Python-oinarridun plugin bat
Comment[fi]=Python-pohjainen liitännäinen kymmenen toiminnon luomiseksi kytkemiseksi Python-skripteihin
-Comment[fr]=Module externe basé sur Python pour créer dix actions et les assigner à des scripts Python
+Comment[fr]=Module externe développé à partir de Python pour créer dix actions et les assigner à des scripts Python
Comment[gl]=Un complemento escrito en Python para crear dez accións e asignalas a scripts escritos en Python.
Comment[it]=Un'estensione basata su Python per creare dieci azioni e assegnarle a script Python
Comment[ko]=작업 10개를 생성하고 이를 Python 스크립트에 할당하는 Python 기반 플러그인
Comment[nl]=Een op Python gebaseerde plug-in voor aanmaken van tien acties en ze dan toewijzen aan Python-scripts
Comment[nn]=Python-basert tillegg som legg til ti handlingar du kan tildela til Python-skript
Comment[pl]=Wtyczka oparta na Pythonie do tworzenia działań i przypisywanie ich skryptom Pythona
Comment[pt]=Um 'plugin' feito em Python para criar dez acções e atribuí-las a programas em Python
Comment[pt_BR]=Um plugin feito em Python para criar dez ações e atribuí-las a scripts em Python
Comment[sv]=Ett Python-baserat insticksprogram för att skapa tio åtgärder och tilldela dem till Python-skript
Comment[tr]=On eylem oluşturmak ve Python betiklerine atamak için Python tabanlı bir eklenti
Comment[uk]=Скрипт на основі Python для створення десяти дій і прив'язування до них скриптів Python
Comment[x-test]=xxA Python-based plugin for creating ten actions and assign them to Python scriptsxx
Comment[zh_CN]=这是一个基于 Python 编写的插件,它可以创建十种操作,并将它们指定到特定 Python 脚本。
Comment[zh_TW]=基於 Python 的外掛程式,用於建立 10 個動作並且將它們指定給 Python 指令稿
diff --git a/plugins/tools/basictools/kis_tool_move.cc b/plugins/tools/basictools/kis_tool_move.cc
index 1b1af76d28..b1da864a00 100644
--- a/plugins/tools/basictools/kis_tool_move.cc
+++ b/plugins/tools/basictools/kis_tool_move.cc
@@ -1,715 +1,780 @@
/*
* Copyright (c) 1999 Matthias Elter <me@kde.org>
* 1999 Michael Koch <koch@kde.org>
* 2002 Patrick Julien <freak@codepimps.org>
* 2004 Boudewijn Rempt <boud@valdyas.org>
* 2016 Michael Abrahams <miabraha@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_tool_move.h"
#include <QPoint>
#include "kis_cursor.h"
#include "kis_selection.h"
#include "kis_canvas2.h"
#include "kis_image.h"
#include "kis_tool_utils.h"
#include "kis_paint_layer.h"
#include "strokes/move_stroke_strategy.h"
#include "kis_tool_movetooloptionswidget.h"
#include "strokes/move_selection_stroke_strategy.h"
#include "kis_resources_snapshot.h"
#include "kis_action_registry.h"
#include "krita_utils.h"
#include <KisViewManager.h>
#include <KisDocument.h>
#include "kis_node_manager.h"
#include "kis_selection_manager.h"
#include "kis_signals_blocker.h"
#include <boost/operators.hpp>
#include "KisMoveBoundsCalculationJob.h"
struct KisToolMoveState : KisToolChangesTrackerData, boost::equality_comparable<KisToolMoveState>
{
KisToolMoveState(QPoint _accumulatedOffset) : accumulatedOffset(_accumulatedOffset) {}
KisToolChangesTrackerData* clone() const override { return new KisToolMoveState(*this); }
bool operator ==(const KisToolMoveState &rhs) {
return accumulatedOffset == rhs.accumulatedOffset;
}
QPoint accumulatedOffset;
};
KisToolMove::KisToolMove(KoCanvasBase *canvas)
: KisTool(canvas, KisCursor::moveCursor())
, m_updateCursorCompressor(100, KisSignalCompressor::FIRST_ACTIVE)
{
setObjectName("tool_move");
m_showCoordinatesAction = action("movetool-show-coordinates");
m_showCoordinatesAction = action("movetool-show-coordinates");
connect(&m_updateCursorCompressor, SIGNAL(timeout()), this, SLOT(resetCursorStyle()));
m_optionsWidget = new MoveToolOptionsWidget(0, currentImage()->xRes(), toolId());
// See https://bugs.kde.org/show_bug.cgi?id=316896
QWidget *specialSpacer = new QWidget(m_optionsWidget);
specialSpacer->setObjectName("SpecialSpacer");
specialSpacer->setFixedSize(0, 0);
m_optionsWidget->layout()->addWidget(specialSpacer);
m_optionsWidget->setFixedHeight(m_optionsWidget->sizeHint().height());
m_showCoordinatesAction->setChecked(m_optionsWidget->showCoordinates());
m_optionsWidget->slotSetTranslate(m_handlesRect.topLeft() + currentOffset());
connect(m_optionsWidget, SIGNAL(sigSetTranslateX(int)), SLOT(moveBySpinX(int)), Qt::UniqueConnection);
connect(m_optionsWidget, SIGNAL(sigSetTranslateY(int)), SLOT(moveBySpinY(int)), Qt::UniqueConnection);
connect(m_optionsWidget, SIGNAL(sigRequestCommitOffsetChanges()), this, SLOT(commitChanges()), Qt::UniqueConnection);
connect(this, SIGNAL(moveInNewPosition(QPoint)), m_optionsWidget, SLOT(slotSetTranslate(QPoint)), Qt::UniqueConnection);
}
KisToolMove::~KisToolMove()
{
endStroke();
}
void KisToolMove::resetCursorStyle()
{
- KisTool::resetCursorStyle();
-
if (!isActive()) return;
- KisImageSP image = this->image();
- KisResourcesSnapshotSP resources =
- new KisResourcesSnapshot(image, currentNode(), canvas()->resourceManager());
- KisSelectionSP selection = resources->activeSelection();
- KisNodeList nodes = fetchSelectedNodes(moveToolMode(), &m_lastCursorPos, selection);
- if (nodes.isEmpty()) {
- canvas()->setCursor(Qt::ForbiddenCursor);
- }
-}
-
-KisNodeList KisToolMove::fetchSelectedNodes(MoveToolMode mode, const QPoint *pixelPoint, KisSelectionSP selection)
-{
- KisNodeList nodes;
-
- KisImageSP image = this->image();
- if (mode != MoveSelectedLayer && pixelPoint) {
- const bool wholeGroup = !selection && mode == MoveGroup;
- KisNodeSP node = KisToolUtils::findNode(image->root(), *pixelPoint, wholeGroup);
- if (node) {
- nodes = {node};
+ bool canMove = true;
+
+ if (m_strokeId && m_currentlyUsingSelection) {
+ /// noop; whatever the cursor position, we always show move
+ /// cursor, because we don't use 'layer under cursor' mode
+ /// for moving selections
+ } else if (m_strokeId && !m_currentlyUsingSelection) {
+ /// we cannot pick layer's pixel data while the stroke is running,
+ /// because it may run in lodN mode; therefore, we delegate this
+ /// work to the stroke itself
+ if (m_currentMode != MoveSelectedLayer &&
+ (m_handlesRect.isEmpty() ||
+ !m_handlesRect.translated(currentOffset()).contains(m_lastCursorPos))) {
+
+ image()->addJob(m_strokeId, new MoveStrokeStrategy::PickLayerData(m_lastCursorPos));
+ return;
+ }
+ } else {
+ KisResourcesSnapshotSP resources =
+ new KisResourcesSnapshot(this->image(), currentNode(), canvas()->resourceManager());
+ KisSelectionSP selection = resources->activeSelection();
+
+ KisPaintLayerSP paintLayer =
+ dynamic_cast<KisPaintLayer*>(this->currentNode().data());
+
+ const bool canUseSelectionMode =
+ paintLayer && selection &&
+ !selection->selectedRect().isEmpty() &&
+ !selection->selectedExactRect().isEmpty();
+
+ if (!canUseSelectionMode) {
+ KisNodeSelectionRecipe nodeSelection =
+ KisNodeSelectionRecipe(
+ this->selectedNodes(),
+ (KisNodeSelectionRecipe::SelectionMode)moveToolMode(),
+ m_lastCursorPos);
+
+ if (nodeSelection.selectNodesToProcess().isEmpty()) {
+ canMove = false;
+ }
}
}
- if (nodes.isEmpty()) {
- nodes = this->selectedNodes();
-
- KritaUtils::filterContainer<KisNodeList>(nodes,
- [](KisNodeSP node) {
- return node->isEditable();
- });
+ if (canMove) {
+ KisTool::resetCursorStyle();
+ } else {
+ useCursor(Qt::ForbiddenCursor);
}
-
- return nodes;
}
bool KisToolMove::startStrokeImpl(MoveToolMode mode, const QPoint *pos)
{
KisNodeSP node;
KisImageSP image = this->image();
KisResourcesSnapshotSP resources =
new KisResourcesSnapshot(image, currentNode(), canvas()->resourceManager());
KisSelectionSP selection = resources->activeSelection();
- KisNodeList nodes = fetchSelectedNodes(mode, pos, selection);
+ KisPaintLayerSP paintLayer =
+ dynamic_cast<KisPaintLayer*>(this->currentNode().data());
- if (nodes.size() == 1) {
- node = nodes.first();
- }
+ const bool canUseSelectionMode =
+ paintLayer && selection &&
+ !selection->selectedRect().isEmpty() &&
+ !selection->selectedExactRect().isEmpty();
- if (nodes.isEmpty()) {
- return false;
- }
+ if (pos) {
+ // finish stroke by clicking outside image bounds
+ if (m_strokeId && !image->bounds().contains(*pos)) {
+ endStroke();
+ return false;
+ }
- /**
- * If the target node has changed, the stroke should be
- * restarted. Otherwise just continue processing current node.
- */
- if (m_strokeId && !tryEndPreviousStroke(nodes)) {
- return true;
+ // restart stroke when the mode has changed or the user tried to
+ // pick another layer in "layer under cursor" mode.
+ if (m_strokeId &&
+ (m_currentMode != mode ||
+ m_currentlyUsingSelection != canUseSelectionMode ||
+ (!m_currentlyUsingSelection &&
+ mode != MoveSelectedLayer &&
+ !m_handlesRect.translated(currentOffset()).contains(*pos)))) {
+
+ endStroke();
+ }
}
- KisStrokeStrategy *strategy;
+ if (m_strokeId) return true;
- KisPaintLayerSP paintLayer = node ?
- dynamic_cast<KisPaintLayer*>(node.data()) : 0;
+ KisNodeList nodes;
- bool isMoveSelection = false;
+ KisStrokeStrategy *strategy;
- if (paintLayer && selection &&
- (!selection->selectedRect().isEmpty() &&
- !selection->selectedExactRect().isEmpty())) {
+ bool isMoveSelection = false;
+ if (canUseSelectionMode) {
+ KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(selection, false);
MoveSelectionStrokeStrategy *moveStrategy =
new MoveSelectionStrokeStrategy(paintLayer,
selection,
image.data(),
image.data());
connect(moveStrategy,
SIGNAL(sigHandlesRectCalculated(const QRect&)),
SLOT(slotHandlesRectCalculated(const QRect&)));
strategy = moveStrategy;
isMoveSelection = true;
+ nodes = {paintLayer};
} else {
+ KisNodeSelectionRecipe nodeSelection =
+ pos ?
+ KisNodeSelectionRecipe(
+ this->selectedNodes(),
+ (KisNodeSelectionRecipe::SelectionMode)mode,
+ *pos) :
+ KisNodeSelectionRecipe(this->selectedNodes());
+
MoveStrokeStrategy *moveStrategy =
- new MoveStrokeStrategy(nodes, image.data(), image.data());
+ new MoveStrokeStrategy(nodeSelection, image.data(), image.data());
connect(moveStrategy,
SIGNAL(sigHandlesRectCalculated(const QRect&)),
SLOT(slotHandlesRectCalculated(const QRect&)));
+ connect(moveStrategy,
+ SIGNAL(sigStrokeStartedEmpty()),
+ SLOT(slotStrokeStartedEmpty()));
+ connect(moveStrategy,
+ SIGNAL(sigLayersPicked(const KisNodeList&)),
+ SLOT(slotStrokePickedLayers(const KisNodeList&)));
strategy = moveStrategy;
+ nodes = nodeSelection.selectedNodes;
}
// disable outline feedback until the stroke calcualtes
// correct bounding rect
m_handlesRect = QRect();
m_strokeId = image->startStroke(strategy);
m_currentlyProcessingNodes = nodes;
+ m_currentlyUsingSelection = isMoveSelection;
+ m_currentMode = mode;
m_accumulatedOffset = QPoint();
if (!isMoveSelection) {
m_asyncUpdateHelper.startUpdateStream(image.data(), m_strokeId);
}
KIS_SAFE_ASSERT_RECOVER(m_changesTracker.isEmpty()) {
m_changesTracker.reset();
}
commitChanges();
return true;
}
QPoint KisToolMove::currentOffset() const
{
return m_accumulatedOffset + m_dragPos - m_dragStart;
}
void KisToolMove::notifyGuiAfterMove(bool showFloatingMessage)
{
if (!m_optionsWidget) return;
if (m_handlesRect.isEmpty()) return;
const QPoint currentTopLeft = m_handlesRect.topLeft() + currentOffset();
KisSignalsBlocker b(m_optionsWidget);
emit moveInNewPosition(currentTopLeft);
// TODO: fetch this info not from options widget, but from config
const bool showCoordinates = m_optionsWidget->showCoordinates();
if (showCoordinates && showFloatingMessage) {
KisCanvas2 *kisCanvas = static_cast<KisCanvas2*>(canvas());
kisCanvas->viewManager()->
showFloatingMessage(
i18nc("floating message in move tool",
"X: %1 px, Y: %2 px",
QLocale().toString(currentTopLeft.x()),
QLocale().toString(currentTopLeft.y())),
QIcon(), 1000, KisFloatingMessage::High);
}
}
bool KisToolMove::tryEndPreviousStroke(const KisNodeList &nodes)
{
if (!m_strokeId) return false;
bool strokeEnded = false;
if (!KritaUtils::compareListsUnordered(nodes, m_currentlyProcessingNodes)) {
endStroke();
strokeEnded = true;
}
return strokeEnded;
}
void KisToolMove::commitChanges()
{
KIS_SAFE_ASSERT_RECOVER_RETURN(m_strokeId);
QSharedPointer<KisToolMoveState> newState(new KisToolMoveState(m_accumulatedOffset));
KisToolMoveState *lastState = dynamic_cast<KisToolMoveState*>(m_changesTracker.lastState().data());
if (lastState && *lastState == *newState) return;
m_changesTracker.commitConfig(newState);
}
void KisToolMove::slotHandlesRectCalculated(const QRect &handlesRect)
{
m_handlesRect = handlesRect;
notifyGuiAfterMove(false);
}
+void KisToolMove::slotStrokeStartedEmpty()
+{
+ /**
+ * Since the choice of nodes for the operation happens in the
+ * stroke itself, it may happen that there are no nodes at all.
+ * In such a case, we should just cancel already started stroke.
+ */
+ cancelStroke();
+}
+
+void KisToolMove::slotStrokePickedLayers(const KisNodeList &nodes)
+{
+ if (nodes.isEmpty()) {
+ useCursor(Qt::ForbiddenCursor);
+ } else {
+ KisTool::resetCursorStyle();
+ }
+}
+
void KisToolMove::moveDiscrete(MoveDirection direction, bool big)
{
if (mode() == KisTool::PAINT_MODE) return; // Don't interact with dragging
if (!currentNode()) return;
if (!image()) return;
if (!currentNode()->isEditable()) return; // Don't move invisible nodes
if (startStrokeImpl(MoveSelectedLayer, 0)) {
setMode(KisTool::PAINT_MODE);
}
// Larger movement if "shift" key is pressed.
qreal scale = big ? m_optionsWidget->moveScale() : 1.0;
qreal moveStep = m_optionsWidget->moveStep() * scale;
const QPoint offset =
direction == Up ? QPoint( 0, -moveStep) :
direction == Down ? QPoint( 0, moveStep) :
direction == Left ? QPoint(-moveStep, 0) :
QPoint( moveStep, 0) ;
m_accumulatedOffset += offset;
image()->addJob(m_strokeId, new MoveStrokeStrategy::Data(m_accumulatedOffset));
notifyGuiAfterMove();
commitChanges();
setMode(KisTool::HOVER_MODE);
}
void KisToolMove::activate(ToolActivation toolActivation, const QSet<KoShape*> &shapes)
{
KisTool::activate(toolActivation, shapes);
m_actionConnections.addConnection(action("movetool-move-up"), SIGNAL(triggered(bool)),
this, SLOT(slotMoveDiscreteUp()));
m_actionConnections.addConnection(action("movetool-move-down"), SIGNAL(triggered(bool)),
this, SLOT(slotMoveDiscreteDown()));
m_actionConnections.addConnection(action("movetool-move-left"), SIGNAL(triggered(bool)),
this, SLOT(slotMoveDiscreteLeft()));
m_actionConnections.addConnection(action("movetool-move-right"), SIGNAL(triggered(bool)),
this, SLOT(slotMoveDiscreteRight()));
m_actionConnections.addConnection(action("movetool-move-up-more"), SIGNAL(triggered(bool)),
this, SLOT(slotMoveDiscreteUpMore()));
m_actionConnections.addConnection(action("movetool-move-down-more"), SIGNAL(triggered(bool)),
this, SLOT(slotMoveDiscreteDownMore()));
m_actionConnections.addConnection(action("movetool-move-left-more"), SIGNAL(triggered(bool)),
this, SLOT(slotMoveDiscreteLeftMore()));
m_actionConnections.addConnection(action("movetool-move-right-more"), SIGNAL(triggered(bool)),
this, SLOT(slotMoveDiscreteRightMore()));
m_canvasConnections.addUniqueConnection(qobject_cast<KisCanvas2*>(canvas())->viewManager()->nodeManager(), SIGNAL(sigUiNeedChangeSelectedNodes(KisNodeList)), this, SLOT(slotNodeChanged(KisNodeList)));
m_canvasConnections.addUniqueConnection(qobject_cast<KisCanvas2*>(canvas())->viewManager()->selectionManager(), SIGNAL(currentSelectionChanged()), this, SLOT(slotSelectionChanged()));
connect(m_showCoordinatesAction, SIGNAL(triggered(bool)), m_optionsWidget, SLOT(setShowCoordinates(bool)), Qt::UniqueConnection);
connect(m_optionsWidget, SIGNAL(showCoordinatesChanged(bool)), m_showCoordinatesAction, SLOT(setChecked(bool)), Qt::UniqueConnection);
connect(&m_changesTracker,
SIGNAL(sigConfigChanged(KisToolChangesTrackerDataSP)),
SLOT(slotTrackerChangedConfig(KisToolChangesTrackerDataSP)));
slotNodeChanged(this->selectedNodes());
}
void KisToolMove::paint(QPainter& gc, const KoViewConverter &converter)
{
Q_UNUSED(converter);
if (m_strokeId && !m_handlesRect.isEmpty()) {
QPainterPath handles;
handles.addRect(m_handlesRect.translated(currentOffset()));
QPainterPath path = pixelToView(handles);
paintToolOutline(&gc, path);
}
}
void KisToolMove::deactivate()
{
m_actionConnections.clear();
m_canvasConnections.clear();
disconnect(m_showCoordinatesAction, 0, this, 0);
disconnect(m_optionsWidget, 0, this, 0);
endStroke();
KisTool::deactivate();
}
void KisToolMove::requestStrokeEnd()
{
endStroke();
}
void KisToolMove::requestStrokeCancellation()
{
cancelStroke();
}
void KisToolMove::requestUndoDuringStroke()
{
if (!m_strokeId) return;
if (m_changesTracker.isEmpty()) {
cancelStroke();
} else {
m_changesTracker.requestUndo();
}
}
void KisToolMove::beginPrimaryAction(KoPointerEvent *event)
{
startAction(event, moveToolMode());
}
void KisToolMove::continuePrimaryAction(KoPointerEvent *event)
{
continueAction(event);
}
void KisToolMove::endPrimaryAction(KoPointerEvent *event)
{
endAction(event);
}
void KisToolMove::beginAlternateAction(KoPointerEvent *event, AlternateAction action)
{
// Ctrl+Right click toggles between moving current layer and moving layer w/ content
if (action == PickFgNode || action == PickBgImage) {
MoveToolMode mode = moveToolMode();
if (mode == MoveSelectedLayer) {
mode = MoveFirstLayer;
} else if (mode == MoveFirstLayer) {
mode = MoveSelectedLayer;
}
startAction(event, mode);
} else {
startAction(event, MoveGroup);
}
}
void KisToolMove::continueAlternateAction(KoPointerEvent *event, AlternateAction action)
{
Q_UNUSED(action)
continueAction(event);
}
void KisToolMove::endAlternateAction(KoPointerEvent *event, AlternateAction action)
{
Q_UNUSED(action)
endAction(event);
}
void KisToolMove::mouseMoveEvent(KoPointerEvent *event)
{
m_lastCursorPos = convertToPixelCoord(event).toPoint();
KisTool::mouseMoveEvent(event);
- if (moveToolMode() == MoveFirstLayer) {
+ if (moveToolMode() != MoveSelectedLayer ||
+ (m_strokeId && m_currentMode != MoveSelectedLayer)) {
+
m_updateCursorCompressor.start();
}
}
void KisToolMove::startAction(KoPointerEvent *event, MoveToolMode mode)
{
QPoint pos = convertToPixelCoordAndSnap(event).toPoint();
m_dragStart = pos;
m_dragPos = pos;
if (startStrokeImpl(mode, &pos)) {
setMode(KisTool::PAINT_MODE);
} else {
event->ignore();
m_dragPos = QPoint();
m_dragStart = QPoint();
}
qobject_cast<KisCanvas2*>(canvas())->updateCanvas();
}
void KisToolMove::continueAction(KoPointerEvent *event)
{
CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE);
if (!m_strokeId) return;
QPoint pos = convertToPixelCoordAndSnap(event).toPoint();
pos = applyModifiers(event->modifiers(), pos);
m_dragPos = pos;
drag(pos);
notifyGuiAfterMove();
qobject_cast<KisCanvas2*>(canvas())->updateCanvas();
}
void KisToolMove::endAction(KoPointerEvent *event)
{
CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE);
setMode(KisTool::HOVER_MODE);
if (!m_strokeId) return;
QPoint pos = convertToPixelCoordAndSnap(event).toPoint();
pos = applyModifiers(event->modifiers(), pos);
drag(pos);
m_accumulatedOffset += pos - m_dragStart;
m_dragStart = QPoint();
m_dragPos = QPoint();
commitChanges();
notifyGuiAfterMove();
qobject_cast<KisCanvas2*>(canvas())->updateCanvas();
}
void KisToolMove::drag(const QPoint& newPos)
{
KisImageWSP image = currentImage();
QPoint offset = m_accumulatedOffset + newPos - m_dragStart;
image->addJob(m_strokeId,
new MoveStrokeStrategy::Data(offset));
}
void KisToolMove::endStroke()
{
if (!m_strokeId) return;
if (m_asyncUpdateHelper.isActive()) {
m_asyncUpdateHelper.endUpdateStream();
}
KisImageSP image = currentImage();
image->endStroke(m_strokeId);
m_strokeId.clear();
m_changesTracker.reset();
m_currentlyProcessingNodes.clear();
+ m_currentlyUsingSelection = false;
+ m_currentMode = MoveSelectedLayer;
m_accumulatedOffset = QPoint();
qobject_cast<KisCanvas2*>(canvas())->updateCanvas();
}
void KisToolMove::slotTrackerChangedConfig(KisToolChangesTrackerDataSP state)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(m_strokeId);
KisToolMoveState *newState = dynamic_cast<KisToolMoveState*>(state.data());
KIS_SAFE_ASSERT_RECOVER_RETURN(newState);
if (mode() == KisTool::PAINT_MODE) return; // Don't interact with dragging
m_accumulatedOffset = newState->accumulatedOffset;
image()->addJob(m_strokeId, new MoveStrokeStrategy::Data(m_accumulatedOffset));
notifyGuiAfterMove();
}
void KisToolMove::slotMoveDiscreteLeft()
{
moveDiscrete(MoveDirection::Left, false);
}
void KisToolMove::slotMoveDiscreteRight()
{
moveDiscrete(MoveDirection::Right, false);
}
void KisToolMove::slotMoveDiscreteUp()
{
moveDiscrete(MoveDirection::Up, false);
}
void KisToolMove::slotMoveDiscreteDown()
{
moveDiscrete(MoveDirection::Down, false);
}
void KisToolMove::slotMoveDiscreteLeftMore()
{
moveDiscrete(MoveDirection::Left, true);
}
void KisToolMove::slotMoveDiscreteRightMore()
{
moveDiscrete(MoveDirection::Right, true);
}
void KisToolMove::slotMoveDiscreteUpMore()
{
moveDiscrete(MoveDirection::Up, true);
}
void KisToolMove::slotMoveDiscreteDownMore()
{
moveDiscrete(MoveDirection::Down, true);
}
void KisToolMove::cancelStroke()
{
if (!m_strokeId) return;
if (m_asyncUpdateHelper.isActive()) {
m_asyncUpdateHelper.cancelUpdateStream();
}
KisImageSP image = currentImage();
image->cancelStroke(m_strokeId);
m_strokeId.clear();
m_changesTracker.reset();
m_currentlyProcessingNodes.clear();
+ m_currentlyUsingSelection = false;
+ m_currentMode = MoveSelectedLayer;
m_accumulatedOffset = QPoint();
notifyGuiAfterMove();
qobject_cast<KisCanvas2*>(canvas())->updateCanvas();
}
QWidget* KisToolMove::createOptionWidget()
{
return m_optionsWidget;
}
KisToolMove::MoveToolMode KisToolMove::moveToolMode() const
{
if (m_optionsWidget)
return m_optionsWidget->mode();
return MoveSelectedLayer;
}
QPoint KisToolMove::applyModifiers(Qt::KeyboardModifiers modifiers, QPoint pos)
{
QPoint move = pos - m_dragStart;
// Snap to axis
if (modifiers & Qt::ShiftModifier) {
move = snapToClosestAxis(move);
}
// "Precision mode" - scale down movement by 1/5
if (modifiers & Qt::AltModifier) {
const qreal SCALE_FACTOR = .2;
move = SCALE_FACTOR * move;
}
return m_dragStart + move;
}
void KisToolMove::moveBySpinX(int newX)
{
if (mode() == KisTool::PAINT_MODE) return; // Don't interact with dragging
if (!currentNode()->isEditable()) return; // Don't move invisible nodes
if (startStrokeImpl(MoveSelectedLayer, 0)) {
setMode(KisTool::PAINT_MODE);
}
m_accumulatedOffset.rx() = newX - m_handlesRect.x();
image()->addJob(m_strokeId, new MoveStrokeStrategy::Data(m_accumulatedOffset));
notifyGuiAfterMove(false);
setMode(KisTool::HOVER_MODE);
}
void KisToolMove::moveBySpinY(int newY)
{
if (mode() == KisTool::PAINT_MODE) return; // Don't interact with dragging
if (!currentNode()->isEditable()) return; // Don't move invisible nodes
if (startStrokeImpl(MoveSelectedLayer, 0)) {
setMode(KisTool::PAINT_MODE);
}
m_accumulatedOffset.ry() = newY - m_handlesRect.y();
image()->addJob(m_strokeId, new MoveStrokeStrategy::Data(m_accumulatedOffset));
notifyGuiAfterMove(false);
setMode(KisTool::HOVER_MODE);
}
void KisToolMove::requestHandlesRectUpdate()
{
KisResourcesSnapshotSP resources =
new KisResourcesSnapshot(image(), currentNode(), canvas()->resourceManager());
KisSelectionSP selection = resources->activeSelection();
KisMoveBoundsCalculationJob *job = new KisMoveBoundsCalculationJob(this->selectedNodes(),
selection, this);
connect(job,
SIGNAL(sigCalcualtionFinished(const QRect&)),
SLOT(slotHandlesRectCalculated(const QRect &)));
KisImageSP image = this->image();
image->addSpontaneousJob(job);
notifyGuiAfterMove(false);
}
void KisToolMove::slotNodeChanged(const KisNodeList &nodes)
{
if (m_strokeId && !tryEndPreviousStroke(nodes)) {
return;
}
requestHandlesRectUpdate();
}
void KisToolMove::slotSelectionChanged()
{
if (m_strokeId) return;
requestHandlesRectUpdate();
}
QList<QAction *> KisToolMoveFactory::createActionsImpl()
{
KisActionRegistry *actionRegistry = KisActionRegistry::instance();
QList<QAction *> actions = KisToolPaintFactoryBase::createActionsImpl();
actions << actionRegistry->makeQAction("movetool-move-up");
actions << actionRegistry->makeQAction("movetool-move-down");
actions << actionRegistry->makeQAction("movetool-move-left");
actions << actionRegistry->makeQAction("movetool-move-right");
actions << actionRegistry->makeQAction("movetool-move-up-more");
actions << actionRegistry->makeQAction("movetool-move-down-more");
actions << actionRegistry->makeQAction("movetool-move-left-more");
actions << actionRegistry->makeQAction("movetool-move-right-more");
actions << actionRegistry->makeQAction("movetool-show-coordinates");
return actions;
}
diff --git a/plugins/tools/basictools/kis_tool_move.h b/plugins/tools/basictools/kis_tool_move.h
index f7f07666c8..fe37827255 100644
--- a/plugins/tools/basictools/kis_tool_move.h
+++ b/plugins/tools/basictools/kis_tool_move.h
@@ -1,209 +1,212 @@
/*
* Copyright (c) 1999 Matthias Elter <me@kde.org>
* 1999 Michael Koch <koch@kde.org>
* 2003 Patrick Julien <freak@codepimps.org>
*
* 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_TOOL_MOVE_H_
#define KIS_TOOL_MOVE_H_
#include <KisToolPaintFactoryBase.h>
#include <kis_types.h>
#include <kis_tool.h>
#include <flake/kis_node_shape.h>
#include <kis_icon.h>
#include <QKeySequence>
#include <QWidget>
#include <QGroupBox>
#include <QRadioButton>
#include "KisToolChangesTracker.h"
#include "kis_signal_compressor.h"
#include "kis_signal_auto_connection.h"
#include "KisAsyncronousStrokeUpdateHelper.h"
#include "kis_canvas2.h"
class KoCanvasBase;
class MoveToolOptionsWidget;
class KisDocument;
class KisToolMove : public KisTool
{
Q_OBJECT
Q_ENUMS(MoveToolMode);
public:
KisToolMove(KoCanvasBase * canvas);
~KisToolMove() override;
/**
* @brief wantsAutoScroll
* reimplemented from KoToolBase
* there's an issue where autoscrolling with this tool never makes the
* stroke end, so we return false here so that users don't get stuck with
* the tool. See bug 362659
* @return false
*/
bool wantsAutoScroll() const override {
return false;
}
public Q_SLOTS:
void activate(ToolActivation toolActivation, const QSet<KoShape*> &shapes) override;
void deactivate() override;
public Q_SLOTS:
void requestStrokeEnd() override;
void requestStrokeCancellation() override;
void requestUndoDuringStroke() override;
protected Q_SLOTS:
void resetCursorStyle() override;
public:
enum MoveToolMode {
MoveSelectedLayer,
MoveFirstLayer,
MoveGroup
};
enum MoveDirection {
Up,
Down,
Left,
Right
};
void beginPrimaryAction(KoPointerEvent *event) override;
void continuePrimaryAction(KoPointerEvent *event) override;
void endPrimaryAction(KoPointerEvent *event) override;
void beginAlternateAction(KoPointerEvent *event, AlternateAction action) override;
void continueAlternateAction(KoPointerEvent *event, AlternateAction action) override;
void endAlternateAction(KoPointerEvent *event, AlternateAction action) override;
void mouseMoveEvent(KoPointerEvent *event) override;
void startAction(KoPointerEvent *event, MoveToolMode mode);
void continueAction(KoPointerEvent *event);
void endAction(KoPointerEvent *event);
void paint(QPainter& gc, const KoViewConverter &converter) override;
QWidget *createOptionWidget() override;
void updateUIUnit(int newUnit);
MoveToolMode moveToolMode() const;
void setShowCoordinates(bool value);
public Q_SLOTS:
void moveDiscrete(MoveDirection direction, bool big);
void moveBySpinX(int newX);
void moveBySpinY(int newY);
void slotNodeChanged(const KisNodeList &nodes);
void slotSelectionChanged();
void commitChanges();
void slotHandlesRectCalculated(const QRect &handlesRect);
+ void slotStrokeStartedEmpty();
+ void slotStrokePickedLayers(const KisNodeList &nodes);
Q_SIGNALS:
void moveToolModeChanged();
void moveInNewPosition(QPoint);
private:
void drag(const QPoint& newPos);
void cancelStroke();
QPoint applyModifiers(Qt::KeyboardModifiers modifiers, QPoint pos);
bool startStrokeImpl(MoveToolMode mode, const QPoint *pos);
QPoint currentOffset() const;
void notifyGuiAfterMove(bool showFloatingMessage = true);
bool tryEndPreviousStroke(const KisNodeList &nodes);
- KisNodeList fetchSelectedNodes(MoveToolMode mode, const QPoint *pixelPoint, KisSelectionSP selection);
void requestHandlesRectUpdate();
private Q_SLOTS:
void endStroke();
void slotTrackerChangedConfig(KisToolChangesTrackerDataSP state);
void slotMoveDiscreteLeft();
void slotMoveDiscreteRight();
void slotMoveDiscreteUp();
void slotMoveDiscreteDown();
void slotMoveDiscreteLeftMore();
void slotMoveDiscreteRightMore();
void slotMoveDiscreteUpMore();
void slotMoveDiscreteDownMore();
private:
MoveToolOptionsWidget* m_optionsWidget {0};
QPoint m_dragStart; ///< Point where current cursor dragging began
QPoint m_accumulatedOffset; ///< Total offset including multiple clicks, up/down/left/right keys, etc. added together
KisStrokeId m_strokeId;
KisNodeList m_currentlyProcessingNodes;
+ bool m_currentlyUsingSelection = false;
+ MoveToolMode m_currentMode = MoveSelectedLayer;
int m_resolution;
QAction *m_showCoordinatesAction {0};
QPoint m_dragPos;
QRect m_handlesRect;
KisToolChangesTracker m_changesTracker;
QPoint m_lastCursorPos;
KisSignalCompressor m_updateCursorCompressor;
KisSignalAutoConnectionsStore m_actionConnections;
KisSignalAutoConnectionsStore m_canvasConnections;
KisAsyncronousStrokeUpdateHelper m_asyncUpdateHelper;
};
class KisToolMoveFactory : public KisToolPaintFactoryBase
{
public:
KisToolMoveFactory()
: KisToolPaintFactoryBase("KritaTransform/KisToolMove") {
setToolTip(i18n("Move Tool"));
setSection(TOOL_TYPE_TRANSFORM);
setActivationShapeId(KRITA_TOOL_ACTIVATION_ID);
setPriority(3);
setIconName(koIconNameCStr("krita_tool_move"));
setShortcut(QKeySequence(Qt::Key_T));
}
~KisToolMoveFactory() override {}
KoToolBase * createTool(KoCanvasBase *canvas) override {
return new KisToolMove(canvas);
}
QList<QAction *> createActionsImpl() override;
};
#endif // KIS_TOOL_MOVE_H_
diff --git a/plugins/tools/basictools/strokes/move_selection_stroke_strategy.cpp b/plugins/tools/basictools/strokes/move_selection_stroke_strategy.cpp
index a70df44608..a49da8a3da 100644
--- a/plugins/tools/basictools/strokes/move_selection_stroke_strategy.cpp
+++ b/plugins/tools/basictools/strokes/move_selection_stroke_strategy.cpp
@@ -1,180 +1,191 @@
/*
* Copyright (c) 2012 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "move_selection_stroke_strategy.h"
#include <klocalizedstring.h>
#include <KoColorSpace.h>
#include <KoCompositeOpRegistry.h>
#include "kis_image.h"
#include "kis_paint_layer.h"
#include "kis_painter.h"
#include "kis_transaction.h"
#include <commands_new/kis_selection_move_command2.h>
+#include "kis_lod_transform.h"
MoveSelectionStrokeStrategy::MoveSelectionStrokeStrategy(KisPaintLayerSP paintLayer,
KisSelectionSP selection,
KisUpdatesFacade *updatesFacade,
KisStrokeUndoFacade *undoFacade)
: KisStrokeStrategyUndoCommandBased(kundo2_i18n("Move Selection"), false, undoFacade),
m_paintLayer(paintLayer),
m_selection(selection),
m_updatesFacade(updatesFacade)
{
/**
* Selection might have some update projection jobs pending, so we should ensure
* all of them are completed before we start our stroke.
*/
enableJob(KisSimpleStrokeStrategy::JOB_INIT, true, KisStrokeJobData::BARRIER);
enableJob(KisSimpleStrokeStrategy::JOB_FINISH);
enableJob(KisSimpleStrokeStrategy::JOB_CANCEL);
}
MoveSelectionStrokeStrategy::MoveSelectionStrokeStrategy(const MoveSelectionStrokeStrategy &rhs)
: QObject(),
KisStrokeStrategyUndoCommandBased(rhs),
m_paintLayer(rhs.m_paintLayer),
m_selection(rhs.m_selection),
m_updatesFacade(rhs.m_updatesFacade)
{
}
void MoveSelectionStrokeStrategy::initStrokeCallback()
{
KisStrokeStrategyUndoCommandBased::initStrokeCallback();
KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice();
KisPaintDeviceSP movedDevice = new KisPaintDevice(m_paintLayer.data(), paintDevice->colorSpace());
QRect copyRect = m_selection->selectedRect();
KisPainter gc(movedDevice);
gc.setSelection(m_selection);
gc.bitBlt(copyRect.topLeft(), paintDevice, copyRect);
gc.end();
KisTransaction cutTransaction(name(), paintDevice);
paintDevice->clearSelection(m_selection);
runAndSaveCommand(KUndo2CommandSP(cutTransaction.endAndTake()),
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::NORMAL);
KisIndirectPaintingSupport *indirect =
static_cast<KisIndirectPaintingSupport*>(m_paintLayer.data());
indirect->setTemporaryTarget(movedDevice);
indirect->setTemporaryCompositeOp(COMPOSITE_OVER);
indirect->setTemporaryOpacity(OPACITY_OPAQUE_U8);
m_initialDeviceOffset = QPoint(movedDevice->x(), movedDevice->y());
m_selection->setVisible(false);
- emit sigHandlesRectCalculated(movedDevice->exactBounds());
+ {
+ QRect handlesRect = movedDevice->exactBounds();
+ KisLodTransform t(paintDevice);
+ handlesRect = t.mapInverted(handlesRect);
+
+ emit this->sigHandlesRectCalculated(handlesRect);
+ }
}
void MoveSelectionStrokeStrategy::finishStrokeCallback()
{
KisIndirectPaintingSupport *indirect =
static_cast<KisIndirectPaintingSupport*>(m_paintLayer.data());
KisTransaction transaction(name(), m_paintLayer->paintDevice());
indirect->mergeToLayer(m_paintLayer, (KisPostExecutionUndoAdapter*)0, KUndo2MagicString());
runAndSaveCommand(KUndo2CommandSP(transaction.endAndTake()),
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::NORMAL);
indirect->setTemporaryTarget(0);
QPoint selectionOffset(m_selection->x(), m_selection->y());
m_updatesFacade->blockUpdates();
KUndo2CommandSP moveSelectionCommand(
new KisSelectionMoveCommand2(m_selection, selectionOffset, selectionOffset + m_finalOffset));
runAndSaveCommand(
moveSelectionCommand,
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::EXCLUSIVE);
m_updatesFacade->unblockUpdates();
m_selection->setVisible(true);
KisStrokeStrategyUndoCommandBased::finishStrokeCallback();
}
void MoveSelectionStrokeStrategy::cancelStrokeCallback()
{
KisIndirectPaintingSupport *indirect =
static_cast<KisIndirectPaintingSupport*>(m_paintLayer.data());
if (indirect) {
KisPaintDeviceSP t = indirect->temporaryTarget();
if (t) {
KisRegion dirtyRegion = t->region();
indirect->setTemporaryTarget(0);
m_selection->setVisible(true);
m_paintLayer->setDirty(dirtyRegion);
}
}
KisStrokeStrategyUndoCommandBased::cancelStrokeCallback();
}
#include "tool/strokes/move_stroke_strategy.h"
void MoveSelectionStrokeStrategy::doStrokeCallback(KisStrokeJobData *data)
{
MoveStrokeStrategy::Data *d = dynamic_cast<MoveStrokeStrategy::Data*>(data);
if (d) {
KisIndirectPaintingSupport *indirect =
static_cast<KisIndirectPaintingSupport*>(m_paintLayer.data());
KisPaintDeviceSP movedDevice = indirect->temporaryTarget();
QRegion dirtyRegion = movedDevice->region().toQRegion();
QPoint currentDeviceOffset(movedDevice->x(), movedDevice->y());
QPoint newDeviceOffset(m_initialDeviceOffset + d->offset);
dirtyRegion |= dirtyRegion.translated(newDeviceOffset - currentDeviceOffset);
movedDevice->setX(newDeviceOffset.x());
movedDevice->setY(newDeviceOffset.y());
m_finalOffset = d->offset;
m_paintLayer->setDirty(KisRegion::fromQRegion(dirtyRegion));
} else {
KisStrokeStrategyUndoCommandBased::doStrokeCallback(data);
}
}
KisStrokeStrategy* MoveSelectionStrokeStrategy::createLodClone(int levelOfDetail)
{
Q_UNUSED(levelOfDetail);
+ // Vector selections don't support lod-moves
+ if (m_selection->hasShapeSelection()) return 0;
+
MoveSelectionStrokeStrategy *clone = new MoveSelectionStrokeStrategy(*this);
+ connect(clone, SIGNAL(sigHandlesRectCalculated(QRect)), this, SIGNAL(sigHandlesRectCalculated(QRect)));
return clone;
}
diff --git a/plugins/tools/defaulttool/CMakeLists.txt b/plugins/tools/defaulttool/CMakeLists.txt
index d7be403f04..447f430e0a 100644
--- a/plugins/tools/defaulttool/CMakeLists.txt
+++ b/plugins/tools/defaulttool/CMakeLists.txt
@@ -1,41 +1,32 @@
project( defaulttools )
set ( defaulttools_SRCS
Plugin.cpp
defaulttool/DefaultTool.cpp
defaulttool/DefaultToolFactory.cpp
defaulttool/DefaultToolTabbedWidget.cpp
defaulttool/DefaultToolGeometryWidget.cpp
defaulttool/ShapeMoveStrategy.cpp
defaulttool/ShapeResizeStrategy.cpp
defaulttool/ShapeRotateStrategy.cpp
defaulttool/ShapeShearStrategy.cpp
defaulttool/ShapeGradientEditStrategy.cpp
defaulttool/SelectionDecorator.cpp
defaulttool/KoShapeGradientHandles.cpp
- connectionTool/ConnectionTool.cpp
- connectionTool/ConnectionToolFactory.cpp
- connectionTool/AddConnectionPointCommand.cpp
- connectionTool/RemoveConnectionPointCommand.cpp
- connectionTool/ChangeConnectionPointCommand.cpp
- connectionTool/MoveConnectionPointStrategy.cpp
- connectionTool/ConnectionPointWidget.cpp
-
referenceimagestool/ToolReferenceImages.cpp
referenceimagestool/ToolReferenceImagesWidget.cpp
referenceimagestool/KisReferenceImageCollection.cpp
)
ki18n_wrap_ui(defaulttools_SRCS
defaulttool/DefaultToolGeometryWidget.ui
- connectionTool/ConnectionPointWidget.ui
referenceimagestool/WdgToolOptions.ui
)
qt5_add_resources(defaulttools_SRCS defaulttools.qrc)
add_library(krita_flaketools MODULE ${defaulttools_SRCS})
target_link_libraries(krita_flaketools kritaflake kritawidgets kritaui)
install(TARGETS krita_flaketools DESTINATION ${KRITA_PLUGIN_INSTALL_DIR})
diff --git a/plugins/tools/defaulttool/Plugin.cpp b/plugins/tools/defaulttool/Plugin.cpp
index 84b25d7c46..534726dfcf 100644
--- a/plugins/tools/defaulttool/Plugin.cpp
+++ b/plugins/tools/defaulttool/Plugin.cpp
@@ -1,38 +1,36 @@
/* This file is part of the KDE project
* Copyright (C) 2007 Thomas Zander <zander@kde.org>
*
* 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 "Plugin.h"
#include "defaulttool/DefaultToolFactory.h"
-#include "connectionTool/ConnectionToolFactory.h"
#include "referenceimagestool/ToolReferenceImages.h"
#include <KoToolRegistry.h>
#include <kpluginfactory.h>
K_PLUGIN_FACTORY_WITH_JSON(PluginFactory, "calligra_tool_defaults.json", registerPlugin<Plugin>();)
Plugin::Plugin(QObject *parent, const QVariantList &)
: QObject(parent)
{
KoToolRegistry::instance()->add(new DefaultToolFactory());
- KoToolRegistry::instance()->add(new ConnectionToolFactory());
KoToolRegistry::instance()->add(new ToolReferenceImagesFactory());
}
#include <Plugin.moc>
diff --git a/plugins/tools/defaulttool/connectionTool/AddConnectionPointCommand.cpp b/plugins/tools/defaulttool/connectionTool/AddConnectionPointCommand.cpp
deleted file mode 100644
index ec7ac96cce..0000000000
--- a/plugins/tools/defaulttool/connectionTool/AddConnectionPointCommand.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "AddConnectionPointCommand.h"
-#include <KoShape.h>
-
-AddConnectionPointCommand::AddConnectionPointCommand(KoShape *shape, const QPointF &connectionPoint, KUndo2Command *parent)
- : KUndo2Command(parent)
- , m_shape(shape)
- , m_connectionPoint(connectionPoint)
- , m_connectionPointId(-1)
-{
- Q_ASSERT(m_shape);
-}
-
-AddConnectionPointCommand::~AddConnectionPointCommand()
-{
-}
-
-void AddConnectionPointCommand::redo()
-{
- if (m_connectionPointId < 0) {
- m_connectionPointId = m_shape->addConnectionPoint(m_connectionPoint);
- } else {
- m_shape->setConnectionPoint(m_connectionPointId, m_connectionPoint);
- }
- updateRoi();
-
- KUndo2Command::redo();
-}
-
-void AddConnectionPointCommand::undo()
-{
- KUndo2Command::undo();
-
- m_shape->removeConnectionPoint(m_connectionPointId);
- updateRoi();
-}
-
-void AddConnectionPointCommand::updateRoi()
-{
- // TODO: is there a way we can get at the correct update size?
- //QRectF roi(0, 0, 10, 10);
- //roi.moveCenter(m_connectionPoint);
- //m_shape->update(roi);
-}
diff --git a/plugins/tools/defaulttool/connectionTool/AddConnectionPointCommand.h b/plugins/tools/defaulttool/connectionTool/AddConnectionPointCommand.h
deleted file mode 100644
index 4d51886773..0000000000
--- a/plugins/tools/defaulttool/connectionTool/AddConnectionPointCommand.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 ADDCONNECTIONPOINTCOMMAND_H
-#define ADDCONNECTIONPOINTCOMMAND_H
-
-#include <kundo2command.h>
-#include <QPointF>
-
-class KoShape;
-
-class AddConnectionPointCommand : public KUndo2Command
-{
-public:
- /// Creates new command to add connection point to shape
- AddConnectionPointCommand(KoShape *shape, const QPointF &connectionPoint, KUndo2Command *parent = 0);
- ~AddConnectionPointCommand() override;
- /// reimplemented from KUndo2Command
- void redo() override;
- /// reimplemented from KUndo2Command
- void undo() override;
-
-private:
- void updateRoi();
-
- KoShape *m_shape;
- QPointF m_connectionPoint;
- int m_connectionPointId;
-};
-
-#endif // ADDCONNECTIONPOINTCOMMAND_H
diff --git a/plugins/tools/defaulttool/connectionTool/ChangeConnectionPointCommand.cpp b/plugins/tools/defaulttool/connectionTool/ChangeConnectionPointCommand.cpp
deleted file mode 100644
index f26e31b0f5..0000000000
--- a/plugins/tools/defaulttool/connectionTool/ChangeConnectionPointCommand.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "ChangeConnectionPointCommand.h"
-#include <KoShape.h>
-
-ChangeConnectionPointCommand::ChangeConnectionPointCommand(KoShape *shape, int connectionPointId, const KoConnectionPoint &oldPoint, const KoConnectionPoint &newPoint, KUndo2Command *parent)
- : KUndo2Command(parent)
- , m_shape(shape)
- , m_connectionPointId(connectionPointId)
- , m_oldPoint(oldPoint)
- , m_newPoint(newPoint)
-{
- Q_ASSERT(m_shape);
-}
-
-ChangeConnectionPointCommand::~ChangeConnectionPointCommand()
-{
-}
-
-void ChangeConnectionPointCommand::redo()
-{
- updateRoi(m_oldPoint.position);
- m_shape->setConnectionPoint(m_connectionPointId, m_newPoint);
- updateRoi(m_newPoint.position);
-
- KUndo2Command::redo();
-}
-
-void ChangeConnectionPointCommand::undo()
-{
- KUndo2Command::undo();
-
- updateRoi(m_newPoint.position);
- m_shape->setConnectionPoint(m_connectionPointId, m_oldPoint);
- updateRoi(m_oldPoint.position);
-}
-
-void ChangeConnectionPointCommand::updateRoi(const QPointF &/*position*/)
-{
- // TODO: is there a way we can get at the correct update size?
- //QRectF roi(0, 0, 10, 10);
- //roi.moveCenter(position);
- //m_shape->update(roi);
-}
diff --git a/plugins/tools/defaulttool/connectionTool/ChangeConnectionPointCommand.h b/plugins/tools/defaulttool/connectionTool/ChangeConnectionPointCommand.h
deleted file mode 100644
index e0117f917f..0000000000
--- a/plugins/tools/defaulttool/connectionTool/ChangeConnectionPointCommand.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 CHANGECONNECTIONPOINTCOMMAND_H
-#define CHANGECONNECTIONPOINTCOMMAND_H
-
-#include <KoConnectionPoint.h>
-#include <kundo2command.h>
-#include <QPointF>
-
-class KoShape;
-
-class ChangeConnectionPointCommand : public KUndo2Command
-{
-public:
- /// Creates new command to change connection point of shape
- ChangeConnectionPointCommand(KoShape *shape, int connectionPointId, const KoConnectionPoint &oldPoint, const KoConnectionPoint &newPoint, KUndo2Command *parent = 0);
- ~ChangeConnectionPointCommand() override;
- /// reimplemented from KUndo2Command
- void redo() override;
- /// reimplemented from KUndo2Command
- void undo() override;
-
-private:
- void updateRoi(const QPointF &position);
-
- KoShape *m_shape;
- int m_connectionPointId;
- KoConnectionPoint m_oldPoint;
- KoConnectionPoint m_newPoint;
-};
-
-#endif // CHANGECONNECTIONPOINTCOMMAND_H
diff --git a/plugins/tools/defaulttool/connectionTool/ConnectionPointWidget.cpp b/plugins/tools/defaulttool/connectionTool/ConnectionPointWidget.cpp
deleted file mode 100644
index bcef851a2d..0000000000
--- a/plugins/tools/defaulttool/connectionTool/ConnectionPointWidget.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "ConnectionPointWidget.h"
-#include "ConnectionTool.h"
-#include <QAction>
-
-ConnectionPointWidget::ConnectionPointWidget(ConnectionTool *tool, QWidget *parent)
- : QWidget(parent)
-{
- widget.setupUi(this);
- widget.alignLeft->setDefaultAction(tool->action("align-left"));
- widget.alignCenterH->setDefaultAction(tool->action("align-centerh"));
- widget.alignRight->setDefaultAction(tool->action("align-right"));
- widget.alignTop->setDefaultAction(tool->action("align-top"));
- widget.alignCenterV->setDefaultAction(tool->action("align-centerv"));
- widget.alignBottom->setDefaultAction(tool->action("align-bottom"));
- widget.alignPercent->setDefaultAction(tool->action("align-relative"));
-
- widget.escapeAll->setDefaultAction(tool->action("escape-all"));
- widget.escapeHorz->setDefaultAction(tool->action("escape-horizontal"));
- widget.escapeVert->setDefaultAction(tool->action("escape-vertical"));
- widget.escapeLeft->setDefaultAction(tool->action("escape-left"));
- widget.escapeRight->setDefaultAction(tool->action("escape-right"));
- widget.escapeUp->setDefaultAction(tool->action("escape-up"));
- widget.escapeDown->setDefaultAction(tool->action("escape-down"));
-
- connect(widget.toggleEditMode, SIGNAL(stateChanged(int)), tool, SLOT(toggleConnectionPointEditMode(int)));
- connect(tool, SIGNAL(sendConnectionPointEditState(bool)), this, SLOT(toggleEditModeCheckbox(bool)));
-}
-
-void ConnectionPointWidget::toggleEditModeCheckbox(bool checked)
-{
- widget.toggleEditMode->blockSignals(true);
- if (checked) {
- widget.toggleEditMode->setCheckState(Qt::Checked);
- } else {
- widget.toggleEditMode->setCheckState(Qt::Unchecked);
- }
- widget.toggleEditMode->blockSignals(false);
-}
diff --git a/plugins/tools/defaulttool/connectionTool/ConnectionPointWidget.h b/plugins/tools/defaulttool/connectionTool/ConnectionPointWidget.h
deleted file mode 100644
index dde1e0420c..0000000000
--- a/plugins/tools/defaulttool/connectionTool/ConnectionPointWidget.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 CONNECTIONPOINTWIDGET_H
-#define CONNECTIONPOINTWIDGET_H
-
-#include <ui_ConnectionPointWidget.h>
-#include <QWidget>
-
-class ConnectionTool;
-
-class ConnectionPointWidget : public QWidget
-{
- Q_OBJECT
-public:
- explicit ConnectionPointWidget(ConnectionTool *tool, QWidget *parent = 0);
-
-private Q_SLOTS:
- void toggleEditModeCheckbox(bool checked);
-
-private:
- Ui::ConnectionPointWidget widget;
- QButtonGroup *m_horzGroup;
- QButtonGroup *m_vertGroup;
-};
-
-#endif // CONNECTIONPOINTWIDGET_H
diff --git a/plugins/tools/defaulttool/connectionTool/ConnectionPointWidget.ui b/plugins/tools/defaulttool/connectionTool/ConnectionPointWidget.ui
deleted file mode 100644
index 86a4487e90..0000000000
--- a/plugins/tools/defaulttool/connectionTool/ConnectionPointWidget.ui
+++ /dev/null
@@ -1,182 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ConnectionPointWidget</class>
- <widget class="QWidget" name="ConnectionPointWidget">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>239</width>
- <height>151</height>
- </rect>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="2" rowspan="7">
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>0</width>
- <height>88</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="0">
- <widget class="QCheckBox" name="toggleEditMode">
- <property name="text">
- <string>Edit Mode</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="labelEscape">
- <property name="text">
- <string>Escape Direction</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QToolButton" name="escapeAll">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="escapeHorz">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="escapeVert">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="escapeLeft">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="escapeRight">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="escapeUp">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="escapeDown">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="labelAlign">
- <property name="text">
- <string>Alignment</string>
- </property>
- </widget>
- </item>
- <item row="7" column="0">
- <widget class="QWidget" name="SpecialSpacer">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- <item row="4" column="0">
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <widget class="QToolButton" name="alignPercent">
- <property name="text">
- <string>%</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="Line" name="line_2">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="alignLeft">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="alignCenterH">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="alignRight">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="Line" name="line">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="alignTop">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="alignCenterV">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="alignBottom">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/plugins/tools/defaulttool/connectionTool/ConnectionTool.cpp b/plugins/tools/defaulttool/connectionTool/ConnectionTool.cpp
deleted file mode 100644
index a510c4c9d5..0000000000
--- a/plugins/tools/defaulttool/connectionTool/ConnectionTool.cpp
+++ /dev/null
@@ -1,988 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2009 Thorsten Zachmann <zachmann@kde.org>
- * Copyright (C) 2009 Jean-Nicolas Artaud <jeannicolasartaud@gmail.com>
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "ConnectionTool.h"
-
-#include <QPointF>
-#include <QKeyEvent>
-#include <QPainter>
-
-#include "AddConnectionPointCommand.h"
-#include "RemoveConnectionPointCommand.h"
-#include "ChangeConnectionPointCommand.h"
-#include "MoveConnectionPointStrategy.h"
-#include "ConnectionPointWidget.h"
-
-#define TextShape_SHAPEID "TextShapeID"
-
-#include <KoCanvasBase.h>
-#include <KoPointerEvent.h>
-#include <KoShapeManager.h>
-#include <KoShapeFactoryBase.h>
-#include <KoShape.h>
-#include <KoShapeGroup.h>
-#include <KoShapeController.h>
-#include <KoShapeLayer.h>
-#include <KoShapeRegistry.h>
-#include <KoSelection.h>
-#include <KoPathSegment.h>
-#include <KoDocumentResourceManager.h>
-#include <KoInteractionStrategy.h>
-#include <KoShapeConfigWidgetBase.h>
-#include <KoConnectionShapeConfigWidget.h>
-#include <KoPathConnectionPointStrategy.h>
-#include <KoStrokeConfigWidget.h>
-#include <KisHandlePainterHelper.h>
-#include <KoViewConverter.h>
-
-#include "kis_document_aware_spin_box_unit_manager.h"
-
-#include <KoIcon.h>
-#include "kis_action_registry.h"
-
-#include <QAction>
-#include <klocalizedstring.h>
-#include <QDebug>
-#include <KoResourcePaths.h>
-#include <kundo2command.h>
-
-#include <math.h>
-
-ConnectionTool::ConnectionTool(KoCanvasBase *canvas)
- : KoToolBase(canvas)
- , m_editMode(Idle)
- , m_connectionType(KoConnectionShape::Standard)
- , m_currentShape(0)
- , m_activeHandle(-1)
- , m_currentStrategy(0)
- , m_oldSnapStrategies(0)
- , m_resetPaint(true)
-{
- QPixmap connectPixmap;
- connectPixmap.load(":/cursor_connect.png");
- m_connectCursor = QCursor(connectPixmap, 4, 1);
-
- KisActionRegistry *actionRegistry = KisActionRegistry::instance();
- m_editConnectionPoint = actionRegistry->makeQAction("toggle-edit-mode", this);
- m_editConnectionPoint->setCheckable(true);
-// addAction("toggle-edit-mode", m_editConnectionPoint);
-
- m_alignPercent = actionRegistry->makeQAction("align-relative", this);
- m_alignPercent->setCheckable(true);
-// addAction("align-relative", m_alignPercent);
- m_alignLeft = actionRegistry->makeQAction("align-left", this);
- m_alignLeft->setCheckable(true);
-// addAction("align-left", m_alignLeft);
- m_alignCenterH = actionRegistry->makeQAction("align-centerh", this);
- m_alignCenterH->setCheckable(true);
-// addAction("align-centerh", m_alignCenterH);
- m_alignRight = actionRegistry->makeQAction("align-right", this);
- m_alignRight->setCheckable(true);
-// addAction("align-right", m_alignRight);
- m_alignTop = actionRegistry->makeQAction("align-top", this);
- m_alignTop->setCheckable(true);
-// addAction("align-top", m_alignTop);
- m_alignCenterV = actionRegistry->makeQAction("align-centerv", this);
- m_alignCenterV->setCheckable(true);
-// addAction("align-centerv", m_alignCenterV);
- m_alignBottom = actionRegistry->makeQAction("align-bottom", this);
- m_alignBottom->setCheckable(true);
-// addAction("align-bottom", m_alignBottom);
-
- m_escapeAll = actionRegistry->makeQAction("escape-all", this);
- m_escapeAll->setCheckable(true);
-// addAction("escape-all", m_escapeAll);
- m_escapeHorizontal = actionRegistry->makeQAction("escape-horizontal", this);
- m_escapeHorizontal->setCheckable(true);
-// addAction("escape-horizontal", m_escapeHorizontal);
- m_escapeVertical = actionRegistry->makeQAction("escape-vertical", this);
- m_escapeVertical->setCheckable(true);
-// addAction("escape-vertical", m_escapeVertical);
- m_escapeLeft = actionRegistry->makeQAction("escape-left", this);
- m_escapeLeft->setCheckable(true);
-// addAction("escape-left", m_escapeLeft);
- m_escapeRight = actionRegistry->makeQAction("escape-right", this);
- m_escapeRight->setCheckable(true);
-// addAction("escape-right", m_escapeRight);
- m_escapeUp = actionRegistry->makeQAction("escape-up", this);
- m_escapeUp->setCheckable(true);
-// addAction("escape-up", m_escapeUp);
- m_escapeDown = actionRegistry->makeQAction("escape-down", this);
- m_escapeDown->setCheckable(true);
-// addAction("escape-down", m_escapeDown);
-
- m_alignHorizontal = new QActionGroup(this);
- m_alignHorizontal->setExclusive(true);
- m_alignHorizontal->addAction(m_alignLeft);
- m_alignHorizontal->addAction(m_alignCenterH);
- m_alignHorizontal->addAction(m_alignRight);
- connect(m_alignHorizontal, SIGNAL(triggered(QAction*)), this, SLOT(horizontalAlignChanged()));
-
- m_alignVertical = new QActionGroup(this);
- m_alignVertical->setExclusive(true);
- m_alignVertical->addAction(m_alignTop);
- m_alignVertical->addAction(m_alignCenterV);
- m_alignVertical->addAction(m_alignBottom);
- connect(m_alignVertical, SIGNAL(triggered(QAction*)), this, SLOT(verticalAlignChanged()));
-
- m_alignRelative = new QActionGroup(this);
- m_alignRelative->setExclusive(true);
- m_alignRelative->addAction(m_alignPercent);
- connect(m_alignRelative, SIGNAL(triggered(QAction*)), this, SLOT(relativeAlignChanged()));
-
- m_escapeDirections = new QActionGroup(this);
- m_escapeDirections->setExclusive(true);
- m_escapeDirections->addAction(m_escapeAll);
- m_escapeDirections->addAction(m_escapeHorizontal);
- m_escapeDirections->addAction(m_escapeVertical);
- m_escapeDirections->addAction(m_escapeLeft);
- m_escapeDirections->addAction(m_escapeRight);
- m_escapeDirections->addAction(m_escapeUp);
- m_escapeDirections->addAction(m_escapeDown);
- connect(m_escapeDirections, SIGNAL(triggered(QAction*)), this, SLOT(escapeDirectionChanged()));
-
- connect(this, SIGNAL(connectionPointEnabled(bool)), m_alignHorizontal, SLOT(setEnabled(bool)));
- connect(this, SIGNAL(connectionPointEnabled(bool)), m_alignVertical, SLOT(setEnabled(bool)));
- connect(this, SIGNAL(connectionPointEnabled(bool)), m_alignRelative, SLOT(setEnabled(bool)));
- connect(this, SIGNAL(connectionPointEnabled(bool)), m_escapeDirections, SLOT(setEnabled(bool)));
-
- resetEditMode();
-}
-
-ConnectionTool::~ConnectionTool()
-{
-}
-
-void ConnectionTool::paint(QPainter &painter, const KoViewConverter &converter)
-{
- // get the correctly sized rect for painting handles
- QRectF handleRect = handlePaintRect(QPointF());
-
- painter.setRenderHint(QPainter::Antialiasing, true);
-
- if (m_currentStrategy) {
- painter.save();
- m_currentStrategy->paint(painter, converter);
- painter.restore();
- }
-
- QList<KoShape *> shapes = canvas()->shapeManager()->shapes();
- for (QList<KoShape *>::const_iterator end = shapes.constBegin(); end != shapes.constEnd(); ++end) {
- KoShape *shape = *end;
- if (!dynamic_cast<KoConnectionShape *>(shape)) {
- // only paint connection points of textShapes not inside a tos container and other shapes
- if (shape->shapeId() == TextShape_SHAPEID && dynamic_cast<KoTosContainer *>(shape->parent())) {
- continue;
- }
-
- painter.save();
- painter.setPen(Qt::black);
- painter.setTransform(converter.documentToView());
- QTransform transform = shape->absoluteTransformation();
- // Draw all the connection points of the shape
- KoConnectionPoints connectionPoints = shape->connectionPoints();
- KoConnectionPoints::const_iterator cp = connectionPoints.constBegin();
- KoConnectionPoints::const_iterator lastCp = connectionPoints.constEnd();
- for (; cp != lastCp; ++cp) {
- if (shape == findNonConnectionShapeAtPosition(transform.map(cp.value().position))) {
- handleRect.moveCenter(transform.map(cp.value().position));
- painter.setBrush(cp.key() == m_activeHandle && shape == m_currentShape ?
- Qt::red : Qt::white);
- painter.drawRect(handleRect);
- }
- }
- painter.restore();
- }
- }
- // paint connection points or connection handles depending
- // on the shape the mouse is currently
- if (m_currentShape && m_editMode == EditConnection) {
- KoConnectionShape *connectionShape = dynamic_cast<KoConnectionShape *>(m_currentShape);
- if (connectionShape) {
- int radius = handleRadius() + 1;
- int handleCount = connectionShape->handleCount();
- for (int i = 0; i < handleCount; ++i) {
- KisHandlePainterHelper helper = KoShape::createHandlePainterHelperView(&painter, connectionShape, converter, radius);
- helper.setHandleStyle(i == m_activeHandle ? KisHandleStyle::highlightedPrimaryHandles() : KisHandleStyle::primarySelection());
- connectionShape->paintHandle(helper, i);
- }
- }
- }
-}
-
-void ConnectionTool::repaintDecorations()
-{
- const qreal radius = handleRadius();
- QRectF repaintRect;
-
- if (m_currentShape) {
- repaintRect = m_currentShape->boundingRect();
- canvas()->updateCanvas(repaintRect.adjusted(-radius, -radius, radius, radius));
- KoConnectionShape *connectionShape = dynamic_cast<KoConnectionShape *>(m_currentShape);
- if (!m_resetPaint && m_currentShape->isVisible() && !connectionShape) {
- // only paint connection points of textShapes not inside a tos container and other shapes
- if (!(m_currentShape->shapeId() == TextShape_SHAPEID &&
- dynamic_cast<KoTosContainer *>(m_currentShape->parent()))) {
- KoConnectionPoints connectionPoints = m_currentShape->connectionPoints();
- KoConnectionPoints::const_iterator cp = connectionPoints.constBegin();
- KoConnectionPoints::const_iterator lastCp = connectionPoints.constEnd();
- for (; cp != lastCp; ++cp) {
- repaintRect = handleGrabRect(m_currentShape->shapeToDocument(cp.value().position));
- canvas()->updateCanvas(repaintRect.adjusted(-radius, -radius, radius, radius));
- }
- }
- }
- if (m_editMode == EditConnection) {
- if (connectionShape) {
- QPointF handlePos = connectionShape->handlePosition(m_activeHandle);
- handlePos = connectionShape->shapeToDocument(handlePos);
- repaintRect = handlePaintRect(handlePos);
- canvas()->updateCanvas(repaintRect.adjusted(-radius, -radius, radius, radius));
- }
- }
- }
- if (m_resetPaint) {
- QList<KoShape *> shapes = canvas()->shapeManager()->shapes();
- for (QList<KoShape *>::const_iterator end = shapes.constBegin(); end != shapes.constEnd(); ++end) {
- KoShape *shape = *end;
- if (!dynamic_cast<KoConnectionShape *>(shape)) {
- // only paint connection points of textShapes not inside a tos container and other shapes
- if (shape->shapeId() == TextShape_SHAPEID && dynamic_cast<KoTosContainer *>(shape->parent())) {
- continue;
- }
-
- KoConnectionPoints connectionPoints = shape->connectionPoints();
- KoConnectionPoints::const_iterator cp = connectionPoints.constBegin();
- KoConnectionPoints::const_iterator lastCp = connectionPoints.constEnd();
- for (; cp != lastCp; ++cp) {
- repaintRect = handleGrabRect(shape->shapeToDocument(cp.value().position));
- canvas()->updateCanvas(repaintRect.adjusted(-radius, -radius, radius, radius));
- }
- }
- }
- }
- m_resetPaint = false;
-}
-
-void ConnectionTool::mousePressEvent(KoPointerEvent *event)
-{
-
- if (!m_currentShape) {
- return;
- }
-
- KoShape *hitShape = findShapeAtPosition(event->point);
- int hitHandle = handleAtPoint(m_currentShape, event->point);
-
- if (m_editMode == EditConnection && hitHandle >= 0) {
- // create connection handle change strategy
- m_currentStrategy = new KoPathConnectionPointStrategy(this, dynamic_cast<KoConnectionShape *>(m_currentShape), hitHandle);
- } else if (m_editMode == EditConnectionPoint) {
- if (hitHandle >= KoConnectionPoint::FirstCustomConnectionPoint) {
- // start moving custom connection point
- m_currentStrategy = new MoveConnectionPointStrategy(m_currentShape, hitHandle, this);
- }
- } else if (m_editMode == CreateConnection) {
- // create new connection shape, connect it to the active connection point
- // and start editing the new connection
- // create the new connection shape
- KoShapeFactoryBase *factory = KoShapeRegistry::instance()->value("KoConnectionShape");
- KoShape *shape = factory->createDefaultShape(canvas()->shapeController()->resourceManager());
- KoConnectionShape *connectionShape = dynamic_cast<KoConnectionShape *>(shape);
- if (!connectionShape) {
- delete shape;
- resetEditMode();
- return;
- }
- //set connection type
- connectionShape->setType(m_connectionType);
- // get the position of the connection point we start our connection from
- QPointF cp = m_currentShape->shapeToDocument(m_currentShape->connectionPoint(m_activeHandle).position);
- // move both handles to that point
- connectionShape->moveHandle(0, cp);
- connectionShape->moveHandle(1, cp);
- // connect the first handle of the connection shape to our connection point
- if (!connectionShape->connectFirst(m_currentShape, m_activeHandle)) {
- delete shape;
- resetEditMode();
- return;
- }
- //add connector label
- connectionShape->createTextShape(canvas()->shapeController()->resourceManager());
- connectionShape->setPlainText(QString());
- // create the connection edit strategy from the path tool
- m_currentStrategy = new KoPathConnectionPointStrategy(this, connectionShape, 1);
- if (!m_currentStrategy) {
- delete shape;
- resetEditMode();
- return;
- }
- // update our handle data
- setEditMode(m_editMode, shape, 1);
- // add connection shape to the shape manager so it gets painted
- canvas()->shapeManager()->addShape(connectionShape);
- } else {
- // pressing on a shape in idle mode switches to corresponding edit mode
- if (hitShape) {
- if (dynamic_cast<KoConnectionShape *>(hitShape)) {
- int hitHandle = handleAtPoint(hitShape, event->point);
- setEditMode(EditConnection, hitShape, hitHandle);
- if (hitHandle >= 0) {
- // start editing connection shape
- m_currentStrategy = new KoPathConnectionPointStrategy(this, dynamic_cast<KoConnectionShape *>(m_currentShape), m_activeHandle);
- }
- }
- } else {
- resetEditMode();
- }
- }
-}
-
-void ConnectionTool::mouseMoveEvent(KoPointerEvent *event)
-{
- if (m_currentStrategy) {
- repaintDecorations();
- if (m_editMode != EditConnection && m_editMode != CreateConnection) {
- QPointF snappedPos = canvas()->snapGuide()->snap(event->point, event->modifiers());
- m_currentStrategy->handleMouseMove(snappedPos, event->modifiers());
- } else {
- m_currentStrategy->handleMouseMove(event->point, event->modifiers());
- }
- repaintDecorations();
- } else if (m_editMode == EditConnectionPoint) {
- KoShape *hoverShape = findNonConnectionShapeAtPosition(event->point);//TODO exclude connectors, need snap guide maybe?
- if (hoverShape) {
- m_currentShape = hoverShape;
- Q_ASSERT(m_currentShape);
- // check if we should highlight another connection point
- int handle = handleAtPoint(m_currentShape, event->point);
- if (handle >= 0) {
- setEditMode(m_editMode, m_currentShape, handle);
- useCursor(handle >= KoConnectionPoint::FirstCustomConnectionPoint ? Qt::SizeAllCursor : Qt::ArrowCursor);
- } else {
- updateStatusText();
- useCursor(Qt::CrossCursor);
- }
- } else {
- m_currentShape = 0;
- useCursor(Qt::ArrowCursor);
- }
- } else if (m_editMode == EditConnection) {
- Q_ASSERT(m_currentShape);
- KoShape *hoverShape = findShapeAtPosition(event->point);
- // check if we should highlight another connection handle
- int handle = handleAtPoint(m_currentShape, event->point);
- setEditMode(m_editMode, m_currentShape, handle);
- if (m_activeHandle == KoConnectionShape::StartHandle ||
- m_activeHandle == KoConnectionShape::EndHandle) {
- useCursor(Qt::SizeAllCursor);
- } else if (m_activeHandle >= KoConnectionShape::ControlHandle_1) {
-
- } else if (hoverShape && hoverShape != m_currentShape) {
- useCursor(Qt::PointingHandCursor);
- } else {
- useCursor(Qt::ArrowCursor);
- }
- } else {// Idle and no current strategy
- KoShape *hoverShape = findShapeAtPosition(event->point);
- int hoverHandle = -1;
- if (hoverShape) {
- KoConnectionShape *connectionShape = dynamic_cast<KoConnectionShape *>(hoverShape);
- if (!connectionShape) {
- QPointF snappedPos = canvas()->snapGuide()->snap(event->point, event->modifiers());
- hoverHandle = handleAtPoint(hoverShape, snappedPos);
- setEditMode(hoverHandle >= 0 ? CreateConnection : Idle, hoverShape, hoverHandle);
- }
- useCursor(hoverHandle >= 0 ? m_connectCursor : Qt::PointingHandCursor);
- } else {
- useCursor(Qt::ArrowCursor);
- }
- }
-}
-
-void ConnectionTool::mouseReleaseEvent(KoPointerEvent *event)
-{
- if (m_currentStrategy) {
- if (m_editMode == CreateConnection) {
- // check if connection handles have a minimal distance
- KoConnectionShape *connectionShape = dynamic_cast<KoConnectionShape *>(m_currentShape);
- Q_ASSERT(connectionShape);
- // get both handle positions in document coordinates
- QPointF p1 = connectionShape->shapeToDocument(connectionShape->handlePosition(0));
- QPointF p2 = connectionShape->shapeToDocument(connectionShape->handlePosition(1));
- int grabDistance = grabSensitivity();
- // use grabbing sensitivity as minimal distance threshold
- if (squareDistance(p1, p2) < grabDistance * grabDistance) {
- // minimal distance was not reached, so we have to undo the started work:
- // - cleanup and delete the strategy
- // - remove connection shape from shape manager and delete it
- // - reset edit mode to last state
- delete m_currentStrategy;
- m_currentStrategy = 0;
- repaintDecorations();
- canvas()->shapeManager()->remove(m_currentShape);
- setEditMode(m_editMode, connectionShape->firstShape(), connectionShape->firstConnectionId());
- repaintDecorations();
- delete connectionShape;
- return;
- } else {
- // finalize adding the new connection shape with an undo command
- KUndo2Command *cmd = canvas()->shapeController()->addShape(m_currentShape, 0);
- canvas()->addCommand(cmd);
- setEditMode(EditConnection, m_currentShape, KoConnectionShape::StartHandle);
- }
- }
- m_currentStrategy->finishInteraction(event->modifiers());
- // TODO: Add parent command to KoInteractionStrategy::createCommand
- // so that we can have a single command to undo for the user
- KUndo2Command *command = m_currentStrategy->createCommand();
- if (command) {
- canvas()->addCommand(command);
- }
- delete m_currentStrategy;
- m_currentStrategy = 0;
- }
- updateStatusText();
-}
-
-void ConnectionTool::mouseDoubleClickEvent(KoPointerEvent *event)
-{
- if (m_editMode == EditConnectionPoint) {
- repaintDecorations();
-
- //quit EditConnectionPoint mode when double click blank region on canvas
- if (!m_currentShape) {
- resetEditMode();
- return;
- }
-
- //add connection point when double click a shape
- //remove connection point when double click a existed connection point
- int handleId = handleAtPoint(m_currentShape, event->point);
- if (handleId < 0) {
- QPointF mousePos = canvas()->snapGuide()->snap(event->point, event->modifiers());
- QPointF point = m_currentShape->documentToShape(mousePos);
- canvas()->addCommand(new AddConnectionPointCommand(m_currentShape, point));
- } else {
- canvas()->addCommand(new RemoveConnectionPointCommand(m_currentShape, handleId));
- }
- setEditMode(m_editMode, m_currentShape, -1);
- } else {
- //deactivate connection tool when double click blank region on canvas
- KoShape *hitShape = findShapeAtPosition(event->point);
- if (!hitShape) {
- deactivate();
- emit done();
- } else if (dynamic_cast<KoConnectionShape *>(hitShape)) {
- repaintDecorations();
- setEditMode(EditConnection, m_currentShape, -1);
- //TODO: temporarily activate text tool to edit connection path
- }
- }
-}
-
-void ConnectionTool::keyPressEvent(QKeyEvent *event)
-{
- if (event->key() == Qt::Key_Escape) {
- deactivate();
- emit done();
- } else if (event->key() == Qt::Key_Backspace) {
- deleteSelection();
- event->accept();
- }
-}
-
-void ConnectionTool::activate(ToolActivation activation, const QSet<KoShape *> &shapes)
-{
- KoToolBase::activate(activation, shapes);
-
- // save old enabled snap strategies, set bounding box snap strategy
- m_oldSnapStrategies = canvas()->snapGuide()->enabledSnapStrategies();
- canvas()->snapGuide()->enableSnapStrategies(KoSnapGuide::BoundingBoxSnapping);
- canvas()->snapGuide()->reset();
- m_resetPaint = true;
- repaintDecorations();
-}
-
-void ConnectionTool::deactivate()
-{
- // Put everything to 0 to be able to begin a new shape properly
- delete m_currentStrategy;
- m_currentStrategy = 0;
- resetEditMode();
- m_resetPaint = true;
- repaintDecorations();
- // restore previously set snap strategies
- canvas()->snapGuide()->enableSnapStrategies(m_oldSnapStrategies);
- canvas()->snapGuide()->reset();
- KoToolBase::deactivate();
-}
-
-qreal ConnectionTool::squareDistance(const QPointF &p1, const QPointF &p2) const
-{
- // Square of the distance
- const qreal dx = p2.x() - p1.x();
- const qreal dy = p2.y() - p1.y();
- return dx * dx + dy * dy;
-}
-
-KoShape *ConnectionTool::findShapeAtPosition(const QPointF &position) const
-{
- QList<KoShape *> shapes = canvas()->shapeManager()->shapesAt(handleGrabRect(position));
- if (!shapes.isEmpty()) {
- std::sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
- // we want to priorize connection shape handles, even if the connection shape
- // is not at the top of the shape stack at the mouse position
- KoConnectionShape *connectionShape = nearestConnectionShape(shapes, position);
- // use best connection shape or first shape from stack (last in the list) if not found
- if (connectionShape) {
- return connectionShape;
- } else {
- for (QList<KoShape *>::const_iterator end = shapes.constEnd() - 1; end >= shapes.constBegin(); --end) {
- KoShape *shape = *end;
- if (!dynamic_cast<KoConnectionShape *>(shape) && shape->shapeId() != TextShape_SHAPEID) {
- return shape;
- }
- }
- }
- }
-
- return 0;
-}
-
-KoShape *ConnectionTool::findNonConnectionShapeAtPosition(const QPointF &position) const
-{
- QList<KoShape *> shapes = canvas()->shapeManager()->shapesAt(handleGrabRect(position));
- if (!shapes.isEmpty()) {
- std::sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
- for (QList<KoShape *>::const_iterator end = shapes.constEnd() - 1; end >= shapes.constBegin(); --end) {
- KoShape *shape = *end;
- if (!dynamic_cast<KoConnectionShape *>(shape) && shape->shapeId() != TextShape_SHAPEID) {
- return shape;
- }
- }
- }
-
- return 0;
-}
-
-int ConnectionTool::handleAtPoint(KoShape *shape, const QPointF &mousePoint) const
-{
- if (!shape) {
- return -1;
- }
-
- const QPointF shapePoint = shape->documentToShape(mousePoint);
-
- KoConnectionShape *connectionShape = dynamic_cast<KoConnectionShape *>(shape);
- if (connectionShape) {
- // check connection shape handles
- return connectionShape->handleIdAt(handleGrabRect(shapePoint));
- } else {
- // check connection points
- int grabDistance = grabSensitivity();
- qreal minDistance = HUGE_VAL;
- int handleId = -1;
- KoConnectionPoints connectionPoints = shape->connectionPoints();
- KoConnectionPoints::const_iterator cp = connectionPoints.constBegin();
- KoConnectionPoints::const_iterator lastCp = connectionPoints.constEnd();
- for (; cp != lastCp; ++cp) {
- qreal d = squareDistance(shapePoint, cp.value().position);
- if (d <= grabDistance && d < minDistance) {
- handleId = cp.key();
- minDistance = d;
- }
- }
- return handleId;
- }
-}
-
-KoConnectionShape *ConnectionTool::nearestConnectionShape(const QList<KoShape *> &shapes, const QPointF &mousePos) const
-{
- int grabDistance = grabSensitivity();
-
- KoConnectionShape *nearestConnectionShape = 0;
- qreal minSquaredDistance = HUGE_VAL;
- const qreal maxSquaredDistance = grabDistance * grabDistance;
-
- Q_FOREACH (KoShape *shape, shapes) {
- KoConnectionShape *connectionShape = dynamic_cast<KoConnectionShape *>(shape);
- if (!connectionShape || !connectionShape->isParametricShape()) {
- continue;
- }
-
- // convert document point to shape coordinates
- QPointF p = connectionShape->documentToShape(mousePos);
- // our region of interest, i.e. a region around our mouse position
- QRectF roi = handleGrabRect(p);
-
- // check all segments of this shape which intersect the region of interest
- QList<KoPathSegment> segments = connectionShape->segmentsAt(roi);
- foreach (const KoPathSegment &s, segments) {
- qreal nearestPointParam = s.nearestPoint(p);
- QPointF nearestPoint = s.pointAt(nearestPointParam);
- QPointF diff = p - nearestPoint;
- qreal squaredDistance = diff.x() * diff.x() + diff.y() * diff.y();
- // are we within the allowed distance ?
- if (squaredDistance > maxSquaredDistance) {
- continue;
- }
- // are we closer to the last closest point ?
- if (squaredDistance < minSquaredDistance) {
- nearestConnectionShape = connectionShape;
- minSquaredDistance = squaredDistance;
- }
- }
- }
-
- return nearestConnectionShape;
-}
-
-void ConnectionTool::setEditMode(EditMode mode, KoShape *currentShape, int handle)
-{
- repaintDecorations();
- m_editMode = mode;
- if (m_currentShape != currentShape) {
- KoConnectionShape *connectionShape = dynamic_cast<KoConnectionShape *>(currentShape);
- foreach (KoShapeConfigWidgetBase *cw, m_connectionShapeWidgets) {
- if (connectionShape) {
- cw->open(currentShape);
- }
- }
- }
- if (mode == Idle) {
- emit sendConnectionType(m_connectionType);
- }
- m_currentShape = currentShape;
- m_activeHandle = handle;
- repaintDecorations();
- updateActions();
- updateStatusText();
-}
-
-void ConnectionTool::resetEditMode()
-{
- m_connectionType = KoConnectionShape::Standard;
- setEditMode(Idle, 0, -1);
- emit sendConnectionPointEditState(false);
-}
-
-void ConnectionTool::updateActions()
-{
- const bool connectionPointSelected = m_editMode == EditConnectionPoint && m_activeHandle >= 0;
- if (connectionPointSelected) {
- KoConnectionPoint cp = m_currentShape->connectionPoint(m_activeHandle);
-
- m_alignPercent->setChecked(false);
- Q_FOREACH (QAction *action, m_alignHorizontal->actions()) {
- action->setChecked(false);
- }
- Q_FOREACH (QAction *action, m_alignVertical->actions()) {
- action->setChecked(false);
- }
- switch (cp.alignment) {
- case KoConnectionPoint::AlignNone:
- m_alignPercent->setChecked(true);
- break;
- case KoConnectionPoint::AlignTopLeft:
- m_alignLeft->setChecked(true);
- m_alignTop->setChecked(true);
- break;
- case KoConnectionPoint::AlignTop:
- m_alignCenterH->setChecked(true);
- m_alignTop->setChecked(true);
- break;
- case KoConnectionPoint::AlignTopRight:
- m_alignRight->setChecked(true);
- m_alignTop->setChecked(true);
- break;
- case KoConnectionPoint::AlignLeft:
- m_alignLeft->setChecked(true);
- m_alignCenterV->setChecked(true);
- break;
- case KoConnectionPoint::AlignCenter:
- m_alignCenterH->setChecked(true);
- m_alignCenterV->setChecked(true);
- break;
- case KoConnectionPoint::AlignRight:
- m_alignRight->setChecked(true);
- m_alignCenterV->setChecked(true);
- break;
- case KoConnectionPoint::AlignBottomLeft:
- m_alignLeft->setChecked(true);
- m_alignBottom->setChecked(true);
- break;
- case KoConnectionPoint::AlignBottom:
- m_alignCenterH->setChecked(true);
- m_alignBottom->setChecked(true);
- break;
- case KoConnectionPoint::AlignBottomRight:
- m_alignRight->setChecked(true);
- m_alignBottom->setChecked(true);
- break;
- }
- Q_FOREACH (QAction *action, m_escapeDirections->actions()) {
- action->setChecked(false);
- }
- switch (cp.escapeDirection) {
- case KoConnectionPoint::AllDirections:
- m_escapeAll->setChecked(true);
- break;
- case KoConnectionPoint::HorizontalDirections:
- m_escapeHorizontal->setChecked(true);
- break;
- case KoConnectionPoint::VerticalDirections:
- m_escapeVertical->setChecked(true);
- break;
- case KoConnectionPoint::LeftDirection:
- m_escapeLeft->setChecked(true);
- break;
- case KoConnectionPoint::RightDirection:
- m_escapeRight->setChecked(true);
- break;
- case KoConnectionPoint::UpDirection:
- m_escapeUp->setChecked(true);
- break;
- case KoConnectionPoint::DownDirection:
- m_escapeDown->setChecked(true);
- break;
- }
- }
- emit connectionPointEnabled(connectionPointSelected);
-}
-
-void ConnectionTool::updateStatusText()
-{
- switch (m_editMode) {
- case Idle:
- if (m_currentShape) {
- if (dynamic_cast<KoConnectionShape *>(m_currentShape)) {
- if (m_activeHandle >= 0) {
- emit statusTextChanged(i18n("Drag to edit connection."));
- } else {
- emit statusTextChanged(i18n("Double click connection or press delete to remove it."));
- }
- } else if (m_activeHandle < 0) {
- emit statusTextChanged(i18n("Click to edit connection points."));
- }
- } else {
- emit statusTextChanged(QString());
- }
- break;
- case EditConnection:
- if (m_activeHandle >= 0) {
- emit statusTextChanged(i18n("Drag to edit connection."));
- } else {
- emit statusTextChanged(i18n("Double click connection or press delete to remove it."));
- }
- break;
- case EditConnectionPoint:
- if (m_activeHandle >= KoConnectionPoint::FirstCustomConnectionPoint) {
- emit statusTextChanged(i18n("Drag to move connection point. Double click connection or press delete to remove it."));
- } else if (m_activeHandle >= 0) {
- emit statusTextChanged(i18n("Double click connection point or press delete to remove it."));
- } else {
- emit statusTextChanged(i18n("Double click to add connection point."));
- }
- break;
- case CreateConnection:
- emit statusTextChanged(i18n("Drag to create new connection."));
- break;
- default:
- emit statusTextChanged(QString());
- }
-}
-
-QList<QPointer<QWidget> > ConnectionTool::createOptionWidgets()
-{
- QList<QPointer<QWidget> > list;
-
- m_connectionShapeWidgets.clear();
-
- KoShapeFactoryBase *factory = KoShapeRegistry::instance()->get(KOCONNECTIONSHAPEID);
- if (factory) {
- QList<KoShapeConfigWidgetBase *> widgets = factory->createShapeOptionPanels();
- Q_FOREACH (KoShapeConfigWidgetBase *cw, widgets) {
- if (cw->showOnShapeCreate() || !cw->showOnShapeSelect()) {
- delete cw;
- continue;
- }
- connect(cw, SIGNAL(propertyChanged()), this, SLOT(connectionChanged()));
- KoConnectionShapeConfigWidget *cw2 = (KoConnectionShapeConfigWidget *)cw;
- if (cw2) {
- connect(cw2, SIGNAL(connectionTypeChanged(int)), this, SLOT(getConnectionType(int)));
- connect(this, SIGNAL(sendConnectionType(int)), cw2, SLOT(setConnectionType(int)));
- }
- m_connectionShapeWidgets.append(cw);
- cw->setWindowTitle(i18n("Connection"));
- list.append(cw);
- }
- }
-
- KoStrokeConfigWidget *strokeWidget = new KoStrokeConfigWidget(canvas(), 0);
- KisDocumentAwareSpinBoxUnitManager* managerLineWidth = new KisDocumentAwareSpinBoxUnitManager(strokeWidget);
- KisDocumentAwareSpinBoxUnitManager* managerMitterLimit = new KisDocumentAwareSpinBoxUnitManager(strokeWidget);
- managerLineWidth->setApparentUnitFromSymbol("px");
- managerMitterLimit->setApparentUnitFromSymbol("px");
- strokeWidget->setUnitManagers(managerLineWidth, managerMitterLimit);
- strokeWidget->setWindowTitle(i18n("Line"));
- list.append(strokeWidget);
-
- ConnectionPointWidget *connectPoint = new ConnectionPointWidget(this);
- connectPoint->setWindowTitle(i18n("Connection Point"));
- list.append(connectPoint);
-
- return list;
-}
-
-void ConnectionTool::horizontalAlignChanged()
-{
- if (m_alignPercent->isChecked()) {
- m_alignPercent->setChecked(false);
- m_alignTop->setChecked(true);
- }
- updateConnectionPoint();
-}
-
-void ConnectionTool::verticalAlignChanged()
-{
- if (m_alignPercent->isChecked()) {
- m_alignPercent->setChecked(false);
- m_alignLeft->setChecked(true);
- }
- updateConnectionPoint();
-}
-
-void ConnectionTool::relativeAlignChanged()
-{
- Q_FOREACH (QAction *action, m_alignHorizontal->actions()) {
- action->setChecked(false);
- }
- Q_FOREACH (QAction *action, m_alignVertical->actions()) {
- action->setChecked(false);
- }
- m_alignPercent->setChecked(true);
-
- updateConnectionPoint();
-}
-
-void ConnectionTool::updateConnectionPoint()
-{
- if (m_editMode == EditConnectionPoint && m_currentShape && m_activeHandle >= 0) {
- KoConnectionPoint oldPoint = m_currentShape->connectionPoint(m_activeHandle);
- KoConnectionPoint newPoint = oldPoint;
- if (m_alignPercent->isChecked()) {
- newPoint.alignment = KoConnectionPoint::AlignNone;
- } else if (m_alignLeft->isChecked() && m_alignTop->isChecked()) {
- newPoint.alignment = KoConnectionPoint::AlignTopLeft;
- } else if (m_alignCenterH->isChecked() && m_alignTop->isChecked()) {
- newPoint.alignment = KoConnectionPoint::AlignTop;
- } else if (m_alignRight->isChecked() && m_alignTop->isChecked()) {
- newPoint.alignment = KoConnectionPoint::AlignTopRight;
- } else if (m_alignLeft->isChecked() && m_alignCenterV->isChecked()) {
- newPoint.alignment = KoConnectionPoint::AlignLeft;
- } else if (m_alignCenterH->isChecked() && m_alignCenterV->isChecked()) {
- newPoint.alignment = KoConnectionPoint::AlignCenter;
- } else if (m_alignRight->isChecked() && m_alignCenterV->isChecked()) {
- newPoint.alignment = KoConnectionPoint::AlignRight;
- } else if (m_alignLeft->isChecked() && m_alignBottom->isChecked()) {
- newPoint.alignment = KoConnectionPoint::AlignBottomLeft;
- } else if (m_alignCenterH->isChecked() && m_alignBottom->isChecked()) {
- newPoint.alignment = KoConnectionPoint::AlignBottom;
- } else if (m_alignRight->isChecked() && m_alignBottom->isChecked()) {
- newPoint.alignment = KoConnectionPoint::AlignBottomRight;
- }
-
- canvas()->addCommand(new ChangeConnectionPointCommand(m_currentShape, m_activeHandle, oldPoint, newPoint));
- }
-}
-
-void ConnectionTool::escapeDirectionChanged()
-{
- if (m_editMode == EditConnectionPoint && m_currentShape && m_activeHandle >= 0) {
- KoConnectionPoint oldPoint = m_currentShape->connectionPoint(m_activeHandle);
- KoConnectionPoint newPoint = oldPoint;
- QAction *checkedAction = m_escapeDirections->checkedAction();
- if (checkedAction == m_escapeAll) {
- newPoint.escapeDirection = KoConnectionPoint::AllDirections;
- } else if (checkedAction == m_escapeHorizontal) {
- newPoint.escapeDirection = KoConnectionPoint::HorizontalDirections;
- } else if (checkedAction == m_escapeVertical) {
- newPoint.escapeDirection = KoConnectionPoint::VerticalDirections;
- } else if (checkedAction == m_escapeLeft) {
- newPoint.escapeDirection = KoConnectionPoint::LeftDirection;
- } else if (checkedAction == m_escapeRight) {
- newPoint.escapeDirection = KoConnectionPoint::RightDirection;
- } else if (checkedAction == m_escapeUp) {
- newPoint.escapeDirection = KoConnectionPoint::UpDirection;
- } else if (checkedAction == m_escapeDown) {
- newPoint.escapeDirection = KoConnectionPoint::DownDirection;
- }
- canvas()->addCommand(new ChangeConnectionPointCommand(m_currentShape, m_activeHandle, oldPoint, newPoint));
- }
-}
-
-void ConnectionTool::connectionChanged()
-{
- if (m_editMode != EditConnection) {
- return;
- }
- KoConnectionShape *connectionShape = dynamic_cast<KoConnectionShape *>(m_currentShape);
- if (!connectionShape) {
- return;
- }
-
- Q_FOREACH (KoShapeConfigWidgetBase *cw, m_connectionShapeWidgets) {
- canvas()->addCommand(cw->createCommand());
- }
-}
-
-void ConnectionTool::deleteSelection()
-{
- if (m_editMode == EditConnectionPoint && m_currentShape && m_activeHandle >= 0) {
- repaintDecorations();
- canvas()->addCommand(new RemoveConnectionPointCommand(m_currentShape, m_activeHandle));
- setEditMode(m_editMode, m_currentShape, -1);
- } else if (m_editMode == EditConnection && m_currentShape) {
- repaintDecorations();
- canvas()->addCommand(canvas()->shapeController()->removeShape(m_currentShape));
- resetEditMode();
- }
-}
-
-void ConnectionTool::getConnectionType(int type)
-{
- if (m_editMode == Idle) {
- m_connectionType = (KoConnectionShape::Type)type;
- }
-}
-
-void ConnectionTool::toggleConnectionPointEditMode(int state)
-{
- if (state == Qt::Checked) {
- setEditMode(EditConnectionPoint, 0, -1);
- } else if (state == Qt::Unchecked) {
- setEditMode(Idle, 0, -1);
- } else {
- return;
- }
-}
diff --git a/plugins/tools/defaulttool/connectionTool/ConnectionTool.h b/plugins/tools/defaulttool/connectionTool/ConnectionTool.h
deleted file mode 100644
index 13c12ef320..0000000000
--- a/plugins/tools/defaulttool/connectionTool/ConnectionTool.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2009 Jean-Nicolas Artaud <jeannicolasartaud@gmail.com>
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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_CONNECTION_TOOL_H
-#define KO_CONNECTION_TOOL_H
-
-#define ConnectionTool_ID "ConnectionTool"
-
-#include <KoToolBase.h>
-#include <KoCanvasBase.h>
-#include <KoSnapGuide.h>
-#include <KoConnectionShape.h>
-#include <QCursor>
-
-class QAction;
-class QActionGroup;
-class KoShapeConfigWidgetBase;
-class KoInteractionStrategy;
-
-class ConnectionTool : public KoToolBase
-{
- Q_OBJECT
-public:
- /**
- * @brief Constructor
- */
- explicit ConnectionTool(KoCanvasBase *canvas);
- /**
- * @brief Destructor
- */
- ~ConnectionTool() override;
-
- /// reimplemented from superclass
- void paint(QPainter &painter, const KoViewConverter &converter) override;
- /// reimplemented from superclass
- void repaintDecorations() override;
-
- /// reimplemented from superclass
- void mousePressEvent(KoPointerEvent *event) override;
- /// reimplemented from superclass
- void mouseMoveEvent(KoPointerEvent *event) override;
- /// reimplemented from superclass
- void mouseReleaseEvent(KoPointerEvent *event) override;
- /// reimplemented from superclass
- void mouseDoubleClickEvent(KoPointerEvent *event) override;
- /// reimplemented from superclass
- void keyPressEvent(QKeyEvent *event) override;
- /// reimplemented from superclass
- void activate(ToolActivation activation, const QSet<KoShape *> &shapes) override;
- /// reimplemented from superclass
- void deactivate() override;
- /// reimplemented from superclass
- void deleteSelection() override;
-
-Q_SIGNALS:
- void connectionPointEnabled(bool enabled);
- void sendConnectionType(int type);
- void sendConnectionPointEditState(bool enabled);
-
-public Q_SLOTS:
- void toggleConnectionPointEditMode(int state);
-
-private Q_SLOTS:
- void horizontalAlignChanged();
- void verticalAlignChanged();
- void relativeAlignChanged();
- void escapeDirectionChanged();
- void connectionChanged();
- void getConnectionType(int type);
-
-private:
- /// reimplemented from superclass
- QList<QPointer<QWidget> > createOptionWidgets() override;
-
- /**
- * @brief Return the square of the absolute distance between p1 and p2
- *
- * @param p1 The first point
- * @param p2 The second point
- * @return The float which is the square of the distance
- */
- qreal squareDistance(const QPointF &p1, const QPointF &p2) const;
-
- /// Returns nearest connection handle or nearest connection point id of shape
- int handleAtPoint(KoShape *shape, const QPointF &mousePoint) const;
-
- enum EditMode {
- Idle, ///< in idle mode we can only start a connector creation, manipulation to existing connectors and connection points not allowed
- CreateConnection, ///< we are creating a new connection
- EditConnection, ///< we are editing a connection
- EditConnectionPoint ///< we are editing connection points
- };
-
- /// Sets the edit mode, current shape and active handle
- void setEditMode(EditMode mode, KoShape *currentShape, int handle);
-
- /// Resets the current edit mode to Idle, standard connector type
- void resetEditMode();
-
- /// Returns the nearest connection shape within handle grab sensitiviy distance
- KoConnectionShape *nearestConnectionShape(const QList<KoShape *> &shapes, const QPointF &mousePos) const;
-
- /// Updates status text depending on edit mode
- void updateStatusText();
-
- /// Updates current shape and edit mode dependent on position
- KoShape *findShapeAtPosition(const QPointF &position) const;
-
- /// Updates current shape and edit mode dependent on position excluding connection shapes
- KoShape *findNonConnectionShapeAtPosition(const QPointF &position) const;
-
- /// Updates actions
- void updateActions();
-
- /// Updates currently selected connection point
- void updateConnectionPoint();
-
- EditMode m_editMode; ///< the current edit mode
- KoConnectionShape::Type m_connectionType;
- KoShape *m_currentShape; ///< the current shape we are working on
- int m_activeHandle; ///< the currently active connection point/connection handle
- KoInteractionStrategy *m_currentStrategy; ///< the current editing strategy
- KoSnapGuide::Strategies m_oldSnapStrategies; ///< the previously enables snap strategies
- bool m_resetPaint; ///< whether in initial paint mode
- QCursor m_connectCursor;
-
- QActionGroup *m_alignVertical;
- QActionGroup *m_alignHorizontal;
- QActionGroup *m_alignRelative;
- QActionGroup *m_escapeDirections;
-
- QAction *m_editConnectionPoint;
-
- QAction *m_alignPercent;
- QAction *m_alignLeft;
- QAction *m_alignCenterH;
- QAction *m_alignRight;
- QAction *m_alignTop;
- QAction *m_alignCenterV;
- QAction *m_alignBottom;
-
- QAction *m_escapeAll;
- QAction *m_escapeHorizontal;
- QAction *m_escapeVertical;
- QAction *m_escapeUp;
- QAction *m_escapeLeft;
- QAction *m_escapeDown;
- QAction *m_escapeRight;
-
- QList<KoShapeConfigWidgetBase *> m_connectionShapeWidgets;
-};
-
-#endif // KO_CONNECTION_TOOL_H
diff --git a/plugins/tools/defaulttool/connectionTool/ConnectionToolFactory.cpp b/plugins/tools/defaulttool/connectionTool/ConnectionToolFactory.cpp
deleted file mode 100644
index cdda1bff4d..0000000000
--- a/plugins/tools/defaulttool/connectionTool/ConnectionToolFactory.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2009 Jean-Nicolas Artaud <jeannicolasartaud@gmail.com>
- *
- * 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 "ConnectionToolFactory.h"
-#include "ConnectionTool.h"
-
-#include <KoIcon.h>
-#include <klocalizedstring.h>
-#include <QDebug>
-
-ConnectionToolFactory::ConnectionToolFactory()
- : KoToolFactoryBase(ConnectionTool_ID)
-{
- setToolTip(i18n("Connect shapes"));
- setIconName(koIconNameCStr("x-shape-connection"));
- setSection(mainToolType());
- setPriority(5);
- setActivationShapeId("flake/always");
-}
-
-ConnectionToolFactory::~ConnectionToolFactory()
-{
-}
-
-KoToolBase *ConnectionToolFactory::createTool(KoCanvasBase *canvas)
-{
- return new ConnectionTool(canvas);
-}
diff --git a/plugins/tools/defaulttool/connectionTool/ConnectionToolFactory.h b/plugins/tools/defaulttool/connectionTool/ConnectionToolFactory.h
deleted file mode 100644
index 213d8b7832..0000000000
--- a/plugins/tools/defaulttool/connectionTool/ConnectionToolFactory.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2009 Jean-Nicolas Artaud <jeannicolasartaud@gmail.com>
- *
- * 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 CONNECTIONTOOLFACTORY_H
-#define CONNECTIONTOOLFACTORY_H
-
-#include "KoToolFactoryBase.h"
-
-/// The factory for the ConnectionTool
-class ConnectionToolFactory : public KoToolFactoryBase
-{
-public:
- /// Constructor
- ConnectionToolFactory();
- /// Destructor
- ~ConnectionToolFactory() override;
- /// reimplemented
- KoToolBase *createTool(KoCanvasBase *canvas) override;
-};
-
-#endif
diff --git a/plugins/tools/defaulttool/connectionTool/MoveConnectionPointStrategy.cpp b/plugins/tools/defaulttool/connectionTool/MoveConnectionPointStrategy.cpp
deleted file mode 100644
index 892fa6dff3..0000000000
--- a/plugins/tools/defaulttool/connectionTool/MoveConnectionPointStrategy.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "MoveConnectionPointStrategy.h"
-#include "ChangeConnectionPointCommand.h"
-#include <KoShape.h>
-#include <KoToolBase.h>
-#include <KoCanvasBase.h>
-
-MoveConnectionPointStrategy::MoveConnectionPointStrategy(KoShape *shape, int connectionPointId, KoToolBase *parent)
- : KoInteractionStrategy(parent)
- , m_shape(shape)
- , m_connectionPointId(connectionPointId)
-{
- Q_ASSERT(m_shape);
- m_oldPoint = m_newPoint = m_shape->connectionPoint(m_connectionPointId);
-}
-
-MoveConnectionPointStrategy::~MoveConnectionPointStrategy()
-{
-}
-
-void MoveConnectionPointStrategy::paint(QPainter &painter, const KoViewConverter &converter)
-{
- KoInteractionStrategy::paint(painter, converter);
-}
-
-void MoveConnectionPointStrategy::handleMouseMove(const QPointF &mouseLocation, Qt::KeyboardModifiers /*modifiers*/)
-{
- m_newPoint.position = m_shape->documentToShape(mouseLocation);
- m_shape->setConnectionPoint(m_connectionPointId, m_newPoint);
-}
-
-void MoveConnectionPointStrategy::cancelInteraction()
-{
- KoInteractionStrategy::cancelInteraction();
- m_shape->setConnectionPoint(m_connectionPointId, m_oldPoint);
-}
-
-void MoveConnectionPointStrategy::finishInteraction(Qt::KeyboardModifiers /*modifiers*/)
-{
-}
-
-KUndo2Command *MoveConnectionPointStrategy::createCommand()
-{
- int grabDistance = grabSensitivity();
- const qreal dx = m_newPoint.position.x() - m_oldPoint.position.x();
- const qreal dy = m_newPoint.position.y() - m_oldPoint.position.y();
- // check if we have moved the connection point at least a little bit
- if (dx * dx + dy * dy < grabDistance * grabDistance) {
- return 0;
- }
-
- return new ChangeConnectionPointCommand(m_shape, m_connectionPointId, m_oldPoint, m_newPoint);
-}
diff --git a/plugins/tools/defaulttool/connectionTool/MoveConnectionPointStrategy.h b/plugins/tools/defaulttool/connectionTool/MoveConnectionPointStrategy.h
deleted file mode 100644
index d77859c705..0000000000
--- a/plugins/tools/defaulttool/connectionTool/MoveConnectionPointStrategy.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 MOVECONNECTIONPOINTSTRATEGY_H
-#define MOVECONNECTIONPOINTSTRATEGY_H
-
-#include <KoInteractionStrategy.h>
-#include <KoConnectionPoint.h>
-#include <QPointF>
-
-class KoShape;
-
-class MoveConnectionPointStrategy : public KoInteractionStrategy
-{
-public:
- /// Constructor
- MoveConnectionPointStrategy(KoShape *shape, int connectionPointId, KoToolBase *parent);
- /// Destructor
- ~MoveConnectionPointStrategy() override;
-
- /// reimplemented from KoInteractionStrategy
- void paint(QPainter &painter, const KoViewConverter &converter) override;
-
- /// reimplemented from KoInteractionStrategy
- void handleMouseMove(const QPointF &mouseLocation, Qt::KeyboardModifiers modifiers) override;
-
- /// reimplemented from KoInteractionStrategy
- KUndo2Command *createCommand() override;
-
- /// reimplemented from KoInteractionStrategy
- void cancelInteraction() override;
-
- /// reimplemented from KoInteractionStrategy
- void finishInteraction(Qt::KeyboardModifiers modifiers) override;
-
-private:
- KoShape *m_shape;
- int m_connectionPointId;
- KoConnectionPoint m_oldPoint;
- KoConnectionPoint m_newPoint;
-};
-
-#endif // MOVECONNECTIONPOINTSTRATEGY_H
diff --git a/plugins/tools/defaulttool/connectionTool/RemoveConnectionPointCommand.cpp b/plugins/tools/defaulttool/connectionTool/RemoveConnectionPointCommand.cpp
deleted file mode 100644
index 08f09ecc48..0000000000
--- a/plugins/tools/defaulttool/connectionTool/RemoveConnectionPointCommand.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 "RemoveConnectionPointCommand.h"
-#include <KoShape.h>
-
-RemoveConnectionPointCommand::RemoveConnectionPointCommand(KoShape *shape, int connectionPointId, KUndo2Command *parent)
- : KUndo2Command(parent)
- , m_shape(shape)
- , m_connectionPointId(connectionPointId)
-{
- Q_ASSERT(m_shape);
- m_connectionPoint = m_shape->connectionPoint(m_connectionPointId);
-}
-
-RemoveConnectionPointCommand::~RemoveConnectionPointCommand()
-{
-}
-
-void RemoveConnectionPointCommand::redo()
-{
- // TODO: check if there is a connection shape attached
- // and handle that appropriately
- m_shape->removeConnectionPoint(m_connectionPointId);
- updateRoi();
-
- KUndo2Command::redo();
-}
-
-void RemoveConnectionPointCommand::undo()
-{
- KUndo2Command::undo();
-
- m_shape->setConnectionPoint(m_connectionPointId, m_connectionPoint);
- updateRoi();
-}
-
-void RemoveConnectionPointCommand::updateRoi()
-{
- // TODO: is there a way we can get at the correct update size?
- //QRectF roi(0, 0, 10, 10);
- //roi.moveCenter(m_connectionPoint.position);
- //m_shape->update(roi);
-}
diff --git a/plugins/tools/defaulttool/connectionTool/RemoveConnectionPointCommand.h b/plugins/tools/defaulttool/connectionTool/RemoveConnectionPointCommand.h
deleted file mode 100644
index a147a704f3..0000000000
--- a/plugins/tools/defaulttool/connectionTool/RemoveConnectionPointCommand.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* This file is part of the KDE project
- *
- * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.net>
- *
- * 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 REMOVECONNECTIONPOINTCOMMAND_H
-#define REMOVECONNECTIONPOINTCOMMAND_H
-
-#include <KoConnectionPoint.h>
-#include <kundo2command.h>
-#include <QPointF>
-
-class KoShape;
-
-class RemoveConnectionPointCommand : public KUndo2Command
-{
-public:
- /// Creates new command to remove connection point from shape
- RemoveConnectionPointCommand(KoShape *shape, int connectionPointId, KUndo2Command *parent = 0);
- ~RemoveConnectionPointCommand() override;
- /// reimplemented from KUndo2Command
- void redo() override;
- /// reimplemented from KUndo2Command
- void undo() override;
-
-private:
- void updateRoi();
-
- KoShape *m_shape;
- KoConnectionPoint m_connectionPoint;
- int m_connectionPointId;
-};
-
-#endif // REMOVECONNECTIONPOINTCOMMAND_H
diff --git a/plugins/tools/defaulttool/defaulttool/DefaultTool.cpp b/plugins/tools/defaulttool/defaulttool/DefaultTool.cpp
index 4f2512c699..9078bea76a 100644
--- a/plugins/tools/defaulttool/defaulttool/DefaultTool.cpp
+++ b/plugins/tools/defaulttool/defaulttool/DefaultTool.cpp
@@ -1,1748 +1,1747 @@
/* This file is part of the KDE project
Copyright (C) 2006-2008 Thorsten Zachmann <zachmann@kde.org>
Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
Copyright (C) 2008-2009 Jan Hambrecht <jaham@gmx.net>
Copyright (C) 2008 C. Boemann <cbo@boemann.dk>
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 "DefaultTool.h"
#include "DefaultToolGeometryWidget.h"
#include "DefaultToolTabbedWidget.h"
#include "SelectionDecorator.h"
#include "ShapeMoveStrategy.h"
#include "ShapeRotateStrategy.h"
#include "ShapeShearStrategy.h"
#include "ShapeResizeStrategy.h"
#include <KoPointerEvent.h>
#include <KoToolSelection.h>
#include <KoToolManager.h>
#include <KoSelection.h>
#include <KoShapeController.h>
#include <KoShapeManager.h>
#include <KoSelectedShapesProxy.h>
#include <KoShapeGroup.h>
#include <KoShapeLayer.h>
-#include <KoShapeOdfSaveHelper.h>
#include <KoPathShape.h>
#include <KoDrag.h>
#include <KoCanvasBase.h>
#include <KoCanvasResourceProvider.h>
#include <KoShapeRubberSelectStrategy.h>
#include <commands/KoShapeMoveCommand.h>
#include <commands/KoShapeTransformCommand.h>
#include <commands/KoShapeDeleteCommand.h>
#include <commands/KoShapeCreateCommand.h>
#include <commands/KoShapeGroupCommand.h>
#include <commands/KoShapeUngroupCommand.h>
#include <commands/KoShapeDistributeCommand.h>
#include <commands/KoKeepShapesSelectedCommand.h>
#include <KoSnapGuide.h>
#include <KoStrokeConfigWidget.h>
#include "kis_action_registry.h"
#include "kis_node.h"
#include "kis_node_manager.h"
#include "KisViewManager.h"
#include "kis_canvas2.h"
#include "kis_canvas_resource_provider.h"
#include <KoInteractionStrategyFactory.h>
#include "kis_document_aware_spin_box_unit_manager.h"
#include <KoIcon.h>
#include <QPainterPath>
#include <QPointer>
#include <QAction>
#include <QKeyEvent>
#include <KisSignalMapper.h>
#include <KoResourcePaths.h>
#include <KoCanvasController.h>
#include <kactioncollection.h>
#include <QMenu>
#include <math.h>
#include "kis_assert.h"
#include "kis_global.h"
#include "kis_debug.h"
#include "krita_utils.h"
#include <QVector2D>
#define HANDLE_DISTANCE 10
#define HANDLE_DISTANCE_SQ (HANDLE_DISTANCE * HANDLE_DISTANCE)
#define INNER_HANDLE_DISTANCE_SQ 16
namespace {
static const QString EditFillGradientFactoryId = "edit_fill_gradient";
static const QString EditStrokeGradientFactoryId = "edit_stroke_gradient";
enum TransformActionType {
TransformRotate90CW,
TransformRotate90CCW,
TransformRotate180,
TransformMirrorX,
TransformMirrorY,
TransformReset
};
enum BooleanOp {
BooleanUnion,
BooleanIntersection,
BooleanSubtraction
};
}
class NopInteractionStrategy : public KoInteractionStrategy
{
public:
explicit NopInteractionStrategy(KoToolBase *parent)
: KoInteractionStrategy(parent)
{
}
KUndo2Command *createCommand() override
{
return 0;
}
void handleMouseMove(const QPointF & /*mouseLocation*/, Qt::KeyboardModifiers /*modifiers*/) override {}
void finishInteraction(Qt::KeyboardModifiers /*modifiers*/) override {}
void paint(QPainter &painter, const KoViewConverter &converter) override {
Q_UNUSED(painter);
Q_UNUSED(converter);
}
};
class SelectionInteractionStrategy : public KoShapeRubberSelectStrategy
{
public:
explicit SelectionInteractionStrategy(KoToolBase *parent, const QPointF &clicked, bool useSnapToGrid)
: KoShapeRubberSelectStrategy(parent, clicked, useSnapToGrid)
{
}
void paint(QPainter &painter, const KoViewConverter &converter) override {
KoShapeRubberSelectStrategy::paint(painter, converter);
}
void finishInteraction(Qt::KeyboardModifiers modifiers = 0) override
{
Q_UNUSED(modifiers);
DefaultTool *defaultTool = dynamic_cast<DefaultTool*>(tool());
KIS_SAFE_ASSERT_RECOVER_RETURN(defaultTool);
KoSelection * selection = defaultTool->koSelection();
const bool useContainedMode = currentMode() == CoveringSelection;
QList<KoShape *> shapes =
defaultTool->shapeManager()->
shapesAt(selectedRectangle(), true, useContainedMode);
Q_FOREACH (KoShape * shape, shapes) {
if (!shape->isSelectable()) continue;
selection->select(shape);
}
defaultTool->repaintDecorations();
defaultTool->canvas()->updateCanvas(selectedRectangle());
}
};
#include <KoGradientBackground.h>
#include "KoShapeGradientHandles.h"
#include "ShapeGradientEditStrategy.h"
class DefaultTool::MoveGradientHandleInteractionFactory : public KoInteractionStrategyFactory
{
public:
MoveGradientHandleInteractionFactory(KoFlake::FillVariant fillVariant,
int priority, const QString &id, DefaultTool *_q)
: KoInteractionStrategyFactory(priority, id),
q(_q),
m_fillVariant(fillVariant)
{
}
KoInteractionStrategy* createStrategy(KoPointerEvent *ev) override
{
m_currentHandle = handleAt(ev->point);
if (m_currentHandle.type != KoShapeGradientHandles::Handle::None) {
KoShape *shape = onlyEditableShape();
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(shape, 0);
return new ShapeGradientEditStrategy(q, m_fillVariant, shape, m_currentHandle.type, ev->point);
}
return 0;
}
bool hoverEvent(KoPointerEvent *ev) override
{
m_currentHandle = handleAt(ev->point);
return false;
}
bool paintOnHover(QPainter &painter, const KoViewConverter &converter) override
{
Q_UNUSED(painter);
Q_UNUSED(converter);
return false;
}
bool tryUseCustomCursor() override {
if (m_currentHandle.type != KoShapeGradientHandles::Handle::None) {
q->useCursor(Qt::OpenHandCursor);
return true;
}
return false;
}
private:
KoShape* onlyEditableShape() const {
KoSelection *selection = q->koSelection();
QList<KoShape*> shapes = selection->selectedEditableShapes();
KoShape *shape = 0;
if (shapes.size() == 1) {
shape = shapes.first();
}
return shape;
}
KoShapeGradientHandles::Handle handleAt(const QPointF &pos) {
KoShapeGradientHandles::Handle result;
KoShape *shape = onlyEditableShape();
if (shape) {
KoFlake::SelectionHandle globalHandle = q->handleAt(pos);
const qreal distanceThresholdSq =
globalHandle == KoFlake::NoHandle ?
HANDLE_DISTANCE_SQ : 0.25 * HANDLE_DISTANCE_SQ;
const KoViewConverter *converter = q->canvas()->viewConverter();
const QPointF viewPoint = converter->documentToView(pos);
qreal minDistanceSq = std::numeric_limits<qreal>::max();
KoShapeGradientHandles sh(m_fillVariant, shape);
Q_FOREACH (const KoShapeGradientHandles::Handle &handle, sh.handles()) {
const QPointF handlePoint = converter->documentToView(handle.pos);
const qreal distanceSq = kisSquareDistance(viewPoint, handlePoint);
if (distanceSq < distanceThresholdSq && distanceSq < minDistanceSq) {
result = handle;
minDistanceSq = distanceSq;
}
}
}
return result;
}
private:
DefaultTool *q;
KoFlake::FillVariant m_fillVariant;
KoShapeGradientHandles::Handle m_currentHandle;
};
class SelectionHandler : public KoToolSelection
{
public:
SelectionHandler(DefaultTool *parent)
: KoToolSelection(parent)
, m_selection(parent->koSelection())
{
}
bool hasSelection() override
{
if (m_selection) {
return m_selection->count();
}
return false;
}
private:
QPointer<KoSelection> m_selection;
};
DefaultTool::DefaultTool(KoCanvasBase *canvas, bool connectToSelectedShapesProxy)
: KoInteractionTool(canvas)
, m_lastHandle(KoFlake::NoHandle)
, m_hotPosition(KoFlake::TopLeft)
, m_mouseWasInsideHandles(false)
, m_decorator(0)
, m_selectionHandler(new SelectionHandler(this))
, m_tabbedOptionWidget(0)
{
setupActions();
QPixmap rotatePixmap, shearPixmap;
rotatePixmap.load(":/cursor_rotate.png");
Q_ASSERT(!rotatePixmap.isNull());
shearPixmap.load(":/cursor_shear.png");
Q_ASSERT(!shearPixmap.isNull());
m_rotateCursors[0] = QCursor(rotatePixmap.transformed(QTransform().rotate(45)));
m_rotateCursors[1] = QCursor(rotatePixmap.transformed(QTransform().rotate(90)));
m_rotateCursors[2] = QCursor(rotatePixmap.transformed(QTransform().rotate(135)));
m_rotateCursors[3] = QCursor(rotatePixmap.transformed(QTransform().rotate(180)));
m_rotateCursors[4] = QCursor(rotatePixmap.transformed(QTransform().rotate(225)));
m_rotateCursors[5] = QCursor(rotatePixmap.transformed(QTransform().rotate(270)));
m_rotateCursors[6] = QCursor(rotatePixmap.transformed(QTransform().rotate(315)));
m_rotateCursors[7] = QCursor(rotatePixmap);
/*
m_rotateCursors[0] = QCursor(Qt::RotateNCursor);
m_rotateCursors[1] = QCursor(Qt::RotateNECursor);
m_rotateCursors[2] = QCursor(Qt::RotateECursor);
m_rotateCursors[3] = QCursor(Qt::RotateSECursor);
m_rotateCursors[4] = QCursor(Qt::RotateSCursor);
m_rotateCursors[5] = QCursor(Qt::RotateSWCursor);
m_rotateCursors[6] = QCursor(Qt::RotateWCursor);
m_rotateCursors[7] = QCursor(Qt::RotateNWCursor);
*/
m_shearCursors[0] = QCursor(shearPixmap);
m_shearCursors[1] = QCursor(shearPixmap.transformed(QTransform().rotate(45)));
m_shearCursors[2] = QCursor(shearPixmap.transformed(QTransform().rotate(90)));
m_shearCursors[3] = QCursor(shearPixmap.transformed(QTransform().rotate(135)));
m_shearCursors[4] = QCursor(shearPixmap.transformed(QTransform().rotate(180)));
m_shearCursors[5] = QCursor(shearPixmap.transformed(QTransform().rotate(225)));
m_shearCursors[6] = QCursor(shearPixmap.transformed(QTransform().rotate(270)));
m_shearCursors[7] = QCursor(shearPixmap.transformed(QTransform().rotate(315)));
m_sizeCursors[0] = Qt::SizeVerCursor;
m_sizeCursors[1] = Qt::SizeBDiagCursor;
m_sizeCursors[2] = Qt::SizeHorCursor;
m_sizeCursors[3] = Qt::SizeFDiagCursor;
m_sizeCursors[4] = Qt::SizeVerCursor;
m_sizeCursors[5] = Qt::SizeBDiagCursor;
m_sizeCursors[6] = Qt::SizeHorCursor;
m_sizeCursors[7] = Qt::SizeFDiagCursor;
if (connectToSelectedShapesProxy) {
connect(canvas->selectedShapesProxy(), SIGNAL(selectionChanged()), this, SLOT(updateActions()));
}
}
DefaultTool::~DefaultTool()
{
}
void DefaultTool::slotActivateEditFillGradient(bool value)
{
if (value) {
addInteractionFactory(
new MoveGradientHandleInteractionFactory(KoFlake::Fill,
1, EditFillGradientFactoryId, this));
} else {
removeInteractionFactory(EditFillGradientFactoryId);
}
repaintDecorations();
}
void DefaultTool::slotActivateEditStrokeGradient(bool value)
{
if (value) {
addInteractionFactory(
new MoveGradientHandleInteractionFactory(KoFlake::StrokeFill,
0, EditStrokeGradientFactoryId, this));
} else {
removeInteractionFactory(EditStrokeGradientFactoryId);
}
repaintDecorations();
}
bool DefaultTool::wantsAutoScroll() const
{
return true;
}
void DefaultTool::addMappedAction(KisSignalMapper *mapper, const QString &actionId, int commandType)
{
QAction *a =action(actionId);
connect(a, SIGNAL(triggered()), mapper, SLOT(map()));
mapper->setMapping(a, commandType);
}
void DefaultTool::setupActions()
{
m_alignSignalsMapper = new KisSignalMapper(this);
addMappedAction(m_alignSignalsMapper, "object_align_horizontal_left", KoShapeAlignCommand::HorizontalLeftAlignment);
addMappedAction(m_alignSignalsMapper, "object_align_horizontal_center", KoShapeAlignCommand::HorizontalCenterAlignment);
addMappedAction(m_alignSignalsMapper, "object_align_horizontal_right", KoShapeAlignCommand::HorizontalRightAlignment);
addMappedAction(m_alignSignalsMapper, "object_align_vertical_top", KoShapeAlignCommand::VerticalTopAlignment);
addMappedAction(m_alignSignalsMapper, "object_align_vertical_center", KoShapeAlignCommand::VerticalCenterAlignment);
addMappedAction(m_alignSignalsMapper, "object_align_vertical_bottom", KoShapeAlignCommand::VerticalBottomAlignment);
m_distributeSignalsMapper = new KisSignalMapper(this);
addMappedAction(m_distributeSignalsMapper, "object_distribute_horizontal_left", KoShapeDistributeCommand::HorizontalLeftDistribution);
addMappedAction(m_distributeSignalsMapper, "object_distribute_horizontal_center", KoShapeDistributeCommand::HorizontalCenterDistribution);
addMappedAction(m_distributeSignalsMapper, "object_distribute_horizontal_right", KoShapeDistributeCommand::HorizontalRightDistribution);
addMappedAction(m_distributeSignalsMapper, "object_distribute_horizontal_gaps", KoShapeDistributeCommand::HorizontalGapsDistribution);
addMappedAction(m_distributeSignalsMapper, "object_distribute_vertical_top", KoShapeDistributeCommand::VerticalTopDistribution);
addMappedAction(m_distributeSignalsMapper, "object_distribute_vertical_center", KoShapeDistributeCommand::VerticalCenterDistribution);
addMappedAction(m_distributeSignalsMapper, "object_distribute_vertical_bottom", KoShapeDistributeCommand::VerticalBottomDistribution);
addMappedAction(m_distributeSignalsMapper, "object_distribute_vertical_gaps", KoShapeDistributeCommand::VerticalGapsDistribution);
m_transformSignalsMapper = new KisSignalMapper(this);
addMappedAction(m_transformSignalsMapper, "object_transform_rotate_90_cw", TransformRotate90CW);
addMappedAction(m_transformSignalsMapper, "object_transform_rotate_90_ccw", TransformRotate90CCW);
addMappedAction(m_transformSignalsMapper, "object_transform_rotate_180", TransformRotate180);
addMappedAction(m_transformSignalsMapper, "object_transform_mirror_horizontally", TransformMirrorX);
addMappedAction(m_transformSignalsMapper, "object_transform_mirror_vertically", TransformMirrorY);
addMappedAction(m_transformSignalsMapper, "object_transform_reset", TransformReset);
m_booleanSignalsMapper = new KisSignalMapper(this);
addMappedAction(m_booleanSignalsMapper, "object_unite", BooleanUnion);
addMappedAction(m_booleanSignalsMapper, "object_intersect", BooleanIntersection);
addMappedAction(m_booleanSignalsMapper, "object_subtract", BooleanSubtraction);
m_contextMenu.reset(new QMenu());
}
qreal DefaultTool::rotationOfHandle(KoFlake::SelectionHandle handle, bool useEdgeRotation)
{
QPointF selectionCenter = koSelection()->absolutePosition();
QPointF direction;
switch (handle) {
case KoFlake::TopMiddleHandle:
if (useEdgeRotation) {
direction = koSelection()->absolutePosition(KoFlake::TopRight)
- koSelection()->absolutePosition(KoFlake::TopLeft);
} else {
QPointF handlePosition = koSelection()->absolutePosition(KoFlake::TopLeft);
handlePosition += 0.5 * (koSelection()->absolutePosition(KoFlake::TopRight) - handlePosition);
direction = handlePosition - selectionCenter;
}
break;
case KoFlake::TopRightHandle:
direction = (QVector2D(koSelection()->absolutePosition(KoFlake::TopRight) - koSelection()->absolutePosition(KoFlake::TopLeft)).normalized() + QVector2D(koSelection()->absolutePosition(KoFlake::TopRight) - koSelection()->absolutePosition(KoFlake::BottomRight)).normalized()).toPointF();
break;
case KoFlake::RightMiddleHandle:
if (useEdgeRotation) {
direction = koSelection()->absolutePosition(KoFlake::BottomRight)
- koSelection()->absolutePosition(KoFlake::TopRight);
} else {
QPointF handlePosition = koSelection()->absolutePosition(KoFlake::TopRight);
handlePosition += 0.5 * (koSelection()->absolutePosition(KoFlake::BottomRight) - handlePosition);
direction = handlePosition - selectionCenter;
}
break;
case KoFlake::BottomRightHandle:
direction = (QVector2D(koSelection()->absolutePosition(KoFlake::BottomRight) - koSelection()->absolutePosition(KoFlake::BottomLeft)).normalized() + QVector2D(koSelection()->absolutePosition(KoFlake::BottomRight) - koSelection()->absolutePosition(KoFlake::TopRight)).normalized()).toPointF();
break;
case KoFlake::BottomMiddleHandle:
if (useEdgeRotation) {
direction = koSelection()->absolutePosition(KoFlake::BottomLeft)
- koSelection()->absolutePosition(KoFlake::BottomRight);
} else {
QPointF handlePosition = koSelection()->absolutePosition(KoFlake::BottomLeft);
handlePosition += 0.5 * (koSelection()->absolutePosition(KoFlake::BottomRight) - handlePosition);
direction = handlePosition - selectionCenter;
}
break;
case KoFlake::BottomLeftHandle:
direction = koSelection()->absolutePosition(KoFlake::BottomLeft) - selectionCenter;
direction = (QVector2D(koSelection()->absolutePosition(KoFlake::BottomLeft) - koSelection()->absolutePosition(KoFlake::BottomRight)).normalized() + QVector2D(koSelection()->absolutePosition(KoFlake::BottomLeft) - koSelection()->absolutePosition(KoFlake::TopLeft)).normalized()).toPointF();
break;
case KoFlake::LeftMiddleHandle:
if (useEdgeRotation) {
direction = koSelection()->absolutePosition(KoFlake::TopLeft)
- koSelection()->absolutePosition(KoFlake::BottomLeft);
} else {
QPointF handlePosition = koSelection()->absolutePosition(KoFlake::TopLeft);
handlePosition += 0.5 * (koSelection()->absolutePosition(KoFlake::BottomLeft) - handlePosition);
direction = handlePosition - selectionCenter;
}
break;
case KoFlake::TopLeftHandle:
direction = koSelection()->absolutePosition(KoFlake::TopLeft) - selectionCenter;
direction = (QVector2D(koSelection()->absolutePosition(KoFlake::TopLeft) - koSelection()->absolutePosition(KoFlake::TopRight)).normalized() + QVector2D(koSelection()->absolutePosition(KoFlake::TopLeft) - koSelection()->absolutePosition(KoFlake::BottomLeft)).normalized()).toPointF();
break;
case KoFlake::NoHandle:
return 0.0;
break;
}
qreal rotation = atan2(direction.y(), direction.x()) * 180.0 / M_PI;
switch (handle) {
case KoFlake::TopMiddleHandle:
if (useEdgeRotation) {
rotation -= 0.0;
} else {
rotation -= 270.0;
}
break;
case KoFlake::TopRightHandle:
rotation -= 315.0;
break;
case KoFlake::RightMiddleHandle:
if (useEdgeRotation) {
rotation -= 90.0;
} else {
rotation -= 0.0;
}
break;
case KoFlake::BottomRightHandle:
rotation -= 45.0;
break;
case KoFlake::BottomMiddleHandle:
if (useEdgeRotation) {
rotation -= 180.0;
} else {
rotation -= 90.0;
}
break;
case KoFlake::BottomLeftHandle:
rotation -= 135.0;
break;
case KoFlake::LeftMiddleHandle:
if (useEdgeRotation) {
rotation -= 270.0;
} else {
rotation -= 180.0;
}
break;
case KoFlake::TopLeftHandle:
rotation -= 225.0;
break;
default:
;
}
if (rotation < 0.0) {
rotation += 360.0;
}
return rotation;
}
void DefaultTool::updateCursor()
{
if (tryUseCustomCursor()) return;
QCursor cursor = Qt::ArrowCursor;
QString statusText;
KoSelection *selection = koSelection();
if (selection && selection->count() > 0) { // has a selection
bool editable = !selection->selectedEditableShapes().isEmpty();
if (!m_mouseWasInsideHandles) {
m_angle = rotationOfHandle(m_lastHandle, true);
int rotOctant = 8 + int(8.5 + m_angle / 45);
bool rotateHandle = false;
bool shearHandle = false;
switch (m_lastHandle) {
case KoFlake::TopMiddleHandle:
cursor = m_shearCursors[(0 + rotOctant) % 8];
shearHandle = true;
break;
case KoFlake::TopRightHandle:
cursor = m_rotateCursors[(1 + rotOctant) % 8];
rotateHandle = true;
break;
case KoFlake::RightMiddleHandle:
cursor = m_shearCursors[(2 + rotOctant) % 8];
shearHandle = true;
break;
case KoFlake::BottomRightHandle:
cursor = m_rotateCursors[(3 + rotOctant) % 8];
rotateHandle = true;
break;
case KoFlake::BottomMiddleHandle:
cursor = m_shearCursors[(4 + rotOctant) % 8];
shearHandle = true;
break;
case KoFlake::BottomLeftHandle:
cursor = m_rotateCursors[(5 + rotOctant) % 8];
rotateHandle = true;
break;
case KoFlake::LeftMiddleHandle:
cursor = m_shearCursors[(6 + rotOctant) % 8];
shearHandle = true;
break;
case KoFlake::TopLeftHandle:
cursor = m_rotateCursors[(7 + rotOctant) % 8];
rotateHandle = true;
break;
case KoFlake::NoHandle:
cursor = Qt::ArrowCursor;
break;
}
if (rotateHandle) {
statusText = i18n("Left click rotates around center, right click around highlighted position.");
}
if (shearHandle) {
statusText = i18n("Click and drag to shear selection.");
}
} else {
statusText = i18n("Click and drag to resize selection.");
m_angle = rotationOfHandle(m_lastHandle, false);
int rotOctant = 8 + int(8.5 + m_angle / 45);
bool cornerHandle = false;
switch (m_lastHandle) {
case KoFlake::TopMiddleHandle:
cursor = m_sizeCursors[(0 + rotOctant) % 8];
break;
case KoFlake::TopRightHandle:
cursor = m_sizeCursors[(1 + rotOctant) % 8];
cornerHandle = true;
break;
case KoFlake::RightMiddleHandle:
cursor = m_sizeCursors[(2 + rotOctant) % 8];
break;
case KoFlake::BottomRightHandle:
cursor = m_sizeCursors[(3 + rotOctant) % 8];
cornerHandle = true;
break;
case KoFlake::BottomMiddleHandle:
cursor = m_sizeCursors[(4 + rotOctant) % 8];
break;
case KoFlake::BottomLeftHandle:
cursor = m_sizeCursors[(5 + rotOctant) % 8];
cornerHandle = true;
break;
case KoFlake::LeftMiddleHandle:
cursor = m_sizeCursors[(6 + rotOctant) % 8];
break;
case KoFlake::TopLeftHandle:
cursor = m_sizeCursors[(7 + rotOctant) % 8];
cornerHandle = true;
break;
case KoFlake::NoHandle:
cursor = Qt::SizeAllCursor;
statusText = i18n("Click and drag to move selection.");
break;
}
if (cornerHandle) {
statusText = i18n("Click and drag to resize selection. Middle click to set highlighted position.");
}
}
if (!editable) {
cursor = Qt::ArrowCursor;
}
} else {
// there used to be guides... :'''(
}
useCursor(cursor);
if (currentStrategy() == 0) {
emit statusTextChanged(statusText);
}
}
void DefaultTool::paint(QPainter &painter, const KoViewConverter &converter)
{
KoSelection *selection = koSelection();
if (selection) {
this->m_decorator = new SelectionDecorator(canvas()->resourceManager());
{
/**
* Selection masks don't render the outline of the shapes, so we should
* do that explicitly when rendering them via selection
*/
KisCanvas2 *kisCanvas = static_cast<KisCanvas2 *>(canvas());
KisNodeSP node = kisCanvas->viewManager()->nodeManager()->activeNode();
const bool isSelectionMask = node && node->inherits("KisSelectionMask");
m_decorator->setForceShapeOutlines(isSelectionMask);
}
m_decorator->setSelection(selection);
m_decorator->setHandleRadius(handleRadius());
m_decorator->setShowFillGradientHandles(hasInteractioFactory(EditFillGradientFactoryId));
m_decorator->setShowStrokeFillGradientHandles(hasInteractioFactory(EditStrokeGradientFactoryId));
m_decorator->paint(painter, converter);
}
KoInteractionTool::paint(painter, converter);
painter.save();
painter.setTransform(converter.documentToView(), true);
canvas()->snapGuide()->paint(painter, converter);
painter.restore();
}
bool DefaultTool::isValidForCurrentLayer() const
{
// if the currently active node has a shape manager, then it is
// probably our client :)
KisCanvas2 *kisCanvas = static_cast<KisCanvas2 *>(canvas());
return bool(kisCanvas->localShapeManager());
}
KoShapeManager *DefaultTool::shapeManager() const {
return canvas()->shapeManager();
}
void DefaultTool::mousePressEvent(KoPointerEvent *event)
{
// this tool only works on a vector layer right now, so give a warning if another layer type is trying to use it
if (!isValidForCurrentLayer()) {
KisCanvas2 *kiscanvas = static_cast<KisCanvas2 *>(canvas());
kiscanvas->viewManager()->showFloatingMessage(
i18n("This tool only works on vector layers. You probably want the move tool."),
QIcon(), 2000, KisFloatingMessage::Medium, Qt::AlignCenter);
return;
}
KoInteractionTool::mousePressEvent(event);
updateCursor();
}
void DefaultTool::mouseMoveEvent(KoPointerEvent *event)
{
KoInteractionTool::mouseMoveEvent(event);
if (currentStrategy() == 0 && koSelection() && koSelection()->count() > 0) {
QRectF bound = handlesSize();
if (bound.contains(event->point)) {
bool inside;
KoFlake::SelectionHandle newDirection = handleAt(event->point, &inside);
if (inside != m_mouseWasInsideHandles || m_lastHandle != newDirection) {
m_lastHandle = newDirection;
m_mouseWasInsideHandles = inside;
//repaintDecorations();
}
} else {
/*if (m_lastHandle != KoFlake::NoHandle)
repaintDecorations(); */
m_lastHandle = KoFlake::NoHandle;
m_mouseWasInsideHandles = false;
// there used to be guides... :'''(
}
} else {
// there used to be guides... :'''(
}
updateCursor();
}
QRectF DefaultTool::handlesSize()
{
KoSelection *selection = koSelection();
if (!selection || !selection->count()) return QRectF();
recalcSelectionBox(selection);
QRectF bound = m_selectionOutline.boundingRect();
// expansion Border
if (!canvas() || !canvas()->viewConverter()) {
return bound;
}
QPointF border = canvas()->viewConverter()->viewToDocument(QPointF(HANDLE_DISTANCE, HANDLE_DISTANCE));
bound.adjust(-border.x(), -border.y(), border.x(), border.y());
return bound;
}
void DefaultTool::mouseReleaseEvent(KoPointerEvent *event)
{
KoInteractionTool::mouseReleaseEvent(event);
updateCursor();
// This makes sure the decorations that are shown are refreshed. especally the "T" icon
canvas()->updateCanvas(QRectF(0,0,canvas()->canvasWidget()->width(), canvas()->canvasWidget()->height()));
}
void DefaultTool::mouseDoubleClickEvent(KoPointerEvent *event)
{
KoSelection *selection = koSelection();
KoShape *shape = shapeManager()->shapeAt(event->point, KoFlake::ShapeOnTop);
if (shape && selection && !selection->isSelected(shape)) {
if (!(event->modifiers() & Qt::ShiftModifier)) {
selection->deselectAll();
}
selection->select(shape);
}
explicitUserStrokeEndRequest();
}
bool DefaultTool::moveSelection(int direction, Qt::KeyboardModifiers modifiers)
{
bool result = false;
qreal x = 0.0, y = 0.0;
if (direction == Qt::Key_Left) {
x = -5;
} else if (direction == Qt::Key_Right) {
x = 5;
} else if (direction == Qt::Key_Up) {
y = -5;
} else if (direction == Qt::Key_Down) {
y = 5;
}
if (x != 0.0 || y != 0.0) { // actually move
if ((modifiers & Qt::ShiftModifier) != 0) {
x *= 10;
y *= 10;
} else if ((modifiers & Qt::AltModifier) != 0) { // more precise
x /= 5;
y /= 5;
}
QList<KoShape *> shapes = koSelection()->selectedEditableShapes();
if (!shapes.isEmpty()) {
canvas()->addCommand(new KoShapeMoveCommand(shapes, QPointF(x, y)));
result = true;
}
}
return result;
}
void DefaultTool::keyPressEvent(QKeyEvent *event)
{
KoInteractionTool::keyPressEvent(event);
if (currentStrategy() == 0) {
switch (event->key()) {
case Qt::Key_Left:
case Qt::Key_Right:
case Qt::Key_Up:
case Qt::Key_Down:
if (moveSelection(event->key(), event->modifiers())) {
event->accept();
}
break;
case Qt::Key_1:
case Qt::Key_2:
case Qt::Key_3:
case Qt::Key_4:
case Qt::Key_5:
canvas()->resourceManager()->setResource(HotPosition, event->key() - Qt::Key_1);
event->accept();
break;
default:
return;
}
}
}
void DefaultTool::repaintDecorations()
{
if (koSelection() && koSelection()->count() > 0) {
canvas()->updateCanvas(handlesSize());
}
}
void DefaultTool::copy() const
{
// all the selected shapes, not only editable!
QList<KoShape *> shapes = koSelection()->selectedShapes();
if (!shapes.isEmpty()) {
KoDrag drag;
drag.setSvg(shapes);
drag.addToClipboard();
}
}
void DefaultTool::deleteSelection()
{
QList<KoShape *> shapes;
foreach (KoShape *s, koSelection()->selectedShapes()) {
if (s->isGeometryProtected()) {
continue;
}
shapes << s;
}
if (!shapes.empty()) {
canvas()->addCommand(canvas()->shapeController()->removeShapes(shapes));
}
}
bool DefaultTool::paste()
{
// we no longer have to do anything as tool Proxy will do it for us
return false;
}
KoSelection *DefaultTool::koSelection() const
{
Q_ASSERT(canvas());
Q_ASSERT(canvas()->selectedShapesProxy());
return canvas()->selectedShapesProxy()->selection();
}
KoFlake::SelectionHandle DefaultTool::handleAt(const QPointF &point, bool *innerHandleMeaning)
{
// check for handles in this order; meaning that when handles overlap the one on top is chosen
static const KoFlake::SelectionHandle handleOrder[] = {
KoFlake::BottomRightHandle,
KoFlake::TopLeftHandle,
KoFlake::BottomLeftHandle,
KoFlake::TopRightHandle,
KoFlake::BottomMiddleHandle,
KoFlake::RightMiddleHandle,
KoFlake::LeftMiddleHandle,
KoFlake::TopMiddleHandle,
KoFlake::NoHandle
};
const KoViewConverter *converter = canvas()->viewConverter();
KoSelection *selection = koSelection();
if (!selection || !selection->count() || !converter) {
return KoFlake::NoHandle;
}
recalcSelectionBox(selection);
if (innerHandleMeaning) {
QPainterPath path;
path.addPolygon(m_selectionOutline);
*innerHandleMeaning = path.contains(point) || path.intersects(handlePaintRect(point));
}
const QPointF viewPoint = converter->documentToView(point);
for (int i = 0; i < KoFlake::NoHandle; ++i) {
KoFlake::SelectionHandle handle = handleOrder[i];
const QPointF handlePoint = converter->documentToView(m_selectionBox[handle]);
const qreal distanceSq = kisSquareDistance(viewPoint, handlePoint);
// if just inside the outline
if (distanceSq < HANDLE_DISTANCE_SQ) {
if (innerHandleMeaning) {
if (distanceSq < INNER_HANDLE_DISTANCE_SQ) {
*innerHandleMeaning = true;
}
}
return handle;
}
}
return KoFlake::NoHandle;
}
void DefaultTool::recalcSelectionBox(KoSelection *selection)
{
KIS_ASSERT_RECOVER_RETURN(selection->count());
QTransform matrix = selection->absoluteTransformation();
m_selectionOutline = matrix.map(QPolygonF(selection->outlineRect()));
m_angle = 0.0;
QPolygonF outline = m_selectionOutline; //shorter name in the following :)
m_selectionBox[KoFlake::TopMiddleHandle] = (outline.value(0) + outline.value(1)) / 2;
m_selectionBox[KoFlake::TopRightHandle] = outline.value(1);
m_selectionBox[KoFlake::RightMiddleHandle] = (outline.value(1) + outline.value(2)) / 2;
m_selectionBox[KoFlake::BottomRightHandle] = outline.value(2);
m_selectionBox[KoFlake::BottomMiddleHandle] = (outline.value(2) + outline.value(3)) / 2;
m_selectionBox[KoFlake::BottomLeftHandle] = outline.value(3);
m_selectionBox[KoFlake::LeftMiddleHandle] = (outline.value(3) + outline.value(0)) / 2;
m_selectionBox[KoFlake::TopLeftHandle] = outline.value(0);
if (selection->count() == 1) {
#if 0 // TODO detect mirroring
KoShape *s = koSelection()->firstSelectedShape();
if (s->scaleX() < 0) { // vertically mirrored: swap left / right
std::swap(m_selectionBox[KoFlake::TopLeftHandle], m_selectionBox[KoFlake::TopRightHandle]);
std::swap(m_selectionBox[KoFlake::LeftMiddleHandle], m_selectionBox[KoFlake::RightMiddleHandle]);
std::swap(m_selectionBox[KoFlake::BottomLeftHandle], m_selectionBox[KoFlake::BottomRightHandle]);
}
if (s->scaleY() < 0) { // vertically mirrored: swap top / bottom
std::swap(m_selectionBox[KoFlake::TopLeftHandle], m_selectionBox[KoFlake::BottomLeftHandle]);
std::swap(m_selectionBox[KoFlake::TopMiddleHandle], m_selectionBox[KoFlake::BottomMiddleHandle]);
std::swap(m_selectionBox[KoFlake::TopRightHandle], m_selectionBox[KoFlake::BottomRightHandle]);
}
#endif
}
}
void DefaultTool::activate(ToolActivation activation, const QSet<KoShape *> &shapes)
{
KoToolBase::activate(activation, shapes);
QAction *actionBringToFront = action("object_order_front");
connect(actionBringToFront, SIGNAL(triggered()), this, SLOT(selectionBringToFront()), Qt::UniqueConnection);
QAction *actionRaise = action("object_order_raise");
connect(actionRaise, SIGNAL(triggered()), this, SLOT(selectionMoveUp()), Qt::UniqueConnection);
QAction *actionLower = action("object_order_lower");
connect(actionLower, SIGNAL(triggered()), this, SLOT(selectionMoveDown()));
QAction *actionSendToBack = action("object_order_back");
connect(actionSendToBack, SIGNAL(triggered()), this, SLOT(selectionSendToBack()), Qt::UniqueConnection);
QAction *actionGroupBottom = action("object_group");
connect(actionGroupBottom, SIGNAL(triggered()), this, SLOT(selectionGroup()), Qt::UniqueConnection);
QAction *actionUngroupBottom = action("object_ungroup");
connect(actionUngroupBottom, SIGNAL(triggered()), this, SLOT(selectionUngroup()), Qt::UniqueConnection);
QAction *actionSplit = action("object_split");
connect(actionSplit, SIGNAL(triggered()), this, SLOT(selectionSplitShapes()), Qt::UniqueConnection);
connect(m_alignSignalsMapper, SIGNAL(mapped(int)), SLOT(selectionAlign(int)));
connect(m_distributeSignalsMapper, SIGNAL(mapped(int)), SLOT(selectionDistribute(int)));
connect(m_transformSignalsMapper, SIGNAL(mapped(int)), SLOT(selectionTransform(int)));
connect(m_booleanSignalsMapper, SIGNAL(mapped(int)), SLOT(selectionBooleanOp(int)));
m_mouseWasInsideHandles = false;
m_lastHandle = KoFlake::NoHandle;
useCursor(Qt::ArrowCursor);
repaintDecorations();
updateActions();
if (m_tabbedOptionWidget) {
m_tabbedOptionWidget->activate();
}
}
void DefaultTool::deactivate()
{
KoToolBase::deactivate();
QAction *actionBringToFront = action("object_order_front");
disconnect(actionBringToFront, 0, this, 0);
QAction *actionRaise = action("object_order_raise");
disconnect(actionRaise, 0, this, 0);
QAction *actionLower = action("object_order_lower");
disconnect(actionLower, 0, this, 0);
QAction *actionSendToBack = action("object_order_back");
disconnect(actionSendToBack, 0, this, 0);
QAction *actionGroupBottom = action("object_group");
disconnect(actionGroupBottom, 0, this, 0);
QAction *actionUngroupBottom = action("object_ungroup");
disconnect(actionUngroupBottom, 0, this, 0);
QAction *actionSplit = action("object_split");
disconnect(actionSplit, 0, this, 0);
disconnect(m_alignSignalsMapper, 0, this, 0);
disconnect(m_distributeSignalsMapper, 0, this, 0);
disconnect(m_transformSignalsMapper, 0, this, 0);
disconnect(m_booleanSignalsMapper, 0, this, 0);
if (m_tabbedOptionWidget) {
m_tabbedOptionWidget->deactivate();
}
}
void DefaultTool::selectionGroup()
{
KoSelection *selection = koSelection();
if (!selection) return;
QList<KoShape *> selectedShapes = selection->selectedEditableShapes();
std::sort(selectedShapes.begin(), selectedShapes.end(), KoShape::compareShapeZIndex);
if (selectedShapes.isEmpty()) return;
const int groupZIndex = selectedShapes.last()->zIndex();
KoShapeGroup *group = new KoShapeGroup();
group->setZIndex(groupZIndex);
// TODO what if only one shape is left?
KUndo2Command *cmd = new KUndo2Command(kundo2_i18n("Group shapes"));
new KoKeepShapesSelectedCommand(selectedShapes, {}, canvas()->selectedShapesProxy(), false, cmd);
canvas()->shapeController()->addShapeDirect(group, 0, cmd);
new KoShapeGroupCommand(group, selectedShapes, true, cmd);
new KoKeepShapesSelectedCommand({}, {group}, canvas()->selectedShapesProxy(), true, cmd);
canvas()->addCommand(cmd);
// update selection so we can ungroup immediately again
selection->deselectAll();
selection->select(group);
}
void DefaultTool::selectionUngroup()
{
KoSelection *selection = koSelection();
if (!selection) return;
QList<KoShape *> selectedShapes = selection->selectedEditableShapes();
std::sort(selectedShapes.begin(), selectedShapes.end(), KoShape::compareShapeZIndex);
KUndo2Command *cmd = 0;
QList<KoShape*> newShapes;
// add a ungroup command for each found shape container to the macro command
Q_FOREACH (KoShape *shape, selectedShapes) {
KoShapeGroup *group = dynamic_cast<KoShapeGroup *>(shape);
if (group) {
if (!cmd) {
cmd = new KUndo2Command(kundo2_i18n("Ungroup shapes"));
new KoKeepShapesSelectedCommand(selectedShapes, {}, canvas()->selectedShapesProxy(), false, cmd);
}
newShapes << group->shapes();
new KoShapeUngroupCommand(group, group->shapes(),
group->parent() ? QList<KoShape *>() : shapeManager()->topLevelShapes(),
cmd);
canvas()->shapeController()->removeShape(group, cmd);
}
}
if (cmd) {
new KoKeepShapesSelectedCommand({}, newShapes, canvas()->selectedShapesProxy(), true, cmd);
canvas()->addCommand(cmd);
}
}
void DefaultTool::selectionTransform(int transformAction)
{
KoSelection *selection = koSelection();
if (!selection) return;
QList<KoShape *> editableShapes = selection->selectedEditableShapes();
if (editableShapes.isEmpty()) {
return;
}
QTransform applyTransform;
bool shouldReset = false;
KUndo2MagicString actionName = kundo2_noi18n("BUG: No transform action");
switch (TransformActionType(transformAction)) {
case TransformRotate90CW:
applyTransform.rotate(90.0);
actionName = kundo2_i18n("Rotate Object 90° CW");
break;
case TransformRotate90CCW:
applyTransform.rotate(-90.0);
actionName = kundo2_i18n("Rotate Object 90° CCW");
break;
case TransformRotate180:
applyTransform.rotate(180.0);
actionName = kundo2_i18n("Rotate Object 180°");
break;
case TransformMirrorX:
applyTransform.scale(-1.0, 1.0);
actionName = kundo2_i18n("Mirror Object Horizontally");
break;
case TransformMirrorY:
applyTransform.scale(1.0, -1.0);
actionName = kundo2_i18n("Mirror Object Vertically");
break;
case TransformReset:
shouldReset = true;
actionName = kundo2_i18n("Reset Object Transformations");
break;
}
if (!shouldReset && applyTransform.isIdentity()) return;
QList<QTransform> oldTransforms;
QList<QTransform> newTransforms;
const QRectF outlineRect = KoShape::absoluteOutlineRect(editableShapes);
const QPointF centerPoint = outlineRect.center();
const QTransform centerTrans = QTransform::fromTranslate(centerPoint.x(), centerPoint.y());
const QTransform centerTransInv = QTransform::fromTranslate(-centerPoint.x(), -centerPoint.y());
// we also add selection to the list of transformed shapes, so that its outline is updated correctly
QList<KoShape*> transformedShapes = editableShapes;
transformedShapes << selection;
Q_FOREACH (KoShape *shape, transformedShapes) {
oldTransforms.append(shape->transformation());
QTransform t;
if (!shouldReset) {
const QTransform world = shape->absoluteTransformation();
t = world * centerTransInv * applyTransform * centerTrans * world.inverted() * shape->transformation();
} else {
const QPointF center = shape->outlineRect().center();
const QPointF offset = shape->transformation().map(center) - center;
t = QTransform::fromTranslate(offset.x(), offset.y());
}
newTransforms.append(t);
}
KoShapeTransformCommand *cmd = new KoShapeTransformCommand(transformedShapes, oldTransforms, newTransforms);
cmd->setText(actionName);
canvas()->addCommand(cmd);
}
void DefaultTool::selectionBooleanOp(int booleanOp)
{
KoSelection *selection = koSelection();
if (!selection) return;
QList<KoShape *> editableShapes = selection->selectedEditableShapes();
if (editableShapes.isEmpty()) {
return;
}
QVector<QPainterPath> srcOutlines;
QPainterPath dstOutline;
KUndo2MagicString actionName = kundo2_noi18n("BUG: boolean action name");
// TODO: implement a reference shape selection dialog!
const int referenceShapeIndex = 0;
KoShape *referenceShape = editableShapes[referenceShapeIndex];
KisCanvas2 *kisCanvas = static_cast<KisCanvas2 *>(canvas());
KIS_SAFE_ASSERT_RECOVER_RETURN(kisCanvas);
const QTransform booleanWorkaroundTransform =
KritaUtils::pathShapeBooleanSpaceWorkaround(kisCanvas->image());
Q_FOREACH (KoShape *shape, editableShapes) {
srcOutlines <<
booleanWorkaroundTransform.map(
shape->absoluteTransformation().map(
shape->outline()));
}
if (booleanOp == BooleanUnion) {
Q_FOREACH (const QPainterPath &path, srcOutlines) {
dstOutline |= path;
}
actionName = kundo2_i18n("Unite Shapes");
} else if (booleanOp == BooleanIntersection) {
for (int i = 0; i < srcOutlines.size(); i++) {
if (i == 0) {
dstOutline = srcOutlines[i];
} else {
dstOutline &= srcOutlines[i];
}
}
// there is a bug in Qt, sometimes it leaves the resulting
// outline open, so just close it explicitly.
dstOutline.closeSubpath();
actionName = kundo2_i18n("Intersect Shapes");
} else if (booleanOp == BooleanSubtraction) {
for (int i = 0; i < srcOutlines.size(); i++) {
dstOutline = srcOutlines[referenceShapeIndex];
if (i != referenceShapeIndex) {
dstOutline -= srcOutlines[i];
}
}
actionName = kundo2_i18n("Subtract Shapes");
}
dstOutline = booleanWorkaroundTransform.inverted().map(dstOutline);
KoShape *newShape = 0;
if (!dstOutline.isEmpty()) {
newShape = KoPathShape::createShapeFromPainterPath(dstOutline);
}
KUndo2Command *cmd = new KUndo2Command(actionName);
new KoKeepShapesSelectedCommand(editableShapes, {}, canvas()->selectedShapesProxy(), false, cmd);
QList<KoShape*> newSelectedShapes;
if (newShape) {
newShape->setBackground(referenceShape->background());
newShape->setStroke(referenceShape->stroke());
newShape->setZIndex(referenceShape->zIndex());
KoShapeContainer *parent = referenceShape->parent();
canvas()->shapeController()->addShapeDirect(newShape, parent, cmd);
newSelectedShapes << newShape;
}
canvas()->shapeController()->removeShapes(editableShapes, cmd);
new KoKeepShapesSelectedCommand({}, newSelectedShapes, canvas()->selectedShapesProxy(), true, cmd);
canvas()->addCommand(cmd);
}
void DefaultTool::selectionSplitShapes()
{
KoSelection *selection = koSelection();
if (!selection) return;
QList<KoShape *> editableShapes = selection->selectedEditableShapes();
if (editableShapes.isEmpty()) {
return;
}
KUndo2Command *cmd = new KUndo2Command(kundo2_i18n("Split Shapes"));
new KoKeepShapesSelectedCommand(editableShapes, {}, canvas()->selectedShapesProxy(), false, cmd);
QList<KoShape*> newShapes;
Q_FOREACH (KoShape *shape, editableShapes) {
KoPathShape *pathShape = dynamic_cast<KoPathShape*>(shape);
if (!pathShape) return;
QList<KoPathShape*> splitShapes;
if (pathShape->separate(splitShapes)) {
QList<KoShape*> normalShapes = implicitCastList<KoShape*>(splitShapes);
KoShapeContainer *parent = shape->parent();
canvas()->shapeController()->addShapesDirect(normalShapes, parent, cmd);
canvas()->shapeController()->removeShape(shape, cmd);
newShapes << normalShapes;
}
}
new KoKeepShapesSelectedCommand({}, newShapes, canvas()->selectedShapesProxy(), true, cmd);
canvas()->addCommand(cmd);
}
void DefaultTool::selectionAlign(int _align)
{
KoShapeAlignCommand::Align align =
static_cast<KoShapeAlignCommand::Align>(_align);
KoSelection *selection = koSelection();
if (!selection) return;
QList<KoShape *> editableShapes = selection->selectedEditableShapes();
if (editableShapes.isEmpty()) {
return;
}
// TODO add an option to the widget so that one can align to the page
// with multiple selected shapes too
QRectF bb;
// single selected shape is automatically aligned to document rect
if (editableShapes.count() == 1) {
if (!canvas()->resourceManager()->hasResource(KoCanvasResourceProvider::PageSize)) {
return;
}
bb = QRectF(QPointF(0, 0), canvas()->resourceManager()->sizeResource(KoCanvasResourceProvider::PageSize));
} else {
bb = KoShape::absoluteOutlineRect(editableShapes);
}
KoShapeAlignCommand *cmd = new KoShapeAlignCommand(editableShapes, align, bb);
canvas()->addCommand(cmd);
}
void DefaultTool::selectionDistribute(int _distribute)
{
KoShapeDistributeCommand::Distribute distribute =
static_cast<KoShapeDistributeCommand::Distribute>(_distribute);
KoSelection *selection = koSelection();
if (!selection) return;
QList<KoShape *> editableShapes = selection->selectedEditableShapes();
if (editableShapes.size() < 3) {
return;
}
QRectF bb = KoShape::absoluteOutlineRect(editableShapes);
KoShapeDistributeCommand *cmd = new KoShapeDistributeCommand(editableShapes, distribute, bb);
canvas()->addCommand(cmd);
}
void DefaultTool::selectionBringToFront()
{
selectionReorder(KoShapeReorderCommand::BringToFront);
}
void DefaultTool::selectionMoveUp()
{
selectionReorder(KoShapeReorderCommand::RaiseShape);
}
void DefaultTool::selectionMoveDown()
{
selectionReorder(KoShapeReorderCommand::LowerShape);
}
void DefaultTool::selectionSendToBack()
{
selectionReorder(KoShapeReorderCommand::SendToBack);
}
void DefaultTool::selectionReorder(KoShapeReorderCommand::MoveShapeType order)
{
KoSelection *selection = koSelection();
if (!selection) {
return;
}
QList<KoShape *> selectedShapes = selection->selectedEditableShapes();
if (selectedShapes.isEmpty()) {
return;
}
KUndo2Command *cmd = KoShapeReorderCommand::createCommand(selectedShapes, shapeManager(), order);
if (cmd) {
canvas()->addCommand(cmd);
}
}
QList<QPointer<QWidget> > DefaultTool::createOptionWidgets()
{
QList<QPointer<QWidget> > widgets;
m_tabbedOptionWidget = new DefaultToolTabbedWidget(this);
if (isActivated()) {
m_tabbedOptionWidget->activate();
}
widgets.append(m_tabbedOptionWidget);
connect(m_tabbedOptionWidget,
SIGNAL(sigSwitchModeEditFillGradient(bool)),
SLOT(slotActivateEditFillGradient(bool)));
connect(m_tabbedOptionWidget,
SIGNAL(sigSwitchModeEditStrokeGradient(bool)),
SLOT(slotActivateEditStrokeGradient(bool)));
return widgets;
}
void DefaultTool::canvasResourceChanged(int key, const QVariant &res)
{
if (key == HotPosition) {
m_hotPosition = KoFlake::AnchorPosition(res.toInt());
repaintDecorations();
}
}
KoInteractionStrategy *DefaultTool::createStrategy(KoPointerEvent *event)
{
KoSelection *selection = koSelection();
if (!selection) return nullptr;
bool insideSelection = false;
KoFlake::SelectionHandle handle = handleAt(event->point, &insideSelection);
bool editableShape = !selection->selectedEditableShapes().isEmpty();
const bool selectMultiple = event->modifiers() & Qt::ShiftModifier;
const bool selectNextInStack = event->modifiers() & Qt::ControlModifier;
const bool avoidSelection = event->modifiers() & Qt::AltModifier;
if (selectNextInStack) {
// change the hot selection position when middle clicking on a handle
KoFlake::AnchorPosition newHotPosition = m_hotPosition;
switch (handle) {
case KoFlake::TopMiddleHandle:
newHotPosition = KoFlake::Top;
break;
case KoFlake::TopRightHandle:
newHotPosition = KoFlake::TopRight;
break;
case KoFlake::RightMiddleHandle:
newHotPosition = KoFlake::Right;
break;
case KoFlake::BottomRightHandle:
newHotPosition = KoFlake::BottomRight;
break;
case KoFlake::BottomMiddleHandle:
newHotPosition = KoFlake::Bottom;
break;
case KoFlake::BottomLeftHandle:
newHotPosition = KoFlake::BottomLeft;
break;
case KoFlake::LeftMiddleHandle:
newHotPosition = KoFlake::Left;
break;
case KoFlake::TopLeftHandle:
newHotPosition = KoFlake::TopLeft;
break;
case KoFlake::NoHandle:
default:
// check if we had hit the center point
const KoViewConverter *converter = canvas()->viewConverter();
QPointF pt = converter->documentToView(event->point);
// TODO: use calculated values instead!
QPointF centerPt = converter->documentToView(selection->absolutePosition());
if (kisSquareDistance(pt, centerPt) < HANDLE_DISTANCE_SQ) {
newHotPosition = KoFlake::Center;
}
break;
}
if (m_hotPosition != newHotPosition) {
canvas()->resourceManager()->setResource(HotPosition, newHotPosition);
return new NopInteractionStrategy(this);
}
}
if (!avoidSelection && editableShape) {
// manipulation of selected shapes goes first
if (handle != KoFlake::NoHandle) {
// resizing or shearing only with left mouse button
if (insideSelection) {
bool forceUniformScaling = m_tabbedOptionWidget && m_tabbedOptionWidget->useUniformScaling();
return new ShapeResizeStrategy(this, selection, event->point, handle, forceUniformScaling);
}
if (handle == KoFlake::TopMiddleHandle || handle == KoFlake::RightMiddleHandle ||
handle == KoFlake::BottomMiddleHandle || handle == KoFlake::LeftMiddleHandle) {
return new ShapeShearStrategy(this, selection, event->point, handle);
}
// rotating is allowed for right mouse button too
if (handle == KoFlake::TopLeftHandle || handle == KoFlake::TopRightHandle ||
handle == KoFlake::BottomLeftHandle || handle == KoFlake::BottomRightHandle) {
return new ShapeRotateStrategy(this, selection, event->point, event->buttons());
}
}
if (!selectMultiple && !selectNextInStack) {
if (insideSelection) {
return new ShapeMoveStrategy(this, selection, event->point);
}
}
}
KoShape *shape = shapeManager()->shapeAt(event->point, selectNextInStack ? KoFlake::NextUnselected : KoFlake::ShapeOnTop);
if (avoidSelection || (!shape && handle == KoFlake::NoHandle)) {
if (!selectMultiple) {
repaintDecorations();
selection->deselectAll();
}
return new SelectionInteractionStrategy(this, event->point, false);
}
if (selection->isSelected(shape)) {
if (selectMultiple) {
repaintDecorations();
selection->deselect(shape);
}
} else if (handle == KoFlake::NoHandle) { // clicked on shape which is not selected
repaintDecorations();
if (!selectMultiple) {
selection->deselectAll();
}
selection->select(shape);
repaintDecorations();
// tablet selection isn't precise and may lead to a move, preventing that
if (event->isTabletEvent()) {
return new NopInteractionStrategy(this);
}
return new ShapeMoveStrategy(this, selection, event->point);
}
return 0;
}
void DefaultTool::updateActions()
{
QList<KoShape*> editableShapes;
if (koSelection()) {
editableShapes = koSelection()->selectedEditableShapes();
}
const bool hasEditableShapes = !editableShapes.isEmpty();
action("object_order_front")->setEnabled(hasEditableShapes);
action("object_order_raise")->setEnabled(hasEditableShapes);
action("object_order_lower")->setEnabled(hasEditableShapes);
action("object_order_back")->setEnabled(hasEditableShapes);
action("object_transform_rotate_90_cw")->setEnabled(hasEditableShapes);
action("object_transform_rotate_90_ccw")->setEnabled(hasEditableShapes);
action("object_transform_rotate_180")->setEnabled(hasEditableShapes);
action("object_transform_mirror_horizontally")->setEnabled(hasEditableShapes);
action("object_transform_mirror_vertically")->setEnabled(hasEditableShapes);
action("object_transform_reset")->setEnabled(hasEditableShapes);
const bool multipleSelected = editableShapes.size() > 1;
const bool alignmentEnabled =
multipleSelected ||
(!editableShapes.isEmpty() &&
canvas()->resourceManager()->hasResource(KoCanvasResourceProvider::PageSize));
action("object_align_horizontal_left")->setEnabled(alignmentEnabled);
action("object_align_horizontal_center")->setEnabled(alignmentEnabled);
action("object_align_horizontal_right")->setEnabled(alignmentEnabled);
action("object_align_vertical_top")->setEnabled(alignmentEnabled);
action("object_align_vertical_center")->setEnabled(alignmentEnabled);
action("object_align_vertical_bottom")->setEnabled(alignmentEnabled);
const bool distributionEnabled = editableShapes.size() > 2;
action("object_distribute_horizontal_left")->setEnabled(distributionEnabled);
action("object_distribute_horizontal_center")->setEnabled(distributionEnabled);
action("object_distribute_horizontal_right")->setEnabled(distributionEnabled);
action("object_distribute_horizontal_gaps")->setEnabled(distributionEnabled);
action("object_distribute_vertical_top")->setEnabled(distributionEnabled);
action("object_distribute_vertical_center")->setEnabled(distributionEnabled);
action("object_distribute_vertical_bottom")->setEnabled(distributionEnabled);
action("object_distribute_vertical_gaps")->setEnabled(distributionEnabled);
updateDistinctiveActions(editableShapes);
emit selectionChanged(editableShapes.size());
}
void DefaultTool::updateDistinctiveActions(const QList<KoShape*> &editableShapes) {
const bool multipleSelected = editableShapes.size() > 1;
action("object_group")->setEnabled(multipleSelected);
action("object_unite")->setEnabled(multipleSelected);
action("object_intersect")->setEnabled(multipleSelected);
action("object_subtract")->setEnabled(multipleSelected);
bool hasShapesWithMultipleSegments = false;
Q_FOREACH (KoShape *shape, editableShapes) {
KoPathShape *pathShape = dynamic_cast<KoPathShape *>(shape);
if (pathShape && pathShape->subpathCount() > 1) {
hasShapesWithMultipleSegments = true;
break;
}
}
action("object_split")->setEnabled(hasShapesWithMultipleSegments);
bool hasGroupShape = false;
foreach (KoShape *shape, editableShapes) {
if (dynamic_cast<KoShapeGroup *>(shape)) {
hasGroupShape = true;
break;
}
}
action("object_ungroup")->setEnabled(hasGroupShape);
}
KoToolSelection *DefaultTool::selection()
{
return m_selectionHandler;
}
QMenu* DefaultTool::popupActionsMenu()
{
if (m_contextMenu) {
m_contextMenu->clear();
m_contextMenu->addSection(i18n("Vector Shape Actions"));
m_contextMenu->addSeparator();
QMenu *transform = m_contextMenu->addMenu(i18n("Transform"));
transform->addAction(action("object_transform_rotate_90_cw"));
transform->addAction(action("object_transform_rotate_90_ccw"));
transform->addAction(action("object_transform_rotate_180"));
transform->addSeparator();
transform->addAction(action("object_transform_mirror_horizontally"));
transform->addAction(action("object_transform_mirror_vertically"));
transform->addSeparator();
transform->addAction(action("object_transform_reset"));
if (action("object_unite")->isEnabled() ||
action("object_intersect")->isEnabled() ||
action("object_subtract")->isEnabled() ||
action("object_split")->isEnabled()) {
QMenu *transform = m_contextMenu->addMenu(i18n("Logical Operations"));
transform->addAction(action("object_unite"));
transform->addAction(action("object_intersect"));
transform->addAction(action("object_subtract"));
transform->addAction(action("object_split"));
}
m_contextMenu->addSeparator();
m_contextMenu->addAction(action("edit_cut"));
m_contextMenu->addAction(action("edit_copy"));
m_contextMenu->addAction(action("edit_paste"));
m_contextMenu->addSeparator();
m_contextMenu->addAction(action("object_order_front"));
m_contextMenu->addAction(action("object_order_raise"));
m_contextMenu->addAction(action("object_order_lower"));
m_contextMenu->addAction(action("object_order_back"));
if (action("object_group")->isEnabled() || action("object_ungroup")->isEnabled()) {
m_contextMenu->addSeparator();
m_contextMenu->addAction(action("object_group"));
m_contextMenu->addAction(action("object_ungroup"));
}
}
return m_contextMenu.data();
}
void DefaultTool::addTransformActions(QMenu *menu) const {
menu->addAction(action("object_transform_rotate_90_cw"));
menu->addAction(action("object_transform_rotate_90_ccw"));
menu->addAction(action("object_transform_rotate_180"));
menu->addSeparator();
menu->addAction(action("object_transform_mirror_horizontally"));
menu->addAction(action("object_transform_mirror_vertically"));
menu->addSeparator();
menu->addAction(action("object_transform_reset"));
}
void DefaultTool::explicitUserStrokeEndRequest()
{
QList<KoShape *> shapes = koSelection()->selectedEditableShapesAndDelegates();
emit activateTemporary(KoToolManager::instance()->preferredToolForSelection(shapes));
}